PreviousRequirements-based Vocabulary Tutorial Object COBOL Tutorials (UNIX)Next"

Chapter 11: GUI Programming Tutorial (Windows & OS/2)

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:

  1. The Bank Application Classes

  2. Bank Application Startup

Time to complete: 25 minutes.

11.1 Bank Application Classes

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

  1. Start the icon labeled GUI Programming in the COBOL Workbench Tutorials group.

    This starts the on-line tutorial GUI Programming.

  2. Select the hotspot labeled Browse Bank Application (you will need to double-click or press Enter on OS/2), below the heading Using This Tutorial.

    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:

11.1.1 Account Classes

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

11.1.2 Application Logic Classes

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.

11.1.3 Interface Classes

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 the title.

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.

11.1.4 Interface Builder Classes

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.

11.2 Bank Application Startup

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:

  1. Create and initialize an EventManager.

  2. Create GUI objects.

  3. Register an interest in events on the GUI objects.

  4. Start the EventManager processing events.

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

  1. Select BankApplication in the class/program selector.

    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.

  2. Select Animate from the COBOL menu.

    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 of the 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.

  3. Step the first line of code (invoke self "new"...).

    Execution transfers to the "new" method of BankApplication.

  4. Step the next line of code (invoke super "new"...).

    This returns an instance of the BankApplication class.

  5. Step the next line (invoke newApplication "initialize"...).

    Execution now transfers to the "initialize" instance method of BankApplication. The code between tags B001 and B002 creates and initializes anEventManager.

  6. Step through the code until you reach the statement below tag B002 (invoke BankWindow "new" ...).

    This statement creates a new instance of the BankWindow class.

  7. Step the statement below tag B002.

    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.

  8. Step the line below tag W010 to initialize the basic Window data (invoke super "initialize").

    The lines between tag W011 and W012 set the size of the BankWindow window.

  9. Step until you reach the line below tag W012 (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.

  10. Step through the code until you reach the first statement below tag W013 (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.

  11. Step through the code until tag W01.

    This sets the position for placing the first button.

  12. Step the first statement below tag W014 (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.

  13. Step the statements between tags W015 and W016.

    This creates a string object for labeling the button.

  14. Step the statements below tag W016 (starting invoke PushButton "new" using self...) to create and label a button.

  15. Step the statements below tag W017 (starting 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.

  16. Step the first statement below tag W018 (move add-account to logicalEvent).

    add-account is a logical event defined inside the copyfile bwindow.evt.

  17. Step the next statement (invoke aButton "translateEvent" using...).

    The "translateEvent" sets up an event translation between the event id in physicalEvent and the event id in 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.

  18. Move the cursor to the statement below tag W021 (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.

  19. Press the Ctrl+Home keys to move the cursor to the top of the BankWindow, then page down until you see the declaration of menuBlock in working-storage.

    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".

  20. Select Where from the View menu to return the text cursor to the execution point.

  21. Step the next line, to enter the "buildMenu" method of SmartSubMenu.

    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.

  22. Move the text cursor to the exit method statement at the end of this method and select Run to Cursor from the Execute menu.

  23. Step the exit method statement.

    The execution point returns to the BankWindow code, below tag W025.

  24. Step the lines between tags W025 and W026.

    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.

  25. Step through the remaining window code up to and including exit method.

    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.

  26. Step through the code up until tag B004 to register interest in all logical events for the Bank window.

    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.

  27. Move the cursor down to the exit method statement and select Run to cursor from the Execute menu.

  28. Step the exit method statement.

  29. This takes you to another exit method statement - step through it.

  30. Step the line invoke aGuiBank "run".

    This sends the "run" message to the BankApplication instance we have just initialized.

  31. Step the line 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.

  32. The Bank window should be on your desktop now (although it may be hidden behind another window). Find it, and select Exit from the File menu.

    This event is picked up and indirectly invokes the "closeApplication" method of BankApplication.

  33. Reselect the Animator V2 window.

    The execution point is now inside the "closeApplication" method. This method closes the window, then stops event processing.

  34. Step the next three statements.

    The execution point returns to the "run" method of BankApplication.

  35. Step the exit method statement.

    The execution point returns to an exit program statement in the class program procedure division of BankApplication.

  36. Step the exit program statement.

    This ends the program.

  37. Select Exit from the Animator V2 File menu.

  38. Select Exit from the Browser File menu.

  39. Select Exit from the Help File menu to close down the on-line tutorial.

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.

11.3 Summary

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.

PreviousRequirements-based Vocabulary Tutorial Object COBOL Tutorials (UNIX)Next"