Tutorial Eight: Creating Classes and Subclasses
In this tutorial, you will create the interface shown in the following figure:
MenuBar with File Menu
A Brief Overview of Classes and Subclasses
A group of widgets that make up a logical component of your user interface can be made into a class. This is a way to use Motif and C++, as described by Douglas A. Young in his book Object-Oriented Programming with C++ and OSF/Motif .
Classes are useful because they allow you to define the look and behavior of these widgets in one central place. Every time this component is used it automatically "inherits" the look and feel from the class definition. The code generated is also more efficient because the definition of these widgets is centralized. Classes can be reused within the same application, across multiple applications, and they can even be shared between users.
Subclasses allow you to build on a class that has already been created and specialize it for your needs. In turn, this new class has all the benefits of classes that are described above (efficient code, reusability, etc.). There are several ways to "specialize" a class once it is subclassed. You can override exposed resources (similar to class instances), add new widget children, and override callbacks. This tutorial gives an example of each of these tasks.
In this tutorial you are going to create a menu class and then specialize this menu class using subclassing. Both classes are useful objects that you may want to use in many different applications, so we will also demonstrate how to save classes as separate UIL files and how to put them on the Palette permanently.
Before You Begin This Tutorial
Make a new directory called
Tut8 and change directories to
· If you have not started Builder Xcessory yet, enter the following at the prompt in the
· If you are already running Builder Xcessory, clear the Builder Xcessory interface.
- If you have questions about clearing the interface, review Clearing an Interface .
You are now ready to begin the tutorial.
The example you will build in the following tutorial is a PulldownMenu containing several menu items. This will hopefully contain meaningful menus that can serve as a template for the menus you use in your own applications.
Note: This tutorial assumes you have chosen C++ as your language.
Creating a Menu Class
In this section, you'll create a file menu class.
- Click on the arrow next to Instance and select Classes.
- Change the Browser to Classes view.
Adding a PulldownMenu
- When you create a PulldownMenu, this action actually creates 3 widget instances: a CascadeButton, which parents a PulldownMenu, which parents a PushButton. This hierarchy is reflected in the Browser.
- For whatever widget instance is currently selected, the only widgets sensitized in the Palette are those that are valid children for that instance. Using Keep Parent makes it easier to add children to a widget instance, especially when that widget instance is a menu.
- Select the PulldownMenu from the Palette and drop it. A popup dialog asks for the name of the class, enter "File".
- Select Keep Parent from the Browser View menu.
- Because Keep Parent is selected, the new pushButton instance you have just created is parented by the currently-selected widget instance, in this case, pulldownMenu.
- This adds 5 PushButtons to the menu (pulldownMenu). This menu should have a total of 6 PushButtons, as shown in the following figure:
- Select the pulldownMenu in the Browser.
- Add a PushButton to the pulldownMenu by double-clicking on the PushButton icon on the Palette.
- Using the previous step, add these items in this order: one PushButton, one Separator, two PushButtons, one Separator, and one PushButton.
- When you double-click on an instance of a class, its exposed resources are identified using the Instance Name. Renaming a class's widget instances makes it easier to remember which resource belongs to which widget instance.
- The separator names can stay the same.
- Rename these instances so that they make more sense. Click on the first PushButton and change its Instance Name to newButton in the Resource Editor (see Editing the Instance Name ).
- Repeat the previous step for the remaining buttons. Change their Instance Names to openButton, readButton, saveButton, saveAsButton, and exitButton, respectively.
Editing the Instance Name
After changing the Instance Name of every PushButton, your interface should look like the one in the following figure:
Renaming the PushButtons
Notice that the changed Instance Names are reflected on the Browser.
After adding items to the menu, the next step is to make the menu look more attractive and easier to use.
Labeling the Menu and Menu Items
To label the menu, follow these steps:
- This accomplishes two things: it selects cascadeButton, and it updates the Resource Editor so that it displays the resources associated with cascadeButton.
- Type the first several letters in "labelString" in the Find Resource search field at the bottom of the Resource Editor until this resource is located.
- The menu on the interface is now labeled "File".
- double-click on cascadeButton on the Browser.
- Find the labelString resource in the Resource Editor.
- Enter "File" (without the quotation marks) in the labelString input field.
To label the menu items, follow these steps:
- In the Browser, double-click on newButton.
- Enter "New" in the labelString input field.
- Repeat the above steps to change the labels of the remaining File menu PushButtons to "Open...", "Read...", "Save", "Save As...", and "Exit."
The menu and menu item labels on all three menus should now match the following figure:
Labeled Menu and Menu Items
In Labeled "New" Menu Item , notice that the changes you have made to the instances' labelString resources are shown on the interface, and the changes you have made to the Instance Names are still shown on the Browser.
Labeled "New" Menu Item
At this point, you should add callbacks for every menu item.
- double-click on newButton.
- Find the activateCallback resource in the Resource Editor.
- Enter "DoNew" as the activateCallback procedure name.
Note: Builder Xcessory automatically adds the
()characters to your routine name. Note also that the placement is automatically set to Code in the Placement option menu to the right of the input field.
Refer to the Builder Xcessory Reference Manual for more information about adding callbacks. You can add callbacks to the remaining buttons, but it is not necessary for this tutorial.
At this point, you should expose some of the resources in the class. Any resources that you think users of your class may want to override should be "exposed". In this example we will expose the positionIndex of the pushButtons and separators, in case users of our File menu want to change the order of the menu items or add new ones.
- The easiest way to do this is to select each instance on the Browser.
- The default setting is None. To select Code, first hold down MB1 on the option menu to display its menu items. (Notice, as the menu items are displayed, that Expose is at the bottom of the menu but is desensitized at the moment.) Now, move the cursor over Code to select it, and release MB1. The Placement of the positionIndex resource for the currently- selected widget instances is now Code. That means when you generate code for this class, the value of the positionIndex resource for the currently-selected widget instances will be hard-coded, and cannot be changed by the application user.
- A small eye icon appears next to Code. (After Code is selected, Expose is sensitized and can be selected on the Placement option menu. Widget instances that are members of a class are the only instances that can be exposed.)
- Exposing a resource means that you can look at and edit that resource in instances or subclasses, which otherwise is not possible for the resources of class members.
- Holding the Ctrl key down, select each of the children of the PulldownMenu (the six PushButtons and two Separators).
- Update the Resource Editor by selecting Update from the View menu.
- Find the positionIndex resource.
- Select Code from the placement option menu located to the right of the positionIndex resource input field (see Exposed positionIndex Resource ).
- Expose the resource by selecting Expose in the Placement option menu.
Exposed positionIndex Resource
Subclassing the "File" Class
You have now finished creating the class "File". The following sections describe how to create a subclass from File.
Designating a receptor
Before creating a subclass, you should first edit the class and designate one of its widget instances as a receptor. This means that you can add children to the class, and whichever widget instance you designate as the receptor will act as the parent to any children you add. In this case, we'll designate pulldownMenu as the receptor.
Note: Any widgets you add to a subclass must have unique names (different from their corresponding superclass widgets) for the code to compile. Builder Xcessory takes care of this for you by automatically prepending the subclass name to the widget names. If you would rather take care of this yourself (by naming the new widgets with unique names on your own), set uniqueSubclassNames in your .bxrc to False, exit, and restart Builder Xcessory.
This tutorial assumes uniqueSubclassNames is set to False. If you choose otherwise, you will notice a difference in that any widget instances you add to a subclass is prepended with "sub_".
- Select pulldownMenu in the Browser.
- Select Make Receptor from the Browser Edit menu. A white square appears next to pulldownMenu in the Browser to indicate a receptor (see PulldownMenu Designated as the "File" Class Receptor ).
PulldownMenu Designated as the "File" Class Receptor
Now you can create a subclass. When you add children to that subclass, they are automatically parented by pulldownMenu.
Creating a subclass
Creating a subclass is creating a variation on a theme. Suppose you plan to use the same menu structure you have just created for more than one reason. First, let's make a subclass to which you will add a "Print" menu button. Use the following steps to create a subclass:
- You have now created a subclass called "FilePlus".
- This does four things for you:
- First, it creates a new interface with all the elements of the superclass (File).
- Second, it adds the subclass name (FilePlus) to the list of classes displayed in the Browser window.
- Third, it creates another tree in the Browser window, representing the subclass you have just created. This tree has a lone child, a widget that represents the superclass. You can now add children to that class by dropping them onto the subclass interface.
- Fourth, it creates a new Palette icon for the new subclass FilePlus. This new icon is placed in the Project Classes group by default.
- Select the class widget (File) in the Browser.
- Select Make Subclass from the Browser Edit menu.
- Enter "FilePlus" in the popup dialog that prompts you to enter a name for the subclass you are creating.
In the next section, you will add children to the subclass you just created.
Adding Children to a Subclass
After creating a subclass, you should add whatever children will make it useful. In this case, add another separator and a new menu item.
- When dragging a widget onto ":File", position the widget slightly lower and more to the right before dropping it. A partial outline of ":File" is displayed when ":File" becomes a valid drop target.
- The interface should now look like the following figure:
- Turn off Keep Parent.
- Using MB2, drag a PushButton from the Palette into the FilePlus subclass, by dropping it on ":File".
- Repeat these steps to add a Separator.
Children Added to the Subclass FilePlus
- Double-click on the pushButton instance to display its resources in the Resource Editor. At the top of the Resource Editor, change its instance name to "printButton". double-click on the separator instance, then change its instance name to "plusSeparator".
- Update the Resource Editor for pushButton, find the labelString resource, and enter "Print" (without the quotes) in the labelString text input field.
- Change the widget instance names of the pushButton and separator to "printButton" and "plusSeparator", respectively.
- Change the labelString resource value of the pushButton to "Print".
Overriding Resources in a Subclass
After creating a subclass, you can override any of the exposed resources of the superclass. In this example we will override some of the positionIndex resources in order to place our new "Print" option.
- The Resource Editor now displays all exposed resources and their current values.
- It is a good idea to expose the same resource for each child you have added, in case you want to make changes later to the subclass or to an instance of the subclass.
- Double-click on the ":File" icon in the "FilePlus" tree in the Browser.
- Change the exitButton.positionIndex resource to "9".
- Double-click on the pushButton child of ":File" in the Browser to update the Resource Editor.
- Find the positionIndex resource.
- Select Code from the placement option menu to the far right of the resource.
- Select Expose from the placement option menu.
- Repeat steps 3 through 6 to expose the positionIndex resource for the separator child of ":File".
Overriding a Callback in a Subclass
After creating a subclass, you can override any of the callbacks of the superclass. To override a callback in C++, all you need to do is define a virtual method with the same name and parameters as the callback method.
- This displays the Class Member Editor ( Defining a Virtual Method ).
- double-click on the FilePlus class icon in the Browser.
- In the Resource Editor, click on the "..." button next to the Class Methods and Data input field.
- Select the Scope tab.
- Select the Protected modifier toggle button.
- Select the Polymorphism tab.
- Enter "DoNew" in the Method Name field
- Enter None as the return type.
- Select the Virtual toggle button.
- Press the New button and enter three parameters of type Widget, XtPointer, and XtPointer with parameter names "w", "p1", and "p2", respectively (see Defining a Virtual Method ).
Defining a Virtual Method
- Click on Apply.
- Dismiss the dialog.
Saving Classes in a Separate File
You may want to use these classes in several applications. In order to do this you should save the classes in a separate include file.
To save the class, File:
- The File Selection dialog is displayed.
- Select the File class icon in the Browser.
- Select Class -> Save Class from the Browser File menu.
Enter the name of the file to save the class,
file.uilin the File Name input field.
- Click on OK.
To save the subclass (FilePlus):
- Select the FilePlus class icon in the Browser.
- Select Class -> Save Class from the Browser File menu.
Enter the name of the file to save the class,
fileplus.uilin the File Name input field in the File Selection dialog.
- Click on OK.
Permanently Placing Classes on the Palette
You may want these classes to appear on your Palette automatically when you start up Builder Xcessory. Select one of the following two options:
· Copy the class into a system directory. This causes the class to appear on the Palette for all users.
· Copy the class into a local directory. This causes the class to appear on the Palette only when you start Builder Xcessory.
In this example we will copy one of the classes into your local directory (see Project, Private, and Public Classes ).
- Notice that File and FilePlus class icons appear in the Project Classes group on the Palette. Just below this section, notice the Private Classes and Public Classes groups.
- Scroll to the bottom of the Palette.
Project, Private, and Public Classes
- With MB2, drag the File class icon from the section in the Palette called Project Classes into the section called Private Classes.
Using a Class in Your Application
Now you are ready to create your application.
- Change the Browser to Instances View. Notice that the display in the Browser clears. You created two classes in Classes view, and both were saved to the Palette. In Instances view, the Browser clears because you have not created an interface yet.
- Create a MainWindow from the Palette. Add a MenuBar from the Palette as a child of the MainWindow instance. The result should look like the following figure:
- Add an instance of your FilePlus class from the Palette as a child of the MenuBar instance (see Adding the Subclass FilePlus ).
Adding the Subclass FilePlus
Generate C++ and compile and run your program. Any code that you place inside the DoNew method in the file
FilePlus.Cis executed when the user presses the New button. If we had used the File object instead of the FilePlus object, the DoNew method in
File.Cwould be executed. You have completed Tutorial Eight.