Designing an Object
Volume Number: 6
Issue Number: 8
Column Tag: C Workshop
Designing an Object with THINK C 
By Enrico Colombini, Brescia, Italy
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Lost and found
As soon as my THINK C 4.0 copy arrived from Symantec, I eagerly dived into the
manual, hastily skimmed through the ‘standard’ section and started reading with
religious care Part Four: Object-Oriented Programming. Many hours later, I was
suffering from a bad case of “Oh, no! Not again!”. It seemed I had to reprogram my
brain from scratch, repeating the painful experience of my first encounter with Inside
Macintosh (loose-leaf version).
Fortunately, people at Symantec correctly predicted this particular illness and
included the appropriate cure in the package: example programs. At page 203, the
manual says: “The easiest way to [create an application] is to take the Starter demo
program and build from it”.
So I heeded the advice and decided to try and write a real application (there is no
sense in writing do-nothing programs). I have to say, it WORKS! In a couple of weeks
all the pieces fell into place and now I am using the Class Library with ease.
This article describes the first object (I should more correctly say: the first
class) I created using the TCL (THINK Class Library), along with some of the problems
I encountered, and how I dealt with them.
But first, let me heartily praise people at Symantec for giving us not only the
example programs, but all the source code of the Library itself! Apart from being a
wonderful (and wonderfully commented) piece of code, it is there to look at every time
you have a problem (“how can I do it? Let me see how THEY did it”). These listings
alone are worth much more than the price of the the package (I hope there aren’t any
Symantec executives around, or they’ll promptly raise it).
The THINK Class Library
MacTutor readers already know about object-oriented programming and C++, so
I’ll pass directly to Symantec’s implementation. Let’s start with the bad news: it’s not
C++, but only a “C with Classes”. You can define classes, create objects (i.e. instances
of these classes) and destroy them. That’s all.
Now the good news: with ‘only’ these enhancements over classic C, Michael Kahl
(the brain behind THINK C) & Co. created the THINK Class Library (TCL). Or, how to
make the life of the Mac developer much easier.
(The TCL seems to be a MacApp competitor. Unfortunately, as I can’t stand
Pascal, I know nothing of MacApp yet: I am waiting for Apple’s C++).
In short, the TCL is a library. It doesn’t contain functions: it contains classes
from which you can create objects. Suppose you need a button: you just create a new
object of class CButton (C stands for Class):
/* 1 */
CButton *b1; /*b1 points to a button object*/
b1 = new(CButton); /*create new object*/
Since the THINK C does not provide for automatic constructor functions (as C++
does), you have to ask this new object to initialize itself, by sending it the message
IButton:
!codeexamples
tart/* 2 */
b1->IButton(); /*initialize button*/
You’ll notice that an object behaves syntactically like a structure. In fact, it is a
special kind of structure containing both variables (instance variables) and functions
(methods) which operate on these variables.
The TCL is composed of a number of different classes, closely related to everyday
Macintosh objects (a button, for example).
What is really great about the TCL is that all the classes in the library are
carefully designed to interact among themselves by exchanging messages (implemented
as function calls) unseen by the programmer. For example, when an update event
occurs, the objects that need to be redrawn automatically receive a Draw message. You
may choose to ignore the redraw problem. Just another example: you may assign a
command number to a button:
/* 3 */
#define B1_PRESSED 1234L
b1->SetClickCmd(B1_PRESSED);
When the user presses this button, the supervisor of the button (that is, the
object to which the button pertains) automatically receives a DoCommand() message
with B1_PRESSED as argument.
Many programmers (including myself) usually don’t like the word
‘automatically’. It generally means that you lose control over what’s happening in your
program. In this case, however, you still have complete control over the behaviour of
every part of the program: if you aren’t satisfied, you may change or redesign it as you
like.
To modify a class you just declare a subclass, that is a new class which is ‘almost
like’ the parent class, except for all the differences that you specify. You can add new
instance variables, add new methods (for example, an AutoClick() method to make a
button press itself for a given amount of time), or redefine (override) existing
methods. You may redesign the entire library, if you want to.
Put a pane in your window
When you initialize a TCL object, you must usually declare a supervisor of that
object A supervisor is another object which will handle the messages that your object
doesn’t know how to handle (got a problem? Pass it on to your boss). It works just like
HyperCard, except that there is no connection with the visual relationship of objects.
The enclosure of an object, on the other hand, is the object visually enclosing the
object you create. It may be the object’s supervisor, but it need not be.
So there are two hierarchies in the program, instead of the one of HyperCard: the
visual hierarchy (object enclosed in object enclosed in object ...) which is used for
purposes of redrawing and assigning mouse clicks, and the chain of command (object
supervised by object supervised by object ...) which is used to pass on commands
(keypresses and menu choices, but also button clicks and other specialized kinds of
messages).
The visual hierarchy is based on panes. A pane is (obviously) something you put
into a window. All visible objects of the TCL which you put inside a window are created
from subclasses of class CPane.
For example, a button is a special kind of pane including a Mac control and the
methods to operate on it. Thus the CButton class is a descendant of the CPane class,
from which it inherits all instance variables and methods.
A pane defines a rectangular area which sits completely inside another pane, with
the only exception of the main pane that usually occupies all the window’s interior.
Panes may overlay, as when you create a button (which is a pane) inside a pane.
When you have fully digested these few concepts, you are more than half way
towards fully understanding the THINK Class Library. Now, as I am not here to write a
tutorial for the TCL, let me start with the description of my class.
A DigitalControl object
In the educational program I was designing, the user had to be able to set some
values with 1-digit precision. A scroll bar was too coarse for the job, and not very
appealing, so I decided to create a new kind of control.
When I say “control”, I don’t refer to a Macintosh CNTL like a scroll bar or a
button, but to a generic device for controlling (selecting) a value: think of the Cache
Memory size selector in the Control Panel, for example.
I needed many of these controls, so I decided it was time to create a new class,
from which objects could be created with the “new” operator.
Figure 1
Figure 1 shows how I wanted my DigitalControl to be: basically, two buttons and a
digital display. The right-hand button raises the displayed value, while the left-hand
button lowers it.
Figure 2
Figure 2 shows how a DigitalControl can be built using standard TCL objects: a
Pane including two Buttons and a Border, which in turn includes a StaticText. All of the
classes from which these objects are created are subclasses of the CPane class.
Add a gray rectangle inside the base pane of the object and you get the actual
appearence of a DigitalControl, as shown in Figure 3.
Figure 3
You may say that the visual effect could be better if the gray rectangle filled all
the base pane, instead of leaving white corners around the buttons. In fact, the first
version of my DigitalControl was transparent (as in Figure 1), so as to show the
picture I put beneath it (using a Picture, another sort of Pane). Unfortunately this
first release of the TCL has problems in correctly redrawing a button over a gray
background: the corners are correctly redesigned if you move another window
overlaying them, but not if you close it.