Dec 232017
Whitewater Group Actor source code for business charts, Version 2.0.
File CHART20.ZIP from The Programmer’s Corner in
Category Miscellaneous Language Source Code
Whitewater Group Actor source code for business charts, Version 2.0.
File Name File Size Zip Size Zip Type
CDESIGN.TXT 16220 4421 deflated
CHART.LOD 1028 304 deflated
CHART20.EXE 124768 50068 deflated
CHART20.IMA 201264 99923 deflated
CHARTSEA.LOD 1129 337 deflated
CITIES.CHT 37 35 deflated
CLASSES 0 0 stored
BRUSH.CLS 1932 823 deflated
CHART.CLS 5328 1818 deflated
CHARTAPP.CLS 987 506 deflated
CHARTCHI.CLS 724 367 deflated
CHARTDIA.CLS 1497 612 deflated
CHARTWIN.CLS 9732 3147 deflated
HBARCHAR.CLS 3203 1124 deflated
PIECHART.CLS 4123 1399 deflated
VBARCHAR.CLS 3093 1123 deflated
CRIME.CHT 78 69 deflated
INSTCHAR.BAT 2540 1068 deflated
MAKECHAR.BAT 1012 380 deflated
READCHAR.TXT 6025 2505 deflated
RES 0 0 stored
CHART.H 1139 427 deflated
CHART.ICO 1038 146 deflated
CHART20.RC 13442 4831 deflated
CHARTDEV.RC 29268 7452 deflated
TEST.CHT 33 28 deflated
ZOO.EXE 40078 23718 deflated

Download File CHART20.ZIP Here

Contents of the CDESIGN.TXT file

Notes on the design of the Chart application

Creating Business Charts in Actor

Charts are a convenient way to convey quantitative information
graphically. If a picture is worth a thousand words, then
surely a pie chart is worth a few hundred bytes. This document
describes how charts can be created in Actor. You will be able
to use the classes as they are within your own applications, or
customize them by creating descendant classes.

Designing the Objects

When developing any program it's important to try to determine
the logical entities in the system and what their functions and
data are. In this case, you want to create vertical and
horizontal bar charts, pie charts and display them in a window.

All chart objects are responsible for drawing themselves,
rescaling if necessary, and loading and saving. The only real
difference between, say, a vertical bar chart and a pie chart
is how it draws. Conceptually, all three kinds of charts are
the same. Therefore, you will want to create a formal class
called Chart from the actual vertical bar chart, horizontal bar
chart and pie chart classes descend. All of the common
characteristics of the charts will be written in the Chart
class and automatically inherited by the descendant classes.
Since there is nothing really chart-like already in the system,
the Chart class should descend directly from Object.

| |
Chart WindowsObject
| |
----------------- Window
| | | |
PieChart | VBarChart ChartWindow

A Chart object is made up of other instance variables. These
include two Collection objects, data and labels, which store
the data points and their text labels. In addition, Chart
objects must keep track of the scale of the chart and the area
in which they are drawn. These can be stored in two Point
instance variables, scale and area. Lastly, two Integer
objects, lead and space to store the lead spacing below or to
the left of the chart and the space between items.

The Chart Classes

The Chart class will contain the generic, reusable code
applicable to all three types of charts. This includes
initialization, scaling and loading and saving. The descendant
classes HBarChart, VBarChart and PieChart will implement the
details of drawing the chart and adjusting the scaling.

You must define the new method for the Chart class. The new
method is required since Chart objects are to be automatically
initialize when they are created. Since the new message is
used to create new objects, it is a class method, so be sure to
select the Options menu Class Methods command before typing it
in. Then after you've compiled it by selecting the Accept!
menu command, switch back to Object Methods.

The new class method for Chart

