VisualAge C++ Visual Application Builder

From EDM2
Revision as of 04:30, 4 April 2018 by Ak120 (Talk | contribs)

Jump to: navigation, search

by Dale R. Nilsson

VisualAge C++ Version 3.0 has a number of new and improved components over its predecessor, C Set++ Version 2.1. This article will focus on the Visual Application Builder, which is a new component of the product and is derived from IBM VisualAge Smalltalk.

The Visual Builder has complete facilities for graphical user interface (GUI) painting based on the user interface components in the IBM Open Class Library, including new controls such as a Toolbar, Animated button, and FlyOver help (also known as 'bubble' help or 'hover' text). The Visual Builder also has the unique ability to combine visual and nonvisual parts by connecting events, actions, and attributes to construct applications. The Visual Builder can generate the C++ code for an application, which is then compiled to create executables.

The Visual Builder

You use the Visual Builder to create visual parts, nonvisual parts, and applications by combining these parts. Because this is a new component, I have found that most users want to understand the definition and generation technology. In this article I'll briefly cover the C++ parts architecture, and then go through the steps to create a simple nonvisual part. Then I'll use the nonvisual part in a simple application.

C++ Parts Architecture

To implement a 'construction from parts' paradigm similar to IBM's VisualAge Smalltalk, we added a Notification Framework to the IBM Open Class Library. This framework and how it works is documented in the book Building VisualAge C++ Parts for Fun and Profit (which is one of the books in the VisualAge Extended Reference Manuals set, part number 30H1680). The Notification Framework is based on the same event/action/attribute paradigm used in VisualAge Smalltalk:

  • Events have a notification identifier and can signal other parts of a change in state using the notifyObservers function. An example in the user interface is the buttonClick event of a push button. Events can trigger actions or attributes.
  • Actions are public member functions within a class which are triggered by events. For naming consistency, actions should be verbs. Examples include the show action for a window and the add action in a Calc nonvisual part (which we will build later).
  • Attributes are public data within a part that specify a property of the part. Attributes have a notification identifier and can be notified by events or can notify other attributes. Attributes are accessed with a get function and changed with a set function.

The Open Class Library has added notification to the classes so they can be used in the Visual Builder. The INotifier class that has been added to the Class Library has two subclasses:

  • IWindow, which contains the protocols (or behavior) for visual parts, including IControl and IFrameWindow
  • IStandardNotifier, which provides the protocol for all the nonvisual parts

So C++ parts are specialized classes which have the Notification Framework and a part interface.

VAC-Fig-1.gif

Building the Sample Application

To illustrate the technology used to create applications with the Visual Builder, let's develop a simple Calc application and I'll explain what is happening along the way. First we'll build the adder nonvisual part, make the visual Calc part, then combine the two parts using connections, and generate and build the application.

Creating Nonvisual Parts

Nonvisual parts can be built using the Part Interface Editor (PIE) in the Visual Builder. To define a new part (for example, adder), first select New from the Part menu, which brings up a dialog box where you can enter part information. For the Class name enter adder, and for the Part type select Nonvisual part ( this automatically sets the base class for the part to IStandardNotifier). Now press the Open button to open the PIE for the adder part. The PIE is a notebook where you specify the attributes Number1, Number2, and Result. In the Attribute name field, enter Number1. In the Attribute type field, select int from the drop-down list. Use the Add with defaults button to save this attribute. Repeat this process for the Number2 and Result attributes. Go to the Action page and enter the add action; use Add with defaults again. Add with defaults will add the default C++ code for the get and set member functions in the adder part.

