|Requirements-based Vocabulary Tutorial||Object COBOL Tutorials (UNIX)|
You can use the GUI Class Library to create applications with graphical user interfaces. This tutorial takes you through the creation of the interface to the Bank application used in some of the earlier tutorials.
This tutorial consists of the following sessions:
Time to complete: 25 minutes.
This session is a brief guide to the different class programs used in the Bank application. You have already looked at some of these classes in the earlier tutorials, but this section recaps those as well as introducing the ones you haven't yet looked at.
It is easier to see how the overall structure of the application with the Browser Class Hierarchy view:
>>To see application structure
This starts the on-line tutorial GUI Programming.
The Class Browser loads the Bank Application, in Class Hierarchy view.
To describe the classes used for the Bank Application, we have grouped them into four types:
The account classes were explained in detail in the Inheritance Tutorial. An account instance stores customer name, number and balance data. The descriptions below are just a brief recap.
|Account||Abstract class implementing basic behavior for account classes and instances.|
|CheckAccount||Class for creating Check Accounts.|
|SavingsAccount||Class for creating Savings Accounts|
|HighRateAccount||Class for creating High Rate Accounts
These classes contain the logic to store and retrieve account objects, and that connect the interface classes to the account objects. The only class method in these classes is "new", to create an instance of the object. The descriptions below refer to the behavior of the instances of these objects.
|AccountManager||Stores all accounts in a Dictionary object. The
Dictionary class, part of the supplied class library, stores objects
against a key. Each element stored in a dictionary must have a unique
key - in this case, we use the account number as the key.
The AccountManager also contains code to enable you to search for accounts with a particular name, and to send all accounts a message such as "printStatement".
|BankApplication||Controls the main window and dialog boxes used by the
application, and also the AccountManager. BankApplication contains the
logic needed to create and interrogate accounts, and move data between
the accounts and the display classes.
In this application, this one class is both responsible for part of the business logic (how you create an account) and manages the state of the interface (when windows and dialog boxes are opened and closed). In a more sophisticated application, these functions might be split between two (or more) objects to separate more completely the physical interface from the business logic.
In the application as it is implemented, there is only ever one instance of either of these classes during a run. Consequently, all the functionality could have been implemented as class methods inside the class object. But by implementing the functionality in the instance object, we have allowed for the possibility of using these objects in an application which, for example, maintained several banks, each with its own AccountManager and main window.
These are the classes which are used to create the interface. Most of them are subclasses of Modal and create the dialog boxes used for the interface. Each of the different types of dialog box used by the application has been implemented by a separate class. The main window for the application is implemented by a subclass of Window.
Generally, these classes contain only initialization code which creates the dialog box fields and controls. Some of these classes also contain methods for interrogating or setting fields.
|BankWindow||A subclass of Window, which creates the main Bank window and its controls.|
|AccDisplayList||Creates the dialog box which displays a list of matching accounts for the query by name function. It has methods for putting data into the list box, and for returning the account selected from the list box.|
|AccountAdder||Creates the Open Account dialog box, and provides methods to interrogate the fields in this box.|
|AccountDisplay||Creates the Account Details dialog box, and provides Credit, Debit and Cancel pushbuttons. Also provides methods for setting the Account Details fields.|
|AccountRetrieveBox||Creates the Retrieve Account dialog box, for getting an account with a specific number. Also provides a method to query the Account Number field, and overrides the "show" method. The replacement "show" method sets the contents of the Account Number field before displaying the dialog box.|
|AmountBox||An abstract class containing the common behavior for the Credit Account and Debit Account dialog boxes. It sets the correct size and adds the amount field to a dialog box. It also provides a method to interrogate the account field, and overrides the "show" method to preset the Amount field to zero.|
|CreditBox||Creates the Credit Account dialog box. A subclass of AmountBox which adds the OK and Cancel buttons and sets the title.|
|DebitBox||Creates the Debit Account dialog box. A subclass of
AmountBox which adds the OK and Cancel buttons and sets
Although CreditBox and DebitBox both have buttons which look the same, their event registration is slightly different. Pushing the OK button credits an account on a CreditBox and debits it on a DebitBox.
|NameBox||Creates the Query Name dialog box. Also provides a
method to interrogate the name field.
The Interface Builder Classes are coding optimization classes which reduce the amount of repetitive code needed to construct each of the interface objects in the previous section. They provide methods which parse blocks of data to create the gadgets and controls for a window or dialog box.
You might wonder why such classes are not part of the GUI Class Library already. The reason is that the interface to the Class Library has been kept as simple and generalized as possible, to make it easy to learn and applicable to all types of application.
The Interface Builder Classes are all written with certain assumptions about the style of interface for the application which uses them. For example, pushbuttons are always created in horizontal rows.
You can use these classes as a cookbook of examples if you want to create similar classes adapted to the style of interface used by your own applications.
|SmartPushButton||A subclass of Pushbutton, which adds a set of pushbuttons to a parent object by reading a block of data. It also returns an OrderedCollection of all the pushbuttons created.|
|SmartSubMenu||A subclass of SubMenu, which adds a set of submenus to a parent object by reading a block of data. It also returns an OrderedCollection of Associations. Each Association has a submenu as its key, and an OrderedCollection of all the menu items in the menu.|
|SmartEntryField||A subclass of TextEntry, which creates and labels an entry field by reading a block of data. Returns the object handle to the text entry field.|
|BankMessage||A subclass of MessageBox, which creates all the message boxes used by the Bank application.|
In this session you will look at some of the code in the Bank Application, using Animator V2. The code you will examine covers the basic steps for creating any GUI application with Object COBOL:
This is similar to the way the BeepWindow was set up in the Writing a Class tutorial, but event registration is handled in a slightly different way. BeepWindow registered events so that when they occur, a message is sent. The GUI objects in the Bank Application register events so that when they occur, a different event is raised.
For example, pushing the Open button on the Bank window causes the clicked event on this button. When the button clicked event occurs, it sends the Bank window the add-account event. The BankApplication class has registered an interest in the add-account event on the Window, so that it gets sent the "addAccount" message when the add-account event is raised.
The physical event of clicking a button has been translated to a logical event add-record on a window. Physical events are all predefined for you in copybook p2cevent.cpy, supplied with the class library. The logical events you can define yourself for an application. The logical events for the Bank Application are all defined as level 78s in copybook bwindow.evt.
This way of processing events helps you to split interface and business logic. The window does not need to know the names of any of the methods in your application, and the application does not need to know about the controls of the menu.
For example, the Bank window has menu and pushbutton controls for some functions, but these functions are all mapped to logical events so the application does not need to know any of the details of the interface.
>> To animate event registration code
This assumes you have left the Class Browser running from the earlier session in this tutorial. If you have not, repeat the instructions to see application structure listed in the section Bank Application Classes.
This assumes that all the Bank application classes are already compiled from working through the earlier tutorials. If they are not, select Check All from the COBOL menu and wait for the Checker to check all classes, before starting Animator V2.
Animator V2 starts with the execution point on the first statement
procedure division for the BankApplication class
(bankapp.int). This is the initialization code for the
BankApplication class, which creates an instance of BankApplication
and sends it the "run" message.
invoke self "new"...).
Execution transfers to the "new" method of BankApplication.
invoke super "new"...).
This returns an instance of the BankApplication class.
invoke newApplication "initialize"...).
Execution now transfers to the "initialize" instance method of BankApplication. The code between tags B001 and B002 creates and initializes anEventManager.
invoke BankWindow "new" ...).
This statement creates a new instance of the BankWindow class.
You are now drawing the first GUI object to be displayed.
This takes you to the initialize method of BankWindow. The mechanism is the same as the one you saw in the session Creating a Window in the Writing a Class Program Tutorial. The "new" message sent to BankWindow gets executed by code inherited from the Window class. The "new" code in the Window class sends the new object the "initialize" message.
invoke super "initialize").
The lines between tag W011 and W012 set the size of the BankWindow window.
move length of windowTitle to i).
This block of code creates a string object and uses it to set a title on the window. The string object is finalized after you have used it.
move 4 to y).
This is the start of the code to create the first button. Although we could have used the "createButtons" method of SmartPushButton to add the buttons to the window, the BankWindow creates the buttons itself to make the event registration mechanism easier for you to follow.
This sets the position for placing the first button.
move p2ce-clicked to physicalEvent).
This event id represents the clicked event on a button, the event raised when the end-user of the application button pushes the button.
This creates a string object for labeling the button.
invoke PushButton "new" using self...) to create and label a button.
invoke aButton "moveTo"...) to position the button on the window, and make it the default button.
The end-user can push the Enter key as an alternative to pushing the default button.
move add-account to logicalEvent).
add-account is a logical event defined inside the
invoke aButton "translateEvent" using...).
The "translateEvent" sets up an event translation
between the event id in
physicalEvent and the event id
logicalEvent. Now, when the button gets the clicked
event, it will raise the add-account event on the window. This itself
does not invoke any method anywhere in the application; it sets up a
level of indirection so that another object can register an interest
in the add-account event on this window.
invoke SmartSubMenu "buildMenu" using...) and select Run to Cursor from the Execute menu.
The code between tags W019 and W021 creates two more pushbuttons in the same way we have just seen. The next statement will create the window menus from a single data block.
Ctrl+Homekeys to move the cursor to the top of the BankWindow, then page down until you see the declaration of
Information to build the menu is in a single data block. Each submenu title is terminated by x"01", menu items by x"02", logical event-ids by x"06" and the entire string by x"00".
We won't step through all the code for this method, as it iterates through all the data passed to it in the menu block. If you scroll through it briefly, you can see that it looks through the menu block, adding submenus and menu items.
Each menu item is followed in the menu block by a logical event id.
Each of these is mapped to
parent (which contains the
handle for the BankWindow instance) against the selected event for the
menu item. The "buildMenu" method parses the data block, and
each time it adds a menu item it sets up an event translation of the
same kind as used by pushbuttons.
One effect of mapping physical events to logical events is that the application only has to register an interest in the add-account event on the window. Without this mapping, it would have to register an interest in the clicked event on the Open pushbutton, and an interest in the select event on the Open menu item. The mapping enables the application to remain ignorant of the details of the window controls.
exit methodstatement at the end of this method and select Run to Cursor from the Execute menu.
The execution point returns to the BankWindow code, below tag W025.
These set up event registration for the close event on the window. The close event is sent by the operating system when it wants to shut an application - usually either the user has selected Close from the window's System menu or closed the application from the task list. The close-window event is the logical event this is mapped to. Selecting Exit from the Bank window File menu also raises the close-window event.
This returns you to tag B003 of the "initialize" method of BankApplication. The code between here and tag B004 registers interest in the logical events of the BankWindow instance, and links them to the methods of this BankApplication instance.
These are not all the logical events for this application, but all the ones which can come from the BankWindow. As the BankApplication creates new dialog boxes, it registers events for those too. For example, when it creates the Account Details dialog box, it registers an interest in the credit-account, debit-account and canceldialog events.
Dialog boxes are created as they are needed, and then stored in the BankApplication's instance data. Once created they are shown or hidden as needed. We could have created all the dialog boxes as part of the BankApplication initialization code, but the startup initialization would take slightly longer.
Note that the close-window event has been mapped to the "closeApplication" method.
The rest of this method is code we have looked at in earlier tutorials.
exit methodstatement and select Run to cursor from the Execute menu.
exit methodstatement - step through it.
invoke aGuiBank "run".
This sends the "run" message to the BankApplication instance we have just initialized.
invoke anEventManager "run".
Animator V2 control is suspended as the EventManager instance is now processing events for the application. The Bank application is now waiting for an end-user event.
This event is picked up and indirectly invokes the "closeApplication" method of BankApplication.
The execution point is now inside the "closeApplication" method. This method closes the window, then stops event processing.
The execution point returns to the "run" method of BankApplication.
The execution point returns to an
statement in the class program procedure division of BankApplication.
This ends the program.
This completes the tutorial on Event Driven GUI Programming. Although we only looked at part of the code for this application, all the GUI control is handled in a similar way. You might want to study or animate other parts of the application to find out how it works.
In this tutorial you learn how to translate physical events to logical events as a way of separating interface details from application logic.
Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.
|Requirements-based Vocabulary Tutorial||Object COBOL Tutorials (UNIX)|