• Keine Ergebnisse gefunden

UI Toolkit Components

Im Dokument PenPomt GO (Seite 126-130)

Page Number Frame Title Bar Menu Bar Pull-down Menu Menu Button

Tab Bars

Vertical Scrollbar Option Sheet Option Table Labels Shadow Popup Choice Toggle Table Command Bar

Bookshelf·

There are many other classes in the VI Toolkit. There are several base classes that provide lower-level functionality. And there are many specialized components classes, such as date handwriting input fields.

For Hello World (toolkit), all we peed is a class that can display a string, such as clsLabel.

III ....

u

... ...

l1li

0

~

... lie

...

~ u

...

To learn more about a class, you can try to

• Use the class browser to get a brief description of it and all its messages

• Read about it in its subsystem's Part of the PenPoint Architectural Reference

• Look up its "datasheets" in the PenPoint API Reference

• Look at its header file in \PENPOINT\SDKIINC.

The class browser, the header, and the documentation all give you the information you need to create an instance of the class.

msgNew Arguments for clsLabel

As you learned in Chapter 3, PenPoint Application Concepts, you create objects by sending msgNew to their class. Different classes allow different kinds of

initialization, so you pass different arguments to different classes. The

documentation states what message arguments a given class needs for msgNew.

In the header file the information is expressed as follows:

msgNew takes P_LABEL_NEW, returns STATUS

This says that you should pass in a pointer to a LABEL_NEW structure when you send msgNew to clsLabel. What you typically do is declare a LABEL_NEW structure in the routine which sends msgNew. You can give this any variable name you want; Hello World (toolkit) calls it In (the first letter of each part of the structure name). At the top of HelloAppInit:

/* ***** ******* **************

the client windovi (a label) .

********* **************/

LABEL NEW STATUS

In;

Before you send msgNew to a class, you must always send msgNewDefaults to that class. This takes the same message arguments as msgNew (a pointer to a LABEL_NEW structure in this case). This gives the class and its ancestors a chance to initialize the structure to the appropriate default values. It saves your code from initializing the dozens of fields in a _NEW structure.

II Create the Hello label window.

ObjCaIIWarn(msgNewDefaults, clsLabel, &In);

Now you're ready to give values to those fields in the structure which you care about. Figuring out what's in a _NEW structure is not easy. It contains

initialization information for the class you are sending it to, along with

initialization information for that class's ancestor, and for its ancestor's ancestor, all the way to initialization arguments for clsObject. Sometimes the only

initializations you're interested in are the ones for the class you've chosen, but in

Tip If you have a programmable editor, you can use tags to quickly jump to structure definitions. See \PENPOINT\SDK\

UTIL\TAGS\TAGS.DOC for more information.

CHAPTER 7 / CREATING OBJECTS (HELLO WORLD: TOOLKIT) 110 Code Run-Through for HELLOTK1.C

the case of the UI Toolkit, you often have to reach back and initialize fields for several of the ancestor classes as well.

In.label.style.scaleUnits

You can look up the hierarchy for a class by looking in the API Reference for that class. The description of the _NEW structure for msgNew always gives the

_NEW_ONLY structures that make up the _NEW structure. Thus, the hierarchy for clsLabel expands to:

When in doubt, rely on msgNewDefaults to set up the appropriate initialization, and modify as little as possible.

All you need do to create a label is pass clsLabel a pointer to a string to give the string a label. However, the LABEL_STYLE structure contains various style fields which also let you change the way the label looks.

We want the text to fill the entire window, so the scaleUnits field looks

promising. This is a bit field in LABEL_STYLE, but rather than hard-code numeric values for these in your code, LABEL.H defines the possible values it can take. One of these is IsScaleFitWindowProper. This tells clsLabel to paint the label so that it fills the window, but keeping the horizontal and vertical scaling the same. Other style fields control the alignment of the text string within the label. In this example, we'd like to center the label.

By the way, one reason that clsLabel has so many style settings and other msgNew arguments is that many other toolkit components use it to draw their text, either by creating lots of labels or by inheriting from clsLabeL Thus clsLabel draws the text in tab bars, infields, in notes, and so on:

1/ Create the Hello label window.

ObjCallRet(msgNewDefaults, clsLabel, &In, s);

In.label.style.scaleUnits = bsUnitsFitWindowProper;

In.label.stYle.xAlignment lsAlignCenter;

In. label. style.yAlignment = lsAlignCenter;

In.label.pString = "Hello World!";

ObjCallRet(msgNew, clsLabel, &In, s);

Now the label window object exists. The Class Manager passes back its UID in In. object. uid. But at this point it doesn't have a parent, so it won't ever show up on-screen.

".. Where the Window Goes

Empty Application appeared on-screen even though it didn't create any windows itself. The Application Framework creates a frame for a document. Frames are a UI Toolkit component. A frame can include other windows. Empty Application's frame has a title bar, page number, and resize boxes; you've seen other applications whose frames also include tab bars, command bars, and menu bars.

Most importantly, a frame can contain a client window, the large central area in a frame. Empty Application didn't supply a client window (hence it looked pretty dull).

Hello World (toolkit) wants the label it creates to be the client window. The messflge msgFrameSetClientWin sets a frame's client window. But the label must have its frame's UID to send a message to its frame. Hello World (toolkit) didn't create the frame, its ancestor clsApp did.

clsApp does not define a message to get the main window. Instead, it provides a message to get diverse information about application instances, including the main window of that application. (An application can have a different main window for itself other than a frame.

Information made public about instances of a class is often called metrics, and the message to get this information for an application is msgAppGetMetrics.

msgAppGetMetrics takes a pointer to an APP _METRICS structure, one of the fields in the structure is main Win. Here is how HelloAppInit gets its main window:

APP METRICS ami

II Get the app's main window (its frame).

ObjCallJmp(msgAppGetMetrics, self, &am, s, error);

II Insert the label in the frame as its client window.

ObjCallJmp(msgFrameSetClientWin, am.mainWin, \

(P_ARGS)ln.object.uid, s, error);

Note that the code sends msgAppGetMetrics to self. We have been talking loosely about Hello World (toolkit) doing this and that, but remember that this code is run as a result of an instance of clsHello World receiving a message, and that clsHelloWorld is a descendant of clsApp. Thus the document is the

application object to which we want to send msgAppGetMetrics. In the middle of responding to one message (msgApplnit), we need to send a message to the same object which received the message. This is actually very common. The Class Manager provides a parameter to methods, self, which identifies the object which received the message.

".. Why msgApplnit?

Earlier you turned on message tracing to Empry Application~ What this does is cause the class manager to dump out every message received by instances of clsEmptyApp. You should have noticed that each Empty Application document receives dozens of messages during the course of a page turn to or from itself.

1.2.4

1.2.5

CHAPTER 7 / CREATING OBJECTS (HELLO WORLD: TOOLKIT) 121 Code Run·Through for HELLOTK1.C

These messages are sent to documents (application instances) by the PenPoint Application Framework.

If you want your application to do something, you must figure out when to do it.

Your process can't take over the machine and do whatever it wants, it must do what it wants in response to the appropriate messages.

One of the hardest things in PenPoint programming is figuring out when to do things.

So, when should Hello World (toolkit) create its label? Because it inserts the label in its frame (using msgFrameSetClientWin), it can't create the label before it has a frame. But it should have a label in its frame before it goes on screen.

It turns out that clsApp creates the document's frame in response to msgAppInit.

Thus Hello World (toolkit) can get its frame and insert the label in its

msgAppInit handler, but it must do so after clsApp has responded to the message.

This is why its method table tells the Class Manager to first send the message to its ancestor:

MSG INFO clsHelloMethods []

msgAppInit, msgAppOpen,

"HelloAppInit", objCallAncestorBefore, Note that doing this relies on knowing what the ancestor class does. You'll spend a lot of time reading Part 2: Application Framework of the PenPoint Architectural Reference to learn about the PenPoint Application Framework messages and how clsApp responds to them.

Im Dokument PenPomt GO (Seite 126-130)