/* Class method to automatically initialize charts. */
Def new(self)
{ ^init(new(self:Behavior));

Initializing Chart Objects

The init method will be used to initialize the instance
variables of new Chart objects. Since the descendant classes
may need to have different starting values for these instance
variables, it's best to break the initialization into several
smaller methods.

/* Initialize a new Chart object and it's variables.
The data and labels collections have an initial size 10
but will automatically grow to accommodate more data.
data: a collection of data values.
labels: a collection of text lables.
space: an integer indicating the spacing between items.
scale: a point indicating the scale to be used.
lead: a point indicating the lead spacing to be used.
Def init(self)
data := new(OrderedCollection, 10);
labels := new(OrderedCollection, 10);
space := 10;

/* Set the scale instance variable to a point.
Descendant classes may override this method. */
Def resetScale(self)
scale := 10@10;

/* Set the lead instance variable to a point.
Descendant classes may override this method. */
Def resetLead(self)
lead := 10@10;

Accessing the instance variables

Rather than use "dot notation", it's better to define some
simple methods to provide access to the underlying instance
variables of Chart objects. This will make it easier for us to
test our chart objects and reduces the dependencies on the
physical representation.

/* Set the labels of a chart to the given collection. */
Def setLabels(self, aCollection)
{ labels := aCollection;

/* Set the data of a chart to the given collection. */
Def setData(self, aCollection)
{ data := aCollection;

/* Set the area of a chart to the given point.
This must be done before drawing. */
Def setArea(self, aPoint)
{ area := aPoint;


Since Chart objects should behave like other graphical objects,
such as rectangles, ellipses and so on, they should respond to
the same messages or protocol for drawing. The convention for
drawing graphical objects is that you send the object a draw
message with the display context of the window you want to draw
in as an argument.

Since drawing a chart consists of drawing the data and then
drawing the labels, you can define this high level approach in
the Chart class, and leave the details to the descendant
classes. Thus the draw method for class Chart is as follows.

/* Draw a chart in the given display context. The area must
have been set, otherwise raise an error condition. */
Def draw(self, context)
if area then
drawData(self, context);
drawLabels(self, context);
error(self, stackTop(), #areaNilError);

This code uses the Actor error message to define a customized
error called #areaNilError. You can define your own errors and
handlers as described in sections 2.1.5 and 3.3.3 of the Actor
Language Manual.

You can also define a drawText method that encapsulates the
Windows TextOut function.

/* Draw the string str in the context at location x,y */
Def drawText(self, x, y, str, context)
Call TextOut(context, x, y, str, size(str));

Saving Charts to Disk

Chart objects respond to load and save messages by saving
themselves to disk as text. The labels and values are written
to disk in response to a save message and read in again in
response to a load message. The code for these methods is
quite straightforward. Section 2.10 of the Actor manual shows
other examples of files in Actor.

Creating Descendants of Chart

Now you can create descendant classes of Chart to implement the
details of drawing horizontal bar charts, vertical bar charts
and pie charts. First create the HBarChart class using the
Options menu Make Descendant command. There are no new
instance variables required in any of the descendant classes.

The HBarChart class must define the drawData and drawLabels
methods. You can redefine the resetScale and resetLead methods
called by the init method to override the default
initialization done in class Chart, if necessary.

The drawLabels and drawData methods are quite similar; they
both loop over the collection and either draw a string or a
rectangle at the appropriate location. The code is shown

/* Code for class HBarChart. This class inherits generic
charting behavior from class Chart. */

/* Draw the labels in the given display context. Compute
positions based on the scale and lead. Convert the label
into a string just in case it is not one already.
x, y and str are temporary variables. */
Def drawLabels(self, context | str, x, y)
x := 1; /* left edge */
do(size(labels), /* for each label */
y := y(lead) + i * (y(scale)+space); /* vert. location */
str := asString(labels[i]); /* convert it */
drawText(self, x, y, str, context); /* draw it */

/* Draw the data elements in the given display context.
Each element is drawn as a gray horizontal rectangle.
Compute the positions based on scale and lead.
x, y and dRect are temporary variables. */
Def drawData(self, context | x, y, dRect)
x := x(lead); /* left edge of bar */
do(size(data), /* for each item */
y := y(lead) + i * (y(scale)+space); /* vert. location */
dRect := rect(x, y, /* create a rect */
x + data[i]*x(scale),
y + y(scale));
fill(dRect, stock(GRAY_BRUSH), context); /* draw it */
/* Override the inherited resetLead method to allow room
for the labels on the left edge of the chart. */
Def resetLead(self)
lead := 90@20;

The code for the vertical bar chart class, VBarChart, is
similar to the above except that the text and rectangles are
drawn in different locations.

Other Windows Facilities

For the PieChart class, the implementation of drawLabels and
drawData are different since drawing a pie chart can be done by
calling a Microsoft Windows function directly. To call the Pie
function directly from Actor you would use the following

/* call the Windows Pie function directly. */

Call Pie(context, xLeft, yTop, xRight, yBottom
xStart, yStart, xEnd, yEnd);

The book Programming Windows by Charles Petzold shows some good
examples of the Pie function. It also shows how brushes are
used in order to provide different color pie segments.

Resizing for all charts is handled by defining a reSize method
for the ChartWindow class. This method in turn sends the chart
a message to compute its new scaling factor according to the
largest data element.

Printing of the charts was based on the TextPrinter class from
our BBS system and has been tested with both laser printers and
dot matrix printers.

Creating Charts

To create a new chart, type in the code shown above, or load
the classes and then type the following lines of code in the

/* Create a new chart */

C := new(HBarChart);
setData(C, #(18, 9, 12));
setLabels(C, #("New York", "Toronto", "Tokyo"));
setArea(C, 100@100);

/* draw it in a window */

W := defaultNew(Window, "Test");
show(W, 1);
Context := getContext(W);
draw(C, Context);
releaseContext(W, context);

If you get a debug dialog box, try examining the source code or
inspecting the chart to see what's wrong. Be sure to release
the context when you've finished drawing and to close the
window when you're done.

Extending the Chart Classes

You can extend these classes by defining methods to rescale
charts, load and save them and so on. All of these features,
as well as printing and editing have been implemented in the
Chart application.

For more information refer to the source code of the chart

About Actor

Actor is an object-oriented programming language for Microsoft
Windows. Actor is a complete development system capable of
creating standalone MS-Windows applications. No licensing fees
are required to distribute applications written in Actor.

Chart was written by Patrick Deupree and Zack Urlocker and
is copyright 1989, The Whitewater Group. All rights reserved.
For more information about Actor contact:

The Whitewater Group
600 Davis St.
Evanston, IL
60201 USA


 December 23, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>