It is very helpful to put these new items on the preferred list for making connections. Go to the Preferred page and select the add action using mouse button 1, then press mouse button 2 to open the pop-up menu. From the menu select Add >> to put add on the preferred list. (That's good use of your mouse buttons!) Repeat these steps to add Number1, Number2, and Result to the preferred list.

To generate the stub code, select Class Editor from the View menu. Enter ADDER.HPV in the User .hpv file field and ADDER.CPV in the User .cpv file field. This specifies the C++ files that will be generated by the Visual Builder that include the attributes we've just added and can be edited by the user. (The Visual Builder always appends to these files.) Then from the File menu, select Save and Generate, then select Part source. This will save the ADDER .VBB part and generate the .CPP and .HPP files. Select Save and Generate and then Feature source... Select the Generate all button to get the .CPV and .HPV files.

VAC-Fig-2.gif

Nonvisual parts still require you to code in C++ (yes, the Visual Builder has no facility for reading your mind). You must edit the add member function at the bottom of the ADDER.CPV file and insert the logic to add Number1 and Number2 as a set function of Result:

Adder& Adder::add()
{
setResult(iNumber1 + iNumber2); // user added code
return *this;
}

Of course, you can easily include, subtract, multiply, and divide actions. By keeping the logic in a separate part, the Visual Builder promotes good object-oriented design through the separation of model and view objects. You have created a reusable adder part that can be used in a number of applications. This is a different approach to most other application builders, which bury code under UI controls. (Such builders don't allow reuse and create maintenance problems. )

If you have existing classes that you want to use in the Visual Builder, you must edit the source code of your classes to add the notification. Each attribute and event needs to have a notification ID like the code generated for ADDER.CPV:

// Feature source code generation begins here...
INotificationId adder::Number1Id = 'adder::number1';
INotificationId adder::Number2Id = 'adder::number2';
INotificationId adder::ResultId = 'adder::result'; 

Then you need to add a notifyObservers statement after attributes are set, as seen by the code generated by the adder part for the Number1 attribute:

adder& adder::setNumber1(int aNumber1)
{
if (](iNumber1 == aNumber1))
{
iNumber1 = aNumber1;
notifyObservers(INotificationEvent(adder::Number1Id, *this));
} // endif
return *this;
}

You must also add enableNotification so the messages get sent. Then make an import file using the .VBE file format (which is also documented in Building VisualAge C++ Parts for Fun and Profit). To see a sample .VBE file, select Export interface from the Part menu on the main Visual Builder dialog. The generated code from this sample will help you see what is needed to add notification to your own classes. You can also use your existing C++ classes and C .DLLs as nonvisual parts.

Making the Visual Part

Now create a Calc visual part that is derived from IFrameWindow. First select New from the part menu and enter Calc for the Class name. When you select Open, the Visual Builder will bring you into the Composition Editor, where you can combine the visual parts with the nonvisual parts. Add an entry field by selecting the IEntryField control from the Data entry category and dragging it to the Calc part canvas. Repeat this step for two more entry fields. Then use the IStaticText control to make three labels over the entry fields. Edit the labels to say Number1, Number2, and Result. From the Frame Extensions category add an IToolBar control by dropping it on the frame window title. You can edit the window title by pressing the Alt key and mouse button 1; then enter Calc Sample. You can do some sizing or aligning as desired, but it is not critical for this sample. Each of the parts has a Settings notebook that is activated by double-clicking on that part. In the Settings notebook you can change all the attributes of a part, such as its part name and label. For this simple sample we will use the defaults. In a 'real' calculator you would add a numeric-only handler to each of the entry fields (this is done on the Handler page of the Settings notebook).

Bring the adder nonvisual part to the Composition Editor by selecting Add part from the Options menu. Specify adder* as the part class (remember--it is case sensitive) and give it a name like 'adder' for easier reference. The asterisk (*) is required in the class name because the adder class does not have a copy constructor and must be called by reference. This is a good design because there is a lot of overhead associated with copying classes at run time.

Making Connections

First we will connect the attributes. Move the mouse pointer over the first entry field and press Alt+mouse button 2. When the pop-up menu appears, select valueAsInt and point the mouse at the adder icon; press mouse button 1 to make the connection. Point to Number1 in the preferred connections list and press mouse button 1 to make the connection (shown in the Composition Editor as light gray or cyan when online). This connects the valueAsInt attribute of the entry field to the Number1 attribute of the adder part (valueAsInt is required because the Number1 attribute is type int). Do the same for the second entry field (the Number2 attribute). Now point at the adder icon and press Alt+mouse button 2. Select More, which brings up the connection dialog. Select Result from the attribute list and point to the Result entry field; press mouse button 1 to make the connection. This is necessary because there is an implied source and target for the attribute-to-attribute connections since the connections are bi-directional (indicated by the filled-in and hollow arrows).

Now connect the buttonClickEvent of the Toolbar button to the add action in the adder nonvisual part. At run time, when the Toolbar button is clicked, the event will notify the adder part to invoke the add action (member function). This makes an event-to-event connection, shown in dark gray or green when online.

VAC-Fig-3.gif

There are many far more complex connections (such as passing parameters to connections) that are similar to attribute-to-attribute connections but are unidirectional and are shown in purple. Also, for each connection, exception handling is incorporated in the generated code. This makes it possible for you to connect the exceptionOccurred event to a message box showException action, which is a good built-in mechanism for error detection. For example, in a 'real' calculator you would want to 'throw' an exception when a divide-by-zero operation is attempted. You would then 'catch' the exception as described above.

Code Generation

Now we need some C++ code, so select the Generate button, which will save the Calc part as CALC.VBB in your working directory. Then the Visual Builder generates the following:

  • CALC.HPP with the declarations
  • CALC.CPP with the definitions
  • CALC.RCI with externalized resource text (in order to externalize all text you must go to the class editor for the part and specify a starting resource ID)
  • CALC.H for the resource file

Because this is the entry point for our application, we need to generate a C++ main(). From the file pull-down, select Generate main to generate CALC.APP, CALC.RC, and CALC.MAK (if you have Generate makefile checked in your options). If you started via Workframe, you will need to select MakeMake from the Project menu to generate a makefile. You then compile and run the application from Workframe (select Build from the Project menu), or from a command prompt, as follows:

[D:\ibmcpp\working] nmake calc.mak >error.dat 

Running the Calc Sample

When you run the application it will look like this:

VAC-Fig-4.gif

You can enter integers in the first two entry fields, then press the button on the toolbar and the result will appear. All this is the result of writing only one line of C++ code! The application is a positionable, sizeable Presentation Manager (PM) window with minimize and maximize capabilities and a system menu. The toolbar can be made to float by dragging it off the frame window, and it can be repositioned to the sides or the bottom of the frame window by dragging and dropping it. This is a simple application, but it shows all the basic steps required to go from design to implementation.

Summary

The Visual Builder is a powerful application development tool that has complete GUI definition and uses the unique 'construction from parts' method. This method provides a visual metaphor to connect visual and nonvisual parts using the event/action/attribute paradigm. You still need to perform object-oriented (OO) analysis and design for applications because the Visual Builder does not prevent you from making implementation errors. But the Visual Builder makes it a lot easier and faster to create C++ based OO applications and lets you focus on the domain-specific coding required for the nonvisual parts.

Good part design

Most well-designed, general purpose parts require parameters. Here's a tip to remember when implementing these parts: You should supply as many default parameters for your classes as possible. Each parameter without a default will require a connection to complete the part definition. This can make the part diagram a bit cluttered and create a lot of unnecessary overhead for these trivial connections.

MultiCellCanvas

When you make a new visual part that is derived from IFrameWindow, the part has an ICanvas placed inside as a client of the window frame. In most cases, you should remove the default canvas and use MultiCellCanvas, which allows controls to expand as the window is stretched at run time. You must designate which columns and/or rows will be expandable within the Settings notebook of MultiCellCanvas. You can use the Apply button to test setting changes while the Settings notebook is open. This lets you see when you make the correct expanding columns or rows, and prevents expanding buttons or fixed-length fields that expand.

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation