Examining the StarView Application Framework
Cross-platform GUI development
Ramin Firoozyé
Ramin heads rp&A Inc. in San Francisco, California. He can be reached through CompuServe at 70751,252 or via the Internet at [email protected].
It's no secret that GUIs are hard to program. Application frameworks like the Microsoft Foundation Classes (MFC) and Borland's Object-Windows Library (OWL) under Windows, Apple's MacApp, and Symantec's Think Class Library (TCL) under MacOS, and InterViews under X-Window systems, all use an object-oriented paradigm to simplify traditional event-based programming. However, all these frameworks are inextricably tied to their specific platforms. There are also portable GUI libraries like XVT and Neuron Data's Open Interface that replace the standard API calls and create a common and portable interface to the native GUI. But these GUI libraries don't necessarily simplify programming--they merely replace the one standard, event-based API with another.
Since, by definition, application frameworks hide the low-level mechanisms of a GUI system, they're ideal for this sort of portable abstraction. A gauge of an application framework's portability is how far you can go without dropping into the native GUI to do something. Any native GUI code instantly renders the program nonportable, and the developer is responsible for porting that code to all target machines. The theory is that if you do stick to framework code, you can move the same source code to another platform, recompile and link, and you have a fully functional application with the look-and-feel of the native system.
StarView 1.0 from Star Division is a cross-platform C++ application framework that operates across Windows, Macintosh, NT, OS/2, OpenLook, and Motif. In addition to offering StarView as a separate product, Star Division uses StarView internally to develop GUI versions of its application products (primarily its StarWriter word processor). C++ code written to its application framework can be copied from one machine to another and rebuilt. What comes out is a native executable that has the speed of a C++ application and the look-and-feel of the native GUI. StarView provides an impressively large assortment of classes covering a wide variety of areas in a GUI application. There are a few areas where it doesn't offer any classes, but where it goes, it goes well.
A GUI Sampler
To get a better idea of how it actually works, I created a "GUI Sampler" that examines how well StarView meets its claims. Source code for the program is available electronically; see "Availability," page 3. I then took the source and recompiled it on other platforms to see if it worked as claimed. I wanted this GUI Sampler to show how things like buttons, lists, colors, dialogs, and fonts moved from one platform to another, and also whether the application framework was robust enough for a general-purpose native application.
I started development under Windows 3.1 with Borland C/C++. StarView also supports Microsoft C++ (as of this writing it has not been tested against Visual C++) and Zortech C++. After the skeleton was developed, I switched to a Macintosh running System 7.1 and MPW C++ and continued development. The final application was moved back to the PC and rebuilt. There's also an NT version of StarView, which I did not test. The NT system I have was October '92 beta, as was StarView, which would make it difficult to determine if problems with it were due to StarView or NT.
The Windows version comes on six diskettes, two each for Borland, Microsoft, and Zortech. The Macintosh version is on one diskette that contains the libraries and MPW tools. There are two hefty three-ring bound manuals. The user's guide has a good description of the application framework and covers the rather large set of examples provided with the system. The reference manual is an alphabetical description of the classes.
StarVision has three main components: the framework library, the DesignEd resource editor, and the resource compiler. The library interface comes in a single #include file (sv.hxx) that contains all the classes and methods implemented under StarView. The library comes in the form of linkable libraries (Mac) or a set of DLLs (under Windows). The DesignEd editor is a stand-alone application that allows you to "paint the screen" instead of having to write text resources by hand. It generates text resource files with StarView's portable resource language. The resource compiler translates this resource file into the local system's resource format, which is then compiled with the native GUI's resource compiler (rc under Borland and rez under MPW). I could not find a description of StarView's resource language in the documentation, although presumably, DesignEd takes care of generating these resources.
An important issue when evaluating a cross-platform tool is whether all the tools are symmetrically available on all its target platforms. Most often, you are expected to develop on one platform and just rebuild on all the others. As far as source code is concerned, StarView is symmetric across these platforms. You can develop under one system and move the source to another. Resources, however, are not symmetric. They're best designed under Windows using a local resource editor such as Whitewater Resource Toolkit or Borland's Resource Editor, and then incorporated into DesignEd. Even though DesignEd supports Macintosh resources such as icons, you can't easily move them back to Windows.
Also, DesignEd has no support for editing bitmaps or icons. Again, you need a program like Borland's Resource Workshop or ResEdit on the Mac. DesignEd had no trouble loading these resouces from external resource files. Although it would have been nice to be able to do everything inside DesignEd, most development environments come with their own bitmap resource editor, so this was not much of a problem. DesignEd performs competently, but after using resource editors like Whitewater Resource Toolkit and Resourcerer, you wish some more user-interface testing had been performed on it. The Macintosh version under the current release also requires more QA testing. It crashed a few times and pronounced some resource language syntax errors, refreshingly enough, in German.
When demonstrating GUI development systems, it is obligatory to show the standard Hello World application. Early Windows, Macintosh, and X examples were written in perverse ways to see how many pages of C code they would take. A fully functional framework reverses this trend. (I stripped out the comments to show how small it can get.) Figure 1 shows the Hello World program written with StarView. The executable this code generates automatically supports resizable windows, iconize and maximize operations, a close box, and redrawing when uncovered by another window.
Browsing the Library
The classes have few surprises. They're well laid out and instantly familiar to anyone who has used an application framework. You subclass Application and override those functions you want to customize. You are required to override the Application::Main virtual function, which is automatically called when you start up. You subclass WorkWindow to create a "main" window. In the application's Main function, you create an instance of your main window, show it, then go into the endless event loop by sending the application an Execute message. The framework automatically calls any function you have overridden when an event triggers it. In the case of the Hello World program, the Paint function of the window is called to redraw the contents of the main window. The framework is allowed to handle everything else in its default fashion.
For a framework to be effective, it has to provide a fair amount of coverage. Table 1 lists the available classes. The implementation of the OutputDevice is very flexible and basically provides "free" printing and print-previewing. You use the same functions for output to the screen, the print-preview window, and the printer. In order to implement this, the OutputDevice class encapsulates some of the functions of the Windows GDI and Macintosh QuickDraw, such as routines to draw boxes and arcs. It's not Display PostScript, but it works well and simplifies printing a great deal.
The Help and HelpEvent classes support context-sensitive help. Under Windows, this translates to calls to the Windows Help engine. Under Macintosh, StarView includes a help engine and help compiler that recognize the same Windows Rich Text Format (RTF) files as the Windows Help engine. Although the Mac engine is somewhat slow, having a common source to online help easily outweighs its shortcomings. You can associate a help ID with every user-interface element. If the user presses F1 or Help, the help engine can automatically display help on the workings of that element. By selecting proper help IDs, you can provide online help down to the workings of a single button.
The Font class is one of the more useful features of this library. Ordinarily, if you write out text in a given typeface, chances are good that the same typeface will not be available on another machine. To help prevent this, the StarView Font class allows you to define a font through its characteristics rather than its name. For example, instead of displaying text in Helvetica bold, you can request a font from the Swiss family of fonts with a heavy weight setting. At run time, StarView maps the specification onto a locally available font that comes closest to the requested specs. Figure 2 shows a screen from the Sampler application, demonstrating some of the families and attributes available on the Macintosh. Of course, this does not prohibit you or the user from specifying local fonts. The OutputDevice class allows you to access all local fonts by name. The Font screen of Sampler uses this to show a list of all local fonts.
Colors are handled as RGB values with up to 16-bits per component. Common colors and patterns can be identified by constants like COL_YELLOW. The set of named constants provides portability and covers basic application needs. For more advanced color handling or painting, you will probably have to subclass the Color class and add a few more features (such as HLS or CYMK support). The color section of the Sampler shows some basic patterns and colors.
Other interesting features available are the MDIWindow class, and the ListBox and ComboBox type classes. What makes them interesting is that they are implemented universally to behave similarly under environments that don't have any direct support for them. MDI under Windows is handled as you would expect. On the Mac, MDI is simulated as an application with multiple open document windows. You can't iconize the windows, but you get tiling, cascading, and other MDI-type activity for free. DropDownLists maps to standard popup menus on the Mac. Variations such as combo boxes are implemented as controls that behave the same as their Windows counterparts. The Lists section of the Sampler demonstrates the variations in list boxes.
Event Handling
Two issues I was most curious about when setting out to look at StarView were how it maps events to functions, and how it handles dialogs. In a normal C program, events are handled inside an event loop with a switch statement. Since StarView takes care of all that in the background, how would it notify your program when someone presses a button or selects an item from a menu bar? This is not a unique problem. Any application framework has to tackle it somehow. A library like MFC takes the route that the programmer is responsible for associating a specific Windows event code with a function through a message map. But, this is not a viable solution when you need portability.
StarView tackles this by matching a set of common events with handlers for each object. For example, a push button generally needs to know when it has been pressed. You have to define a member handler function of the PushButton class. You then call the ChangeClickHdl method of the PushButton class to link the "click" event with the member function. When the user presses the button, your handler function is automatically called. These handlers abstract system dependencies and reduce the need to deal with nonportable event codes.
The handlers cover the most frequently used events for each control. You are free, of course, to go nonportable and patching into the event loop and dealing with custom events in any way you want. I found the handler method to be simple and effective for taking care of all the needs of the Sampler routine. Since buttons are derived from controls (which are derived from windows), you can associate handlers with a fairly large number of events available to all the classes in this hierarchy.
Dialog boxes were another area of curiosity. One of the distinct characteristics of an application framework is how it transfers information to and from a dialog box. Dialog boxes are used to display information on the state of the program to the user and allow them to change the settings. The framework should provide a way to set the values of the individual elements and an easy way to obtain their values when done. MFC and OWL use special transfer-buffer mechanisms automatically read and loaded by dialogs.
StarView takes a more traditional approach. A dialog layout is customarily designed using DesignEd. In the source code, you have to subclass ModalDialog or ModelessDialog. For each control defined in the dialog, you need to provide an instance of the control and handler methods to take care of any immediate action like selection or mouse clicks. Many frameworks implement controls in a similar manner. Personally, I think MFC 2.0's Dialog Data Exchange (DDX) mechanism is one of the best implementations for automating dialog setup and unloading. I hope the StarView design team takes a strong look at DDX for their future releases. On all other accounts, the dialog mechanism works well and is capable enough.
Missing Links
In addition to the GUI classes, StarView supports classes that implement a variety of abstract data types; see Table 2. A few problems should be mentioned, however. Even with such an extensive collection of classes, some areas not covered by StarView (though they are arguably not part of the GUI proper). Two important areas are classes that handle directories and files in a portable manner, and support for object persistence. Star Division recommends use of BKS's Poet package for object persistence. I would have preferred to see simple persistence built in. There are many occassions where you don't need a heavy-duty and relatively expensive library like Poet.
Without a portable directory and file class, however, the code automatically becomes nonportable anywhere files are referenced. The most glaring problem comes up when external resources are referenced in a StarView resource file. The path to the file is stored in the resource file for subsequent access. The path to a DOS file does not work under any other system. A portable path class would take care of that.
Another problem has to do with class naming. Class names under StarView are easy to read and comprehend: The main application class is called Application. This, however, increases the chance of conflict when sharing class libraries with others or when using third-party class libraries. OWL and MacApp both prepend the letter T to each class (for example, TApplication) . TCL and MFC use the C character instead (CApplication). A simple scheme, such as SVApplication, would help avoid future class-naming conflicts.
On the Mac Side
The Macintosh version has problems with the implementation of some of the interface elements and the way it stores resources. The Mac toolbox provides built-in support for interface elements like modal dialogs and alerts. StarView appears to bypass these and implement its own, presumably to provide full cross-platform support. However, the StarView MessageBoxes do not look anything like standard Mac Alerts, and ModalDialogs appear not to be completely modal within the application. When you have a modal dialog box open, your menu items should not be accessible. I found that I could invoke another menu item from the application through its accelerator key, even when a modal dialog was up. Now this is not necessarily a big problem if you have the sources to the class library handy and can track down the bugs, but StarView does not include class-library sources. The sources are available, but you have to make separate arrangements with Star Division. I think it's very important to provide sources with a class library, even for an additional (but reasonable) price. There is a burgeoning trade on bug-fixes to various other class-library sources on CompuServe and the Internet. This would not be possible if the sources were not easily accessible. I hope the lack of included sources is just a packaging oversight and Star Division remedies this.
The other Mac problem has to do with the resources created by DesignEd. When compiled, these are stored inside custom resources with names starting with SV. Modal dialog layouts, button settings, menus, and other common resources are all stored in these custom resources, presumably to simplify access by the class library. However, you cannot look at the contents of these resources with a program like ResEdit. This can be a problem when debugging and removes one of the benefits of resources; namely, the ability to localize a binary program using resource-editing tools like ResEdit. StarView should either use standard Mac resources or at least provide ResEdit TMPL resources to allow the contents of the custom resources to be viewed and edited.
Being cross-platform unfortunately also means not implementing certain useful, but platform-dependent, functions like AppleEvents. This raises the general issue that cross-platform development will never be a simple recompiling task. When developing across platforms, a prudent developer will allocate some time for fine-tuning the application to match prevailing local standards. Using #ifdefs to bracket platform-dependent code will help keep nonportable code out of the core functions.
Conclusion
Overall, I found StarView to be a highly competent and well-designed application framework. Any problems I encountered with the components were minor and paled in comparison to the amount of time saved moving from one platform to another. It was very comforting to know that programmers at Star Division were using the same class library to implement their own mainstream applications. This, I think, makes Star Division more adept at catching problems and fixing them than other library vendors, who wait for their users to shake out their bugs for them.
StarView's main competition in the area of cross-platform C++ application frameworks is Inmark's zApp and the forthcoming Bedrock from Symantec/Apple. However, zApp does not currently support the Macintosh, and Bedrock appears to be targeted at Macintosh and Windows only. With Microsoft's Visual C++, all application frameworks have to compete against a highly visual and interactive development environment. If StarView is to become a viable mainstream development environment, it will undoubtedly have to withstand comparison with Visual C++ and may have to work hard to match its features.
Regardless, I found StarView's features sufficient for the majority of application development tasks a developer will encounter in the brave new GUI world.
For More Information
Star Division
2180 Sand Hill Road, Suite 320
Menlo Park, CA 94025
800-888-8527
Windows 3.x, Macintosh, OS/2 2.1, or Windows NT: $499.00
Openlook or Motif: $1499.00
(no run-time royalties)
Table 1: Built-in classes
<I>Accelerator </I>Keyboard accelerator <I>Application </I>General-purpose application framework <I>AutoCheckBox </I>Automatically checked check box <I>AutoRadioButton </I>Automaticaly checked radio button <I>AutoScrollBar </I> Scrollbar with thumb managed automatically <I>AutoTimer </I>Timer that is automatically restarted <I>AutoTriStateBox </I>Automatically checked tri-state box <I>Bitmap </I>Color bitmaps <I>Brush </I>Logical brush used for general-purpose output <I>Button </I>General-purpose button (clickable region) <I>CheckBox </I>Manual check box <I>Clipboard </I>General-purpose clipboard for Cut/Copy/Paste <I>Color </I>Device-independent RGB color <I>ComboBox </I>A combo box (single-line edit and a list box) <I>Config </I>Configuration-file support (like WIN.INI) <I>Control </I>General-purpose control <I>Cursor </I>Text cursor <I>DefPushButton </I> Default push button <I>Dialog </I>Standard dialog class <I>DropDownComboBox </I> A drop-down combo box (single-line edit and popup) <I>DropDownListBox </I> A drop-down list box (list box as popup) <I>Edit </I>Editable text field <I>ErrorBox </I>Message box for errors <I>FixedBitmap </I>Static bitmaps for dialog boxes and windows <I>FixedIcon </I>Static icon for dialog boxes and windows <I>FixedText </I>Static text in dialog boxes and windows <I>Font </I>Portable font class <I>FontMetric </I>Characteristics of fonts <I>GDIMetaFile </I>Stores a sequence of output operations <I>GroupBox </I>Groups controls together <I>Help </I>Interface to the help-viewer subsystem <I>HelpEvent </I>Supports context-sensitive help <I>Icon </I>Color and black-and-white icons <I>InfoBox </I>Message box for displaying information <I>KeyCode </I>Physical keyboard values <I>KeyEvent </I>Keyboard-press events <I>ListBox </I>Scrollable list box <I>MapMode </I>Portable measurement units with scaling <I>MDIApplication </I>Application that supports MDI windows <I>MDIWindow </I>MDI widow supported by <I>MDIApplication</I> <I>Menu </I>Menu bars, pop-up menus, bitmap menus, submenus <I>MessBox </I>Message box <I>ModalDialog </I>Modal dialog box <I>MouseEvent </I>Mouse movement and click events <I>MultiLineEdit </I>Multiple-line edit field <I>OutputDevice </I>Portable support for all output <I>Pen </I>Logical pen for output operations <I>PhysicalPrinter </I> Physical printer interface <I>Pointer </I>Mouse pointer <I>PopupMenu </I>General-purpose pop-up menus <I>Preview </I>Automatic print-preview support <I>Printer </I>Portable printer-output device <I>PushButton </I>Standard push button <I>QueryBox </I>Message box to present a query <I>RadioButton </I>Manual radio button <I>Resid </I>Interface to portable resources <I>ResMgr </I>Support for multiple resource files <I>Resource </I>Root of all classes loaded from resources <I>ScrollBar </I>Manually controlled scrollbars <I>SingleLineEdit </I>One-line editable text field <I>Sound </I>System beep <I>SysMessBox </I>Message box that is system modal (on top) <I>System </I>Global information about local platform <I>SystemWindow </I>Base class for <I>Dialogs</I> and <I>WorkWindows</I> <I>Timer </I>Timed event generation <I>TriStateBox </I>Manual on/off/don't know check box <I>VirtualDevice </I> Offscreen bitmap support <I>WarningBox </I>Message boxes to show warnings <I>Window </I>General-purpose window class <I>WorkWindow </I>Top-level application window
Table 2: General-purpose non-GUI classes
<I>Container </I>General-purpose collection of pointers <I>DynArray </I>Dynamic arrays <I>Fraction </I>Single and double floating numbers <I>Link </I>Mechanism to link events to objects <I>List </I>Linked List <I>MetaAction </I>Support for actions <I>MetaFile </I>A file containing <I>MetaAction</I>s <I>Pair </I>A pair of values <I>Point </I>X and Y coordinates <I>Queue </I>A FIFO queue of pointers <I>Range </I>Minimum and maximum range of values <I>Rectangle </I>General-purpose rectangles <I>Selection </I>Range of values within a pair <I>Size </I>Two-dimensional representation of size <I>Stack </I>A stack of pointers <I>String </I>General support for strings <I>Table </I>Table class with key access <I>UniqueIndex </I>Table of unique indexes <I>SysDepen </I>Nonportable system-dependent internals
Figure 1: StarView version of the Hello World program.
#include <sv.hxx> class TheApplication : public Application { public: virtual void Main(int, char *[]); }; class TheWindow : public WorkWindow { public: TheWindow(Window *parent, WinBits windowStyle) : WorkWindow(parent, windowStyle) {} virtual void Paint(const Rectangle &); }; void TheWindow::Paint(const Rectangle&) { DrawText(Point(100,100), String("Hello World!")); } void TheApplication::Main(int, char *[]) { TheWindow aWindow(NULL, WB_APP | WB_STDWORK); aWindow.Show(); Execute(); } TheApplication anApplication;
Figure 2: Text screen from Sampler.
Copyright © 1993, Dr. Dobb's Journal