Advanced GUI Development Guide
Advanced GUI Development Guide
VisualAge Generator
Advanced GUI Development Guide
Learning to Walk, Run, and then Fly!!!
December 1996
SG24-4238-00
VisualAge Generator
Advanced GUI Development Guide
Learning to Walk, Run, and then Fly!!!
December 1996
IBML
Take Note!
Before using this information and the product it supports, be sure to read the general information
in Appendix E, “Special Notices” on page 363.
This edition applies to Version 2.2 of IBM VisualAge Generator Developer for OS/2. Program
Number 5622-580 for use with the OS/2 Operating System.
When you send information to IBM, you grant IBM a non-exclusive right to use or distribute
the information in any way it believes appropriate without incurring any obligation to you.
Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
How to Use This Redbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
How This Redbook Is Organized . . . . . . . . . . . . . . . . . . . . . . . . xx
Walk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xx
Run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Fly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
PART 1. WALK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Contents v
9.2.2 Data Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
9.2.3 Visual Conditional Logic . . . . . . . . . . . . . . . . . . . . . . . . 176
9.3 Iterations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
9.3.1 Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
9.3.2 Other Iterations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
9.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
9.5 What You Should Now Be Able to Do . . . . . . . . . . . . . . . . . . . 181
Contents vii
Chapter 15. Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
15.1 What Is an Object? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
15.1.1 Real World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
15.1.2 Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
15.1.3 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
15.1.4 Modularity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
15.1.5 Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
15.1.6 Delegation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
15.1.7 Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
15.2 Object Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
15.3 Object Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
15.3.1 The Word Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
15.3.2 Actions, Attributes, and Events . . . . . . . . . . . . . . . . . . . . 312
15.3.3 Class Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
15.3.4 Private and Public . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
15.4 Designing for Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
15.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
15.6 What You Should Now Be Able to Do . . . . . . . . . . . . . . . . . . 314
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
Contents ix
x VisualAge Generator GUI Development Guide
Figures
1. GUI Application Definition Window . . . . . . . . . . . . . . . . . . . . . 5
2. Settings Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3. Pop-up Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4. The Tool Bar of the GUI Application Definition Window . . . . . . . 23
5. Hover Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6. Tab Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7. The Parts List Window . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
8. Data Display Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
9. Data Entry Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
10. Window with List Box and Push Buttons . . . . . . . . . . . . . . . . 53
11. Setting Position of the Top Edge of a Notebook . . . . . . . . . . . . 54
12. Sample Window with Text and Label Parts to Be Distributed . . . . 55
13. Form Covering the Text and Label Parts . . . . . . . . . . . . . . . . 55
14. Distributing the Text and Label Parts . . . . . . . . . . . . . . . . . . 56
15. ITF Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
16. Setting Breakpoints and Watchpoints for a Record . . . . . . . . . . 62
17. Viewing Data Items in a Working Storage Record . . . . . . . . . . 63
18. General Preferences for Testing Applications . . . . . . . . . . . . . 64
19. Trace Entry Filter Window . . . . . . . . . . . . . . . . . . . . . . . . . 70
20. Walkback Error Dialog for Index Out of Range Error . . . . . . . . . 74
21. [Link] File for Index Out of Range Error . . . . . . . . . . 76
22. Walkback Error Dialog for Missing Public Interface Feature Error . 79
23. [Link] File for Missing Public Interface Feature Error . . 80
24. A Simple Event-Driven Application (Stage 1) . . . . . . . . . . . . . . 91
25. Connect Window of the Window Part . . . . . . . . . . . . . . . . . . 92
26. A simple event-driven application (stage 2) . . . . . . . . . . . . . . 97
27. Settings Window of a Connection . . . . . . . . . . . . . . . . . . . . 98
28. Changing the Order of Connections . . . . . . . . . . . . . . . . . . . 100
29. The Data Item Definition Window . . . . . . . . . . . . . . . . . . . . . 108
30. Record Definition Window . . . . . . . . . . . . . . . . . . . . . . . . . 112
31. Record Item Usage Window . . . . . . . . . . . . . . . . . . . . . . . . 114
32. Record Definition Window with Three Data Items Defined . . . . . . 116
33. GUI Application That Moves Data between a Window and a
Working Storage Record Record . . . . . . . . . . . . . . . . . . . . . 118
34. Visual Parts Created with Quick Form . . . . . . . . . . . . . . . . . 121
35. Visual Parts Created from a Structured Working Storage Record
Using Tear-Off and Quick Form . . . . . . . . . . . . . . . . . . . . . . 127
This book is written for system architects, application system designers and
developers, and those interested in object programming with visual
programming technologies such as VisualAge Generator.
We assume that you are familiar with VisualAge Generator Developer, the
use and management of members and member specification libraries
(MSLs), and the process of developing and testing applications—not just
graphical user interface (GUI) applications—in an OS/2 environment with
VisualAge Generator.
We hope that you have reviewed the VisualAge Generator GUI User ′ s Guide
and Reference , especially these chapters:
• Chapter 1, “Introduction to GUI Application Definition”
• Chapter 2, “Visual Construction Fundamentals”
• Chapter 3, “Additional Techniques”
Most chapters in this book include GUI programming examples to help you
understand and practice the VisualAge Generator GUI application
programming concepts discussed. By the time you have finished reading the
book, you will be a much better VisualAge Generator GUI application
programmer and have an appreciation for how powerful the tool can be if
you use the right approach.
We recommend that you perform all of the GUI programming examples for
each chapter in sequence even if you consider yourself a skilled VisualAge
Generator GUI application programmer. You will be surprised at how much
there is to learn about VisualAge Generator GUI application development.
Note: Some examples begin with the code developed in previous examples.
The answers are on the diskette included with this publication.
Walk
The first part of the book teaches you how to walk so that you have a good
solid foundation before you begin more adventurous programming.
Run
The second part of the book teaches you how to run so that you can quickly
implement functional, effective, and capable GUI application systems.
Preface xxi
Discusses the options and approaches available for implementing
validation and error management in a GUI application system.
Fly
The third part of the book teaches you how to fly so that you can soar to new
heights and implement reusable components and full systems using an
object-oriented approach to VisualAge Generator GUI application
development.
Before we go on we must note that this book would not have been possible
without the attention and assistance provided by Alex Akilov a member of the
VisualAge Generator development team and “King-GUI” of the VisualGN
CForum.
Thanks also to Maggie Cutler and Christine Dorr for their editing and
manuscript support.
Comments Welcome
We want our redbooks to be as helpful as possible. Should you have any
comments about this or other redbooks, please send us a note at the
following address:
redbook@[Link]
In this book we discuss how VisualAge Generator can be used to build GUI
applications. In this chapter we first discuss the characteristics of GUI
development. Then we describe the components of a GUI and their
characteristics and implementation in VisualAge Generator. We assume that
you have a basic understanding of the VisualAge Generator Developer and
know how to define member specification libraries (MSLs).
• At any time during their interaction with the computer, users are in
control and decide what they want to do next. The applications are
driven by events caused by user actions.
A business GUI application communicates with the user through one or more
windows . This is the only way in which the graphical interface is established
between the application and the user. All visual parts must be materialized
ultimately through a window to become visible and accessible by the user of
a GUI application.
The elements that make up a GUI application are called parts . All parts that
can be used as elements of a GUI (that is, they can be made visible and
accessible to the user) are called visual parts or widgets .1 By default the first
visual part that is defined within a GUI application becomes its primary part .
However, you can make any other visual part the primary part of the GUI
application.
The default primary part when you create a new GUI application is a window.
The white area surrounding the window on the GUI application definition
window is called the free-form surface . It represents the GUI application
itself, the one you are developing at the moment. On the free-form surface
you define the nonvisual parts and those visual parts that are not visible to
the user but are used for programming purposes. A single GUI application
member can contain multiple windows. Because of the complexity this
causes, we recommend that you not define more than one window per GUI
application. In fact, you may find that you prefer to define more than one GUI
application per window so that you can construct your application from
reusable and maintainable parts. See Chapter 4, “Window and Part Position
Management” on page 45 for a detailed discussion on window design for
GUI applications. In Chapter 11, “Building VisualAge Generator Parts” on
1 Although menus can be made visible to the user, we do not consider them visual parts.
2. Select or define an MSL where the members of the GUI application are to be
stored.
4. In the New Member pop-up window click on the GUI radio button and the
Open... push button or double-click on the GUI icon to open the GUI application
definition window directly.
The GUI application definition window opens and shows a GUI application with a
window as its primary part.
The window you see is identical to that shown in Figure 1 on page 5.
To run or test a GUI application, it must have a window as its primary part.
The visual parts that should be visible to the user should be placed inside
the window. The window is shown on the screen when you test or the user
starts a GUI application.
2. Because you have not named the GUI application yet, a Save As window pops
up where you enter the member name GUITST1. VisualAge Generator stores the
GUI application in the MSL as a GUI application member with the name you
entered.
Each part has a public interface . The contents of the public interface of a
part depend on the part′s type and describe how the developer and the user
can interact with the part. The public interface consists of actions, attributes,
and events, collectively called features . Interactions between parts are
visually defined by drawing connections between features of the parts. We
describe the features of parts and how to draw connections in Chapter 6,
“Event-Driven Programming” on page 89.
The Settings notebook consists of a General tab and optionally additional tabs,
depending on the part′s type. All tabs themselves consist of one or more pages of
attribute definitions. Figure 2 on page 8 shows the first page of the General tab of
the Settings notebook of a window.
To display the settings of a part, do the following:
2. In the Open Member pop-up window enter the member name GUITST1 and click
on the Open... push button.
The GUI application with the window part is displayed.
3. Double-click with mouse button 1 on the part for which you want to display the
settings window, in this case the window part.
The settings window of the window part is displayed (see Figure 2 on page 8).
4. Look through all the pages of the Settings notebook and try to understand
their meaning.
It is not necessary that you understand all the details of the settings window
now. This exercise should give you only a feeling of the contents of the
settings of a window part. If you want to know more about a setting, click on
Help.
All parts, including connections and the free-form surface, have a pop-up
menu, also called a context menu or object menu. The pop-up menu is a list
of frequently used functions you can use to manipulate the part. To access
the pop-up menu of a part, click on it with mouse button 2. If the part has a
settings window, the first selectable entry in the pop-up menu of the part is
Open Settings. If you click on the entry with mouse button 1, the settings
The pop-up menu also tells you whether or not a visual part that is not
contained in another part is the primary part. If it is not, the pop-up menu
contains a Become Primary Part entry. This option enables you to change
the primary part of the GUI application.
A GUI application that does not have a window as its primary part is called
an embeddable GUI application or embeddable part . If an embeddable part is
included in another GUI application, it is called an embedded GUI application .
GUI applications that are embedded in a window are visible to the user.
2. In the New Member pop-up window click on the GUI radio button and the
Open... push button.
3. Delete the window part from the free-form surface by selecting it with mouse
button 1 (the corners of the window part will become highlighted) and pressing
the Delete key.
4. Add a push button part to the empty free-form surface of the GUI application
definition window by clicking on the push button icon in the parts palette and
then on the free-form surface.
The parts palette is on the left side of the GUI application definition—you will
see two columns of icons. They represent the categories of parts and the
individual parts available for use in VisualAge Generator. A push button part
should be visible at the top of the right column (it is the first part in the first
category). The parts palette is reviewed in detail in 2.1, “Using the Parts
Palette and Tool Bar” on page 21.
5. Save this GUI application as member name GUIEMB1 and close the GUI
application definition window.
You have now created a reusable embedded GUI application. To use this
embedded GUI application in another GUI application, do the following:
3. Select the GUIEMB1 member from the drop-down list in the Add GUI application
window.
5. Move the crosshair to the window part in GUITST1 and click mouse button 1.
The embedded GUI application part is defined at the spot of the crosshair.
6. Save the GUITST1 GUI application and close the GUI application definition
window.
If you embed a GUI application that has a window as its primary part it is
called an external GUI application . An external GUI application cannot be
placed in a container, such as a window, of another GUI application; it has to
be placed to the free-form surface of that GUI application.
2. In the New Member pop-up window click on the GUI radio button and the
Open... push button.
7. Select the GUIEMB1 member from the drop-down list in the Add GUI application
window.
9. Move the crosshair to the window part and click mouse button 1. The
.. embedded GUI application part is defined at the spot of the crosshair.
.
10. From the Options pull-down menu select Add GUI application....
11. Select the GUITST1 member from the drop-down list in the Add GUI application
window.
12. Click on the OK push button. Your cursor symbol becomes a crosshair when
over the free-form surface. (An invalid option cursor is shown when the
pointer is above the window part.)
13. Move the crosshair to the free-form surface and click mouse button 1. A n
external GUI application part is defined at the spot of the crosshair.
14. Save the GUI application as GUITST2 (we test the GUI applications in 1.3,
“Testing GUI Applications with ITF” on page 12).
Hint
To change the title of a part directly without accessing its settings, keep the ALT
key pressed and click on the part with mouse button 1. You can now change the
title by typing in the text you want to use.
To save the new title text, click on any spot outside the part.
If you test an application, a window called the Test Monitor is started in the
background. This window is the interface to the Interactive Test Facility (ITF)
of VisualAge Generator. It allows you to track and debug your applications
without generating them into executable code.
The ITF supports both the interpreted execution of GUI and server
applications. Tracing of code is supported for both application types.
To use a certain database during the test session when no explicit connects
have been coded in the application, indicate the database name in the
VisualAge Generator profile. Select Profile and then Database preferences...
to change the name of the database used. The first time the database is
accessed through ITF, VisualAge Generator binds the [Link] package to
the database.
In addition to allowing ITF to interact with the database, the bind also
determines the format in which date and time values are returned to
VisualAge Generator. If the format is incorrect, you can manually bind the
package to the database using the correct format parameter:
where XXX indicates the datetime format used. See the DB2 documentation
appropriate for your DB2 database system for more information about
binding a package to the database. The ITF is discussed in more detail in
Chapter 5, “Testing and Debugging GUI Applications” on page 59.
2. From the Tools pull-down menu select Test. Which window can you see? Why
can′t you see the window of the external GUI application?
Embeddable parts reside in their own separate .app file. They get generated
automatically if they are embedded in a GUI application that you generate
and you set the Embedded GUIs check box in the Generated Code tab in the
generation options notebook. This equals the /GENEMBEDDEDGUIS
generation option. VisualAge Generator tables and non-GUI applications are
generated separately. The generated VisualAge Generator table has an
extension of .tab. Non-GUI application generation output is dependent on the
target runtime environment. See Generating VisualAge Generator
Applications for details.
Any GUI application that has a window as the primary part causes a
command file to be generated when the target environment is OS/2. The
command file can be used to start up the application. The command file
contains only the following line:
If you generate a GUI application that uses an object factory to create parts
at runtime, ensure that you generate these dynamically created embeddable
parts or GUI applications as well.
1. Close any open GUI application definition window and the Test Monitor
window.
Build a member list of the GUI applications you have defined so far.
2. From the File pull-down menu select Member list... to open the Member List
Criteria dialog.
3. Define the Member name as * and GUI applications as the only selected
Member Type Criteria by selecting the none radio button and then the GUI
toggle button. Click on the Build list... push button. A member list window will
be shown.
5. From the File pull-down menu select Generate... to open the Generate dialog
for GUI application GUITST1.
a. Select a Target system of OS/2 and provide appropriate file names for the
Command and Message log files.
b. Do not select any of these toggle buttons: Append to command file, build
command file only, or LAN based generation.
7. Click on the Set options... push button to open the OS/2 Generation Options
notebook.
8. Select (if not already selected) the Embedded GUIs toggle button on the
Generated Code notebook page.
9. Define a directory name in the Generation output directory entry field on the
Output files notebook page.
10. Click on the OK push button to close the OS/2 Generation Options notebook.
11. Click on the OK push button of the Generate dialog to start the generation
command file. Answer Yes to the confirmation dialog. This will start the
VisualAge Generation Monitor which will generate the GUITST1 GUI application.
12. If you selected the View messages toggle button on the Generate dialog, you
will see a View Messages dialog with the messages received during
generation. Click on the OK push button to close the View Messages dialog.
13. Click on the Cancel push button to close the Generate dialog for GUI
application GUITST1.
14. Close the VisualAge Generation Monitor by clicking on the Stop monitor push
button. Answer Yes to the confirmation dialog.
The ITF can call generated server applications if the called application name
is in the linkage table identified in the ITF general preferences profile.
Linkage table processing for an ITF call differs from runtime.
ITF uses the existence of the application in the linkage table identified in the
ITF general preferences profile to determine whether a call is to be a remote
call. If the a generated application is to be called, ITF passes the linkage
table file name, less the path information, to the runtime remote call support
routines. These routines then process like runtime, using the linkage table
name passed by ITF.
Note: This processing does not guarantee, or require, that the linkage table
identified in the ITF general preferences profile be the same referenced by
the CSOLINKTBL environment setting.
1. Open an OS/2 window and change to the generation output directory identified
during GUI application generation.
2. Issue the dir GUI*.* command, and you should see these files, which were
created during generation:
E:\vgenout\vgui─dir GUI*.*
The .APP files are the Smalltalk code for external GUI application GUITST1 and
embedded GUI application GUIEMB1. A [Link] file was also generated
for external GUI application GUITST1.
The command tells VisualAge Generator to use the Smalltalk GUI application
runtime image to open (load, create, and open) the generated Smalltalk code
for the GUITST1. GUI application. The GUIEMB1 GUI application will also be loaded
since it is embedded in GUITST1..
4. Enter the command GUITST1. You should see a window with a push button, just
as you saw when you tested the GUITST1 GUI application.
5. Close the window and issue this command to force a shut down of the
Smalltalk GUI application runtime image:
EZE2RUN KILL
Only visual parts defined on the free-form surface can become the primary
part. A GUI application has one and only one primary part. A GUI
application must contain at least one visual part. An executable GUI
application must have a window as its primary part. For a part to become
visible to the user it must be either a window or a visual part that is
ultimately embedded inside a window.
GUI applications can also contain one or more embedded or external GUI
applications. A GUI application can be included in more than one GUI
application. An embeddable GUI application does not have a window as its
primary part. An embeddable GUI application can be embedded in a
window. An external GUI application has a window as its primary part. An
external GUI application cannot be embedded in a window, but you can make
it part of the GUI application by placing it on the free-form surface.
To add a part to a GUI application, select it from the parts palette and move
the mouse pointer over the location where you want the part to appear. If a
part is a nonvisual part, you cannot drop it onto a part that includes other
parts such as a window. In such cases the pointer turns into a no-entry sign.
You can place parts on the free-form surface. Although the user will not be
able to see the parts, they can be useful for programming the logic of your
program. We discuss building logic into an application in more detail in
Chapter 6, “Event-Driven Programming” on page 89 and Chapter 9,
“Visually Building Logic” on page 161.
If you want to add multiple parts to the GUI application without having to
select the part every time, select the Sticky setting underneath the parts
palette. This action places a part of the type selected from the parts palette
in the GUI application every time you click mouse button 1 on the free-form
surface or in a part that can include other parts such as a window. Deselect
the setting to stop adding multiple parts.
The Sticky setting can also be used to apply the same font or color setting to
multiple parts.
You delete a part from the GUI application by selecting it and either choosing
Delete from the Object menu or pressing the Delete key. When you delete a
part, you also delete any subparts it contains, associated promote part
features, and connections.
Once you have dropped the part in the GUI application, you can select it by
clicking on it with mouse button 1. The selected part will be highlighted with
handles in the form of filled in boxes at the corners.
You can select multiple parts by holding down the Ctrl key and clicking on
other parts. In this way you build up a set of selected parts. You deselect a
part by holding down the Ctrl key and selecting the part again. You deselect
multiple parts by holding down mouse button 1 and dragging the pointer over
the parts to be deselected. A part can be added to a set only if it is included
in the same part (for example, parts in the same form) as the other selected
parts.
If you have selected one or more parts, you can change their layout. You
can move parts by dragging them to a different location. You can size them
by dragging one of the handles (black box) to a different spot. You can align,
size equally, and distribute selected parts over the surface of the part in
which they are included by using the different options from the tool bar. The
primary part (last part selected) in a set determines to which part the other
parts are aligned or sized. The primary part in a set of selected parts will be
highlighted with handles in the form of filled in boxes at the corners. The
other selected parts will have handles in the form of outlined boxes. The
handles of this part are filled boxes instead of outlined boxes. Figure 4 on
page 23 shows the different types of actions available on the tool bar.
You can also distribute parts within the bounding box of a set of selected
parts. The bounding box is defined by the top left-hand corner and bottom
right-hand corner of the set of selected parts. From the Object menu of a set
of selected parts, select Layout and then Distribute and then either
Horizontally in bounding box or Vertically in bounding box, depending on the
layout. The Horizontally in surface and Vertically in surface options are
identical to using the distribute options in the tool bar.
If you make an error when adding, removing, or manipulating parts, you can
undo and redo the changes using the respective options from the Edit menu.
You can even get a list of all the actions that can be undone or redone.
The VisualAge Generator parts may not map one-to-one to the parts
mentioned in Object-Oriented Interface Design, IBM Common User Access
Guidelines , and there are nonvisual parts that are specific to VisualAge
Generator that are mainly used for implementing logic. Table 1 on page 24
lists all of the VisualAge Generator parts, the parts palette category to which
they belong, and their use.
Data Entry A grid that can be used to display an array of information. The
Table container details part provides similar a display with improved
function.
Label Static text that can be used to indicate the meaning of another part
Enables a user to scroll through a list of values within a range. Use
Spin
for situations where the range is limited and the increments are
Button
logical.
A composite part can include other parts. Any alignment or distribution that
is performed on those other parts is performed within the composite part.
Most composite parts can also be included in other composite parts; for
example, a window can include a group box that includes a number of entry
fields. In fact, if you want to have an embeddable part that includes multiple
entry fields, you must place them in a composite part such as a form. The
form will be the primary part in the embeddable part. When this part is
embedded in another GUI application, all entry fields included, along with the
primary part, will be visible in the embedding GUI application.
(*): The formatted text part has a converter that differs from the converter of
the other parts. Instead of checking the format after the user has provided
an entry, the formatted text part converter does not allow the user to enter
any character that does not conform to the definition of the data type.
If you open the settings window of a part, you get a number of tabs and
pages (each tab can contain multiple pages). A number of the settings are
generic for the part with which you are working. A number of characteristics
always have the same meaning, however. Table 2 through Table 5 on
page 33 present the names, default settings, and descriptions of the most
commonly used attributes in the settings windows of the different parts. For
full descriptions, see the VisualAge Generator GUI User ′ s Guide and
Reference .
Table 2 (Page 1 of 3). Common Attribute Settings for General Tab of Settings Window
Attribute Default Description
Setting
Label type <blank> Indicates whether a graphic image or text string is shown in the part.
If Graphic is selected, there are options for the image. If Text is
selected, there are options for the text string.
Label partNamex The label that is shown in the part
string
Data type <none> The data type to which any data represented in the part should
conform. If the data does not conform a string showing ** error ** is
shown. You can further customize the data type to indicate formats,
valid ranges, and default values by clicking on the Customize...
button.
Reformat on Indicates whether the data should be reformatted according to the
data on data type settings when the field loses focus
focus
change
Mnemonic <blank> Indicates the letter that is part of the label that will get an
underscore. The mnemonic can be accessed by pressing the letter
when the group in which the part is included has the focus or
combining the key with the Alt key when the group does not have
the focus.
Hint
VisualAge Generator does not allow you to change the default values of the parts.
However, you can create a GUI application that includes all of the parts that you
use in your application development and give them the correct default settings.
Put this common part GUI application in a common MSL and always have it open
when you are developing an application. You can then copy and paste the parts
from the common part GUI application instead of obtaining parts from the parts
palette. This will ensure that the parts have the correct initial settings.
You could get a similar result by promoting parts to the palette. Just remember
that VisualAge Generator updates often reset the palette to what was shipped with
the product (so they can add new parts to the product).
Parts have different uses. The CUA standards define the use of parts in the
context of your application.
Each part has settings. The settings determine the initial layout and behavior
of the parts. Most parts have similar types of settings.
• Identify the basic tool bar control functions of the VisualAge Generator
GUI application builder
We do not discuss the basic use of the GUI application definition or the parts
palette. These topics are covered in Chapter 2, “Visual Construction
Fundamentals,” of the VisualAge Generator GUI User ′ s Guide and Reference .
3.1 Window
The part that forms the base for your GUI application is the window.
A window is the only valid part for running or testing a GUI application. All
user functions have to be visualized somehow by means of components of a
window so that they become visible on the screen and accessible to the
user. A window holds other parts. Any parts placed inside a window
automatically have a relationship with the window, their parent.
As for all parts, it is advisable to set standards within your organization for
the settings of the parts to ensure that all windows in an application look and
feel the same to the user.
The sizing and positioning of windows and other visual parts can affect the
look and feel of the GUI application for different users who use different
resolution settings for their displays. Designing flexible GUI applications
requires careful planning and consideration. We review this topic in detail in
Chapter 4, “Window and Part Position Management” on page 45.
System Users cannot access any other windows that are open in the
operating system until they have closed the window opened
in this mode ( openSystemModalWidget ).
Full Application
Users cannot access any other windows that are open in the
current application (the VisualAge Generator GUI runtime
environment) until they have closed the window opened in
this mode ( openFullApplicationModalWidget ).
Application Users cannot access the window that opened the application
modal window until they have closed the window opened in
this mode ( openApplicationModalWidget ).
Modeless The windows mode does not restrict the user from acting on
any other windows ( openWidget ).
The text that is used for hover help is the text that has been entered as the
label string of the part. Although the part is shown as graphic, you can
switch between these two modes and define the label string.
Hover help is shown only when the composite part that holds the part for
which you want hover help has the hoverHelpEnabled attribute set to true.
2. Open the settings of the window part and set the check the toggle button
Enable hover help over all children on the second page of the general tab in
the settings notebook.
4. Open the settings of the push button and change the label string to “Closes
the application.”
5. Choose the Graphic radio button for the label type option.
6. Choose the Image radio button for the graphic type option.
7. Select a bitmap file (.BMP) using the Find... push button and then save the
push button settings. (There should be some bitmaps in your c:\os2\bitmap
subdirectory; [Link] is a nice choice.)
9. Test the application. (Save the GUI application as HOVERHLP.) Hold the mouse
cursor over the push button. VisualAge Generator will show you the text you
entered as the label string for the push button.
Note: Clicking on the push button will not close the application because we
did not make the required connection.
Each composite part has a tabbing order related to its parts. The tabbing
order is initially equal to the order in which you have added the parts. You
can change the tabbing order manually or let VisualAge Generator determine
the default tabbing order (from left to right and from top to bottom). To let
VisualAge Generator determine the tabbing order, select Set Tabbing
followed by Default Ordering from the Object menu of the composite part.
To manually adjust the tabbing order, select Set Tabbing followed by Show
Tab Tags from the Object menu of the primary part. Each part that has been
set to be traversable gets a numbered tag indicating its order in the tabbing
sequence (see Figure 6 on page 41).
2 The tabbing order also determines the order in which parts are created.
Drag the number of a field to a different location to change the tabbing order.
The target of this operation gets the indicated number in the tab sequence.
You cannot drag the number outside the part in which it is included. Instead
use the number of the composite part, which is represented in blue.
If a part is traversable but does not have the tab group attribute set, it is
shown as part of a group. Use the tab key to access the group. Press the
tab key again to leave the group. Within the group you can use the cursor
movement keys to move between the parts. A group is specified with
sequence numbers indicating the group and the order in the traversal
sequence (for example, 1:2).
The order of traversal can be changed similarly to the way you change the
tabbing order. A group always has the same tab group indicator (1) if it is
not part of its own composite part. The only way you can have another part
earlier in the tab sequence is by putting the group in a composite part.
In the parts list each part has an Object menu that enables you to open the
settings of the part, change its name, or delete it. You can also change the
part name by holding down the Alt key and clicking mouse button 1 just as
you do to change the title of a window in the GUI application.
The parts list can be invaluable for finding parts that have been covered by other
parts. You can also use the parts list to save a lost part, that is, a part where one
of the dimensions has become 0 and you no longer can see or manipulate it in the
GUI builder visual view.
3.5 Summary
Many modes can be used to open a window. Each mode can alter the flow
of how a user interacts with the GUI application system. The window part is
used to show other parts to a user.
Parts that can have both graphic and textual representations can be provided
with hover help. The tab sequence of the parts can be adjusted and the
parts included in a GUI application can be viewed through the Parts List
window.
• Control the tabbing order of your window and understand its implications
First we discuss the design aspects of defining windows and the visual parts
within a window. Then we describe the properties of a window related to
window management and how to use them effectively. Finally we suggest
techniques for defining visual parts within a window so that they will adjust
automatically to changes in the runtime environment.
Our initial suggestion is that you develop data display and data entry
functions as separate components that can be reused.
In addition to the data display and data entry components used to exchange
data between the user and the GUI application, a window has parts that
enable users to:
• Control the type of interaction they want to perform (for instance, display
or modify data)
These parts will be used in both data display and data entry windows.
You may decide to define windows that combine the features and functions of
both data display and data entry windows. However, consider these issues
before deciding to mix the window types:
Decisions regarding the separation of data display and data entry windows
must be incorporated as part of your local standards for GUI application
development so that you can:
Our suggestion to separate data display and data entry windows is only one
technique for making GUI windows as simple as possible. We also suggest
that you consider using only a subset of the parts available for GUI
application development. This will increase both programmer productivity
and the usability of the GUI application.
In the sections that follow we describe the visual parts used in the data
display and data entry windows and these development issues related to the
process of building dynamic GUI applications.
4.2.1 Windows
The attributes of a window part that are used for positioning and sizing a
window are defined in the General and Layout Tabs of the Settings window.
We describe the attributes and their use in 3.1, “Window” on page 35.
Some visual parts, such as a window located in the Canvas category of the
parts palette, can contain other visual parts. These parts have some special
attributes, called Child Placement Rules , in their General settings. There is
no need to change any of the default settings.
If you want to change the Layout settings of a window, consider the following
rules:
Notes:
1. If one of the values of coordinates X and Y is set to 0 or has been
erased, the window will pop up at a random position every time it is
opened.
2. If you set Width or Height to 0, the window shrinks to a size that is
unusable.
A value of 50 for the Width and Height with Proportional grid displays a
window with a size that is half the width and height of the screen. A value of
Note: First check all toggle buttons for Proportional grid and then change
the contents of the entry fields. Apply your changes and look at the new
window layout first before you click on OK to ensure that your changes are
acceptable.
The other attributes of interest for positioning and sizing visual parts are
defined in the Layout settings of the part. The content of the Layout settings
of a visual part depends on the placement of the part. If the part is defined
on the free-form surface, the Layout settings describe the coordinates of the
upper-left corner and the size of the part. Note that these parts do not offer
a Proportional grid specification in their settings.
If the part or embedded GUI application is defined inside another visual part,
that part is called its parent part . The Layout settings describe the position
of the part′s (or embedded GUI application′s) edges relative to the parent
part, to other parts, called targets , defined within the same parent part, or to
another edge of itself. In addition no attachment or proportional grid is
definable.
The best way to understand how the Layout settings can be used to control the
visual view of a set of parts is to try it:
1. From the File pull-down menu select New member.... In the New Member
pop-up window click on the GUI radio button and the Open... push button.
3. Add a second push button or, if you created it, add the embedded GUI
application GUIEMB1, to the bottom of the window. To embedded GUIEMB1:
a. From the Options pull-down menu select Add GUI application.... Select
the GUIEMB1 member from the drop-down list in the Add GUI application
window.
b. Click on the OK push button (your cursor symbol becomes a crosshair and
move the crosshair to the window part and click mouse button 1. The
embedded GUI application is defined at the spot of the crosshair.
4. Size and align the push button and the embedded GUI application so that they
are balanced in the bottom area of the window.
5. Add a list box to the window part above the push buttons. Size the list box so
that it is about as wide as the outside edges of the push buttons (see
Figure 10 on page 53).
7. Test the GUI application. Resize the window by grabbing the bottom
right-hand corner of the window and dragging the corner to a new point on
your display. What happens when you make the window larger or smaller?
9. Resize the window part directly in the GUI application definition window by
grabbing the bottom right-hand corner of the window and dragging the corner
to a new point on the free-form surface. What happens when you make the
window larger or smaller?
You should now see that visual parts added to a window, by default, do not
resize at all when the window is resized and that the behavior in test mode is
the same as when you manipulate the window part in the GUI application
definition window.
Let′s change the Layout settings of the visual parts on the window to modify
the resizing behavior:
10. Resize the window so that you return to the original view (see Figure 10 on
.. page 53).
.
11. Double click on the list box to open up the settings window. Using the Layout
page of the Settings notebook, change the Edge selection and Attachment type
settings for the list box to these values:
12. Resize the window part directly in the GUI application definition window by
grabbing the bottom right-hand corner of the window and dragging the corner
to a new point on the free-form surface. What happens to the list box and the
push buttons, when you make the window larger or smaller?
We now have the list box sizing with respect to the window, but it can size
right over the top of the push buttons! Let′s fix that:
13. Double-click on the left of the two push buttons to open up the settings
window. (If this is the embedded GUI application, you will have to use mouse
button 2 to open the Object menu for the part and select the Open settings
option.)
14. Using the Layout page of the Settings notebook, change the Edge selection
and Attachment type settings for the left push button to these values:
15. Double-click on the right of the two push buttons to open up the settings
window. (If this is the embedded GUI application, you will have to use mouse
button 2 to open up the Object menu for the part and select the Open settings
option.).
16. Using the Layout page of the Settings notebook, change the Edge selection
and Attachment type settings for the left push button to these values in this
order:
You may need to reposition and line up the push buttons after these changes
so the initial view is the same as before (see Figure 10 on page 53).
17. Resize the window part directly in the GUI application definition window by
grabbing the bottom right-hand corner of the window and dragging the corner
to a new point on the free-form surface. What happens to the list box and the
push buttons, when you make the window larger or smaller?
We now have the list box sizing with respect to the window and using two different
techniques, the push buttons staying below the list box. Try and change the push
button settings so that they stay inside the window.
Controlling the layout for multiple visual parts in a composite part such as a
window or form can be a complex task. Consider the following approaches
in your GUI applications:
• Group visual parts in forms and GUI builders and then focus on
managing the layout of these composite parts.
• Test the visual layout of your GUI applications on all target display
resolutions.
5. Click mouse button 1 on the Bottom radio button and set the Attachment
type to Parent bottom edge and the Offset to 0.
6. Set the Attachment type and Offset for the Left and Right radio buttons to
the Parent left and right edge respectively, with an Offset of 0.
7. Click mouse button 1 on the OK push button to both apply the setting
changes and close the Settings notebook.
Try other top/bottom and left/right offset values to see how they affect the
appearance of the part in the window.
Figure 12. Sample Window with Text and Label Parts to Be Distributed
1. Drop a form on the text and label parts. Size the form to cover the area
that you want to use for the text and label parts (see Figure 13). If you
want to visibly group the text and label parts, use a group box instead of
a form.
3. Select all text and label parts, drag them, and drop them on the form.
4. Select all text parts and click mouse button 1 on the distribute vertically
button.
5. Select all label parts and click mouse button 1 on the distribute vertically
button (see Figure 14). You may need to align the parts as well.
6. Select the form, drag it, and drop it back on the window. The text and
label parts will come along with the form. We recommend that you
move the entire form instead of the texts and labels only. The form is
not visible on execution, but it is useful for maintenance.
4.4 Summary
There are two fundamental types of windows: the data display window and
the data entry window. The function of a window will impact its design. A
flexible GUI application system is based on clear, simple, and easy-to-use
windows.
The visual view of a GUI applications is based on how you arrange and
control the layout of the visual parts.
Windows have options that can control their visual aspects, sizing rules, and
where they will be shown on the display. Other composite parts, such as
Visual parts placed on other visual parts have powerful layout options that
allow you to control the relationships between visual parts on a given
composite part during resizing activity.
Layout options allow you to control and manipulate visual parts to fine tune
the runtime view of the GUI application.
• Understand and use the layout control options for visual parts when
placed on the free-form surface and on other visual parts
• Manipulate the visual view of parts, using the layout and distribution
options
3 We did not study this new feature of VisualAge Generator 2.2 in our project. To learn more, search
on the word partitioning in the VisualAge Generator Developer help facility.
ITF is started as soon as you test an application. The interface with ITF
consists of the Test Monitor window (see Figure 15 on page 61).
Stack Monitor
Each application, process, or statement group that is executed is
pushed on the stack. When execution is complete, the entry is
popped off the stack. To open the member for editing,
double-click on it.
Watchpoint Monitor
The watchpoint monitor shows the current values of variables
(data items) that you have chosen to include in the list of
watchpoints. You can edit the content of a variable by
double-clicking on it.
Statement Monitor
The statement monitor shows the current position within a
process or a statement group. You can reposition the statement
pointer by clicking on the statement to execute next. You can
also set a breakpoint by clicking on a statement with mouse
button 2.
Action buttons
Action buttons enable you to control the flow of statement
processing. The action button functions, in order from left to right,
are:
From the View menu you can hide or show the first three parts of
the test monitor.
Testpoints can be set by selecting Options and then Set testpoints from the
menu. For records and VisualAge Generator tables you can set breakpoints
and watchpoints, for processes, statement groups, and applications you can
set breakpoints or tracepoints. Select the member (or EZE word) you want to
work with and then the type of testpoint you want to set. Figure 16 shows an
example of setting breakpoints and watchpoints on a data item in a record.
You can choose to have the ITF implement calls to VisualAge Generator
applications as calls to generated server applications through the use of a
linkage table. In this case the entire application tree after a call to the first
generated application must consist of generated applications. Control
returns to the ITF after the completion of the initial call to a generated server
application.
If you deselect the Monitor statements during RUN toggle button (see
Figure 18), you will not see the statements in the statement monitor portion
of the Test Monitor window during testing. If you stop testing or reach a
breakpoint, the active statements will be visible in the statement monitor
area. If you deselect the Monitor statements during RUN button, you are
reducing the workload on ITF and improving the performance (relative
execution speed) of testing.
For the fastest possible ITF test run, turn off the Break on event entry option and
minimize the Test Monitor window. This will allow the ITF to process your logic
with minimal overhead. This approach is excellent for demonstrating code to end
users with minimal overhead and without having to first generate and prepare the
applications for a runtime environment.
To start a trace, select Trace and Trace all from the menu of the Test
Monitor. All activity will now be written to the trace. If you want to view the
trace, choose Trace and View trace... from the menu. These actions will
bring up a window with all of the trace entries. You can open as many of the
trace log windows as you want. You can modify the trace options (Trace all,
Tracepoints only, Trace nothing) only after you have stopped or paused the
testing activity. You can trace the initial activity of a GUI application, the
activity that occurs before the first pause, by:
Now the trace log will contain the initial events that occur in the GUI
application.
These entries contain the events that are signaled throughout the
system and cause a certain action to be performed. If the entry
concerns an attribute-to-attribute connection, the arrow indicates
whether the connection is unidirectional or bidirectional.
Hint
Application identifier
Statement
Application call
Parameter value
Switching processes
A trace log window can have a filter applied to it to indicate that only certain
entries should be included. To apply a filter for one trace log window, click
on the Set Filters... push button on the trace log window. To apply a default
trace log filter, select Profiles and Test and Default trace entry filters... from
the menu.
Figure 19 shows the Trace Entry Filter window. Table 8 lists the toggle
button options in the Trace Entry Filter window.
You can have a different set of filter options for each open trace log window.
It is quite convenient, for instance, to have a trace log window with just the
GUI events and another trace log window with all of the procedural coding.
Breakpoints
You can use breakpoints to stop the execution of a procedural program.
With breakpoints you have more control over where the test run is
stopped. Breakpoints, once set, can be disabled to allow you to run the
application without interruption. The breakpoints can be enabled again
when required.
Sometimes the ITF test run will not hear your stop request. This can
occur because the processing is complete before your request was
received. You can always reduce the relative execution speed to give
your stop request more time to be heard. There are also some rare
cases with GUI application where the system input queue is blocked
during the processing of the GUI application request. If this is the case,
you need to use the Alt+PrintScreen key combination.
Hint
When an error occurs in the ITF, respond to the question of whether you want to
exit with “No.” Look at the trace to see where the application stopped. In this way
you do not have to look at the [Link] file.
In this section we look at how you can set up your system to write out error
information to the [Link] file and how to read the information to
determine why your GUI application failed.
Hint
VisualAge Generator also writes out error information to the [Link] file
when you have set up debug support. Often this is the best place to look first. The
[Link] file should contain an entry for the connection that failed. This may
be enough to point you to the problem in your GUI application without having to
read the [Link] file.
You cannot edit the [Link] file with the E command while VisualAge
Generator is running. The file is locked. Use the EPM command instead—but do
not save the file.
The first GUI application contains a window with a push button. The clicked
event of the push button is connected to the atIndex: action of an ordered
collection on the free-form surface of the GUI application. A parameter of 0
has been provided as part of the connection between the push button and
the ordered collection. When we save and test the GUI application and then
click on the push button, an error occurs.
Figure 20. Walkback Error Dialog for Index Out of Range Error
To find the last stack dump scan the [Link] file (Figure 21 on
page 76) from bottom up until you find a blank line ( 1). Then look forward
in that particular dump for the word “ Error: ,” or the line that matches the
topmost line in the stack dump, which is the error that occurred ( 2).
Everything above this point is related to the processing the error handler
does to log the error and put up the message and can be ignored. However,
the first line after the word “ Error: ” is the top of the stack when the problem
occurred. Remember that this is a stack dump, and the deeper (further
down) you go the earlier in time you are traveling (within the current stack).
All of the entries in the [Link] file are Smalltalk lines of code.
They first state the Smalltalk object involved followed by the action that was
performed on the object. The lines that follow indicate the values for any
parameters, if relevant.
The lines after this first indication of the error explain the message that was
sent to a part that caused the error.
As we work down in the stack we see that in Smalltalk you can send any
message to any part, but there is the chance that the part you are sending it
to does not understand the message. This will result in a
doesNotUnderstand: situation ( 3).
The message that is not understood is a connection that was visually built by
you or was caused by procedural logic in a process or statement group. The
first meaningful indicator of this message will be the line in the
[Link] file that includes the message that was sent.
This can be found by first looking further down for an indication that
something went wrong. This is identified by Exception: (ExUserBreak) A
break has occurred. ( 4).
If we continue down in the stack we can see that the connection involved
was clicked of a push button to atIndex of an ordered collection with an index
of 0 provided as the parameter. ( 5).
4 You may notice that the data in a [Link] file for one error is there twice. When you scan
back from the bottom and stop at the first blank line, you have found the second of two stacks
written for the error. Only this stack is shown in Figure 21 on page 76. This stack will help you find
the problem in your GUI application.
If you had a complete [Link] file and were to continue to scan back to the next blank line,
you will see the first of the two stacks written for the error. The fact that there are two stacks for
the same error may actually be a bug, so if you do not see two stacks, it might be that the bug was
fixed.
1
Walkback at 2:18:53 PM on 11-01-96
(ExCLDTIndexOutOfRange) Index out of range.
EaRuntimeStartUp class(EsImageStartUp class)>>#outputWalkback:on:process:
arg1 = ′ ( ExCLDTIndexOutOfRange) Index out of range.′
arg2 = a CfsWriteFileStream
arg3 = UIProcess:(11-01-96 2:14:37 PM){running,3}
temp1 = 43
temp2 = EaRuntimeStartUp
temp3 = EsImageStartUp class>>#outputWalkback:on:process:
temp4 = nil
temp5 = 3
temp6 = 10
temp7 = 10
temp8 = false
temp9 = 0
temp10 = 10
[optimized] in EaRuntimeStartUp class(EsWindowSystemStartUp class)>>#outputWalkback:process:
BlockContextTemplate(Block)>>#when:do:exitWith:retryReturn:
arg1 = an ExceptionalEventCollection
arg2 = [] in EsWindowSystemStartUp class>>#outputWalkback:process:
arg3 = [] in Block>>#when:do:
arg4 = an Object
temp1 = [] in Block>>#when:do:exitWith:retryReturn:
temp2 = [] in Block>>#when:do:exitWith:retryReturn:
temp3 = nil
BlockContextTemplate(Block)>>#when:do:
arg1 = an ExceptionalEventCollection
arg2 = [] in EsWindowSystemStartUp class>>#outputWalkback:process:
temp1 = an Object
temp2 = nil
EaRuntimeStartUp class(EsWindowSystemStartUp class)>>#outputWalkback:process:
arg1 = ′ ( ExCLDTIndexOutOfRange) Index out of range.′
arg2 = UIProcess:(11-01-96 2:14:37 PM){running,3}
temp1 = ′ D:\EZERDEV2\TEMP\[Link]′
temp2 = -1
temp3 = a CfsWriteFileStream
EaRuntimeStartUp class(EsImageStartUp class)>>#outputWalkback:
arg1 = ′ ( ExCLDTIndexOutOfRange) Index out of range.′
2 EaRuntimeStartUp class>>#reportError:resumable:startBP:
arg1 = ′ ( ExCLDTIndexOutOfRange) Index out of range.′
arg2 = false
arg3 = 320
UIProcess(Process)>>#reportError:resumable:
arg1 = ′ ( ExCLDTIndexOutOfRange) Index out of range.′
arg2 = false
temp1 = 320
[optimized] in UndefinedObject(ExceptionalEvent class)>>#initializeSystemExceptions
blockarg1 = a Signal
Figure 21 (Part 1 of 3). [Link] File for Index Out of Range Error
Figure 21 (Part 2 of 3). [Link] File for Index Out of Range Error
Figure 21 (Part 3 of 3). [Link] File for Index Out of Range Error
To force a walkback we edited the first GUI application, deleted the promoted
feature named MyPrivateFeature , and saved this GUI application. Now when
we test the first GUI application, an error occurs (see Figure 22), and a stack
dump is written to the [Link] file.
Figure 22. Walkback Error Dialog for Missing Public Interface Feature Error
The [Link] file can contain multiple stack dumps, each of which is
delimited by blank lines.
To find the last stack dump, scan the [Link] file (Figure 23 on
page 80) from bottom up until you find a blank line ( A). This is the start of
the stack dump.
Note: We have cut out only the stack dump we want, so our start is at the
top. In a busy [Link], you could have quite a few stack dumps.
After the date and time information for the stack dump the error text is listed
( B.) If we look down in the stack dump, we can find this text multiple times.
Look for the instance of the text in parenthesis ( C). The [Link]
file may start to make more sense after this point.
If we scan down from the last point ( C), we can see text that defines the
error and the members involved ( D). This information will help in finding
and removing the problem in the GUI application.
Figure 23 (Part 1 of 4). [Link] File for Missing Public Interface Feature Error
Figure 23 (Part 2 of 4). [Link] File for Missing Public Interface Feature Error
Figure 23 (Part 3 of 4). [Link] File for Missing Public Interface Feature Error
Figure 23 (Part 4 of 4). [Link] File for Missing Public Interface Feature Error
• Using the line that appears at the top of the stack, ( B) look for the last
occurrence of that line ( X2).
From these case studies you should now have an appreciation of the value of
the [Link] file. In it you can not only find the connection that was
at fault but also some more information about the context within which the
error occurred. There is a lot of information in the file that is not relevant to
you as a developer, but if you look for the key lines that were mentioned in
the description you will be able to better analyze any problems that you
encounter in running your applications.
EZE2RUN PROFILE ON
After you have run your application, you set the profile option to OFF with
this command:
The debug setting must be defined for the profile option to function (see 5.2.1,
“Setting Up Debug Mode” on page 73).
Event History
The event history section lists all events that have occurred in the
system and is identical to a trace in the ITF. 5
Event Profile
The event profile section also lists all the events that have
occurred in the system, but now in descending order according to
the amount of time they took to complete. The elapsed time is the
time it took to execute the event (in milliseconds). The elapsed
time can include user think time if the event is the first event in a
sequence initiated by a user action.
The number of signals is how many times the event was found in
the event history listing (which is the first section of the profile
output). The sequence collection identifies the position of each
event that was signaled in the event history (there is a sequence
identifier for each entry in the event history on the left).
OnStackCount indicates the depth of connections from where this
event was signaled.
The [Link] file can be useful when you are trying to analyze the
performance problems for a GUI application. A full discussion of
performance is available in Chapter 13, “Performance” on page 251.
5 There seems to be a problem because not all parts listed in the profile data have names. We have
reported this as a bug to the lab.
EZE2RUN BENCH ON
This information is also written to the [Link] and is part of the first
part of the file concerning the loading of applications:
The file shows the breakdown of the loading of the application and how much
time (in milliseconds) was associated with each load. The debug setting
must be defined for the bench option to function (see 5.2.1, “Setting Up
Debug Mode” on page 73).
5.4 Summary
The VisualAge Generator ITF enables you to run applications without having
to generate or prepare them first. Once you are satisfied with your
application, you can generate it, producing a .APP file as output. When
started with the EZE2RUN command, the .APP file is used with the VisualAge
Generator runtime image, to implement the function of the GUI application.
Within the ITF you can analyze the behavior of your application, using
testpoints and looking at the contents of data. The ITF also provides a trace
of all actions that occurred in the application. You can control your view of
this trace information with trace log filters.
When you want to stop the execution of a test run, you can interrupt the
procedural logic with the stop push button or press the Alt+PrintScreen key
combination.
You can analyze the cause of errors in a GUI application, in both the ITF and
runtime, by looking at the [Link] file, which contains information
about the conditions in which the error occurred. The [Link] file
is written out when you set the EZERDEBUG and EZERRUN_DEBUG
environment variables.
In runtime you can also get a trace of all events that occurred in the system.
To get this trace you execute the command EZE2RUN PROFILE ON. The
[Link] file contains a chronological account of the events that
To get information about the load times of GUI applications you either have
to set the EZERBENCH environment variable or use the EZE2RUN BENCH ON
command.
• Use the facilities of the Test Monitor to analyze the behavior of your
applications
• Obtain debug information, runtime traces, and information about the load
times of GUI applications
An event can be defined as a change in the state of the system. For example,
when a user clicks on a push button, the state of the push button changes
from being up to being pressed down (clicked). This change in state (event)
can be used to trigger an action, such as closing a window.
Events are inherently asynchronous, although the actions that are triggered
by one event may be sequenced. This is contrary to procedural
programming languages that require you to perform actions in a certain
predetermined order. A procedural program has a flow and requires you to
ask “What should happen next?” When building an event-driven system, you
ask “What should happen when the user clicks on the push button?” This
type of question is characteristic of event-driven application environments
such as those provided by OS/2 and Windows. Building applications for such
environments by providing answers to questions about events is easier than
when you have to describe all questions (as you would for a procedural
programming language).
This example shows how a connection is made between an event and an action.
1. Create a new GUI application and place a push button on the window with the
label “Close.”
2. Select the Object menu of the push button by clicking on the push button with
mouse button 2.
3. Select Connect.
5. Move the spider to the window and click with mouse button 1.
7. Test the application by clicking on the test button in the tool bar (save the GUI
application as CONTST1).
You can see these three elements of the interface of a part when you select
the Connect menu of a part.
You can bring up the Connect menu directly by holding down the Alt key and
clicking on the part with mouse button 2. If the part does not have a Connect
menu, the Connect window with all of the actions, attributes, and events of the part
is shown instead.
To get the Connect window with all features, choose All features... from the
Connect menu. Figure 25 shows an example of a Connect window with
actions, attributes, and events.
Event-to-Action
By choosing an event from the source part and an action from the target
part, you create an event-to-action connection. The connection is shown as a
green arrow, with the arrowhead pointing to the target part. The connection
we created in our previous example between the clicked event of the push
button and the closeWidget action of the window is an event-to-action
connection.
Attribute-to-Attribute
An attribute-to-attribute connection ensures that data for both the source and
the target part are kept synchronized. Any changes in the source are
propagated to the target and vice versa. This type of connection causes a
blue line to be created with pinheads at both ends.
The source attribute can be made read only by opening the settings of the
connection (by either double-clicking on the connection or selecting the
Object menu of the connection and choosing Settings) and checking the
Read-only source toggle button. If you want the target end to be read only,
you can reverse the connection by clicking on the Reverse push button. This
action makes the source the target and the target the source. The pinhead
at the read-only side of the connection becomes hollow, so you can see the
unidirectional character of the connection.
Changing the value of an attribute of a part always causes the state of the
part to change, and thus an event is signaled. This change only has
consequences if the related event is used to perform some kind of action.
Attribute-to-Action
An attribute-to-action connection is identical to an event-to-action connection.
The change in the value of the attribute represents a change in the state of
the part. The change causes an event to be signalled.
Hint
When using a change in an attribute as an event, select it from the list box
containing the events in the Connect window. This selection ensures that the
connection created is not an attribute-to-attribute connection and will not become
one when you change the source or target of the connection.
Providing Parameters
Parameters can be provided to a connection either hard coded or by
connecting an attribute of a part to the connection.
Any parameters that are provided during runtime by connecting an attribute to the
parameter of the connection override these initial settings.
The data type of the parameter should conform to the expected format. If it
does not, a warning is displayed. Sometimes the GUI builder guesses at the
data type compatibility because it has insufficient information, so you can
sometimes ignore the warnings.
To move the items from one list box to another list box and view the item that is
selected in both windows, do the following:
2. To see the entry that was selected from the left List Box, connect the
selectedItem attribute of the leftmost List Box to the object attribute of the
label. This attribute-to-attribute connection ensures that the selected entry
from the left List Box is shown in the label.
3. Make the same connection between the right List Box and the entry field
above it.
4. Connect the clicked event of the “>>” push button to the items attribute of
the right list box. The items attribute contains all of the elements of the List
Box. Notice that the line that is created is dashed and requires a parameter.
The parameter that is provided should be of the same type as the target of the
connection, in other words, items.
5. Connect the items attribute of the left List Box to the value attribute of the
connection. This will move the data from the left List Box to the right List Box
when the push button is clicked.
7. Test the application. Select an entry from the left List Box. Notice that the text
in the label changes. C l i c k o n t h e “ > > ” p u s h b u t t o n . The entries from the
left List Box are moved to the right List Box. Select one of these entries. The
result shows up in the entry field. Now type the text of one of the other items
in the List Box in the entry field. This item is selected in the list.
Hint
If you are changing the connection from, for example, an event-to-attribute
connection to an event-to-action connection, the list with the target features does
not contain the actions of the target part. You can type in the action name in the
entry field for the target part. Make sure that you type in the name correctly. The
VisualAge Generator GUI builder is case sensitive, and typing mistakes cause
runtime errors.
Each segment of this line now in turn has three dots, one of which can again
be changed to change the path of the segment. This breakdown of lines into
segments continues for as long as you need to change the path of the line in
more detail, thus enabling you to make a clear visual layout of the
connections.
Deleting a Connection
To delete a connection, select it and either:
You can select multiple connections just as you can select multiple parts in
VisualAge Generator. Drag over them using mouse button 1 or add
individual connections to the selection by holding down the Control key and
clicking mouse button 1.
If you delete a part that still has connections attached to it, you will be asked
whether you are sure that you want to delete the part. This check is
especially useful if you have hidden connections by using the Hide
connections option from the Tools menu or from the tool bar.
Setting the trace indicator writes out a trace that can be viewed from the
Test Monitor window by choosing Trace and the View trace.... The trace
contains all of the events that were triggered, in chronological order.
The following event trace (as available in the ITF Trace log window) shows the
event-action combinations in chronological order that occurred in our application
when executed according to the script in the previous GUI programming example
(see Connections on page 96):
2. Selecting the item from the List Box causes the object attribute of the label to
be changed to the selectedItem attribute of the List Box (trace entry 3).
3. Clicking the push button causes the items of the first List Box to be copied to
the second List Box (trace entry 4).
4. Selecting the item from the right List Box causes the value of the object
attribute of the entry field to be changed to the value of the selectedItem
attribute of the List Box (trace entry 5).
5. Changing the entry field (trace entries 6-11). Because the Notify change on
each keystroke is set for the entry field in its settings, each keystroke causes
the attribute-to-attribute connection to be executed. When this attribute is not
set, the connection executes only when the entry field loses focus.
6. Clicking the Close push button causes the window to be closed (trace entry
12).
To use the trace effectively it is important that the entries are readable.
Having entries with “List1” and “List2” is not very meaningful. It would be
better to have “liLeftList” and “liRightList” (see Appendix B, “VisualAge
Generator Naming Convention” on page 341). The names shown in the trace
are equal to the names of the parts. You can change the name of a part
through its settings or by using the parts list. The trace from the previous
example, now without Notify change on each keystroke set, would look like
this:
A filter can be set on the trace either permanently or just for the session you
are running. The trace file can be seen as a database, and the filter as a
way of looking at the data that is there. See 5.1.5, “Using Trace Log
Windows” on page 65 for more information about using filters and the trace
log.
Hint
You can open multiple trace windows for a single tested application, each with its
own filter applied to it.
Events that cause actions are represented as lines between parts in the
VisualAge Generator GUI builder. These lines connect an event to an action,
an event to an attribute, or an attribute to another attribute. A connection
can require a parameter to be passed to it. The actions that occur based on
a certain event can be reordered.
The events that are executed by the system can be viewed by looking at the
trace of an application. The trace contains a chronological log of all
event-to-action and attribute-to-attribute connections.
The chapter focuses on the use of data in a GUI application; it does not cover
all aspects of data related to VisualAge Generator. For more information
about data and platform considerations, see the VisualAge Generator
manuals.
As a general rule, define data items as global only if they are part of your
organization′s data model. All other data items should be local. This
approach will keep the number of VisualAge Generator members defined in
your MSLs small, which will enhance the usability and maintainability of your
application system. It is also in line with the use of VisualAge Generator in a
Computer Aided Software Engineering (CASE) environment where data
definitions are driven by a data model. 6
Thus the data type specifies the internal format of the data item and
determines how the item is processed when referenced.
Bin The Bin data types support numeric data and store it in binary
format. The Bin data types can store large numbers in a smaller
number of bytes than other numeric data types.
6 For instance, using DataAtlas and TeamConnection, you can use the definition of a shareable data
element on which you can base the definition of elements in your data model and application (global
data items). You could define a telephone number to be a shareable data element, with both a
home telephone number and work telephone number deriving their definition from the shareable
data element. If you create a global data item, it always has to be linked to a shareable data
element. If you do not explicitly define one, it is created for you.
Numc Numc data types are identical to Num but only support C as the
byte value of the positive sign in EBCDIC. Therefore no
conversion occurs.
Pack Pack data types support packed numeric data, which has two
digits in every byte. Pack only supports C as the byte value of the
positive sign in EBCDIC and therefore does no conversion.
Pacf Pacf data types support packed numeric data. Pacf supports both
F and C as the byte value of the positive sign in EBCDIC.
Therefore it requires conversion and is slower.
That said, generation options (/POSSIGN) can be used to control the techniques
( F or C) for identifying the sign in numeric data types. Review Generating
VisualAge Generator Applications for more information.
Mixed Mixed data types support data items that can contain both
single-byte character set (SBCS) and DBCS data. The length
specified for a mixed data type is the number of single-byte
characters that the field can contain.
Which data type you use depends on the platforms on which the data is
used, the database system you use, and performance implications. These
considerations are documented in the VisualAge Generator manuals.
On the Data Item Definition window, you define the following characteristics
of a data item:
Description
To document the data item, enter a 1- to 30-character
case-sensitive description in the Description entry field. The
description of a data item, if entered, becomes the label of data
entry fields, lists, or container columns that are created by using
Quick Form , a VisualAge Generator function to create default
visual parts and labels from other parts. If the data item does not
have a description the name of the data item is used instead. See
7.2.2, “Quick Form” on page 120 for more information about using
Quick Form to create default entry fields and labels from data
items.
Data type
Choose one of the numeric or nonnumeric data types.
The allowable size of a data item depends on its use. A data item can be
used in either a working storage record or a VisualAge Generator table.
Table 9 shows the possible specifications of length, bytes, and decimal
places of data items according to the type of structure in which the data item
is used.
To create a global data item named ITMTST1 representing numeric data in packed
format with nine digits before and two after the decimal point, do the following:
2. On the New Member pop-up window click on the Item radio button and the
Open... push button.
5. Enter 11 into the Length spin button because the total length of the data item
is 11 digits (9 plus 2).
7. Toggle between the Length and Bytes radio buttons. Notice how the values
are related.
If you save a global data item with the name of a global data item that
already exists in one of the MSLs of the active MSL concatenation, VisualAge
Generator displays a warning message. However, you can replace the old
global data item if it was defined in your read/write MSL, or you can create a
new global data item with the same name if the old global data item was
defined in a read-only MSL of the active MSL concatenation.
1. Decimal places are not available for data items within a SQL record if you select a data type
other than Pack.
2. You can specify any number between 1 and 18 as the number of digits for a data item with a
data type of Pack. However, for performance reasons, use only an odd number of digits for
packed data items in an SQL record.
Data in working storage record is temporary data, that is, it exists only as
long as the GUI application is executed. It is not saved when the GUI
To define a record you create a new member with type RECD in the MSL.
Select File and New member... from the VisualAge Generator Developer
menu and select Recd as the type of member to be created. Figure 30
shows the Record Definition window for defining a working storage record.
Organization
Looking at the Organization group box, you can see that a record
can not only be a working storage record but the Record
Definition window can also be used to define various other types
of data organizations. However, in GUI applications we mainly
use working storage records. The other record types are typically
used for VisualAge Generator server applications.
Multiple methods are available to open the Record Definition window. In this
example we show the two most commonly used methods for defining working
storage records in GUI applications:
b. On the New Member pop-up window click on the Recd radio button and
the Open... push button.
The Record Definition - Untitled window is displayed.
Note: The organization defaults to Indexed in VisualAge Generator.
a. Open the GUI Application Definition window for a new GUI application.
b. Select the Data Member Parts category and the Record Member Part from
the parts palette.
c. Move the crosshair to the free-form surface and drop the record member
part (click with mouse button 1).
The Add Subpart window is displayed.
d. Enter RCDTST2 as the name of the new record in the Add Subpart drop-down
list and click on the OK push button.
Note: If you want to use an existing record, click on the drop-down
symbol to display the records that are yet defined in the MSL and
select one of them.
f. Close the GUI application definition window. Do not save the GUI
application.
To get the appropriate contents of the pull-down menu and have the left
arrow icon displayed on the Developer window, you have to open the Record
On the Record Item Usage window, you define the following properties of a
record item:
Name
The name of the data item is mandatory and must follow the
VisualAge Generator naming rules. You can use an asterisk (*)
instead of a real name for a local data item to represent a filler
data item . Filler data items represent space holders within the
working storage record. You can use Char filler data items with
length 1 to get single blanks between adjacent aggregate data
items that are to be displayed using a list box instead of a
container details view.
A data item other than a filler data item must have a unique name
within one working storage record. It can be referenced by this
name in processing statements of a logic part of the GUI
application in which the working storage record is defined.
Level
Level is a whole number between 3 and 49 or the number 77. It is
used to define either data structures (level numbers 3, 4, ..., 49) or
Occurs
Occurs is a whole number between 1 and 32767. It is used to
define data arrays. The default value is 1. We discuss Occurs in
section 7.4, “Occurs Items” on page 128.
Item Scope
The Item Scope is preselected to the value defined in the Record
Definition window.
If you specify the name of a global data item that already exists in
one of the MSLs of the active MSL concatenation and you select
Global item scope, the global data item with all of its
characteristics is inserted into the record. If you enter a name of
an existing global data item and you select Local item scope,
VisualAge Generator asks you whether you want to use the
characteristics of the existing data item as the default for the new
local data item.
Hint
Instead of entering the name of an existing global data item in the Record
Definition window, you can select the global data item from a member list of the
active MSL concatenation, drag it to the Data Items list, and drop it at the location
where you want to insert the data item into the record.
If you click on the Define... push button, the (Local) Data Item Definition
window is displayed. We describe the Data Item Definition window in section
7.1.3, “Defining Data Items” on page 108.
If you click on the Insert push button, the Record Item Usage window closes,
and the data item is inserted into the record at the location where you have
dragged the object icon. If you want to define more than one data item at
the same location in the record, click on the Next push button. The data item
is inserted, but the Record Item Usage window remains open, and you can
define the next data item.
You do not have to define the exact characteristics for each data item at the
moment you insert it into the record. You can simply add all of your data items
and then update their characteristics later.
After a data item is inserted into the record, its name and all of its
characteristics are displayed in the Data Items list on the Record Definition
Window (see Figure 32) The first untitled column is called the prefix area . It
shows either the sequence number of the data item within the record, or a
dashed arrow if the data item is a global data item that is not completely
defined yet.
Figure 32. Record Definition Window with Three Data Items Defined
If you move the mouse pointer over the prefix area or the name of a data
item, it changes its shape to a Swiss cross to let you know that you can
select the area to make updates to the data item. If you select the prefix
area, the entire data item is highlighted. If you select the data item name,
only the name is highlighted.
If you double-click on the prefix area of a data item with mouse button 1, the
Record Item Usage window is displayed. There you can update the usage
information for the data item. If you double-click on the name of a data item
with mouse button 1, the Data Item Definition window is displayed. There
you can update the characteristics of the data item.
For documentation purposes you can define any text to describe the record.
To provide a description of the record, select Prologue from the Define
3. Drag the object icon to the Data Items list and drop it.
The Record Item Usage window for the data item opens. Its scope is preset to
Local.
4. Enter ITEM1 as the data item′s name and click on the Next push button.
5. Enter ITEM2 as the data item′s name and click on the Next push button.
6. Enter ITEM3 as the data item′s name and click on the Insert push button.
The three items are inserted into the Data Items list with sequence numbers 1,
2, and 3 in their prefix areas.
8. Change the length of the data item to 10 bytes and click on the OK radio
button.
10. Change the type to Num and the length of the data item to six digits with no
decimal places and click on the OK radio button.
12. Change the type to Pack and the length of the data item to nine digits with two
decimal places and click on the OK radio button.
13. Maximize the Record Definition window to see all the columns of the data
items.
You can see all your definitions and changes reflected in the Data Items list.
The Record Definition window should look like the one in Figure 32 on
page 116.
14. Close the Record Definition window and save the changes you made to record
RCDTST1.
The easiest way to move data entered in a GUI into a working storage record
or from a working storage record to a GUI in a GUI application is to define on
a window one visual part (for example, an entry field) per single data item of
the working storage record and an attribute-to-attribute connection between
the data item and the visual part. The connection must connect the
DATAITEM data attribute of the record to the appropriate attribute of the
visual part. For an entry field, for example, this is the object attribute. Every
time the contents of one of the connected parts are changed, the contents of
the other part are changed to the same value as well. Figure 33 shows a
GUI application that moves data entered into one text field on the window to
the working storage record and back to the other text field.
Figure 33. GUI Application That Moves Data between a Window and a Working
Storage Record Record
To define a GUI application that moves data from a window to a working storage
record, do the following:
1. Open the GUI Application Definition window for a new GUI application.
4. Drop two label parts one below the other on the left half of a window part.
They are defined with the default names Label1 and Label2 by the GUI builder.
6. Drop two entry fields one below the other to the right of the label parts on the
window. They are defined with the default names Text1 and Text2 by the GUI
builder.
7. Deselect the Sticky toggle button or click on the Selection Tool icon on the
Tool Bar.
9. Open the settings window of the label parts and change their names from
Label1 and Label2 to Input and Output.
10. From the Data Member Parts category select the Record Member part.
11. Drop the record part to the right of the window part on the free-form surface.
12. On the Add Subpart window enter RCDTST2 as the name of the record.
13. Open the Record Definition window and select Working storage and Local.
14. Define a local data item inside the working storage record with the following
characteristics:
Name: ITEM1
Type: Char
Length: 10
Use the default values for all other properties of the data item.
15. Close the Record Definition window and save the record.
18. Drag the spider to the record RCDTST2 and drop it. The Connect window for the
.. record part opens.
.
19. Select the attribute ITEM1 data and click on the OK push button.
This defines an attribute-to-attribute connection between the two parts.
20. Define an attribute-to-attribute connection of the same kind between Text2 and
the ITEM1 data attribute of RCDTST2.
• A data type and character limit specification for the visual part that fits
the characteristics of the source part
If you use the self attribute of the source, part Quick Form creates the visual
parts and connections for every attribute of the source part. Figure 34 on
Quick Form is especially useful for creating visual parts on a window from
data items of a working storage record that are used to enter data that is
moved to working storage record and for displaying data stored in a working
storage record. Instead of creating the visual parts manually, you can use
Quick Form to automatically define these parts together with a descriptive
label for each.
To use Quick Form to create the appropriate definitions of visual parts from the
data items of a record part, do the following:
1. Open a new GUI application. Define record RCDTST1 on the free-form surface of
the GUI application. You created record RCDTST1 in the Defining a Working
Storage Record on page 117.
2. Open the pop-up menu of RCDTST1 and select Quick Form. A selection list is
displayed. It contains the names of the data items of the record and self as
.. attributes of the record.
.
3. Select ITEM1, move the mouse pointer in form of a cross-hair near the
upper-left corner inside the window and click with mouse button 1.
The GUI builder creates a label, entry field, and connection to the ITEM1 data
item. This is the same kind of connection we defined manually in the Moving
Data between a GUI and a Working Storage Record on page 119.
4. Open the pop-up menu of RCDTST1 and select Quick Form again. Select the self
attribute, move the mouse pointer below the ITEM1 label, and click with mouse
button 1.
The GUI builder creates a label, entry field, and connection for each of the
data items of the record.
5. Open the settings of the entry fields and look at the Input Field Specifications
defined by Quick Form.
You see that the data type and the character limit of the text field were set
according to the data type and length of the data item.
7. Open the Data Item Definition window for each data item (click on its name).
ITEM1: Cust-Name
ITEM2: Cust-Number
ITEM3: Amount-to-pay
10. Delete all the parts inside the window of the GUI application.
11. Repeat the definition of visual parts from record RCDTST1 using Quick Form and
self.
Now the descriptions of the data items are used as labels for the text fields.
You can also subdivide a data item into several other definitions. For
example, by substructuring a credit card number, you can access the
valid-through date without having to substring the data.
To define a structured data item in a record or table you use the relative
level of those data items that are part of the structure. The rules for level are
as follows:
• The lower the level of a data item, the higher it is in the hierarchy of the
data structure of the record.
• The data item or items with the lowest level number represent the top
data elements within the record structure.
• The sum of the byte lengths of the substructures of one structure must
be equal to the length of the structure.
When you create a record containing structured data, you have to calculate
and define the correct length of all structured data items. However, you can
let the VisualAge Generator Developer record definition editor either
calculate the length of a data item or validate the data structure of the whole
record. The validation checks for each structured data item if its length
specified is the sum of the lengths of its substructures. In addition it checks
whether the names of all data items of the record are unique.
Hint
To let the record definition editor calculate the length of a data item, select the
data item row in the Data Items list of the Record Definition window and select
Calculate substructure length from the Options pull-down menu.
You can ask the record definition editor to validate the data structures of the
record by selecting Validate data structure from the Options pull-down menu.
Validation is always performed when you save the member.
6. Select the ADDR data item in the Record Definition window (click on its prefix
area).
8. Change the length of data item ADDR to 53 bytes. To open the data item
editor from a record definition, double-click directly on the data item name.
9. Select Validate data structure from the Options pull-down menu to check
whether the length values of the structures are correctly defined. If
necessary, correct them.
10. Close the Record Definition window and save your changes made to the
record.
The data items with level numbers between 3 and 49 define the data
structure of a record. Instead of, or in addition to, the data structure, you can
define one or more single, unrelated data items within a working storage
record. Single data items are referred to as level-77 data items. They are
defined with a level of 77 and have to be defined as the last data items of the
working storage record. Level-77 data items can neither be structured nor
represent an array. Use level-77 data items to store intermediate data, such
Because they are not part of the data structure of the working storage record
VisualAge Generator treats level-77 data items differently from non-level-77
data items in the following circumstances:
• If the working storage record is changed, the level-77 data items are not
triggered.
Any attribute of any part within VisualAge Generator can be torn off . Tearing
off an attribute exposes all the attributes, actions, and events available to
that attribute. In the case of a data item, this includes its substructured
items, which are its attributes.
To tear off an attribute of a part, select Tear-off Attribute... from the Object
menu and select the attribute to tear off from the list of attributes that is
presented to you. If there is text in brackets to the right of the attribute, it
tells you what type the attribute is. For example, Compound in brackets
informs you that the attribute at its left represents a structured data item.
A variable part representing the attribute that was torn off is placed on the
free-form surface. The part is called attribute of partName. The torn-off
attribute is connected to the part from which it was torn off by an
attribute-to-attribute connection connecting the attribute to the self attribute
of the variable part. You can now perform actions on the torn-off attribute,
for example, you can create a Quick Form from one of its attributes. If you
use Quick Form on self of the torn-off record attribute, you create parts for
each of the substructured data items. Figure 35 on page 127 shows an
example of torn-off attributes in a GUI application.
2. Resize the window part so that it is longer (see Figure 35 on page 127).
3. At the top of the window define the visual part for CNAME and at the bottom of
the window the visual part for PR from record RCDTST3 using Quick Form.
You can achieve the same result using Quick Form and self and delete all
labels and text fields of the parts not needed.
7. Using Quick Form and the self attribute of the torn-off attribute DTE of RCDTST3,
define the visual parts for DAY, MON, and YEAR.
9. From ADDR of RCDTST3 define the visual parts for all nonstructured data items on
the window, using Quick Form (these are all data items except ZIP).
11. From ZIP of ADDR of RCDTST3 define the visual parts for STATE and PC, using
Quick Form.
Data items with an occurs value greater than 1 are called occurs items . An
occurs item can be substructured, but none of the data items within its
substructure can be defined with an occurs value greater than 1. Level-77
data items cannot have an occurs value greater than 1. Figure 36 shows a
working storage record with various forms of aggregate data.
Figure 36. Working Storage Record Representing Various Forms of Aggregate Data
3. Define the data items shown below at the end of the data structure of the
record:
To create a working storage record structure that allows you to store multiple
messages, where each message in turn contains multiple placeholder values, do
the following:
7. By moving data from a certain index of the array of VALUE in the first working
storage record to VALUE in the second working storage record, you would be
able to access the single placeholder values.
getFieldAtIndex:
Gets a pointer to the element at the index that is passed as the
parameter to the connection
getValueAtIndex:
Gets the value of the element at the index that is passed as the
parameter to the connection
setValueAtIndex:Using:
Changes the value at the specified index, the anIndex attribute of
the connection, to the value specified in the value attribute of the
connection
getValuesStartingAt:to:
Gets the values of a range of elements starting at the index that is
passed as the firstIndex parameter and ending at the index that is
passed as the lastIndex parameter. This action can be useful for
loading lists, combos, and radio button sets with array data.
setValuesStartingAt:to:using:
Changes the values starting at the specified index, the firstIndex
attribute of the connection, until the second specified index,
lastIndex , to the values specified in the aCollection attribute of the
connection
You should always use these actions when accessing an array of data from a
working storage record because it requires you to specify a specific element
or range of elements in the array to access. This ensures that VisualAge
Generator does not have to figure out where the array no longer contains
relevant data (blanks or zeros), which is a very expensive bit of processing,
especially for sparsely filled arrays.
When you use the Quick Form facility of the GUI builder to create a
representation of an array, it creates an attribute-to-attribute connection.
You should always delete that connection and replace it with a connection,
using one of the actions for accessing array elements.
2. Tear off the MCONS attribute of the RCDTST3 working storage record.
3. Select Quick Form from the pop-up menu of the MCONS torn-off attribute.
4. Select self from the selection list and click on the window part of the GUI
application to drop the visual parts.
A label, a container details, and an attribute-to-attribute connection are
created.
6. By default the Quick Form does not create a connection using the
getFieldsStartingAt:to: action on the occurring data item. Delete the current
connection to the container details.
7. Determine which event should refresh the data in the list, for instance,
aboutToOpenWidget event of the window part. Connect this event to the
getFieldsStartingAt:to: action of the torn-off attribute MCONS.
8. Open the settings of the connection and click on the Set parameters... push
button. Provide 1 as the first index and 12 as the last index. Normally you
would provide these parameters dynamically. Click on OK to close the window
and on OK again to close the settings of the connection.
9. Connect the result attribute of the connection (this contains the pointer to the
data) to the items attribute of the container details. To connect to the
container details and not a column of the container details, click on the scroll
bar for the part.
To define a VisualAge Generator table and provide it with initial contents, do the
following:
1. Create a VisualAge Generator table member using the New member... option
from the File menu. Double-click on the table icon.
2. Set the type of the table to Unspecified. The other table types require a
specific format but are only used by VisualAge Generator TUI applications.
4. Make sure Fold table contents is not checked. If it is, all the contents of the
VisualAge Generator table will be converted to upper case.
5. Set the table to resident and shared. If the VisualAge Generator table is not
shared, the VisualAge Generator table in each GUI application has is own
independent data. A resident VisualAge Generator table is automatically
shared. A VisualAge Generator table that is not resident is released from
memory when the VisualAge Generator GUI application runtime services are
killed.
6. Define the following structure and data items to be used in the VisualAge
Generator table:
10 FIRSTITEM char 5
10 SECONDITEM char 5
Use the Object icon (the arrow in the top-left corner of the VisualAge
Generator Developer) to add data items to the table.
Notice that you cannot set the occurs of the data item or make a level-77 data
item part of the VisualAge Generator table. You can substructure items,
however.
7. Select Define and then Table contents... from the menu. You will get a
spreadsheet-like form where you can define the initial contents of the
VisualAge Generator table.
Although the VisualAge Generator table has initial contents, its contents can
be changed during execution of the application. The data can be changed by
using procedural code or visual logic. The contents of the VisualAge
Generator table are shared across GUI applications if you have defined the
VisualAge Generator table to be shared. Thus any changes made to the
VisualAge Generator table in one GUI application are automatically picked
up by the VisualAge Generator table in another GUI application, without
having to have any attribute-to-attribute connections between the GUI
applications. If you use the same VisualAge Generator table in a server
application, the changes are not picked up automatically.
Although one or more attributes change when you change the contents of a
VisualAge Generator table, the events related to these attributes do not get
signaled. You have to explicitly refresh or access the data again to get the
new values.
To share data in the VisualAge Generator table between GUI applications, do the
following:
1. Create a GUI application and drop a VisualAge Generator table part on the
free-form surface. Choose the VisualAge Generator table previously defined
from the drop-down list (VGTBLE).
2. Create a quick form of the VisualAge Generator table table columns attribute
on the window. This creates a container details, the default visual part for lists
of data. Arrange the container details columns to improve the viewable area.
4. Save this GUI application again but this time as member GUITAB1. We are not
done with this GUI application, so do not close the GUI builder window.
5. Add a push button to the window of the GUI application. Add GUITAB2 as an
external GUI application to the free-form surface of GUITAB1. Connect the
clicked event of the push button to the openWidget action of the external GUI
.. application.
.
7. Test the application. Open the second application by clicking on the push
button. Change data in either of the two container details.
Experiment to find methods of triggering visibility to the changed VisualAge
Generator table data in the two different GUI applications. These techniques
work:
a. Close the GUITAB2 GUI application and reopen it using the push button in
the GUITAB1 GUI application.
b. Edit a cell in one GUI application. Click on that same cell, and then
another cell, in the other GUI application on the other GUI application
8. Make these changes to the GUITAB2 GUI application to control when the data is
refreshed:
b. Connect the clicked event of the push button to the refreshAllItems action
of the container details in the window.
9. Save GUITAB2.
10. Test the GUITAB1 application. Open the second GUI application by clicking on
the push button. Change data in the container details of the first GUI
application.
Now when you click on the push button in the second GUI application, the
container details data will be refreshed from the source, the VisualAge
Generator table.
Hint
The contents of a VisualAge Generator table, when modified during a test cycle,
remain in memory. If you want to refresh the contents of the VisualAge Generator
table from the member definition, stop the ITF. When you next start a test run, the
VisualAge Generator table contents will match the contents defined for the
member.
7.6.1 Characteristics
The ordered collection is a part in the parts palette of the GUI Application
Definition window. It is part of the Models category. The ordered collection
is a nonvisual part.
7.6.2 Use
The ordered collection can be accessed and used like any other part. An
ordered collection has the following actions:
Finding items
Items can be located in an ordered collection by providing the
index: at: and atIndex: . The index has to be provided as a
parameter. An invalid index causes a run-time error. The actions
place the value in the result attribute of the connection. Items can
also be located by their value: includes: and indexOf: . The former
Size information
The isEmpty attribute indicates whether the ordered collection is
empty. It contains a Boolean value. The size attribute of the
ordered collection indicates the number of elements in the
ordered collection. If isEmpty is true, size is zero.
The ordered collection also has an attribute called iterator . This attribute is
explained in more detail in 9.3, “Iterations” on page 177.
2. Put a list box, three push buttons, and an entry field on the window. Give the
push buttons the labels “Add,” “Delete,” and “Clear.”
4. If you click on the Add push button, you add the entry in the entry field to the
ordered collection. Connect the clicked event of the Add push button to the
add: action of the ordered collection. Provide the object attribute of the entry
field as the parameter (anObject attribute) to this connection.
5. To show the ordered collection in the list box connect the self attribute of the
ordered collection to the items attribute of the list box.
6. If you click on the Delete push button, you will remove the selected entry from
the list box. Connect the clicked event of the Delete push button to the
remove: action of the ordered collection. Provide the selectedItem attribute of
the list box as the parameter to the connection.
7. To clear the list connect the clicked event of the Clear push button to the
removeAll: action of the ordered collection. Connect the self attribute of the
ordered collection as the parameter (aCollection) to this connection.
The actions of the ordered collection allow you to remove entries from a
working storage record or VisualAge Generator table. When the entry is
removed, the remaining entries shift in the array to fill in the gap left by the
entry that was removed. This is done with the ordered collection action
instead of procedural logic.
1. Create a new GUI application. Put a label and push button on the window.
2. Put a VisualAge Generator table on the free-form surface. On the Add Subpart
window enter VGTBLE as the name of the VisualAge Generator table. This was
created in Defining a VisualAge Generator Table on page 134.
3. Make a quick form of the VisualAge Generator table attribute table columns
and drop it on the window. This will show a container details with the data.
4. Tear-off table columns. From this torn-off attribute, tear off the data attribute.
5. Connect the size attribute of this ordered collection to the object attribute of
the label.
6. Connect the clicked event of the push button to the removeAtIndex: action of
the ordered collection. Provide 1 as a hard coded parameter to the
connection.
Torn-off attributes of other parts can also be valuable. This example shows the
usage of the selectedItems.
This example shows the possibility of the tear-off ordered collection to change the
contents of a VisualAge Generator table. The example builds on the previous GUI
programming example (Using Ordered Collections on page 139, GUI application
GUITST7).
2. Delete the connection from the Delete push button to the ordered collection.
3. Put two extra push buttons on the window. Give them the labels “Select all”
and “Deselect all.”
4. Tear off the selectedItems attribute of the multiple select list. Notice that in
the tear off selection list the selectedItems attribute is identified as an ordered
collection in parentheses behind the attribute name.
5. Connect the clicked event of the Select all push button to the addAll: action of
the torn-off attribute. Provide the self of the ordered collection that contains
the list as the parameter to the connection.
6. Connect the clicked event of the Deselect all push button to the removeAll:
action of the torn-off attribute. Provide the self of the torn-off attribute as the
parameter to the connection.
7. Delete the Clear push button. Change the connection from the Delete push
button. Instead of connecting to the remove: action, connect it to the
removeAll: action and provide it the self attribute of the torn-off attribute as
the parameter to the connection.
Select the action, attribute, or event from the list and provide it with a
meaningful name (see Appendix B, “VisualAge Generator Naming
Convention” on page 341 for more information about naming promoted
features). Click on the Promote push button to add the feature to the list of
promoted features.
To see all of the features of the GUI application, including your newly added
feature, bring up the Connect window of the free-form surface.
To add a feature to the interface of a GUI application and use it to share data with
another GUI application, do the following:
1. Create a new GUI application. Put an entry field on the GUI application.
2. Select Promote Part Feature... from the Object menu of the entry field.
3. From the list of attributes select object. Replace the default name in the
Promote feature name field with “customerNameData.”
6. Create a new GUI application. Add the previously created GUI application by
dropping a GUI application member part on the free-form surface and
selecting the GUI application GUISHR1 from the list.
7. Put an entry field and a push button on the window. Connect the clicked event
of the push button to the openWidget action of the external GUI application
GUISHR1.
Sharing data between GUI applications requires that you promote the data
you want to share. The attribute we promoted in the previous GUI
programming example is the object attribute of an entry field. We could have
used any two attributes that have a compatible type, for example, data items
from a working storage record.
Pass by Value
With pass by value, a copy of the data is passed when it is needed by the
GUI application. Instead of using an attribute-to-attribute connection, you
therefore use an event-to-attribute connection and provide the value of the
attribute that has to be changed as the parameter.
If you change the value in the GUI application to which it is passed, the
change does not effect the original data that represents the source. If you
want to provide the ability to pass back the changed value as well, you would
have to have the GUI application that changed the value signal an event
indicating that it has finished executing the function. You can promote an
event in the GUI application for this purpose. Use this event, in the related
GUI application, as the start of an event-to-attribute connection, to update the
source value. Provide the promoted attribute that was used to pass the
value to the GUI application that changed it, as the parameter for the update
of the source of the value.
This example builds on the Promoting a Feature on page 144. To pass data using
the pass by value technique do the following:
3. Make a second connection from the push button. Connect the clicked event of
the push button to the customerNameData attribute of the GUI application and
provide the entry field object as a parameter (value) to the connection.
6. Test the application. Change the data in the entry field and then click on the
push button. Change the data in the application that is opened. Close the
window and see the value in the initial window change.
Pass by Reference
VisualAge Generator also offers a part that enables you to store a pointer:
the variable part. The variable part is one of the parts in the Models
category of the parts palette. It only has one attribute: self . This attribute
contains the memory location of the part to which the variable part is
connected. Thus the variable part should always be connected to another
part. If it is not, it does not point anywhere and might cause incorrect
references when you try to use it. Because a variable part contains the
memory location of the part to which it is connected, a variable part can
point to any VisualAge Generator part, not just a working storage record.
Once you have connected the variable part to another part by connecting the
self attribute of that part to the self attribute of the variable part, you can
perform any actions on the variable part that you would be able to do on the
part itself, for example, access its attributes (data). Since it points to the part
it uses the same memory location upon which to perform the action. The
variable part has become a way of looking at and acting upon the part.
But how can you make a connection to an action that is not defined for the
variable part. As mentioned before, one of the only attributes of a variable
part is the self attribute. The variable part can choose an entry from the
Connect window that contains unlisted action/attribute/event... . Figure 39 on
page 147 shows the window that is shown with an entry field in which you
can type the name of the action, attribute, or event you want to perform,
change, or use. As long as you are sure that the feature is implemented in
the part to which the variable part is connected, this will work. If it is not,
your connection may fire but it will not trigger an action or change an
attribute.
VisualAge Generator also provides you with an option that enables you to
make a variable part look just like a VisualAge Generator member. Choose
Build features based on member... from the Object menu of the variable part.
This selection brings up a window with an entry field. Type the name of the
VisualAge Generator member whose interface you want the variable part to
use. Once you have set this feature and you look at the interface of the
variable part, it will look just like the interface of the member on basis of
which you have build its features. Using this option does not mean that the
variable part actually points at this member. If you connect the variable part
to the self attribute of a push button, it points to the push button, and you can
click it.
Hint
You may have noticed that the variable part looks a lot like a torn-off attribute.
Both are represented graphically as parts surrounded by brackets. A torn-off
attribute is indeed a variable part. It points to one of the attributes of the part
from which it has been torn off.
You can also easily create connections by dropping the same type of part the
variable part represents on the free-form surface. Tear off the self attribute. Make
your connections to this tear-off and, when you are finished, delete the original
part.
2. Add a variable part to the free-form surface of GUI application. Promote the
self attribute of the variable part as customerName.
3. Choose Connect... from the Object menu of the variable part. Select the entry
unlisted attribute... from the list of attributes. Type in “object” as the attribute
name. Be sure it is in lower case. Make the connection to the object attribute
of the entry field.
A warning message box will be shown. Accept the warning and continue to
make the connection.
6. Select Change member name... from the Object menu of the external GUI
application on the free-form surface and select GUISHR4) from the drop-down
list.
A warning message box will be shown. Accept the suggestion and change the
subpart name.
7. Change the connections from the external GUI application (GUISHR4) to use the
customerName attribute instead of the customerNameData attribute.
8. Change the connections from the entry field on the window part in which the
external GUI application is embedded to using self instead of object
10. Test the application. Change the data in the entry field and then click on the
push button. Change the data in the application that is opened. Notice that
the data now also changed in the original entry field. Close the window.
Remember that events indicating that the data has changed are not signaled.
You have to request the newest data every time you use it. See 7.5.1,
“VisualAge Generator Table Characteristics” on page 134 for more
information and examples.
Table 11. Data Type Relationship between GUI Application Parts and
VisualAge Generator Data Items.
D Default data type automatically assigned when Quick Form function is used.
O Optional data type that can be set.
Cells left empty represent an invalid relationship.
To customize the data type, click on the Customize... push button on the
settings window of the part. The data type can be customized to include:
• A definition of how the data, once entered, is represented to the end
user
• A default value
If the data, as provided by the user or the program, does not conform to the
specifications, either data type or range, the part will show “** error **” in
the field.
Data items either have a numeric or nonnumeric data type. Data items are
only relevant as part of a structure such as a working storage record or a
VisualAge Generator table. The definition of the data item can be either
global (shared by all uses of the global data item) or local (defined within the
context of the structure).
Data structures can be used to group data items. This grouping provides for
both data management and GUI application functions such as Quick form.
Data structures can also be torn off in a GUI application so that direct access
to the lower level data items and the occurring data items is possible. An
ordered collection can be torn off of a working storage record or a &VGt..
Multiple techniques are available for sharing data between GUI applications.
Each technique works differently and has subtle operational attributes that
will affect your choice for sharing data.
• Know that you should use the DATAITEM data attribute to connect to an
entry field.
• Understand the difference between the string and object of an entry field
• Use a working storage record to share data within one GUI application
and between GUI applications
• Callable Function
• Process Member Part
• Statement Group Member Part
The process and statement groups are nonvisual parts that are placed on the
free-form surface of a GUI application. To execute the process or statement
group, use the execute action—one of the features available for procedural
nonvisual parts. The logic in processes and statement groups used in GUI
applications is generated into Smalltalk for runtime implementation just like
the other parts and visual connections defined as part of a GUI application.
In processes and statement groups in GUI applications you can only access
and change data in working storage records or VisualAge Generator tables.
After the process has been executed, the data is changed in the GUI
application and causes the events related to the attribute values to be
signaled.
The working storage records and VisualAge Generator tables that you
access have to be present on the same free-form surface as the process or
statement group that uses them. A variable part used to represent a working
storage record or a VisualAge Generator table in a GUI application does not
support procedural access to the working storage record or VisualAge
Generator table member.
If you do require some logic to access data in a record that is passed to your
GUI in a variable, you can either:
• Signal an event from your GUI to the GUI that contains the real copy of
the record and ask that GUI to perform the logic for you
or
• Pass the statement group part defined in the GUI that owns the data to
your GUI as a variable as well, then execute the statement group
indirectly, just like you access the data.
You can use the Build Features Based on Member function from a statement group
part as well as from a record member.
You can access the data from a working storage record or a VisualAge
Generator table by referencing the data item. You reference the data item
by placing the name of the data item in the procedural code. The data item
can be qualified as being part of a specific working storage record by
prefixing the data item with the name of the working storage record and
separating the two with a period. This is the preferred method of referencing
a data item because it can occur in multiple working storage records on the
free-form surface of the GUI application. You do not have to refer to the data
item differently if it is part of a substructure.
Although you can place an SQL row record on the free-form surface, we
recommend that you not do so. First of all, if the SQL row record is passed
to an application as a parameter, the application cannot use the same SQL
row record as a process option for an I/O operation. In addition, the use of
an SQL row record makes your representation dependent on the database
type used by your application.
10 REQUEST-STRUCTURE
12 PARTNAME
12 ACTION
12 PARAMETER
The exact levels as stated are not required as long as the structure contains
three data items. You are also free to choose the names of the data items.
The data items must be defined as character but can be of any length as
long as they can contain the required information. In fact you are building up
a connection and defining its characteristics.
Because a working storage record is used, you can set the values using a
process. Remember that the VisualAge Generator GUI builder is case
sensitive, so you should insert data with the correct case to the structure.
Values keep their case in procedural logic if they are enclosed by double
quotes.
The action is executed by choosing an event (often the has executed of the
process that filled the working storage record) and connecting it to the
performRequest action of the GUI application part that can be accessed from
the free-form surface. This creates a dashed line that expects requestObject
as its parameter. Connect the REQUEST-STRUCTURE attribute of the
working storage record to the connection, and your action is executed when
the event is signaled.
While the perform request approach is powerful and flexible, quite a bit of
overhead is involved in the implementation of the performRequest action.
See 9.2, “Conditional Logic” on page 173 for a review of all your options and
13.3.6, “Perform Request Considerations” on page 264 for a study of the
performance implications for the perform request technique.
[Link] = ″Window″ ;
[Link] = ″backgroundColor″ ;
[Link] = ″Blue″ ;
5. When the push button is clicked, the process should be executed. Connect the
clicked event of the push button to the execute action of the process.
6. Connect the has executed event of the process to the performRequest action
of the free-form surface. Pass it the PERFREQ-STRUCTURE attribute of the
working storage record as the parameter.
8.3.2 Algorithms
Algorithms can be built with processes or statement groups using all the
language features that are available in VisualAge Generator (for example,
conditional statements, loops, and tests). When defining a process, you can
use a template to find the statement you want to use. Choose Edit and then
Insert after with template... when in the process or statement group editor.
This brings up the window shown in Figure 41 on page 158.
Procedural logic in a GUI application cannot perform I/O. It can only access
record member parts that are on the free-form surface of the same GUI
application. Procedural logic can only directly change working storage
records and VisualAge Generator tables in the GUI application. You can use
the perform request to indirectly execute other actions in the GUI application.
Clicking a Push Button: The following event occurs when you click a push
button either as a user action or using the click action:
01 clicked7
Enabling a Part: The following event occurs when you enable a part with the
enable action:
01 enabled
01 aboutToOpenWidget
02 aboutToMapWidget
03 resized
04 openedWidget
05 mappedWidget
06 gettingFocus
7 The clicked action of a push button is usually preceded by a set of events for the part that had the
focus before the click. If a text field had the focus, you will get the string, object, and loosingFocus
events signaled from the field before the clicked action is signaled for the push button.
01 closeWidgetRequest
02 aboutToCloseWidget
03 closedWidget
04 destroyedPart
The closeWidgetRequest event occurs only when the user uses the system
menu to close the window.
Editing an Entry Field: The following events occur chronologically when you
enter data into an entry field:
01 gettingFocus
02 object
03 string
04 userInputConvertError
05 losingFocus
The object and string events occur only when the value in the entry field has
changed. The value changes at each keystroke when Notify change on each
keystroke has been set in the settings of the entry field. This value changes
when the field loses focus only if this indicator has not been set.
The order in which the changes in the data items occur as events is not
predefined. The order cannot be guaranteed.
RECORD
Level Name
10 LEVELONE
20 LEVELTWO
30 LEVELTHREE
30 THREEEXTRA
20 TWOEXTRA
10 ONEEXTRA
The level 10 item can have multiple occurrences. This does not change the
behavior as described here.
To access all of the data, you would need to tear off parts of the working
storage record. In this case it has been torn off as three separate parts,
which are referred to as:
• The change of a data item causes both the data and the self event of the
data item to be signaled.
• If the data item is part of a substructure, the data event is signaled for all
of the data items of which it is part.
• Changing a data item causes the data event of the record to be signaled.
Figure 43 shows the hierarchy of data items and the changes that are
caused if one of the data items is changed.
Figure 43. Hierarchy of Data Items and the Effects of a Data Item Change
Hint
You can create your own event traces by creating an application where you
connect all possible relevant events to a dummy action. Test the application with
the trace set on and analyze the trace to see the sequence in which the events
occur. By using the name of the dummy action as a filter in the trace, you only get
the relevant trace entries.
The order in which separate parts are created depends on the order in which
they were put onto the primary part during definition and not on the ordering
or layout of these parts on the primary part. The parts defined first are also
created first. The order corresponds to the tabbing order of the parts in the
window and can be viewed by using the parts list. By changing the tabbing
order the order of creation is changed.
Before the parts on the primary part have been created and opened, all
attribute-to-attribute connections within the GUI application trigger, but they
only trigger if the attribute values of the parts concerned are not
synchronized.
3. Connect the aboutToOpenWidget event of the window to the set action of the
toggle button and the aboutToOpenWidget event of the push button to the
clear action of the toggle button.
4. Test the application (save the GUI application as VSLTST1) and see whether the
toggle button gets set or not.
5. Turn on the ITF tracing, open a Trace log window, and restart the GUI
application This will show you the order in which connections were fired.
A parts needs to be created before other parts can communicate with it.
Creating a part is a different action on a part than opening it. The difference
is explained in more detail in Chapter 11, “Building VisualAge Generator
Parts” on page 195 No attribute values of these parts can be set from
outside the part until the part has been created.
The order in which the primary part is closed is not opposite to the order in
which it is created. The part itself, the GUI application, is closed first followed
by the primary part and all the parts contained in the primary part. These
parts are closed in the order in which they were put onto the primary part
and not in reverse order of which they were created.
Figure 44 shows the basic structure of an event and its handler and the
difference between asynchronous and synchronous handling of the event.
Event Trees
Now that we know about event handlers and their synchronous or
asynchronous posting of events, let us look at the sequence of events.
An event can cause an action to be performed. The action can cause its own
set of events to be performed, and so on. One complete sequence of actions
based on one event is called an event tree . Like most trees, the event tree
can have branches when along the way an event again causes multiple
actions to be taken. There are three basic event sequence characteristics:
• The order in which events occur from the initiating part depend on the
order of the connections as set in the Reorder connections from window.
If the event has been promoted and triggers actions in the GUI
application in which it is embedded, these actions occur after the events
within the current GUI application are signaled.
Sequencing Events
In an event-driven system, it is not evident which event will occur next
because all events are essentially asynchronous. To force a certain event to
occur next, you can trigger an action that will cause an event to be signaled
that is dispatched synchronously. This event can then be used for the next
action.
If the part that causes the event to be signaled is used only for this purpose, it is
best to use a label and connect to its enable action and use its enabled event.
This connection consumes the least system resources.
Sequencing events like this is one of the ways to ensure that they happen in
the expected order. If there is a relationship between two paths, you have to
make sure that the dependency is correct. Figure 46 illustrates this point.
Passing Parameters
The concept of synchronously and asynchronously dispatched events also
has an effect when providing parameters for a connection. You have to
ensure that the connection containing the value of the parameter is fired
before the connection requiring the parameter is fired. The GUI
programming example that follows illustrates this point.
2. Place two entry fields on the window. Uncheck the Signal events on each
keystroke toggle button in the Settings window of the entry fields. This
ensures that a change to the contents of the part occurs only when the field
loses focus and the value has changed.
3. Connect the object event (be sure to choose the event and not the attribute) of
one of the entry fields to the backgroundColor attribute of the window.
6. Edit the GUI application, remove the connection providing the parameter, and
retest the application. Note that the application now works as intended. But
why?
You may have noticed that when the first connection was made (entry field
object event to window backgroundColor attribute) it did not have a dashed
line. It had a solid line. This may be telling us that the triggering event
automatically includes the associated attribute. If so, this is one less
connection that is required.
The result attribute of a connection will trigger once the connection has
completed. By using the result attribute as an action trigger you can start
other connections in sequence.
5. Add a working storage record (RCDTST1, created in the Chapter 7, “Working with
Data in VisualAge Generator” on page 105 example) and a process (VSLPROC) to
the free-form surface.
6. Add this code to the VSLPROC process: MOVE ′ PROC DATA′ TO RCDTST1.ITEM1;
9. Test the application (save as VSLTST3) and click on the push button.
What happens? (You may have to adjust the relative execution speed of the ITF
test run to see the order of processing. Change the speed to 7 and test again.)
10. Move the push button end of the connection between the push button and the
window so that it starts with the result of the connection between the push
button and the process.
What happens?
Now the window should be opened after the process has executed. This removes
the screen flash associated with the arrival of the contents of the entry field after
the window has opened.
To use perform request logic to open a message window when an error has been
detected in a piece of procedural code, do the following:
1. Create a GUI application with an entry field and a push button on the window.
Make the push button close the window.
2. Promote the object attribute of the entry field as this is where you want the
message to be displayed. Save the GUI application as MSGWIN.
3. Create another GUI application. Put the MSGWIN GUI application, a working
storage record (PERFREQ2), and a process (PR-ERRORCHECK) on the free-form
surface. Add an entry field and a push button to the window.
4. Define the PERFREQ2 working storage record so it has the following structure:
7. The contents (object) of the entry field should be connected to the PERFREQ2
attribute MESSAGE data.
9. Connect the has executed event of the process to the performRequest action
of the free-form surface. Pass it the PERFREQ-STRUCTURE attribute of the
working storage record as the request object of the connection to the
performRequest action.
10. Test the application (save as VSLTST4). Click on the push button (nothing
happens right?). Enter some data in the entry field in the first window and
click on the push button (now what happens?).
Because you are using an attribute, you must be careful that no other
changes to the data item or the working storage record of which it is part
cause the event to be fired. Therefore you should use level-77 data items for
this purpose. Changes to the working storage record of which they are part
do not influence the data item.
This example shows the same error window as in the previous example, now using
a data item as a toggle for opening the window.
2. Create a new working storage record (TRIGGER) with the following data items:
10 MESSAGE char 60
77 MSGTRIGGER char 1
3. Replace the perform request working storage record with the new working
storage. The easiest way to do this is to hold down the Altkey and click on the
working storage record with mouse button 1. Now change the name from
PERFREQ to TRIGGER.
5. Replace the previous process with the new process. The easiest way to do
this is to hold down the Altkey and click on the process with mouse button 1.
Now change the name from PR-ERRORCHECK to TR-ERRORCHECK.
7. Create a connection between the TRIGGER attribute MSGTRIGGER data and the
openWidgit action of the MSGWIN GUI application.
To create and use a visual part that allows you to implement conditional logic
without the need to implement the perform request or data triggering mechanism
on every occurrence, do the following:
1. Create a new GUI application. Replace the window with a label part that has a
labelString value of “Flag.” This will be the primary part just to indicate what
part we are embedding when using the part.
a. Connect the enabled events of the setFlag and clearFlag labels to the self
action of the “Condition” variable part.
b. Connect the enabled event of the checkFlag label to the “unlisted action
...” enable of the “Condition” variable part.
c. Connect the self attribute of the true label to the value attribute of the
connection between the setFlag label and the “Condition” variable part.
d. Connect the self attribute of the false label to the value attribute of the
connection between the clearFlag label and the “Condition” variable part.
5. Promote the following features using a promoted part feature name that
matches the labelString for each part:
6.
.. Save this GUI application as member FLAG.
.
1. Create a new GUI application. Add the created FLAG GUI application to the
free-form surface of the new GUI application.
2. Put two push buttons on the window: “Set” and “Clear.” Connect the clicked
event of the push buttons to the setFlag and clearFlag actions of the FLAG GUI
application, respectively.
3. Put a third push button on the window: “Check.” Connect the clicked event of
this push button to the checkFlag action of the embedded GUI application.
7. Test the application. Click on Set and then Check, Clear and then Check, what
happens?
9.3 Iterations
Iterations are useful for repeating an action a number of times until a certain
criterion is satisfied. In this section we explain a number of methods to
achieve this using visual connections. Since the end of a loop depends on a
condition, there is some relation to the paragraph about conditional logic.
9.3.1 Iterator
Loops are often used to go through all of the elements in an array and
perform some kind of action on them. Within VisualAge Generator the
ordered collection is a kind of array (see 7.6, “Ordered Collections” on
page 137 for a description of ordered collections). The ordered collection
contains a subpart, called the iterator . The iterator is a pointer to one of the
To access the iterator choose Tear-off attribute from the Object menu of the
ordered collection. Choose iterator from the list of attributes and drop the
part on the free-form surface.
Actions:
iterate Advances the cursor to the next element in the collection, if there
is a next element, and answers a Boolean indicating whether the
cursor was advanced
next Advances the cursor to the next element in the collection, if there
is a next element, and gives a pointer to the next element as a
result
nextLine Advances position past next line delimiter and returns all
elements up to the delimiter. This action works if you are
iterating over a string or a collection that contains two
consecutive elements that correspond to the character CR
(carriage return) followed by the character LF (linefeed).
peek Returns the value of the next item in the array but does not move
the pointer
Attributes:
atEnd Boolean indicating whether the end of the array has been reached
Events:
atEnd Change of the Boolean indicating whether the end of the array
has been reached
To use the iterator to close the windows that were opened by the system, do the
following:
1. Create a new GUI application. Put an entry field on the window. Save the
window as VSLTST6.
2. Create another GUI application. Add the VSLTST6 GUI application as an external
GUI application on the free-form surface three times.
5. Connect the clicked event of the Open push button to the openWidget action of
each of the three external GUI applications. Connect the clicked event of the
Open push button three times to the add: action of the ordered collection.
Provide the self attribute of a different GUI application as a parameter on each
of the connections. (Connect self to anObject.)
6. Tear off the iterator attribute of the ordered collection. Tear off the current
attribute from the torn-off iterator attribute.
7. Connect the clicked event of the Close push button to the reset action of the
iterator. This resets the iterator to the beginning.
8. Drop a label on the free-form surface. Connect the clicked event of the Close
push button to the enable action of the label. Connect the enabled event of
the label to the iterate action of the iterator. This puts the cursor on the next
element in the array.
9. Connect the enabled event of the label to the closeWidget action of the torn-off
current attribute of the iterator (you will need to choose unlisted action... and
type in the action yourself).
10. Connect the closedWidget event of the torn-off current attribute of the iterator
(again by using the unlisted event... option from the Connect window) to the
enable action of the label. This starts the next iteration.
12. Open all the windows by clicking on the Open push button and close them all
by clicking on the Close push button.
9.4 Summary
Algorithms usually consist of sequences, iterations, and conditional
statements. These basic concepts can be built in VisualAge Generator using
different techniques.
Events have handlers, which can be actions. These handlers may perform a
number of actions and in turn cause a number of events to be signaled.
These events can occur asynchronously, which means they are put last on
the stack of events to be handled, or synchronously, which means they are
put first on the stack.
When writing your own handlers, it is important to make sure that they are
atomic. They should have a begin and an end with a predefined state. In
addition you should clearly define the events that are signaled by the handler
and whether they are synchronous or asynchronous.
The techniques described to build conditional code can also be used to build
iterations. Iterations are basically the re-execution of an action depending on
whether a certain condition has been met.
• Describe the order of events as they occur in the system based on the
definition
The default way to fill a container details with data would be to have the
connection from a working storage record structure to the items attribute of
the container details. This default connection does not perform well,
however, because it has to figure out how many data items have actually
been filled by comparing each to the default value. A better method of filling
a container details is by providing an array with a known size (start and end)
and providing this information to the container details.
The container details fills efficiently when you use the above technique. A
relationship is also created between the working storage record and the
container details. The action passes the container details a pointer to the
data in the working storage record. So any changes you make in the
container details are also represented in the working storage record.
The container details provides the user with information spread over a
number of columns. Often the columns spread out past the right-hand
boundary of the container details, thus requiring the user to scroll right. The
data that is shown in the container details often contains one or more data
items that uniquely define the row. The user will want to keep seeing this
data even though he or she scrolls right. The lockedColumns feature, which
can be set in the settings or at runtime, defines the number of columns that
should always remain visible, starting at the left-most column.
From the settings you can modify the look and feel of the container details.
You can set the rows to have an etched look, making them gray with a
backdrop. You can also make the container details read only if the user is
not allowed to make changes in the data or when you are using the
container details only as a selection mechanism.
To enable the function of the packetRequested for the container details, you
have to set the packetEnabled attribute of the container details to true. This
will ensure that the packetRequested event gets signaled when a new packet
is required. Before doing this, however, you have to set the total number of
rows you are going to fetch in the totalRows attribute of the container details.
This ensures that the scroll bar of the container details is set up correctly, to
look like the container details already contains the total number of rows of
data, although in fact it does not.
When both the packetEnabled and totalRows attributes have been set, you
are ready to start using the packet request capabilities of the container
details. Use the packetRequested event as your signal to go and fetch the
next set of data. The packetSize attribute can be used to predefine the size
of the packets so that they match the size of the working storage record
array you use to hold the data. Instead of adding this data to the container
details directly, however, you have to use the packet attribute.
By tearing off the packet attribute, you get access to its features, which
include:
startRow The start position of the page of data at which the scrollbar is
currently located
endRow The end position of the page of data at which the scrollbar is
currently located
The difference between the endRow attribute and the startRow attribute
determines the size of the packet of data. This is dependent on the size of
the container details on the window.
Now, when the packetRequested event is signaled, you can get the packet of
data that corresponds to the startRow until endRow of your result set. The
result of this fetch should be placed in the dataRows attribute of the tear-off
of the packetRequested event. The technique you use here should be the
same technique used for entering data into the container details in the most
efficient way; in other words, use the getFieldsStartingAt:to: action.
This mechanism works fine if you can predict the values in your result set
between startRow and endRow . If you are using a relational database
system, this can be quite difficult. You could, however, write a query that
does exactly that using a WHERE clause similar to that which will be used to
get the data:
On basis of the resulting value of key , you can build up the rest of your result
set.
You will have to weigh the performance of this query against the requirement
for seamless scrolling.
This example uses the features of a container details to create an application that
allows seamless scrolling through a set of data.
1. Create a new GUI application. Create a working storage record, PACKETWS, with
the following structure and put it on the free-form surface:
10 TOTALROWS bin 9
10 STARTROW bin 9
10 ENDROW bin 9
10 PACKETSIZE bin 9
10 PACKETNUMBER num 3
10 ROWS char 21 occurs 50
15 NUMBER bin 9
15 TEXT char 17
20 TEXT-P1 char 14
20 TEXT-P2 num 3
77 INDEX bin 9
2. Make a Quick Form from the ROWS attribute. This results in a container
details. Remove the attribute-to-attribute connection that is created.
3. Add an entry field and a push button to the window. Connect the object
attribute of the entry field to the TOTALROWS data attribute of the working
storage record.
;/* Note: Uncomment the marked (/*C) lines and the packetsize
;/* will vary with the visible size of the CDV.
;/* Endrow and startrow values automatically vary
;/* by visible size of the CDV.
10. Connect the STARTROW data and ENDROW data attributes of the working
storage record to the startRow and endRow attributes of the torn-off packet
.. attribute.
.
12. Enter a number to represent the total rows in the container details in the entry
field and click on the push button. Scroll down in the container details. You
will see the CDV-GET-DATA statement group being triggered to get the next
packet.
It helps if you set ITF watch points on these data items from the PACKETWS
working storage record:
Try a new total rows value and click on the push button again.
Try changing the size of the container details. (If you connect the container
details to the window using the container details layout settings you can do
this during testing to see the dynamic change in packetSize if you have
removed the comments from the statements marked with /*C).
If you edit the data in a column of the container details, the data in the
associated working storage record is updated automatically. The
aboutToBeginEdit and aboutToEndEdit container details column events can
be used as triggers for checking the values of the data. You could also be
ready for a change to any cell in the container details by using the event
cellValueChanged . Remember that, as with entry fields, the data gets
updated only when the cell loses focus. The cell does not lose focus when
the user uses a menu to start the save action, so you will have to make sure
that the cell loses focus yourself (for example, by explicitly putting the focus
on another part). The container details and the columns in it have the same
features as an entry field for validating information (see 12.2, “Data
Validation Errors” on page 221 for a more detailed explanation of validation).
Whether or not a part supports drag and drop is indicated in the settings of
the part. You can change the characteristics only during definition of your
GUI application, not at runtime. For both drag and drop there are three
options: move, copy, or link:
• Move—When both the source and target support move, you can move
data from the source to the target (default operation when you allow
both move and copy).
• Copy—When both the source and target support copy, you can move
data from the source to the target. (Press the Ctrl key to copy if both
move and copy are supported.)
• Link—creates a link between the source and the target, making the parts
point to each other. (Use Ctrl+Shift and mouse button 2 to make a link.)
This example shows you how to drag and drop between two list boxes.
• Create a new GUI application.
• Put two list boxes on the window beside each other. Change the settings of
the left one to allow you to drag (both move and copy) and the right one to
allow you to drop (both move and copy).
• Add some hard coded values to the left list box.
• Test the application (save the GUI application as DRAGDROP).
Try both moving and copying some data (select an item first). Notice that the
icon indicates whether dropping is allowed and shows you whether you are
about to copy or move the item. When you are copying the selected item, you
see a plus sign in the icon that is being dragged.
Each part that allows drag and drop has a feature called dragDropSpec . You
can tear off this attribute. This gives a number of additional features that
allow you to react to certain events in the drag and drop process. See the
In this example we build a simple editor, using the file accessor part.
• Create a new GUI application. Put a multi-line edit part on the window.
• Put two push buttons on the window. Label one Open..., one Save.
• Put a file accessor part on the free-form surface. Connect the buffer attribute
of the file accessor part to the object attribute of the multi-line edit part.
• Connect the clicked event of the Open.. push button to the selectFile action as
well as the read action of the file accessor part.
• Connect the clicked event of the Save push button to the write action of the
file accessor part.
• Test the application (save the GUI application as FILEACC).
This example implements a message box with the simple question as to whether
the user is sure about closing the window.
• Create a new GUI application. Put a message prompter on the free-form
surface. Set the message prompter to provide a question. Enter “Are you
sure you want to close the window?” as the message text. Make sure you
select the Yes, No radio button.
• Connect the closeWidgetRequest event of the window to the
cancelCloseRequest: action of the window. This stops the close and allows
you to decide what to do.
• Connect the closeWidgetRequest event of the window to the prompt action of
the message prompter.
• Connect the okYesRetry event of the message prompter to the closeWidget
action of the window.
• Test the application (save the GUI application as CNFRMSG).
Test both the negative and positive answers to the question stated in the
message box.
10.5 Summary
VisualAge Generator provides a number of facilities that can enhance the
GUI.
The container details provides a tabular view of data. It enables the user to
scroll through the data, change the size of the columns, and edit directly
within the table. As a developer you can control the look and feel of the part,
the scrolling process, and any editing that is done by the user. In using the
container details, be aware of the implications that large sets of data, and
allowing the user to change them, can have on your system design.
The file accessor part enables you to access data from an operating system
file through a buffer. The user is provided with the standard operating
system file dialog to select a file. Once selected, read, and changed, you
can write the data back to the file.
• Use the container details and understand both its features and
limitations.
You create an embeddable part just as you would create any other GUI
application. Create a GUI member. Because the primary part will not be a
window, the first thing you can do is delete the window. If this embeddable
part will be used to construct a visible part of the user interface, determine
which part the end user is going to see and place it on the free-form surface.
If it is the first part to be placed on the free-form surface, it will automatically
become the primary part. If not, you can explicitly make it the primary part
by choosing Become primary part from the Object menu.
2. Create a working storage record, ADDRESS-WS, that contains the following data
items:
10 ADDRESS char 92
20 STREET char 50
20 CITY char 30
20 STATE char 2
20 ZIPCODE char 10
3. Put a form on the free-form surface. Make sure it is the primary part by
looking at its Object menu. If the menu option Become primary part is not
available, the form is the primary part.
4. Put the ADDRESS-WS working storage record on the free-form surface. Tear off
the ADDRESS data item. Quick Form the self attribute of this tear-off onto the
.. form. Align the fields to make the part aesthetically viewable.
.
5. Add a push button with the label “Clear” to the free-form surface (the user will
not see this push button). Connect the clicked event of the push button to the
ADDRESS data attribute of the working storage record. This connection will
clear the contents of the structure in the working storage record and therefore
clear the entry fields. Since we do not provide a parameter to the connection,
blanks are automatically passed.
6. Add a process to the free-form surface called SET-ADDRESS and provide it with
the following code:
7. Save the part as ADDRESS and close the GUI application definition.
8. Create a new GUI member. Choose Options Add GUI application... from the
menu and choose ADDRESS from the list of GUI members.
To create a new category, choose Add new category. Give the category a
meaningful name and choose bitmaps to represent the category when it is
closed and opened. If you want to delete a category, select it and choose
Options Modify palette Delete category from the menu. You can only delete
categories that are not part of the default product configuration.
Choose Add new part and select the GUI member to be added to the palette
from the list. You can also set an icon to be used as the icon in the parts
palette. Choose the category to which the part should be added and click on
Promote. If you want to delete a part, select it and choose Options Modify
Once you have added a part to a category, you can access it like any other
part in VisualAge Generator GUI builder. The GUI member must be in your
concatenation of MSLs in order to use it from the palette.
Determine the actions that you would like to be able to perform on the
embedded object. Next, determine how this function can be provided.
Determine the part and the corresponding action, event, or attribute within
the embeddable part that allows you to implement this function. Choose
Promote part feature... from the Object menu of this part. Figure 49 on
page 200 shows the window from which features are promoted to the
interface of the embeddable part.
Select the action, attribute, or event from the list and provide it with a
meaningful name (see “Promoted Features” on page 351 for more
information about naming promoted features). Click on the Promote push
button. The feature is added to the list of promoted features. If the
embeddable part is embedded in a GUI application, the embeddable part′ s
Connect menu contains all of the promoted features.
To remove promoted features, select them from the list of promoted features
of a part and click on the Remove push button. To rename promoted
features, you must remove them and then promote them again.
In this example we add the capability to access and clear the address data from
the part in which the embeddable part is embedded.
1. First we have to determine which features allow us to access and clear the
data:
• Accessing the data is possible through the data attribute of the working
storage record.
• Clearing the data can be performed by clicking on the Clear push button.
• Filling the working storage record with data is done by executing the
SET-ADDRESS process.
3. Select Promote part feature... from the Object menu of the working storage
record.
4. Select the data attribute from the list of attributes and promote it with a
promoted feature name of addressData. Close the promoted features window.
5. Select Promote part feature... from the Object menu of the push button.
6. Select the click action from the list of actions and promote it as clear. Close
the promoted features window.
7. Select Promote part feature... from the Object menu of the process.
8. Select the execute action from the list of actions and promote it as fillData.
Close the promoted features window.
10. Open the ADDRWIN GUI application (created in Defining an Embeddable Part on
page 197).
11. Add two push buttons to the window underneath the embeddable part. Label
the first one “Fill” and the second, “Clear.” Change the names of the push
buttons to “pbFill” and “pbClear,” respectively.
12. Connect the clicked action of the Fill push button to the fillData attribute of the
ADDRESS embeddable part.
13. Connect the clicked action of the Clear push button to the clear attribute of the
ADDRESS embeddable part.
14. Save and test the application. Clicking on Fill should set the address data;
clicking on Clear should clear it.
Working Storage
When two GUI applications contain a working storage record, data can be
passed from one application to the other through an attribute-to-attribute
connection. This makes data available in both GUI applications. If you make
the connection unidirectional, one of the working storage records becomes
read only.
This example moves data from one GUI application to another, using working
storage records.
3. Connect the data attribute of the working storage record to the addressData
attribute of the embeddable part. This connection will keep the data of the two
working storage records in synchronized.
4.
.. Save and test the application.
.
The trace clearly shows that the two working storage records are synchronized four
times (at initialization, when the data has been filled, and twice when the data has
been cleared).
Once you have connected the variable part to another part by connecting the
self attribute of that part to the self attribute of the variable part, you can
perform any actions on the variable part that you would be able to perform
on the part itself. Because it points to the part, it uses the same memory
location upon which to perform the action. The variable part has become a
way of looking at and acting on the part.
Hint
You may have noticed that the variable part looks a lot like a torn-off attribute.
Both are represented graphically as parts surrounded by brackets. A torn-off
attribute is indeed a variable part. It points to one of the attributes of the part
from which it has been torn off.
But how can you make a connection to an action that is not defined for the
variable part. As mentioned before, the only listed attribute of a variable part
is the self attribute. The variable part has the possibility to choose an entry
from the Connect window that contains unlisted action/attribute/event... . In
the Information Required window (Figure 50 on page 205) you can enter the
name of the action, attribute, or event you want to perform, change, or use.
As long as the feature is implemented in the part to which the variable part
is connected, this will work. If it is not, a runtime error will occur.
Hint
Using the destroyPart action on a variable part does not destroy the part to which
the variable part points. It destroys the variable part itself.
If you want to destroy the part to which the variable part points, define an action,
for instance, destroyMe, in the part to which the variable part points. Connect the
destroyMe action to the destroyPart action of the part. Then, when you want to
destroy the part to which the variable part points, use the destroyMe action of the
variable part. The request will be forwarded to the destroyPart action of the target
part.
VisualAge Generator also enables you to make a variable part look just like
a VisualAge Generator member. Choose Build features based on member...
from the Object menu of the variable part. This brings up a window with an
entry field. Type the name of the VisualAge Generator member whose
interface you want the variable part to use. Once you have set this feature
and you look at the interface of the variable part, it looks just like the
interface of the member on the basis of which you have built its features.
Using this option does not mean that the variable part actually points at this
member. If you connect the variable part to the self attribute of a push
button, it points to the push button and you can click on it.
You can also easily create connections by dropping the same type of part the
variable part represents on the free-form surface. Tear off the self attribute. Make
your connections to this tear-off. When you are finished, delete the original part.
This example moves data from one GUI application to another, using variable
parts.
1. Save the ADDRWIN GUI application (last modified in Sharing Data between GUI
Applications Using Working Storage Records on page 202) with the new name
ADDRVAR.
2. Delete the ADDRESS-WS working storage record from the free-form surface of the
ADDRVAR GUI application.
3. Add a variable part to the free-form surface of ADDRVAR. Choose Build features
based on member... from the Object menu of the variable part and enter
ADDRESS-WS.
4. Edit the embedded GUI application ADDRESS and promote self of the ADDRESS-WS
working storage record as address.
Remember when using a variable part you must provide it with the pointer to
the part (self attribute) to which it should point. You could remove the
addressData feature because you no longer need it in the ADDRVAR GUI
application, but we will leave it because it is still referenced by the ADDRWIN GUI
application.
6. Connect self of the variable part you added to the newly created address
feature of the ADDRESS embedded GUI application.
7.
.. Save and test the ADDRVAR GUI application.
.
The trace clearly shows that the memory address of the working storage record is
passed only once to the variable part. Thereafter the two parts point to the same
memory location, and no further events are triggered to synchronize their content.
Hint
Often you will need embedded parts to communicate with the window in which they
are contained. You can do this by passing the embedded part the self attribute of
the parent (in this case a window). Promote the self attribute of the variable part
in the embeddable part and connect this to the the self attribute of the window
where it is embedded. In this way you can act on the variable part as if it is the
window in which the embeddable part is embedded.
Creating parts at runtime is especially useful if you do not know which parts
should be on the window or when you want to load parts into memory in the
background to reduce the initial load time of the application. In this section
we focus on ways to create parts at runtime.
The settings of the object factory contain one main feature besides the part
name: instanceClassName . The instanceClassName defines the type of part
that should be created by the object factory. The field can contain either a
VisualAge Generator GUI application name or the classname of a VisualAge
Generator part. The instanceClassName can also be set dynamically by
using a connection that changes its attribute value.
Once you have set the instanceClassName of the object factory, all attributes
of the interface of the part that you are trying to create are automatically
added to the interface of the object factory. By setting values for these
attributes, a newly created part will have the values of these attributes as
they are at the time the part is created.
The only action of the object factory, new creates a new part of the type
specified in the instanceClassName attribute. It creates this part in memory
only; it does not show it. The newly created part is pointed to by the
instance attribute of the object factory. When this feature is torn off, it is a
variable part pointing to the part you just created. By acting on this variable
part, you can act upon the part itself. To make the part visible to the end
user you can perform the openWidget action on the part if it is a GUI
application with a window as its primary part. “Adding Parts at Runtime” on
page 213 describes techniques for making other parts visible to the end
user.
1. Create a GUI application with an entry field on the window. Resize and
reposition the window on the free-form surface and then save the GUI
application as OFWIN.
2. Create another GUI application with a push button called “Open” on the
window.
3. Add the OFWIN GUI application to the free-form surface. Connect the clicked
event of the push button to the openWidget action of the external GUI
application.
Every time you click on the push button, the same copy of the window with the
entry field is shown. Lets modify the GUI application to open new instances of the
entry field GUI application.
1. Put an object factory on the free-form surface of the OPENWIN1 GUI application.
Open its settings and type OFWIN in the instanceClassName entry field.
3. Delete the OFWIN external GUI application from the free-form surface
4. Connect the clicked event of the push button to the new action of the object
factory. Also connect the clicked event of the push button to the openWidget
action of the torn-off instance attribute of the object factory. Make sure the
new action is performed before the openWidget action.
Click on the push button several times. You will notice that each time you click on
the push button a new window is created. Type some text in an entry field of one
of the windows and see if this influences the contents of the other windows. The
windows are completely independent of each other.
Every time you perform the new action, a new part is created and the
instance attribute contains a pointer to the last created part. If you do not
store the pointers to the previously created parts somewhere, you will never
be able to access them again. You can store the pointers to the parts in an
ordered collection by making a connection to the add: action of the ordered
collection and giving it the instance attribute of the object factory as its
parameter.
Accessing the part in the ordered collection requires that you know the index
of the part in the ordered collection. You can use the atIndex: action of the
ordered collection to determine the pointer to the part. Connect the result of
4. Connect the clicked event of the push button with the add: action of the
ordered collection. Provide the instance attribute of the object factory as the
anObject parameter for the connection. Use the Reorder connections from
push button Object menu option to make sure the add: action is performed
after the GUI application has been newly created but before the window is
opened.
5. Add an entry field to the window and a second push button called “Close.” The
idea is that clicking on Close will close the window number as stated in the
entry field.
Note: You can change the entry field data type to Integer or Number, so it
matches the data type requirements of the target parameter (we have not
made this connection yet), but this was not required in our testing.
7. Connect the clicked event of the Close push button to the atIndex: action of the
ordered collection. Provide object of the entry field as the anIndex parameter
for the connection. Connect the result of the connection to the self attribute of
the variable part.
8. Connect the clicked event of the Close push button to the unlisted action...
action of the variable part. Type in closeWidget as the action to be taken and
click on OK.
9. Connect the clicked event of the Close push button to the removeAtIndex:
action of the ordered collection. Provide object of the entry field as the
parameter. This ensures that the ordered collection does not contain parts
that no longer exist. All the open windows move one down in the hierarchy if
they were opened after the window that was just closed.
Open a couple of windows and see whether you can close a specific window and
open some more windows.
Note: You may trigger a walkback if you use an index value that does not exist in
the ordered collection. You cannot close a window that does not exist.
In 3GL language terms, you would say that the application data is the code
segment and the associated data is the data segment. The same code
segment can be used to process different data segments.
• The openWidget action is performed and the GUI application had not
been opened yet
• The GUI application of which it is part (in the case of embeddable part)
is created
Once the GUI application has been loaded into memory, it can be
communicated with. It does not have to be visible; its data need only be
loaded into memory. For some attributes of the GUI application to have an
effect, they must be set before the application opens.
Hint
When it is relevant that data is passed after the part has been created but before it
is opened, it is best to use an event-to-attribute connection to change the data in
the part. This connection must fire before the widget is opened but after it has
been created.
After a GUI application has been used, it is typically closed. This closing
causes both the definition and the data to be kept in memory. This is useful
from a caching perspective but also takes up resources if the data is not
going to be used again. If there are attribute-to-attribute connections to the
data, these connections still exist, and the associated data will be
synchronized as changes occur in the system. This can cause tremendous
overhead.
This example shows that the data associated with a GUI application will not be
deleted unless you use the destroyPart action.
2. Test the application. Open the window by clicking on the push button. Type
text in the entry field. Close the window that is shown, using the system
menu. Now open the window again by clicking on the push button. The text
will still be there.
3. Connect the closedWidget event of the OFWIN GUI application on the free-form
surface to the destroyPart action of the same OFWIN GUI application.
5. Test the application again and see whether the previous behavior still exists.
Hint
An alternative to the connection to the destroyPart action is the destroyOnClose
attribute setting for the external GUI application on the free-form surface. A n
external GUI application has settings with respect to the GUI application free-form
surface where it has been included. Currently the only available setting is the
destroyOnClose attribute. The setting is only for this instance of the external GUI
application on the free-form surface; it does not affect other external GUI
application instances.
The following actions allow you to add and remove parts from a parent part
at runtime:
removeSubpartNamed:
This action removes the named part from the part at which the action is
directed. The result attribute of the connection will contain a pointer to
the part. The part is removed from the parent of which it is part but will
still exist in memory. 8
subpartNamed:
This action provides you with a pointer to the part of which the name is
provided. By connecting the result to a variable part the part can be
acted upon.
subpartNamed:put:
This action will put a part on the containing part at which it is directed
and provide it with the given name. The second argument is a pointer
to the part, in other words its self . The part will be made part of the
container but will not be visible. An openWidgit must be issued on the
part to make it visible.
subpartNamed:put:beforePartNamed:
This action is similar to the subpartNamed:put: action except that the
part is added before the part that is named in the component sequence.
The initial component sequence can be viewed by looking at the parts
list of a window. The component sequence mainly has an effect on the
sequence in which parts are created and destroyed. This setting is
only guaranteed if you first close and then reopen the window.
subpartNamed:putOpened:
This action is similar to the subpartNamed:put: action except that the
part added will also be displayable (visible) in the target container.
subpartNamed:putOpened:beforePartNamed:
This action is a combination of the previously defined actions. The part
is shown and opened at a certain location in the component sequence.
8 The implementation of this action is not complete. The lab may change it, such that there is no
result attribute. The implementation may change so that the part you have removed is also
destroyed. Experiment as required to ensure that you understand the function provided.
1. Create a new GUI application. Add a menu bar to the window with one popup
menu item. Change the name of this item to “List.”
2. Add an object factory to the free-form surface of the GUI application. Set
“AbtPushButtonView” as its instanceClassName. Tear off the instance
attribute of the object factory.
4. Connect the clicked event of the push button to the new action of the object
factory.
7. Connect the object of the entry field to the name attribute of the connection
between the push button and the pop-up menu.
9. Test the application. Every time you click on the push button, an item should
be added to the menu with the name as provided in the entry field.
[Link]
[Link]
Part Placement
A part is placed within an x,y grid indicated on the part in which it is
contained. The origin of the grid has coordinates (0,0). Parts have a width
and height indicated in pixels. To change both the x,y position and the
height and width, use the corresponding actions of a part and provide the
new values as its parameters.
If you do not want the change to show up and you want to move the window
or parts on the window before it opens, connect the hide action of the
window to the aboutToOpenWidget event of the window. Next, change the x,
y position and the height and width. Finally, show the window again by
performing the show action.
1. Create a new GUI application. Place four entry fields on the window, labeling
them x, y, width, and height.
2. Put a group box on the window and place a list box inside the group box.
4. Connect the clicked event of the push button to the x, y, width, height actions
of the list box and provide the object values of the entry fields as its
parameter.
6. Test the application. Notice that the list box is moved and sized inside the grid
set by the group box because this is the part in which it is contained.
The group box is resized with the list box although no relationship has been
set between the two parts. This is because the resizePolicy rules, based on
the current settings, require that a composite part resize automatically to try
and accommodate the child parts within it.
The initWidgetSize of the window can also be used to change the initial
position and size of the window. This attribute must be set before the
window is opened but after it has been created. The attribute can be torn off
from the window and contains two attributes: origin and corner . Each
attribute can be torn off from the tear-off of initWidgetSize . They are points
requiring an x and y value. Set the values after you have created the
window and before you open it.
Using the initWidgetSize , you can determine an offset for opening a new
window. This enables you to create an application that opens its windows in
a cascaded manner, allowing the user to always see the title bar of the
window. Figure 51 shows an example of an application with cascaded
windows.
Placing parts relative to each other and making them resize automatically is
discussed in 4.3, “Defining Visual Parts inside Other Visual Parts” on
page 50.
11.3 Summary
Embeddable parts are a way of creating reusable components and building
applications from those components. Embeddable parts also enable you to
hide complexity.
A variable part is a pointer. It points to the part that it will represent with its
self attribute. A variable part can point to any part in VisualAge Generator.
GUI errors
Connections can cause errors, such as when you try to index into an
array with an invalid value. We look at ways of preventing errors in
connections from occurring.
In the sections that follow we discuss these errors and explain how to inform
users about the occurrence of errors.
To make sure the control returns to the GUI application after the error has
occurred, add the (REPLY option to the call to the server application, as in
this example:
The following sample code checks for the value of EZERT8 after a call to a
process:
Soft errors
Soft errors do not cause the application to abend but indicate a state
that is recoverable. For instance the database returns a No Record
Found (NRF) indicator when no value was found. If a value was
expected, this is apparently an error. If a value was possibly expected,
it is no error.
After each I/O process, you will have to check for errors and determine
which soft errors are allowed and which are not allowed. You can implement
the checking as a standard error routine. The error routine should also save
the relevant error indicators to a working storage record that is passed back
to the GUI application because the value of the error indicator, such as
SQLCA, is lost when the application is left or another SQL statement or
function is executed.
12.2.1 Masking
It is always better to prevent users from making errors rather than fixing the
consequences once errors have been made. This is an important part of
user interface design.
With VisualAge Generator you can use parts that require the user to make a
choice, such as radio buttons and list boxes. At runtime you can set the
items attribute of these parts with the valid values. The optimal way of
retrieving lookup data is discussed in more detail in “Cache, Cache, Cache”
on page 268.
VisualAge Generator also includes a part called Formatted Text in the Data
Entry category. This part is an entry field with an additional feature. It
allows you to give it an edit mask. An edit mask restricts the user from
typing in anything other than those elements that correspond to the
definition.
The mask is stated as a string; the different characters in the string indicate
the type of character expected at a certain point.
You can also add literals to the string by enclosing them in quotation marks.
For instance, a U.S. telephone number would be: ″(″999″)-″999″-″9999.
VisualAge Generator even provides a number of standard edit masks.
In this example we create a masked field for a credit card number and expiration
date entry by a user.
1. Create a new GUI application. Put a Formatted Text part and a normal entry
field on the window.
2. Open the settings of the Formatted Text part. Change the Edit mask type to
String and click on the Customize... push button.
3. Enter 9999B99999B9999B99″/″99 as the format string (see Figure 52) and save
the settings.
4. Connect the object attribute of the Formatted Text part with the object
attribute of the entry field.
5. Test the application (save as member VALMASK). After you have entered data in
the Formatted Text part, tab out, and see the results in the entry field. What
happens if you enter data in the entry field? What about entering data that
does not match the Formatted Text rules?
Converter
Each VisualAge Generator part that contains data can be set to be of a
certain data type in its Settings. This setting can be further specified by
customizing, for example, the allowable range of values. 7.8, “Data Format
in a GUI Application” on page 149 contains a more detailed explanation of
the different settings of data types.
The setting is stored in the converter attribute of the part. The converter, like
the iterator explained in 9.3.1, “Iterator” on page 177, is a part in itself with
its own behavior. You can use the part by tearing off the converter attribute
from the part that contains it.
• Actions
− (none)
• Attributes
9 Although a data type is in fact a collection of valid values, we include it for practical reasons.
10 The exact list of features shown for a converter depends on the part from which it is torn off. A n
entry field, for instance, lists a subset of the mentioned features. Some features not listed for the
entry field part converter, but shown in our list, may actually exist. For example, an entry field with
a data type of string would have the min and max attributes, among others. These can be accessed
by using an unlisted attribute.
• Events
The list of events is similar to the list of attributes. The events are the
changes that occur to the attributes.
The values for the different attributes of the converter can be set at runtime. 11
Change the converter of one part, for example, on the free-form surface, and
assign the converter of this part to the converter of a part on a window. Use
an event-to-attribute connection to make sure the value gets passed.
11 Although Formatted Text also has a format attribute that contains the way it looks and is validated,
its value cannot be changed at runtime. But, there is an unlisted attribute, formatString, which is
the mask for the Formatted Text part.
2. Put an entry field on the window and a label on the free-form surface.
We will change the converter of the entry field on the window by changing the
converter of the label on the free-form surface and copying the settings to the
entry field on the window.
3. Change the data type of the label on the free-form surface to “string” and
customize some of its characteristics.
5. Create a quick form on the window of the self attribute of the torn-off
converter attribute (you may want to size the window part to be taller first).
6. Add a push button to the window and connect the clicked event of the push
button to the converter attribute of the entry field.
7. Provide the self attribute of the torn-off converter attribute as the parameter to
the connection.
Hint
The attributes of the converter for an entry field only contain a subset of the
attributes of the converter of a label. Additional values can be set for an entry
field, however. Just use the converter of a label to set the values. Use an
event-to-attribute connection to change the value of the converter attribute of the
entry field. Use the self of the converter attribute of the label as the parameter to
this connection.
You could also use the unlisted features for the torn-off converter for the entry field
to access the missing string data type attributes.
Using the converter causes the field to show the string “**error**” if the
value does not conform to the converter and has lost focus. The object
attribute of the field will contain the original value, that is, the value before it
was changed to an invalid value. If you do not want to use the converter, set
the data type of the part to “(none).”
The verificationRoot of the Form Input Checker can be connected to the self
attribute of any part with a converter or any part that contains other parts,
such as a window or form. In this case the Form Input Checker checks all
fields that are part of the composite part.
This example shows how to use the Form Input Checker to check the correctness of
the contents of an entry field and turn the background color of the entry field red if
an error is signaled.
5. Connect the verificationRoot attribute of the Form Input Checker to the self
attribute of the first entry field.
6. Connect the losingFocus event of the first entry field to the check action of the
Form Input Checker. Using losingFocus ensures that the check always occurs
when the user tabs out of the entry field. The object, string, and
userInputConvertError events get signaled only when the user has changed
the data.
8. Connect the checkFailed event of the Form Input Checker to the setFocus
action of the first entry field. This ensures that you are not allowed to leave
the field until you have correctly entered the data.
The Form Input Checker generates a message when an error occurs. The
message is contained in the errorMessage attribute. The message has the
following format:
To show the error message to the user, connect the checkFailed event of the
Form Input Checker to the showErrorToUser of the same Form Input Checker.
Note: Use caution with the checkFailed -to- showErrorToUser connection.
When we defined it during our testing, using VisualAge Generator V2.2
(FixPak 1), we had to use ALT+Print Screen, to break out of a visual loop if
we triggered the check attribute of the Form Input Checker using an entry
field event such as loosing focus . The showErrorToUser action works well
when an independent event, such as push button clicked , is used to trigger
the check action of the Form Input Checker.
The solutions provided for checking against a list of possible values can be
combined with other solutions.
When you do not find a value, one possible action is to use a process that
sets up the display of an error message. One of the advantages of using a
VisualAge Generator table is that it only has to be defined once and resides
in memory to be shared by all GUI applications in which it has been
embedded (see 7.5, “VisualAge Generator Tables” on page 133 for a further
explanation of VisualAge Generator tables).
This example shows the use of a VisualAge Generator table to check for the valid
entry of airport codes. The table contains two columns and could also be used for
populating a (drop down) list. Often, though, users are happier with typing in the
codes they are used to using.
10 AIRPORTCODE char 3
10 AIRPORTNAME char 50
2. Populate the table with some airports you are familiar with, use upper case
letters for the airport codes.
3. Create a new GUI application. Add two entry fields to the window. Customize
the settings for the first entry field to ensure that three characters are entered
and Uppercase conversion is on for the input.
10 AIRPORTCODE char 3
10 AIRPORTNAME char 50
77 CHECKSUCCEEDED char 1
77 CHECKFAILED char 1
The working storage record will be used as a trigger that causes the entry field
to turn red when an incorrect value has been entered. It will also contain the
value the user has entered for the airport code and return the airport name
that matches the code.
5. Connect the first entry field to the AIRPORTCODE data attribute of the working
storage record. Connect the second entry field to the AIRPORTNAME data
attribute of the working storage record.
6. Create a process, CHECK, that will check whether the airport code entered by the
user is correct. The process contains the following statements:
8. Select Define and Structure list... options from the VisualAge Generator
Developer menu active while editing the CHECK process.
.. This will show you the statement groups you need to define.
.
[Link] = ″ Y″ ;
MOVE [Link](EZETST) TO [Link];
10. The CHECKFAIL statement group should contain the following logic:
[Link] = ″ Y″ ;
MOVE ′ ′ TO [Link];
11. Connect the losingFocus event for the first entry field to the execute action of
the process.
12. Connect the CHECKFAILED data event of the working storage record to the
backgroundColor attribute of the first entry field. Provide “Red” as its
parameter.
13. Connect the CHECKFAILED data event of the working storage record to the
setFocus action of the first entry field.
14. Connect the CHECKSUCCEEDED data event of the working storage record to
the backgroundColor attribute of the first entry field. Provide an empty
parameter value.
An Ordered Collection: You can also use an ordered collection with values
to check the validity of a certain entry. The ordered collection can be
populated from a working storage record, a list box, or any other array of
data.
You can check whether a value is in the ordered collection by triggering the
indexOf: action and providing the connection with the value you want to
check for. If the value is found in the ordered collection, the result attribute
of the connection will contain a nonzero value. You can check this value in a
process or statement group similar to the check performed when using a
VisualAge Generator table.
Logic
Validation can be performed in processes or statement groups to see if data
items contain valid values. Therefore the data must always be moved to
data items first. Once the data is available, the process can check whether it
is valid. Using logic to check the data can be combined with other solutions.
Defining the validating processes requires that you define the rules to which
the data elements in your business should abide and building the rules into:
If an error occurs, initialize the display of an error message to the user can
by using a triggering data item in a working storage record. See the
example of using a VisualAge Generator table to validate data.
When to Validate
When to validate is first of all dictated by the preferred behavior of the
application toward the user. From this perspective three requirements can
be defined:
• The user should not be allowed to continue unless the error is corrected
if the error could cause inconsistent data in your application.
• On each keystroke
• If you perform an action that requires the data to have been validated
Keystroke: Using each keystroke to check whether data has been changed
causes a lot of additional actions to be performed throughout the system,
especially when a checking mechanism is used that is not very quick. For
example, going to the server to check against the database if a value is valid
on each keystroke is probably not a very good idea.
This option does allow you to conform to the requirements from a user
interface perspective.
If you use both the message box of the Form Input Checker and the
losingFocus event to show errors to the user, you will encounter problems.
Because the opening of a window is an action that causes asynchronous
events, if you use the setFocus action to put the control back on a field that
was incorrect, the field will get focus. However, because another window is
modal on top of it, it will directly lose focus again, causing an endless loop of
errors to occur.
To circumvent this behavior, use a flag that indicates whether the window or
the field has actually lost focus. Set the flag on the losingFocus event of the
window. Do not validate while the flag is set. Clear the flag on the
gettingFocus event of the window. Make sure validation is performed when
the flag is not set.
Given these three options and their consequences, checking the data on
losing focus is the most viable solution if you can circumvent using the Form
Input Checker message box to indicate that an error has occurred.
Do not ignore a simple option: Use a Validate push button on all input
(data entry window) GUI applications. This allows users to decide when
they want their input proofread . This could be at the end or part way
through the data entry process; their choice. You would also trigger this
validation logic prior to a save request. Very flexible, and maybe easier
to implement!
How to Validate
If you decide to validate the data when a field loses focus, there are a
number of considerations to be made concerning the implementation of the
validation. First of all you have to decide which, or which combination of,
mechanisms to use. You also have to decide what to do about some special
circumstances, such as cross-field dependencies.
Reusability
The reusability of the validation across different platforms and between
TUI and GUI applications.
Ease of implementation
If it is easier to build and maintain a specific instance of validating logic
instead of building reusable parts then there is no reason for reusable
validation mechanisms.
Required data
If you need data from the database to be able to perform a check,
checking in logic is the only option (if it is not possible to build up a list
of possible values).
The first observation is that business data with the same validating
requirements are used in multiple places throughout the application. This
leads to the observation that the implementation of the check should be
independent of the location where the check is used. Within a VisualAge
Within this part you can select one or a combination of mechanisms that best
suit the needs for that specific business data element. The combination
could be a Form Input Checker, a list of possible values, and a check on the
database. These can be sequenced so that you first perform checks on the
client; only when those checks have been successfully performed do you
check the data item against the server validation. This is also an advantage
of checking the data when a field loses focus instead of upon an action.
This example shows the implementation of a generic part for a business data
element with the following characteristics:
• The value should be an integer value.
• It should be between 2222222222 and 7777777777.
• The sum of the individual digits should be divisible by 11.
1. Create a new GUI application. Since the embeddable part for validating is not
going to be visible, replace the window with a label. We use a label to indicate
the name of the part when it is not visible and will only be used on the
free-form surface. Give the label the text “digitCheck.”
2. Place a variable part on the free-form surface and change its name to digit.
Promote the self attribute of the variable part as digit.
3. Now we have to provide the part with the correct converter. Put a label on the
free-form surface, give it the integer data type. Customize the label so that it
has minimum and maximum values of 2222222222 and 7777777777. Provide a
default value of 2345678901. Tear off the converter attribute of this label part
(you will have to carefully resize the label part first).
4. Make a connection from the variable part to the variable part (yes, to itself),
between the aboutToOpenWidget unlisted event to the converter unlisted
attribute. Connect the self attribute of the converter as a parameter to the
previous connection. You first need to connect it to the result attribute of the
connection then edit the connection and change the result text into value.
This will make sure the converter is copied to the field that is represented by
.. the variable part in this embedded GUI application.
.
6. Create a working storage record named VALREUSE-WS with the following structure
and put it on the free-form surface:
10 DIGIT num 10
12 SINGLEDIGIT num 1 occurs 10
10 TOTAL num 2
10 REMAINDER num 2
10 INDEX num 2
10 ERRORREASON char 80
77 CHECKFAILED char 1
77 CHECKSUCCEEDED char 1
7. Connect the object attribute of the variable part (and thus of the field) using
unlisted attribute...) to the DIGIT data attribute of the working storage record.
8. Create a process named VALREUSE-CHK with the logic to check whether the sum
of the individual digits can be divided by 11.
INDEX = 1;
TOTAL = 0;
WHILE INDEX LE 10;
TOTAL = TOTAL + SINGLEDIGIT(INDEX);
INDEX = INDEX + 1;
END;
REMAINDER = TOTAL // 11;
IF REMAINDER EQ 0;
CHECKSUCCEEDED = ″ Y″ ;
ELSE;
CHECKFAILED = ″ Y″ ;
MOVE ″ PROC01 Input not divisible by 11.″ to ERRORREASON;
END;
9. Put the process on the free-form surface and execute it when the check of the
Form Input Checker succeeds. We still have to show the user that something
is wrong.
10. Connect the checkfailed event of the Form Input Checker to the CHECKFAILED
data attribute of the working storage record. Provide a parameter value of ″Y″
for this connection.
11. Connect the CHECKFAILED data event of the working storage record to the
backgroundColor attribute of the variable part (which you have to type in using
unlisted attribute...). Do the same for the CHECKSUCCEEDED data event of
.. the working storage record.
.
12. Make two labels. Make the label for one “Red” and the other “Green.”
Connect “Red” label to the result attribute of the connection that occurs from
the working storage record when the check fails. Connect the “Green” label to
the result attribute of the connection that occurs if it succeeded. Change both
label-to-connection connections to have value as their target instead of result
by typing the correct value into the settings of the connection.
13. Connect the CHECKFAILED data event of the working storage record to the
setFocus action on the variable part (use unlisted action...).
Now we have to tell the user what is wrong. There could be two things; input
out of range or input not divisible by 11.
14. Connect the Form Input Checker errorMessage attribute to the ERRORREASON
data attribute of the working storage record.
17. Create a new GUI application. Put two entry fields and a push button on the
window and put the embedded GUI application you created (VALREUSE) on the
free-form surface.
18. Connect the self attribute of the first entry field to the digit attribute of the
embedded GUI application.
19. Name the push button “Validate Window.” Connect the clicked event of the
push button to the checkDigit action of the embedded GUI application.
20. Make the window part wider and then add a label to the bottom of the window.
Stretch the label (or use the layout settings) to make it as wide as the window
part. Better yet, connect the label to the left and right sides and the bottom of
the window so they size together. Make sure the label is tall enough to
display a text string.
21. Edit the settings and change the label string to several blanks (general
settings page 1), the Alignment to left (general settings page 2), and the
Border width to 1 (general settings page 3). This will give us a framed box to
put validation messages in during runtime.
22. Connect the errorReason attribute of the embedded GUI application to the
object attribute of the label.
23. Test the application (save the member as VALRTST) and see if it works as it
should. Good input values: 2345678000, 3382810017, and 7758299800.
Make sure your input fails the range and division tests. You should see
appropriate messages in the label after you have clicked on the push button.
The combination of fields could in itself be seen as one field. To this the
same would apply as when trying to validate one field. Put the
implementation into a separate part if the combination of fields is a recurring
theme in the application. The parts for checking the individual fields are part
of this aggregate part.
In this example we build on the part that checks the validity of a digit that has to
consist of 10 digits and of which the sum of the individual digits must be divisible
by 11. We now have a window in which this type of data element occurs twice.
The first occurrence has to be a smaller digit than the second. We will check the
two entry fields in the window separately and then together.
1. Edit the GUI application VALRTST and embed a second instance of the digit
checking embedded GUI application. Save the GUI application as VALRTST2.
2. Connect the self attribute of the second entry field to the digit attribute of the
new embedded GUI application instance.
4. Save the embeddable part and return to the VALRTST2 GUI application. From
both embedded GUI applications, tear off the digit attribute.
10 DIGIT1 num 10
12 DIGIT1CHAR char 10
10 DIGIT2 num 10
12 DIGIT2CHAR char 10
10 ERRORREASON char 80
77 CHECKSUCCEEDED char 1
77 CHECKFAILED char 1
6. Connect the object attribute (use unlisted attribute...) of the tear off of the digit
attribute of the first embedded GUI application to the DIGIT1 data attribute of
the working storage record and the same attribute of the second embedded
.. GUI application to the DIGIT2 data attribute of the working storage record.
.
IF DIGIT1 LE DIGIT2 OR
DIGIT1CHAR IS BLANKS OR
DIGIT2CHAR IS BLANKS;
CHECKSUCCEEDED = ″Y″ ;
ELSE;
CHECKFAILED = ″Y″ ;
MOVE ″PROC02 First entry not less than second.″ to ERRORREASON;
END;
8. Connect the CHECKFAILED data event of the working storage record to the
backgroundColor attribute of both torn-off attributes (using unlisted attribute...).
9. Add a label with the value “Pink” to the free-form surface. Use this label as
the parameter by first connecting the object of the label to the result attribute
of the previous two connections(CHECKFAILED data to backgroundColor) and
then changing the connection target from result to value by editing the
settings of the connection.
10. Remove the connection between the first embedded GUI application and the
label in the window used to show error text. Add a connection from the
ERRORREASON data attribute of the working storage record to the object
attribute of the label.
11. Add a connection between the errorReason attribute for each embedded GUI
application to the ERRORREASON data attribute of the working storage record.
This will show any error messages to the user.
12. Connect the checkSucceeded event of the first embedded GUI application to
the check action of the second embedded GUI application. Connect the
checkSucceeded event of the second embedded GUI application to the execute
action of the VALREUSE-CHK2 process.
This will allow each entry field to be edited in sequence and then the cross
edits to be performed.
If a variable part does not have type information associated with it, you can only
directly promote self. To promote another attribute, you have to first choose Tear
off attribute... from the Object menu of the variable part. Select Other... and type
in object. This makes a tear-off of the object attribute. Now promote self of this
tear-off as value.
12.2.3 Formatting
Typically, the values that a user enters in a field are formatted according to
the converter of the field. If the converter as set in the Settings or at runtime
indicates that a digit should be shown with two decimal places, it is shown
that way when the users leaves the field.
When the converter has not been defined for a field, you have to create your
own converter to ensure that the field shows the data in the format in which
the user would like to see it (for example, currency format). Because this is
a lot of work, we suggest that you always use the converter. Set it in a
reusable part as described in “How to Validate” on page 233.
More dangerous are conditions that are unintentional and do not cause a
runtime error. These situations are best covered by a good design resulting
in an accurate test plan.
Message Table
A message table contains messages corresponding to a certain message
code. The code determines the description to be provided to the user when
the error as indicated by the message code occurs. The table can be a
VisualAge Generator table or a DB2 table. The optimal way of retrieving this
message data is discussed in more detail in “Cache, Cache, Cache” on
page 268.
Placeholders
The variable part of the message indicates the specific circumstances in
which the error occurred. They are indicated within the message with a
special character reserved for the purpose, for instance, %. If an error
occurs and both the message code and variable information are provided by
the application in error, you will need a process to replace the placeholders
with their replacements. You have to find the message and search the string
for the placeholders. Then substitute each occurrence of the placeholder
with its respective replacement.
In this example we show a technique that formats a specific error message given
the requested message code, values for up to three identified placeholders in the
generic error message and a VisualAge Generator table with message code and
unformatted message text values.
1. Create two working storage records, MSGWS1 and MSGWS2, with the following
structures:
MSGWS1
10 MESSAGECODE char 3
10 PLACEHOLDER char 20 occurs 3
10 BASEPLACEHOLDER char 20
12 CHARBASEPLACEHOLDER char 1 occurs 20
MSGWS2
2. Create a VisualAge Generator table, MSGTBL with the following structure and
provide the contents with some values (make sure they have some
placeholders):
10 MESSAGECODE char 3
.. 10 MESSAGE char 198
.
3. Create a process (MSG-PROC) with the following code which will build the
formated message from the text in the VisualAge Generator table and the
provided placeholders. Placeholders in the base message are represented as
a single character (“%”).
/* Find placeholder end (Only supports one word) and load to target
MOVE [Link](PLACEHOLDERINDEX) TO [Link];
IF ″ ″ IN [Link];
MOVEA [Link](1)
TO [Link](INSERTINDEX) FOR EZETST;
INSERTINDEX = EZETST;
END;
4. Create a GUI application and place the working storage records, the VisualAge
Generator table, and the process on the free-form surface. Put four entry
.. fields and a push button on the window.
.
5. Connect the object attribute of the first entry field to the MESSAGECODE data
attribute of the working storage record MSGWS1.
6. Tear off the PLACEHOLDER attribute of the MSGWS1 working storage record.
8. Connect the object attribute of each remaining entry field as the value
attribute for the connections between the push button and the torn off the
PLACEHOLDER attribute. Match the entry field order and the indexes
hardcoded in the connections.
9. Connect the clicked event of the push button to the execute action of the
MSG-PROC process.
10. Make the window part wider and then add a label to the bottom of the window.
Stretch the label (or use the layout settings) to make it as wide as the window
part. Better yet, connect the label to the left and right sides and the bottom of
the window so they size together. Make sure the label is tall enough to
display a text string.
11. Connect the MESSAGE data attribute of the working storage record MSGWS2 to
the object attribute of the label.
12. Test the application (save the member as MSGFUN). Enter a message ID in the
first entry field, values for any marked placeholders (“%”) in the remaining
entry fields and click on the push button. A formatted message will be
displayed in the label.
Hint
To add a border to a label change the Border width attribute on page 3 of the
General tab of the settings notebook.
Because this message window is not a part like other parts in your
application, it is more difficult to interact with.
• You are free to determine the modality of the window. The message
window can be system modal, modal to your application, or modal to the
window that you provide as its parent.
• Because the message prompter is a part, you have more control over it
than you do over the message window.
• You can choose the default push button.
Own Message Window: Of course you can build your own message window.
Building your own message window is the only viable solution if your
application has to support multiple languages at runtime.
We advise you to use the message prompter part as your message window
for all situations, unless it is possible to use an information area or the
support of multiple languages at runtime is of critical importance to your
application. Although the current implementation of the message prompter
does not provide support for a help push button, this function is expected.
A line can be entered at the beginning of a multiline edit by using the action
insertTextAtPosition . This action requires two parameters: text and position .
If you leave position blank, the string is added to the beginning of the
multiline edit. To be sure the text is on a line by itself, put a linefeed
character (ASCII code 13) at the end of the string you want to enter. 12
If you want to put the text at the end of the multi-line edit use a very large
number for position. This, as long as the number is larger than the multi-line
edit contents, will put the new text at the end.
12 This can be added generically to your application that builds up the error messages. Performing it
only when the EZESYS variable indicates that the application is running in a client environment.
2. Add a push button, an entry field, and a multi-line edit to the window and a file
accessor part to the free-form surface.
3. Connect the clicked event of the push button to the insertTextAtPosition action
of the multi-line edit. Provide the object attribute of the entry field as the text
parameter of the connection.
5. Put a label on the free-form surface and give it a file name as its text.
Connect the object attribute of the label to the fileSpec attribute of the file
accessor part.
6. Connect the buffer attribute of the file accessor part to the object attribute of
the multi-line edit.
7. Connect the clicked event of the push button to the write action of the file
accessor part.
8. Test the application (save as member VALLOG). Enter a message in the entry
field and click on the push button. The text is added to the multi-line edit and
is written out to the file. Look at the difference if you add ASCII character 13
at the end of the string you are adding. (To add ASCII character 13, hold the
Alt key and type “0013” on the numeric keypad.)
Note: With VisualAge Generator V2.2 (FixPak 1) the use of an afterPosition
parameter value of 0 results in a rewrite of the first byte of the existing data.
This was fixed in FixPak 2.
12.5 Summary
Errors can occur in your server application, business data, and GUI
applications.
Restricting data entry can be achieved by using parts like list boxes, radio
button sets, and Formatted Text.
The converter is an attribute of every part that has a data type. It determines
the valid values for a part. These can be changed at runtime The Form
Input Checker uses this information to determine whether a value has been
correctly entered by a user. A list of possible values and logic can also be
used to check the correctness of data.
The preferred time to validate data is when a field loses focus. It is best to
use a reusable part that corresponds to a certain business element definition
as the validating element in your application. If there are cross-field
dependencies, these can be taken care of by combining the relevant
validating parts.
Error messages can be logged by adding them to a multi-line edit and writing
the multi-line edit out to a file.
• Know the difference between hard and soft errors and the implication for
your application design.
• Define the elements that are of importance in ensuring that your system
only contains correct data and that the data is represented in a correct
manner to the user.
• Define the basic elements of data that can restrict the possible values.
• Use and understand the converter, Form Input Checker, lists of possible
values, and logic to check the validity of entries.
• Show error messages using the message prompter and log them to a
file.
Thus you might exploit some powerful feature within the product, such as
perform request, that, unknown to you, requires that thousands of lines of
code be executed to get the job done in the generated code. There may be
other, more efficient ways of achieving the same result. If this piece of code
is not in a time-critical section of the application, everything is fine.
However, if the code is time-critical, the use of this particular technique could
result in a serious performance degradation.
Thus, you must balance productivity, reuse, and ease of use against
performance requirements—the age-old “software engineering trade-off.”
The following rules apply to the timing of the loading of a GUI application into
memory. The GUI application is loaded into memory when:
In the file you can indicate which files to load and which to open. The file
will have the following format:
LOAD APP1
LOAD APP2
OPEN ENTRYAPP
A GUI application also must be made visible to the user. This opening of the
window also costs time. It costs less time when the GUI application is
already loaded into memory. For example, if you open a GUI application
from another window, close it, and then reopen the GUI application, the time
associated with opening the GUI application the second time (not the time
associated with loading it into memory—this is obviously zero since it is still
You can analyze the loading and opening time by looking at the
[Link] file after you have run an application with the PROFILE and
BENCH options of EZE2RUN set ON (see 5.3, “Runtime Trace” on page 84 for
a more detailed discussion of the [Link] file).
You can even put the required LOAD commands and a SAVE command into
a file which you run every time you update or install a version of VisualAge
Generator.
We recommend that you start from a fresh GUI runtime image when doing
this to avoid leaving junk in your image. However, a LOAD command for a
GUI that has been presaved into the image should do a destructive load and
override the previous copy.
You should also avoid doing a SAVE on a GUI runtime image after doing any
OPENs as that would save object instances; they are not something you want
in your runtime image.
The time required to load an application is not directly associated with the
file size of the .app file that contains the generated Smalltalk code for the
GUI application. The .app file can be relatively small but use a lot of features
from the basic VisualAge Generator runtime image. That said, a larger .app
file will take more time to load most of the time, because there are more
parts to create.
Any parts that are placed on the free-form surface do not noticeably affect
the time associated with loading the GUI application but parts that are placed
Parts on the free-form surface do have to be created, and this can take quite
a bit of time. Remember, you have to load and then create before you can
open. Processes, statement groups, and working storage records on the
free-form surface can represent a significant portion of the time required to
load, create, and open a GUI application. To reduce the influence of logic
and data parts, consider these techniques:
• Use a common entry point process or statement group for procedural
logic. Only this logic part has to be on the free-form surface, the other
logic parts can be executed by name. This removes some logic parts
from the free-form surface and can also reduce the visual clutter.
To balance the benefits and cost of embeddable parts, ensure that their use
is warranted and they are well designed. In other words, ensure that the GUI
being embedded is or will be used elsewhere and shared data references
are implemented with variable parts. If multiple, different embedded GUIs
are similar in function, consider generalizing them into a single,
general-purpose, embedded GUI. This will provide even greater reuse
benefits, while the memory and performance cost, if reused effectively, will
be justified.
For example, the backgroundCreatePart action allows you to utilize user think
time and/or server call wait time to do something useful; namely, the target
GUI application of the backgroundCreatePart action will be loaded (if not
already) and the Smalltalk parts will be created. Once completed, a
subsequent openWidget has far less work to do.
Object Factory
The difference between opening a GUI application directly, using openWidget
(when it still needs to be loaded), and using an object factory for this purpose
is relatively small. Because using an object factory provides you with more
flexibility in your programming, we suggest using the part for opening most
of your external GUI applications.
Using the object factory ensures that the user can open multiple instances of
the same window and even allows you to dynamically determine which
window to open. You will of course need to add some facility for managing
the different windows (for example, their parent-child relationship) and the
way in which data is passed between them.
A side benefit of using the object factory is the potential to reduce the
number of connections and the complexity of the GUI application. This may
result in better performance and easier maintenance.
The memory size and the amount of swapping that occurs within your
operating system can be controlled to fine tune your system (see 13.6,
“Tuning Runtime Performance” on page 276).
13.3 Logic
Besides the amount of time it takes to load a GUI application, it is also
important to consider the amount of time associated with different actions.
Actions can also have an impact on the time it takes to load a GUI
application if they occur when the GUI application is opened. In this section
we focus on several issues to consider when using visual programming.
If the one invocation of the common entry point can implement the
processing required for multiple logical user events, this can greatly improve
GUI application performance. Performance is improved by reducing the
amount of time spent synchronizing data in a GUI application. Data is
synchronized at the end of each logic part that is triggered with the execute
action. If one logic part invokes another logic part there is no
synchronization at the end of the invoked set of logic.
Let′s try to explain the cascading of data changes a bit further, using an example:
1. Create two GUI applications (TGRGUI1 and TGRGUI2). Put a push button on the
window of both GUI applications and place the same working storage record
on the free-form surface of both. The working storage record only has to
contain one data item. (You can use the record TRIGGER created during Using a
Data Item Toggle to Open a Message Window on page 175 if you wish.)
2. Place an entry field connected to the record data item on the first GUI
application (TGRGUI1). Disable the Signal events on each keystroke setting of the
entry field.
3. Add the second GUI application (TGRGUI2) as an external GUI application on the
free-form surface of both applications.
Note: Embedding an application within itself may give you a warning that you
may be creating a recursive call. In this case we control the opening of the
window using the push button so we run no risk of creating a recursive call.
4. Connect the clicked event of both push buttons to the openWidget action of the
TGRGUI2 external GUI application.
5. Promote the data attribute from the working storage record of the second GUI
application. Connect the data attribute of the working storage record on both
GUI applications to the promoted feature from the GUI application.
7. To understand the overhead of all of the data synchronization you can use one
of the following techniques:
a. Turn on test run tracing, open up a Trace Log window, and watch the
connections that are triggered when you modify the data in the entry field
and tab out. Try this with a small number of open windows first, then
open more and try again.
b. Generate the application and run it with the PROFILE and BENCH options
set on. Open about 10 windows and then enter a text string in the entry
field. Tab out of the entry field and close all windows.
Once you have run the application and stopped the runtime image, open
the [Link] and take a look at it.
You will notice that every time you opened a window the data-to-data connection
fired between all the GUI applications that were already open. This also happened
when you changed the contents of the entry field. You can imagine what kind of
activity would occur in your system if you had a lot of these kinds of connections.
The use of synchronized data across multiple GUI applications is one of the
most common performance problems. Fortunately, there are other options.
1. Replace the working storage record in the TGRGUI2 GUI application with a
variable part. Use Build features based on member... to have the variable
part give you the same features as for the working storage record when you
look at the Connect window. Promote self of the variable part.
3. Connect the self attribute of the variable part to the promoted feature of the
external GUI application in TGRGUI2.
4. Connect the self attribute of the working storage record to the promoted
feature of the external GUI application feature of the external GUI application
in TGRGUI1.
5. Use the ITF or generate the GUI applications (as described in Using Data
Triggers and Connections: Part 1 on page 259) and evaluate the changes in
runtime triggering.
We can see that the connection between the TGRGUI1 and TGRGUI2 GUI applications
and the TGRGUI2 and TGRGUI2 GUI applications still all fire each time a GUI application
is opened. But now when we update the data in the entry field, this event is only
signaled once. This is due to the fact that you are changing the data at a certain
memory location and the variable parts do nothing more than point at that memory
location. The memory location itself did not change, so the connections did not get
triggered.
But why do we still need this synchronization of the GUI applications every
time they are opened? Let′s take our example one step further to look at
this behavior.
1. Delete the self attribute to promoted feature connections in both TGRGUI1 and
TGRGUI2.
2. Make a connection between the clicked event of the push button in TGRGUI1 and
TGRGUI2 and the promoted feature of the TGRGUI2 external GUI application.
3. Provide the self attribute of the working storage record (in TGRGUI1) or the
variable part (in TGRGUI2) as the parameter to this connection.
4. Use the ITF or generate the GUI applications (as described in Using Data
Triggers and Connections: Part 1 on page 259) and evaluate the changes in
runtime triggering.
This time, on opening a new GUI application, only one connection is triggered. The
conclusion is that any time you use multiple GUI applications, whether they are
embedded or external, you should use event-to-attribute connections for the
transfer of data between these applications. Also use a variable part whenever
possible. This will keep the data across all GUI applications identical without the
need for updating each one.
Let′s look at how we can use a VisualAge Generator table to share data.
Remember a VisualAge Generator table can be shared among GUI applications
without connections.
1. Save the TGRGUI1 and TGRGUI2 GUI applications as TGRTAB1 and TGRTAB2.
2. Change the references to TGRGUI2 to TGRTAB2 in both the TGRTAB1 and TGRTAB2 GUI
applications.
3. Create a VisualAge Generator table (TGRTBLE) with the same structure as the
working storage record. (If you used the TRIGGER working storage record, just
add the message data item.) Add a row with some data value as the
VisualAge Generator table contents.
4. Replace the variable part and working storage record with the VisualAge
Generator table in both the TGRTAB1 and TGRTAB2 GUI applications.
5. Quick Form the VisualAge Generator table to the window in both the TGRTAB1
and TGRTAB2 GUI applications. Delete the entry field in the the TGRTAB1 GUI
application.
A VisualAge Generator table is always an array, so the Quick Form of the
VisualAge Generator table will create a container details. You can use this to
change the VisualAge Generator table data at runtime.
6. Use the ITF or generate the GUI applications (as described in Using Data
Triggers and Connections: Part 1 on page 259) and evaluate the changes in
runtime triggering. Change the contents of the container details cell and then
see whether this change is visible in the other GUI applications you have open
(it should not be).
“Touch” the container details cell in one of the other GUI applications and then
tab out. You should now see a change in the container details cell data value.
You will notice that using a VisualAge Generator table causes very little action.
There is no need for synchronization when a GUI application is opened and no
need to signal the other GUI application that the data of the VisualAge Generator
table has changed.
This directly comes back to the difference in how you use VisualAge Generator
tables. You will explicitly need to refresh any attribute-to-attribute connections to
the data in the VisualAge Generator table. The VisualAge Generator table does
not signal, across GUI applications, that the VisualAge Generator table data has
changed. Signals of data changes do occur within a single GUI application.
Process to Process
Visual programming does some things exceptionally well. Other things, such
as control flow, are best done within a procedural language. For example,
connecting has executed of one process to execute of another process is
roughly 10 times slower than coding a PERFORM of the second process
within the first one.
There are times when this visual control flow logic is appropriate, especially
if other actions are also dependent on has executed of the processes.
However, because of the magnitude of the performance cost, use
process-to-process connections only when absolutely necessary.
Iterator
The iterator is a useful part for creating visual loops. Its implementation
causes a lot of events to be signaled, however. Do not use the iterator as a
substitute for writing a loop in procedural code; reserve it for special
circumstances, such as when you want to perform an action other than
changing the content on every element in the ordered collection.
See Using the Iterator on page 179 for a GUI programming example that
uses the iterator.
• getFieldsStartingAt:to:
These actions are available from the tear-off attribute of the occurs item
(array) in the VisualAge Generator record member and from the table
columns attribute of the VisualAge Generator table.
The use of the occurs item actions is much more efficient than connecting
directly to the occurs item. For example, the getFieldsStartingAt:to: action
copies from 1 to n items of the array. By contrast, if the items attribute of the
occurs item is connected to the rows attribute of the Table part, the entire
occurs item (array) is scanned, and all items up to and including the last
nondefault item are copied to the Table. In an array with an occurs value of
50, if you connect the items to the Table, VisualAge Generator looks at each
data item in the array to see if it is a nondefault value before displaying the
values. If the getFieldsStartingAt:to: action is used, VisualAge Generator
copies the 50 items without the overhead of checking for a default value.
Zeroes or blanks will show in this case. If the application can determine the
number of valid data items in the array, you can set parameters for the
getFieldsStartingAt:to: action, further accelerating the Table population
process.
An event needs to trigger the occurs item actions. Often the best event is
the has Executed of the Logic Member part in which the data for the Table is
accumulated or created. Then define the parameters as appropriate in the
Settings or with connections to the parameters on the event-to-action
connection. Finally, connect the rows of the Table to the result of the
event-to-action connection.
Try using data triggers (see 9.2.2, “Data Item” on page 175) instead of a
performRequest action when possible.
13.4 Client/Server
When developing any client/server application system, it is important to
consider performance. Of course, one could say the same thing of any
software program, whether client, server, or stand-alone. However, a
client/server system introduces processing characteristics and possibilities
for communicating between machines that are not encountered in a
stand-alone environment.
One of the big advantages of VisualAge Generator is the fact that you can
execute the business transaction on the server platform. Imagine the
following situation: To enter a new flight into its reservation system, a travel
agency has to look up and update about 20 database tables. The flight has
to be entered into the reservation system for each day of an entire season
(around 200 days). Therefore, if you were not able to write this code to
execute on the server platform, you would cross the network boundary 4000
times for this single business transaction. For a single transaction, this is
very slow; combined with all other transactions by all other users, it is
unrealistic.
In all cases where a business transaction includes more than one server call,
combining the calls into a single call, an umbrella server application that
calls the multiple applications in turn, can result in noticeable improvements.
Particular attention should be given to the size of arrays within the answer
set. If some server calls return relatively few rows of data and others return
many rows, consider using separate records to handle each case. Additional
record definitions will affect maintenance and memory requirements.
Megadata concerns those situations in which you fetch data from a data
source but do not know exactly how much data will be returned, or the
amount of data that is returned is larger than the allowable or preferable
size. Typically this issue is resolved by implementing a paging mechanism.
The user can fetch the data in pages (whether this is evident to the user or
not in the implementation of the user interface is not relevant for this
discussion).
Each page contains a fixed number of rows. Getting the next page involves
your knowing the location of the last row in the previous page. This row can
be uniquely identified by the values for the data items of the primary key of
that row and the values for the data items in the sort key for that row.
Fetching a next page is then searching for all values greater than or less
than (depending on the sort order) this key.
Getting the previous page involves exactly the opposite mechanism against
the first row in the previous page. But getting a previous row seems strange
because you have already fetched the row, so why should you fetch it again?
Especially if you are not memory constrained on the client for holding large
amounts of data. Although you will not get the latest information from the
database when scrolling back using the previous data (this facility is
reserved for a refresh option of the list), you will be able to respond quickly
to a user request.
This example provides an understanding of how you can deal with Megadata. We
will not go to the server but we will use a process to either fill a working storage
record with the next 20 rows, if paging forward, or the previous data in the working
storage record, if paging backward.
Note: A very similar example is provided in the VisualAge Generator Developer
samples directory as [Link].
1. Create a new GUI application. Add a list box to the window and two push
buttons, one labeled “Previous” and one labeled “Next.”
2. Drop a working storage record, MEGADATAWS with the following structure on the
free-form surface:
3. Connect the ROW data attribute of the working storage record to the items
attribute of the list box.
IF PAGE GT PAGES;
TRIGGER2 = ″Y″ ;
END;
PAGE = PAGE + 1;
IF PAGE GT PAGES;
INDEX = 1;
/* Imagine that this is your call to a server
/* application
WHILE INDEX LE 20;
NUMBER(INDEX) = (20 * PAGE) + INDEX;
INDEX = INDEX + 1;
END;
ELSE;
TRIGGER = ″Y″ ;
.. END;
.
7. Connect the clicked event of the Next push button to the execute action of the
MEGA-PROC-LOAD and MEGA-PROC processes, in that order.
IF PAGE GT 1;
PAGE = PAGE - 1;
TRIGGER = ″Y″ ;
END;
9. Connect the clicked event of the Previous push button to the execute action of
the MEGA-PROC-LOAD and MEGA-PROC-BACK processes, in that order.
11. Connect the size attribute of the ordered collection to the enabled attribute of
the Previous push button. This will disable the push button when there are no
entries in the ordered collection (size is zero and zero is false). Once the size
grows the push button is enabled (any value greater than zero is true). We do
not disable the push button in this example if you scroll forward and then
backward.
12. Connect the size attribute of the ordered collection to the PAGES data attribute
of the working storage record.
13. Connect the TRIGGER data event to the atIndex: action of the ordered
collection. Provide PAGE data as the parameter. Connect the result attribute
of the connection to the ROW data attribute of the working storage record.
14. Connect the TRIGGER2 data event to the add: action of the ordered collection.
Provide the ROW data attribute of the working storage record as the
parameter.
Do not store the data attribute of a working storage record in an ordered collection.
You will not be able to access it. Always use a substructured data item for this
purpose.
Most applications use some form of lookup data, for example, airport codes,
descriptions for codes, message codes. This data does not change as often
as other data, and you could presume that it stays the same during the
duration of a session when the user uses the application. The data may also
be used in several places throughout the application.
In these situations it could be useful to fetch the data only once, when it is
accessed for the first time. This can be done in VisualAge Generator with
VisualAge Generator tables. 13
13 You could also implement this function with working storage records or parts, although you would
have to pass these around in your application by using event-to-attribute connections.
1. Create a new GUI application. It will be used as a non-visible part. Delete the
window and add a label as its primary part. Provide the label with an
appropriate name such as “AirportData.”
10 AIRPORTCODE char 3
10 AIRPORTNAME char 50
3. Add 20 blank rows to the VisualAge Generator table. The VisualAge Generator
table has a static size so this must be defined before you start out using it.
AIRPORTCODE(1) = ″SFO″ ;
AIRPORTNAME(1) = ″San Francisco International″ ;
AIRPORTCODE(2) = ″SJC″ ;
AIRPORTNAME(2) = ″San Jose (CA)″ ;
AIRPORTCODE(3) = ″AMS″ ;
AIRPORTNAME(3) = ″Amsterdam Schiphol″ ;
AIRPORTCODE(4) = ″DFW″ ;
AIRPORTNAME(4) = ″Dallas/Fort Worth″ ;
AIRPORTCODE(5) = ″RDU″ ;
AIRPORTNAME(5) = ″Raleigh/Durham″ ;
5. Add a toggle button to the free-form surface of the GUI application. Promote
the set action as getAirportData. Promote the enable action as
refreshAirportData .
You could just trigger off of the aboutToOpenWidget event of the primary part
of this GUI application to initialize the data, but if you were actually calling a
server application you may need to synchronize the data every few hours.
.. The distinct event, refreshAirportData provides that flexibility.
.
6. Connect the selection and the enabled events of the toggle button to the
execute action of the process. The selection event only gets signaled when
the selection is changed. This is only the first time, since thereafter the toggle
button will already have been set. The enabled event can be signaled multiple
times.
8. Create a second GUI application and add the embedded GUI application
AIRDATA and the AIRPORT VisualAge Generator table to the free-form surface.
9. Put three push buttons on the window. Give them labels of Get Data, Load
Data, and Refresh Data.
10. Connect the clicked events of the push buttons to these AIRDATA embedded GUI
application actions:
11. Quick Form the AIRPORT VisualAge Generator table on the window to create a
container details. Delete the connection between the VisualAge Generator
table and the container details.
12. Connect the clicked event of the Load Data push button to the container
details items attribute. Use the table columns attribute of the AIRPORT
VisualAge Generator table as the parameter.
a. Minimize and then restore the window with the container details
b. Cover and then uncover the container details area with another window
This should reinforce the view that you must control the refresh of data
from VisualAge Generator tables that are being used as global shared
data without connections.
Records with substructured items require more processing than flat records
of the same size. Thus processing the record to pass on a client/server call
can be quite costly. However, additional record definitions will affect
maintenance and memory requirements.
Data Types
VisualAge Generator′s GUI runtime optimizes data items with no decimal
positions.
Scavenge
A scavenge is to copy the objects still used by the system from
the currently used new space to the other new space region.
This occurs when the amount of free memory available in the
new space reaches a specific amount. Thus, any unused objects
are left in place, which is similar to freeing the memory. A
scavenge is a quick process that can occur frequently.
Scavenging is so quick, it is not noticed by the end user.
Increasing or decreasing the size of new space results in an
increase or decrease in the number of scavenges.
Garbage Collection
A garbage collection is when tenured objects in the new space
are moved to old space and all unused objects in the old space
are freed. When the availability of free memory in the new
space reaches a certain amount after a scavenge, IBM Smalltalk
does a garbage collection. If the amount of free memory in the
old space reaches a certain amount after a garbage collection,
IBM Smalltalk asks the operating system for more old space
VisualAge Generator V2.2 enables you to modify the old space (MO),
the new space (MN), and the memory increment (MI). Thus, if you
have a relatively small suite of GUI applications and data, the defaults
can be reduced to run in a smaller footprint. Alternatively, if you have
a very large suite of GUI applications and data, increasing these
values can result in dramatic performance improvements.
EZERRUN_MO
This environment variable enables you to tune the memory
requirements for GUI runtime for either the OS/2 or Windows
environment. It represents the amount of preallocated memory
reserved for tenured objects during GUI runtime. The value is in
megabytes (MB).
The default is approximately 2 MB more than the size of the
image file (EZE2RUN). The minimum recommended setting is
500 KB more than the size of the image file (EZE2RUN). The
maximum recommended setting depends on the amount of
memory installed on your machine and the size of the GUIs you
are running. If you change this environment variable, you must
stop and start the GUI runtime support for the change to take
effect.
The following is an example of how to set the MO option to 8 MB:
EZE2RUN STOP
SET EZERRUN_MO=8
EZE2RUN START
EZERRUN_MN
This environment variable enables you to tune the memory
requirements for GUI runtime for either the OS/2 or Windows
environment. It represents the amount of preallocated memory
reserved for newly created objects during GUI runtime. To
calculate the actual amount of memory reserved, multiply this
number by 2. IBM Smalltalk reserves two memory areas each of
this size for the purposes of scavenging. The value is in
kilobytes (KB).
EZE2RUN STOP
SET EZERRUN_MN=256
EZE2RUN START
EZERRUN_MI
This environment variable enables you to tune the memory
requirements for GUI runtime for either the OS/2 or Windows
environment. It represents the amount of memory to request
once the reserved memory is used. The value is in kilobytes
(KB).
The default is 2000 KB. The minimum recommended setting
depends on the size of the GUIs you are running and the amount
of data the GUIs use. 256 KB can be used if your memory
requirements are small. The maximum recommended setting
depends on the amount of memory installed on your machine
and your memory requirements. Generally, the memory
increment will not need to be larger than 2000 KB. If you change
this environment variable, you must stop and start the GUI
runtime support for the change to take effect.
The following is an example of how to set the MI option to 500
KB:
EZE2RUN STOP
SET EZERRUN_MI=500
EZE2RUN START
If you have a suite of 5 GUIs that are reasonably small and the GUIs
do not manipulate huge amounts of data and you are running the suite
on an 8 MB Windows machine or a 12 MB OS/2 machine, to determine
an optimal setting, do some trial and error testing. It is recommended
that you start by doing the following:
For example, you are currently using 3.9 MB of 4.0 MB. If you need an
additional 200 KB, which puts you over the amount reserved, you will
be using 4.1 MB of 6.0 MB of memory. This is actually OK if you know
that your GUI suite will eventually need all this memory. But if you
know your GUI suite will not need that much memory, it is wasted
memory. It would be more efficient to set MI to 500 KB. Then you
would be using 4.1 MB of 4.5 MB of memory. On the other hand, it is
more efficient to allocate one larger chunk of memory than multiple
smaller chunks. However, make sure you really need the memory you
are requesting.
There are other factors that can determine the memory requirements
for a suite of GUI applications: for example, proper design of your
GUIs and the use of expensive controls. This article does not address
these factors. Some of these factors have already been addressed in
previous articles and others will be addressed in the future.
13.7 Summary
Performance considerations are an integral part of application development.
When using a product that generates code for you, it is worthwhile knowing
which implementations generate better performing code than others. In
Consider using cache to store data that you might need again later.
Apparent possibilities for caching include backward paging in a megadata
solution and fetching lookup information with a low frequency of change.
Once you have generated your application with the generation options that
optimize performance, you can tune the runtime performance of your system
by changing the amounts of memory allocated by VisualAge Generator for
certain activities. This is a machine-related activity. The settings can be
different for different machines in your organization.
This part will enable you to develop VisualAge Generator GUI applications in
large-scale application development efforts, providing you with the rules and
skills required to build maintainable and reusable code.
14 In this chapter we limit ourselves to looking at the support of business processes. Building technical
embeddable parts to support the applications is expanded on in Chapter 15, “Objects” on page 307
and Chapter 16, “Objects in VisualAge Generator” on page 315.
Within an application all these actions are performed through either a menu
or push buttons. The CUA guidelines even state that any action that can be
performed using a push button on a window that also has a menu should
also be available in the menu. We call the part with which the user controls
the business object the controls part.
There are many architectural options, such as that shown in Figure 54, that
provide value by standardizing the approach used to design and implement
reusable parts for an application system.
The name of the VisualAge Generator member should comply with the
VisualAge Generator naming standards. Appendix B, “VisualAge Generator
Naming Convention” on page 341 suggests a possible naming convention
based on the application architecture.
All calls to server applications within the business object must be performed
from within a process or a statement group, as opposed to direct visual
server calls. You are free in this choice as long as the choice is consistently
applied within your organization. Using a process or a statement group
allows you to check for errors after the call to the server application returns,
by checking either the return codes you pass in a working storage record or
the EZERT8 variable. 15
For example, suppose you have an insurance business object that contains a
working storage record with all of the base data on insurance. If you create
a fire insurance business object, you will want to use the characteristics of
the insurance business object and add on to those. Although fire insurance
will have its own working storage record with data specific to fire insurance,
for any generic insurance information it will refer to the insurance business
object. To refer to this information, the fire insurance business object
includes a variable part that is connected to the promoted self attribute of the
working storage record in the insurance business object.
15 You must have called the application with the (REPLY option.
The data does not get passed to other associated parts like the
representation part. These parts use variable parts to connect to the
promoted self attributes of the data to use the data in the business object.
A business object can contain other business objects. The umbrella servers
of these embedded business objects should be combined if an action would
cause umbrella servers in more than one of the embedded business objects
to be called. This is dictated by the client/server design considerations of
your system.
Stated differently: any time an action causes a call to two separate umbrella
servers, there should probably be a business object containing the business
objects involved.
• There is only one GUI application that defines this business object (this
GUI application may be decomposed into other GUI application,s but
only the one business object GUI application is embedded when used).
• The parts in the business object and its interface comply with the
naming convention.
• There are no variable parts in the business object except if the business
object contains other business objects to whose data it needs to refer.
In this example we create a business object for a baby in a nursery. The server
application and database are simulated by a VisualAge Generator table.
2. Replace the window with a label. Change the label to “Baby - RBBBZDB.”
10 BABYID char 5
10 NAME char 35
10 BIRTHDATE char 10
10 WEIGHT num 4,2
10 MOTHERID char 5
5. Create a working storage record, RBBBZWD, with the same structure as the
VisualAge Generator table.
6. Create a working storage record, RBBB0WK, with only the following structure:
BABYID
7. Make sure the VisualAge Generator table and both working storage records
are on the free-form surface of the business object. Promote self of the RBBBZWD
working storage record as babyInformation. Promote self of the RBBB0WK
working storage record as babyKeyData.
8. Put a process on the free-form surface: RBBBZP-GETBABY. Give the process the
following code:
[Link] = [Link](EZETST);
[Link] = [Link](EZETST);
[Link] = [Link](EZETST);
[Link] = [Link](EZETST);
Each of these representations looks at and should interact with the same
business object. If a new representation requires new server logic, you
should change the original business object.
Therefore the representation part contains parts that point to the attributes
that allow you to hook up to the attributes of the business object. If the
attributes of the business object have been exposed as the self attribute of a
working storage record, you use a variable part in your representation. If
they have been exposed in any other way, you provide them as such.
The representation part only contains the controls for viewing the data not,
for taking user actions, like opening up a detail window from a list. Menus
and push buttons are contained in a separate part. Any user actions that
can be taken, such as double-clicking an entry in a list, are promoted as
events and should cause the corresponding action in the controls part to be
executed.
There are a number of reasons why the subdivision is made in this way.
First of all the CUA guidelines prescribe that you can always reach the effect
of a direct-manipulation action, such as double-clicking, through the use of a
push button and/or a menu. The second reason is that you can have
multiple views for each business object. But the actions you can do on a
business object are independent of its representation. So whether using a
picture view or a detail information view to look at a house, the user should
be able to sell the house to the customer.
The interface of the representation part contains features that allow you to
pass in the information, refresh the view of the information, and determine
the state of the view (for example, the row that is selected in a list). It also
contains the menu attributes of those parts that could have an object menu.
Because the representation is affected by the security level of the user, any
security mechanism should also be implemented in the representation part
(see “Security” on page 328 for a more detailed discussion about the
possibilities for implementing a security mechanism in your GUI
applications).
• The representation part contains all parts that are visible to the user
except the main set of buttons, the menu, and the window.
• The representation part does not contain data itself that is represented.
It always points to data in the business object. The only exceptions are
VisualAge Generator tables for lookup data and temporary variables that
are not part of the business object.
In this example we create two representations for the Baby business object. The
first representation shows the detail information for the baby. The second
representation shows a picture of the baby.
3. Add a variable part to the free-form surface. Select Build Features Based on
Member... and enter RBBB0WD. Make a Quick Form of the self attribute of the
variable part on the form. Format and arrange the fields on the form.
5. Add a second variable part to the free-form surface. Select Build Features
Based on Member... and enter RBBB0WK.
6. Connect the BABYID data attribute of this variable part to object of the
BABYID entry field.
14.4 Controls
A user can act on the business object by direct-manipulation techniques
(drag-and-drop, double-clicking) or by using push buttons or items in the
menu. The controls object contains the latter.
Each business object has its own controls object, although this can in turn
consist of shared elements such as default menus or push button sets.
There is one controls object per business object. The controls object is
independent of the specific implementation of the representation. For
example, it should be possible for the car salesperson to sell a car when
showing the picture of the car or the detail technical information of the car.
The standard menu structure can be built in an embeddable part of its own.
One of the great features of a menu is that you can override any of the menu
items by connecting another pop-up menu to the menu attribute. So if the
standard menu is an embeddable part of its own, promoting the menu
attributes of the different cascaded buttons in the menu allows you to
override the menu items.
The control object embeds the standard menu. In the control object you
place those menu items that you want to override.
You should also promote the label of the first menu item in the menu bar.
When the application is run, this menu item should show the name of the
business object with which the user is currently working. Connect a label
with the name of the business object to the promoted feature to ensure this
behavior.
The menu directs all user actions if it is present on the window. Otherwise
all user actions are performed through push buttons. Therefore any action
the user takes is redirected to the same action on the menu. This makes
maintenance of the actions a lot easier.
For example, if your window has an Open as details... push button and an
Open as details... menu item and will open the detail window when the user
double-clicks on an entry in the list, these actions should all be directed to
the menu item. The clicked event of the push button should be connected to
the click event of the menu item. Likewise the defaultActionRequested of the
list should be connected to the click action of the menu item. In this case the
maintainability of the code outweighs the performance overhead of using
clicked to click connections.
This choice of implementation means that you have to promote the click
actions and clicked events of all menu items for which the reaction is
implemented outside the controls or standard menu part.
• Object-specific actions
Push Buttons
Push buttons are used to provide quick access for users to items that are
also available on the menu. For example, in a data entry application, you
can provide the user with a Save and new push button that has the default
focus, thus allowing the user to enter data and either click the push button or
press Enter to save it and get a cleared window to start entering the next set
of data.
The push buttons should be made visible to the user. They are therefore
part of the primary part of the controls part. The clicked event of the push
buttons is connected to the click action of the related menu item.
Whenever a user is not allowed to access a certain action under his or her
current security profile, and this is not dependent on the state of the object,
the part should be destroyed. If a user is temporarily not allowed to access
an action because of the state of the object, the action should be disabled.
These rules have an effect on the controls part. You should design for and
implement states of the object. An object will have a finite number of states.
Whenever the state changes, you have to check whether the change affects
any of the parts that are used to represent or act on the business object. If
so, the corresponding action should be taken.
• The controls part contains all of the push buttons and menus in the
system. Exceptions are embeddable parts that are made part of the
controls part or push buttons that are directly related to a certain field in
the representation part.
• The menu window menu, if present, is the only part from which actions
and events are promoted. If there is no window menu, events and
actions are promoted from the push buttons.
• The controls part embeds the standard menu.
• The menus and push buttons should comply with the CUA standards.
• An object menu should only be used for objects that get focus when
clicked on with mouse button 2.
In this example we create a simple controls part for the nursery application. The
controls part contains a Refresh push button and a menu containing only the
Refresh option as a choice in the View menu.
5. Drop a Menu Cascade part on the Popup Menu part. This will create a Menu
Cascade part with a connection to a new Popup Menu part. Give the Menu
Cascade part a label string of View.
6. Drop a Menu Choice part on the Popup Menu part that is connected to the
View Menu Cascade. Give the Menu Choice part a label string of Refresh.
7. Promote the clicked event of the Refresh Menu Choice as refresh. Connect
the clicked event of the push button to the click action of the Refresh Menu
Choice.
8. Change the part names of all parts so the reflect your standards using the
parts list.
Each business object has its own common part. It is reused over different
representations of the same business object.
For performance reasons always pass data using an event that corresponds
to the request for opening the window to the attribute that is to be set in the
newly created window. The data attribute is the parameter to this
connection. Always pass the data attribute of the working storage record,
not any single data item of the working storage record. Although the key
could just consist of one data item, you are not sure this will always be the
case.
Note: There may be exceptions to this rule. You may need to expose
level-77 data items as data triggers for application-specific goals. The idea
behind always passing the data attribute of a working storage record is that
16 Passing self would cause ambiguity about the memory location of both working storage records.
• The common part only contains those parts that are part of the interface
of the entire application.
• Other applications are opened from the common part. The exact
implementation depends on your organization′s implementation for
opening other GUI applications.
14.6 Interaction
Once all of the parts have been created, they can be combined in a GUI
application with a window as its primary part.
Promote all features from the common part that need to be accessible by
other applications to the interface of the GUI application. Examples are the
data attributes of key working storage records and the attributes that indicate
the global parts such as a user part.
Check the interfaces of the parts to see whether any features were promoted
but not connected. Evaluate whether these features are required. Keep in
mind that they can be used by other implementations of the same part.
• The common part is placed in the bottom right-hand corner and the
business object in the top right-hand corner of the free-form surface.
• The connections are made as described above.
In this example we combine the baby business object part (Creating a Business
Object on page 291), the representation part (Defining Views for a Business Object
on page 294), and the controls part (Defining Views for a Business Object on
page 294), in a functional GUI application. We did not implement a common part
for this example.
3. Add the controls part (RBBBDDC) to the window Arrange the parts as required.
c. Controls part (RBBBDDC) refresh event to the getBaby action of the business
object part (RBBBZDB).
14.7.1 Design
In applying the architecture to your application design, recognize the parts
that will be the business objects and the representations that are possible on
the business object. Several techniques can be used for determining the
business objects in your system. You can take the Entity-Relationship (ER)
model as your base, design the interface according to an object base
paradigm (as suggested in the CUA standards), or design your system
completely on the basis of business objects.
Your design should at least separate out the logical (business) parts from the
representations on these parts. It should separate the user actions from the
actions on the logical (business) parts.
The design should also include a definition of the states that the business
object can be in, the actions that cause transitions between the states, and
the consequences of each transition. This is not a requirement from an
architecture perspective but from a perspective of building an event-driven
application.
14.7.2 Documentation
Applications must be documented to allow for maintenance. Standardization
is in this sense a form of documentation. It is preferable, though, to have
other forms of documentation also.
#models
Part: ′ models′
Attribute: #self
#refreshList
Part: ′ pbRefreshList′
Action: #enable
#pageInfo
Part: ′ pageInfo′
Attribute: #self
COMPONENTS
FORM: frmModels
CONTAINER DETAILS: cdvModels
CONTAINER DETAILS COLUMN: colMake
CONTAINER DETAILS COLUMN: colModel
VARIABLE: models
PUSH BUTTON: pbRefreshList (″refreshList″ )
VARIABLE: pageInfo
CONNECTIONS
Event-to-Action connection
Event: ′ pbRefreshList′ , # enabled
Action: ′ ROW of models′ , # getFieldsStartingAt:to:
Parameter settings:
#firstIndex : 1
Attribute-to-Attribute connection
From: ′ models′ , # ROW
To: ′ ROW of models′ , # self
To print the member to a file, set the print location in the File and Print
setup... option to a filename. Information can be extracted from this file
by using a REXX application. For more information about the use of
printouts as a basis for tools around VisualAge Generator, see
Appendix C, “VisualAge Generator Tooling” on page 353.
.ESF-based documents
A GUI application can be exported into a readable external source
format (ESF) file. This format can be used to write a utility to extract
some additional information. See Appendix C, “VisualAge Generator
Tooling” on page 353 for more information about using .ESF files as a
basis for tools around VisualAge Generator.
14.8 Summary
Application development requires applications that are built to comply to
some form of standard architecture for the sake of maintainability and
reusability of the code that is written. In this chapter we suggest such an
architecture and provide you with the rules to which you should comply in
building your applications.
The business object provides the interface to the business processes and
transactions that you are trying to support in your applications. Often these
have been built as server applications.
User actions are represented through menu item or push button controls.
The controls part includes these controls. Although certain actions will be
available through both a menu item and a push button, the menu is leading
in the implementation.
Looking at an object as something from our every day life, we can describe it
as having:
• State
The state indicates the current condition of the object. The car is red.
The contract has expired. These are all indications of the state of an
object.
• Identity
Each object is unique. Your car differs from the car of your neighbor. If
you have twins, each is unique, even if you have to identify them by
putting red socks on one and blue socks on the other.
This base nature of an object and the fact that an object is something that is
just out there in the world in which we live indicate that so far we have not
lost touch with reality. The challenge is in describing these objects true to
life.
15.1.2 Abstraction
Einstein′s theory of relativity also has its impact on our description of the
world. It is exactly that: our description of the world. We are describing our
view of what these objects look like. In fact as application designers we
have the even more difficult task of describing how somebody else, the user,
looks at the world.
In determining how the world looks, our description should allow for only one
explanation. It should contain the essential characteristics of the object we
are trying to picture. Imagine we had to describe a mammal. What would be
the essential characteristics of a mammal? The fact that it lives on the land?
No. The fact that it gives birth from a womb? No.
15.1.3 Encapsulation
When interacting with an object, we generally do not want to know how the
object performs its task. To be able to listen to your CD-player, you do not
have to know how the technology is implemented that gets the data from the
15.1.4 Modularity
Objects can be grouped to form a module. This grouping of objects can in
itself be seen as an object. As an object it has the same requirements. It
should have clearly defined boundaries. As a general rule for grouping one
could say that the communication of an object within its group must be more
frequent than its communication over the boundary.
15.1.5 Hierarchy
One of the key concepts that object-oriented theory adds to the realm of
application design is the concept of hierarchy. A hierarchy defines a ranking
and ordering of objects, just like the one described in relation to the concept
of modularity. This ranking and ordering can cause a relationship where one
object is part of another object (aggregation) or where one object is a kind of
another object (inheritance).
Aggregation
An object can itself consist of other objects. Just think of a car. It consists of
wheels, a motor, and numerous other parts that are interrelated. Put all of
these parts separately on the floor of your garage, and you do not have a
car. You only have a potential for creating a car. Combined in a certain
manner, the parts are a car.
Each part of the car is in itself an object and can again contain numerous
other parts for which the same rule applies. If any of the parts does not
comply with the standards, you either do not have a car or you have a bug
(or, depending on your view of life, you have a feature).
If you start out describing all of the characteristics of a vehicle, and then
those things that are different for cars followed by those aspects that are
different for a certain model category, and so on, you would be writing a lot
less.
15.1.6 Delegation
Another common design technique that allows objects to accept messages
but not implement them directly is delegation . This means that an object can
defer the processing of something to another object. This can be done, for
example, by signaling some event from a control GUI application that tells
the target GUI application to do some work. The control GUI application may
even ask the parent GUI application to perform a specific operation that the
control GUI application knows it cannot accomplish by itself.
This approach can impact system design and performance. You can share
one instance of a complex object that implements a highly used function and
let this instance know when you need some work done as opposed to
embedding (duplicating) the complex object everywhere you need it.
In a development domain, this is a bit more difficult. The user can stop the
application, shut down the machine, and go home. The object is gone from
memory. Objects can be stored, however.
When the price of the stock drops below the selling level, the state of the
object changes. Its state now indicates “Get rid of this stock.” This signal
(event) can be used to trigger the selling action on the stock market.
For example, CD-player is a class. The class contains the definitions of the
CD-player. It describes that a CD-player has a holder for a CD and can be
played to produce signals that can be turned into sound. The CD-player also
has a serial number and is a certain brand. Your CD-player has serial
number “123.” The class defines the fact that every CD-player has a serial
number and that the serial number should comply with certain rules
(numeric, less than eight digits). The serial number of my CD-player just has
a value.
The class can be viewed as a template from which instances are created.
Each instance obtains the behavior and characteristics of the class from
which it is created.
If you are uncomfortable with object orientation, just design your parts and
look for similarities. If you want to, you can tap into the full power of
15.5 Summary
Object orientation is implicitly present in the application architecture. It
allows reusable and maintainable code to be written.
In the next chapter we provide more detail on how you can use VisualAge
Generator to implement these concepts.
First, we look at some of the aspects we have seen in other parts of this
book and try to explain the behavior from an object-oriented standpoint.
Next, we look at the characteristics of objects and how they can be
implemented in VisualAge Generator. From this we distill some powerful
possibilities.
Any time you take a part from the palette and place it on the free-form
surface, you are preparing your GUI application to create an instance of the
class at runtime. Each class instance is unique and has a different name in
the GUI application. This is true for all parts in the palette, except the
The GUI application part is a class. You can embed multiple instances of a
GUI application into another GUI application. If this is true, we are in fact
saying that a GUI application is a class. Every GUI application you have built
so far is in fact a class. It has an interface (the promoted features) and
defines the behavior and characteristics of all the instances created from the
class.
A part consists of other parts, just like a car consists of a motor, seats, and a
steering wheel. Each part can be accessed individually, if it is part of the
interface of the part. In fact, a tear off is a variable part. This is indicated by
the bracket surrounding the part. It points to the attribute in the part from
which it is torn off.
16.2.3 Encapsulation
The interface of the GUI application is separated from the implementation. If
you change the implementation of a feature without changing the interface,
you only have to regenerate the part, and not the applications in which it is
embedded.
16.2.4 Aggregation
Aggregation is implemented in most parts in the product. You can also
implement aggregation in your own classes (GUI applications). In fact the
application architecture uses aggregation. The application consists of four
objects: business object, representation, controls, and common. Building up
an object from other objects is the same as embedding parts in a GUI
application.
The parts that are embedded can be either private to the part in which they
are contained or public. If they are public, they are accessible through the
interface and can be torn off. If you promote the self of the embedded part,
you can tear off the part from the part in which it is embedded and access all
of its features.
1. Create a GUI application. Replace the window with a form and place three
entry fields on the form.
2. Promote the self attribute of one of the entry fields. If you choose the first
entry field the default name is text1.
6. Tear off the promoted attribute text1 from the AGGFORM embedded GUI
application.
7. Connect the clicked event of the push button to the backgroundColor attribute
of the torn off attribute. Provide the object attribute of the new entry field as
the parameter.
8. Test the application (save the GUI application as AGGWIN). The embedded part
AGGFORM is an aggregation of entry fields. Because you promoted self, you can
interact with one of the entry field subparts.
16.2.5 Inheritance
Relationships where one part is a type of another part occur a lot in
application development using GUIs. A message window is a kind of modal
window, which is in turn a kind of window.
Implementing Inheritance
Inheritance in VisualAge Generator can be implemented by embedding the
part from which you want to inherit in the part that inherits. It provides you
with all of the function of the class that is embedded.
This example shows how you can inherit the behavior of an ordered collection to
create a collection of whose contents can be reversed.
1. Create a new GUI application. Delete the window and replace it with a label.
Provide the label with the text “reversibleCollection.”
2. Put an ordered collection on the free-form surface. This is the part from which
we will inherit the behavior. Promote the features of the ordered collection to
the interface using the same name as they have as part of the ordered
collection. Because we want to inherit all features of the ordered collection we
need to promote all of the features because the ordered collection is not the
primary part. Promote the self attribute of the ordered collection as
orderedCollection.
3. Add a label to the free-form surface and provide it with the text “reverse.”
Promote the enable action of the label as reverse. We have created the base
for an added feature to the ordered collection.
4. Add a working storage record named RVOC-WS with a the following structure:
10 SIZE num 3
10 INDEX num 3
77 TRIGGER char 1
5. Connect the SIZE data attribute of the working storage record to the size
.. attribute of the ordered collection.
.
INDEX = INDEX + 1;
IF INDEX LE SIZE;
TRIGGER = ″Y″ ;
ELSE;
INDEX = 0;
END;
7. Connect the enabled event of the label that causes the reverse to the execute
action of the process.
8. Connect the TRIGGER data event of the working storage record to the
removeAtIndex action of the ordered collection and provide the INDEX data
attribute of the working storage record as the parameter.
9. Add the removed object back to the top of the ordered collection with these
connections:
a. Connect the TRIGGER data event of the working storage record to the
add:beforeIndex: action of the ordered collection
10. Connect the TRIGGER data event of the working storage record to the execute
action of the process.
13. Create a listbox that will contain the contents of the ordered collection.
14. Add a push button and entry field to the window part. Implement connections
that support adding the object of the entry field to the ordered collection.
15. Add another push button to the window part. Connect clicked of the push
button to the reverse action of the embedded GUI application RVOC.
16. Test the application (save the member as RVOCTEST). You have created a part
that does everything the base ordered collection part does and more.
Multiple inheritance requires that conflicts in the interface (both car and boat
can have an action startEngine that differ) need to be resolved. If a language
adds inherited features to the public interface by default, this can be difficult.
Because VisualAge Generator defaults to private, you have the choice of
choosing any implementation and even overriding it with your own.
Virtual Class
A virtual class is a class that has to be redefined for it to be used. You have
to inherit from it to use its features. A virtual class is especially useful for
visual parts that can contain other parts. If you make container details part
with your own characteristics and embed this part elsewhere, you can no
longer add columns to the container details.
To be able to use the virtual class you have to promote the self attribute of
the variable part. When embedding, connect this attribute to the part that
should inherit the characteristics and behavior.
This example shows how you can use a virtual class to create a generic container
details.
1. Create a new GUI application and replace the window with a label that
indicates that this will be a container details object.
2. Put a variable part on the free-form surface and give it the name
“containerDetailsView.” Promote the self attribute of the variable part as
containerDetailsView.
3. Put another variable part on the free-form surface and give it the name
“information.” Promote its self attribute as information.
4. Put a label on the free-form surface with the name “refreshList” and promote
the enable action as refreshList.
6. Place two labels on the free-form surface. Give one a value of 1. Connect the
object attribute of this label to the firstIndex attribute of the connection (first
make a connection to result and replace it with firstIndex in the settings of the
connection).
8. Connect the result of the connection to the items attribute of the variable part
that represents the container details.
9.
.. Save the GUI application as VRTCDV
.
To use this virtual class we need to implement the part in a GUI application
that uses a container details. A quick example can be created using these
steps:
2. Add a VisualAge Generator table to the free-form surface The table should
have at least two columns and several rows of data. The MSGTBL created in
Displaying Customized Messages on page 242 works very well. (We could also
use a working storage record with an array but VisualAge Generator tables
already have data.)
3. Quick form the table columns attribute of the VisualAge Generator table to
create a container details on the window part. Delete the connection between
the VisualAge Generator table and the container details.
6. Connect the table columns attribute of the VisualAge Generator table to the
information attribute of the VRTCDV GUI application.
7. Add an entry field and a push button to the window part. Connect the entry
field object attribute to the numberOfRows attribute of the VRTCDV GUI
application. Connect the push button clicked event to the the refreshList
action of the VRTCDV GUI application.
8. Test the application (save the member as VRTCDVT). You have made a generic
solution for efficient loading of your container details that can be used by
everyone in your organization.
16.2.6 Communication
Communication between objects takes place by sending messages. Within
VisualAge Generator the connections that you create implement the
message communication between objects. The connection is made between
parts of the interface of both objects. In VisualAge Generator the receiver is
not responsible for replying. The communication is unidirectional except for
bidirectional attribute-to-attribute connections. Sending a message that is
not understood by the receiver may cause a runtime error if the part is not a
variable part.
17 Although the described techniques work, they are not documented and therefore not guaranteed to
be supported in future releases of the product. Because of the shared code base between
VisualAge for Smalltalk and VisualAge Generator, deviations seem unlikely, however.
An object factory can be used to create new parts at runtime. In fact the object
factory creates new instances of a class. You provide the object factory with the
name of the class in the attribute instanceClassName and when you perform the
action new on the object factory a new instance is created. We will use this
function to pull classes out of the VisualAge Generator GUI application
programming environment that are not directly accessible:
1. Create a new GUI application and place an object factory on the free-form
surface.
4. Connect the aboutToOpenWidget event of the window to the new action of the
object factory.
5. Put a list box, a push button, and an entry field on the window.
6. Connect the items attribute of the list box to the self attribute of the instance
of the sorted collection.
7. Connect the clicked event of the push button to the add: action of the instance
of the sorted collection. Provide the object attribute of the entry field as the
parameter to this connection.
8. Test the application (save the member as SORTOF). The entries you add to the
list box will be sorted.
This example shows the use of the external source format of VisualAge Generator
to change the class of a part.
2. Save the GUI application as SORTESF and then export it to an .ESF file selecting
the Export GUI application members in external format toggle button.
3. Edit the .ESF file and replace the word “OrderedCollection” with
“SortedCollection” (there are two instances).
4. Save the .ESF file and import it into your current VisualAge Generator MSL,
replacing the original GUI application.
When you frequently use the same business object in your application this
technique:
• Reduces the number of parts in memory
Hint
Icons and push buttons can be dynamically added to a part that can contain other
parts by using the subpartNamed:putOpened: range of actions. See “Adding Parts
at Runtime” on page 213 for a more detailed description of these actions.
10 APPNAME char 8
10 APPDESC char 50
3. Tear off the table columns attribute of the VisualAge Generator table.
4. Put a list box on the window. Connect the APPDESC data attribute from the
table columns tear-off to the items attribute of the list box.
5. Add an object factory to the free-form surface. Tear off the instance attribute
of the object factory.
6. Add a working storage record named APPWS with the following structure to the
free-form surface:
10 APPNAME char 8
10 APPDESC char 50
7. Add a process named APP-PROC with the following logic to the free-form surface:
8. Connect the APPNAME data attribute of the working storage record to the
instanceClassName attribute of the object factory.
9. Connect the selectedItem attribute of the list box to the APPDESC data
attribute of the working storage record.
10. Connect the defaultActionRequested event of the list box to the execute action
of the process, the new action of the object factory, and the openWidget action
of the instance.
11. Test the application (save the member as APPENT). Double-clicking on an item
in the list should start the corresponding application.
Security
A requirement for almost any application is the support for a security
mechanism as dictated by the organization. The concept of objects
facilitates an easy, natural implementation of security.
In a security mechanism there are two actors: the application and the user.
Security is part of the description of their interaction. This interaction can
take two general forms:
From this perspective both the user and the application can be described as
objects in the application system. The user provides the application with
information about who the user is, what the security level of the user is, and
depending on the implementation of security, even which applications (and
parts of applications) the user is allowed to access.
At any point in the application, the part of the application can then:
• Provide its information to the user, at which point the user determines
what he or she is and is not allowed to do
or
• Require the user information from the user object, at which point the
application determines what the user is and is not allowed to do.
The general rule for a user interface is that any actions that can never be
taken by users with their current security clearance should not be present in
the interface. Any actions that could be available dependent on the state of
the application should be disabled.
Because a certain security state most likely has an effect on multiple aspects
of the user interface, it is best to describe each of these possible states the
application can be in. Each state should trigger the action to destroy or
disable parts.
Because the GUI application itself is never 100% secure, you ought to
consider rechecking the security level of the user in the server application.
Application Management
The interaction between GUI applications is an important part of the final
business application. The application architecture indicates that this
interaction should be part of the common part. Because GUI applications
can also be dynamically created with an object factory, you could also
envision a part that requires you to provide it with the name of the
application that needs to be opened and takes care of the rest.
The fact that VisualAge Generator uses the same code base as VisualAge for
Smalltalk allows you to create classes that are part of VisualAge for
Smalltalk but are not included in the palette of VisualAge Generator. You
can create them by using an object factory or by changing the class name of
a part in an exported application.
• Check box
Limitation: When using a check box to indicate the state of multiple
objects, if some of them have the settings and others do not, you cannot
set shade the check box.
Solution: Do not provide a check box to show the state over multiple
objects.
• Clear
Limitation: It is not possible to use the default delete folder of the
operating system as the destination of the Clear choice.
Solution: This is not a firm requirement of CUA. Do not implement.
• Column heading
Limitation: VisualAge Generator GUI applications do not allow the user
to edit the headings of a column themselves.
Solution: This is not a firm requirement of CUA. Do not implement.
• Contextual help
Limitation: Within VisualAge Generator there is no support for contextual
help during a direct-manipulation operation.
Solution: This is not a firm requirement of CUA. Do not implement.
• Delete
Limitation: It is not possible to use the default delete folder of the
operating system as the destination of the Delete choice.
Solution: This is not a firm requirement of CUA. Do not implement.
Limitation: The Delete key cannot be assigned as a shortcut key in
VisualAge Generator.
Solution: Use Alt+Delete as the shortcut key for deletion.
• Delete folder
Limitation: It is not possible to use the default delete folder of the
operating system.
Solution: Make your own delete folder or do not implement a delete
folder in your application.
• Device
Limitation: VisualAge Generator does not contain functions for querying
or using the available operating system devices.
Solution: This is not a firm requirement of CUA. If you want to use a
“life” list of devices and use the device, however, build a program in
another language or tool to provide this list and access the device.
• Entry Field
Limitation: You cannot provide a visible cue to the user that the data in
an entry field can be scrolled.
Solution: This is not a firm requirement of CUA. Do not implement.
• Folders
Limitation: VisualAge Generator has not implemented the concept of
folders. It has a container part, but it is platform specific.
Solution: Do not design your product to work with folders.
Limitation: VisualAge Generator does not support objects in your
application to be stored in the operating system folders.
Solution: This is not a firm requirement of CUA. Do not implement.
• Help
Some functionality that is suggested should be part of the operating
system provisions for help and the tool with which you build your help
files. These aspects do not influence VisualAge Generator′s capability to
support CUA-compliant applications.
Limitation: VisualAge Generator does not provide a help facility on its
message prompter part.
• Icon
Limitation: VisualAge Generator does not support the use of a small icon
next to the system menu that can be the source or target for direct
manipulation.
Solution: This is not a firm requirement of CUA. Do not implement.
• Information area
Limitation: VisualAge Generator does not allow you to determine
whether the user tried to select an object with unavailable-state
emphasis. You can therefore not give a message about this fact in the
information area.
Solution: This is not a firm requirement of CUA. Do not implement.
• Input focus
Limitation: VisualAge Generator does not support setting the input focus
on the part that was nearest to where the user clicked. It requires this
action to be exact.
Solution: This is not a firm requirement of CUA. Do not implement.
• Keyboard
Limitation: VisualAge Generator does not allow all interactions that are
possible using the mouse to be performed using the keyboard, for
instance, scrolling right in a container details that is read only.
Solution: Be aware of the limitations and try to limit the situations in
which they occur.
• Message
Limitation: VisualAge Generator does not provide a help facility on its
message prompter part.
Solution: Do not implement yet or use your own message window.
• Mnemonic
Limitation: VisualAge Generator cannot provide an audible cue when the
user types a character for a mnemonic of a push button that is not part
of the window (this is supported for the menu). This is only relevant if
mnemonics are supported.
Solution: Either do not provide mnemonics or break this rule.
Limitation: The mnemonic should be reacted to independent of whether
the upper-case or lower-case character is pressed. VisualAge
Generator does not make this distinction for mnemonics of push buttons.
Solution: Wait for correction of this shortcoming of the product.
• Mouse
• Object
Limitation: Objects or GUI applications in VisualAge Generator can not
be registered with the operating system.
Solution: All objects within your application system should be managed
by your application system.
Limitation: VisualAge Generator does not allow objects within your
application to support interaction with the standard objects provided by
the operating system.
Solution: This is not a firm requirement of CUA. Do not implement.
• Paste
Limitation: VisualAge Generator has no indicator whether the clipboard
currently contains a value or not. You cannot disable the Paste option
without pasting and checking the contents.
Solution: Provide a message when the user tries to paste while the
clipboard is empty.
• Pointer
Limitation: VisualAge Generator does not show the pointer in a
shadowed version when the object that is being dragged will be copied.
Instead VisualAge Generator shows either a plus sign or no sign,
indicating that the object is either copied or moved. Disadvantage is
that you only see this when you move the object over a valid drop target.
Solution: Use as provided by VisualAge Generator.
• Pointing device
Limitation: VisualAge Generator does not allow all interactions that are
possible using the mouse to be performed using the keyboard, for
instance, scrolling right in a container details that is read only.
Solution: Be aware of the limitations and try to limit the situations in
which they occur.
• Pop-up menu
• Print
Limitation: VisualAge Generator does not contain functions for querying
or using the available operating system devices.
Solution: This is not a firm requirement of CUA. If you want to use a
“life” list of devices and use the device, however, build a program in
another language or tool to provide this list and access the device.
Limitation: VisualAge Generator does not allow objects within your
application to support interaction with the standard objects provided by
the operating system.
Solution: This is not a firm requirement of CUA. Do not implement.
• Progress indicators
Limitation: You cannot show a progress indication on a server call
because VisualAge Generator is single threaded, and server calls will
not give back control to the calling GUI application until they are
finished.
Solution: Provide a probable waiting time indication.
• Push button
Limitation: Esc is not supported as an accelerator for a Cancel push
button.
Solution: Do not implement.
Limitation: The mnemonic of the push button should be reacted to
independent of whether the upper-case or lower-case character is
pressed. VisualAge Generator does not make this distinction.
Solution: Wait for correction of this shortcoming of the product.
• Radio button
Limitation: VisualAge Generator does not support mnemonics on radio
buttons.
Solution: This is not a firm requirement of CUA. Do not implement.
• Reflection
Limitation: The concept of a reflection is not fully supported by VisualAge
Generator.
• Scroll bar
Limitation: VisualAge Generator does not allow scrolling right in a
container details that is read only by using the keyboard.
Solution: Be aware of the limitations and try to limit the situations in
which they occur.
• Scrolling increment
Limitation: Scrolling increment is not supported on all list parts in
VisualAge Generator.
Solution: This is not a firm requirement of CUA. Do not implement.
• Shortcut keys
Limitation: No shortcut keys that are not combined with the Alt, Ctrl, or
Shift are supported by VisualAge Generator.
Solution: Use alternative shortcut key combinations for those standard
shortcut keys that are affected.
• Source emphasis
Limitation: Source emphasis is not supported on direct manipulation with
VisualAge Generator.
Solution: Implement direct manipulation without source emphasis.
• Split
Limitation: VisualAge Generator does not support windows to be split
into panes that can be manipulated by the user. It does not support
addition of features to the system menu.
Solution: Do not provide windows that have to split. Use two windows
instead or present the data in a container details and use the
lockedColumns attribute to show a certain number of the leftmost
columns.
• Split window
See Split
• Target emphasis
Limitation: Target emphasis is not supported on direct manipulation with
VisualAge Generator.
Solution: Implement direct manipulation without target emphasis.
• Tool palette
Limitation: VisualAge Generator does not allow you to change the mouse
pointer to indicate the tool that was chosen.
Solution: Implement without this change in mouse pointer function.
• Value set
Limitation: The mnemonic of the value set push button should be reacted
to independent of whether the upper-case or lower-case character is
pressed. VisualAge Generator does not make this distinction.
Solution: Wait for correction of this shortcoming of the product.
• Window layout
Limitation: Providing the user with a choice of clipping or resizing
window contents upon sizing of the window is not easily supported by
VisualAge Generator.
Solution: This is not a firm requirement of CUA. Do not implement.
• Window navigation
Limitation: Not all parts support mnemonics in VisualAge Generator.
Solution: This is not a firm requirement of CUA. Do not implement.
• Work area
Limitation: VisualAge Generator has not implemented the concept of
work areas. It has a container part, but it is platform specific.
Solution: Do not design your product to work with work areas.
Limitation: VisualAge Generator does not support objects in your
application to be stored in the operating system work areas.
Solution: This is not a firm requirement of CUA. Do not implement.
Be aware of the fact that standard dialogs that can be used in your
VisualAge Generator GUI applications are presented to you in the language
of your operating system.
• Be aware of the fact that the length of labels and entry fields in different
languages should be different and that your window should automatically
resize to adjust for these differences.
B.1 Considerations
A number of technical and organizational aspects influence the names that
can be used for VisualAge Generator members.
B.1.1 Requirements
The naming convention must comply with the allowable lengths of VisualAge
Generator members and parts and with the restriction in the use of special
characters. Refer to the VisualAge Generator documentation for a summary
of these restrictions.
B.1.2 Uniqueness
Member names must be unique both within and outside its type. For
example, having a process and an application called ACLDDDP is not
allowed in VisualAge Generator.
B.1.8 Aliases
To avoid aliases being assigned during COBOL or C++ generation and to
improve the readability of the generated COBOL or C++ program, these
standards should be followed:
• Do not use double-byte character set (DBCS) names for item names if
our application contains SQL processes.
Where:
B business object
R representation part
C controls part
X common part
M object menu
• Use the eighth character of the GUI application names for additional
information.
• Use only three characters as the business and object identifier and use
the additional character for another purpose.
B.2.1 Descriptions
On a number of VisualAge Generator members, several characters are
available as a suffix to give a further description of the member. The
following uses of these descriptions are suggested:
Example: ACLD0PU-MAIN
• Processes with an I/O process option
These processes will have a suffix indicating the process option used
separated by a hyphen (-). This suffix can be enhanced with a further
distinction (for instance, recognition of forward and backward scrolling).
Finally, a business logic indication can be added (BLB - business logic
before; BLA - business logic after).
Example: ACLD0PA-SIQ-FW-BLA.
Table 14 shows the abbreviations of process options.
Records
A number of general record structures can be recognized that are useful in
building an application. The following meaningful additions are made to the
working storage record names to make them easy to identify and use:
• bboowWL
Contains the result of the fetched data for the list (array).
• bboowWD
Contains all of the data of one row for the details window.
• bboowWK
Contains the key data items for the record.
• bboowWC
Contains all of the input data on the user′s search screen. These values
are used for the search. The occurs is 1 and is the communication
between the client and the server.
• bboowWV
Contains the controls for the search criteria values. It is identical to the
above mentioned record, except that every data item occurs twice. The
items are used to store the high and low values used during searching.
This record is only used within the atomic server application.
• bboowWS
Contains the controls for the values for scrolling (upper and lower
limits).
When redefinitions are made (for instance, not all data is shown in a specific
list), these can be indicated using a redefinition sequence number or an
alphanumeric addition that makes the name meaningful (for instance,
ACLD0WL-NAME).
Data Items
Data items that correspond to columns in a database system use the same
names as the columns they represent. These data items should be declared
Common Records
Within the organization a number of common records can be defined that
contain information that needs to be shared between applications. These
records can be named as you see fit, although consistency and
recognizability are suggested. The records should be standardized on an
organizational level.
Part Names
A GUI part is a self-contained software component with a public interface
consisting of a set of external features that enable the part to interact with
other parts (actions, attributes, and events).
When you add parts to the free-form surface or to the windows on the
free-form surface, the VisualAge Generator GUI Definition Facility
automatically assigns names to the part, according to the part type and how
many other parts of that part type exist in the GUI application. You may have
a considerable number of parts from the same category, such as push
buttons or data entry fields. As you modify and enhance the GUI application,
it becomes difficult to distinguish among the different parts. We suggest that
you use names like pbXxxxx (pbHelp).
Using these names makes the connection descriptions shown at the bottom
of the window and in the trace more readable.
Promoted Features
The public interface of parts in VisualAge Generator should use the following
naming convention:
• Actions
Actions are stated as verbs. If the action requires parameters, a colon
delimits the words indicating the type of parameter expected. The first
word is lower case as is the first word after a colon. All other words
start with an upper case letter (for instance, getFieldsStartingAt&:.to&:. ).
Remember no spaces are allowed within the names of actions.
• Attributes
:guiapp
..
.
:script
..
.
:escript
..
.
:eguiapp
The definition of the GUI application is contained between the script tags.
The definition consists of three sections in the following sequence:
Internal structure
This section of the .ESF file (see Figure 56 on page 354) identifies the
parts that are to be created as part of the GUI application This part of
the file is identified by the word calculatePartBuiler ( 1A).
calculatePartBuilder (1A)
″Create the edit time part tree for the MEMBER.″
″ MEMBER recalculatePartBuilderRecordFromArchivalCode. ″
] aMEMBER ] (1C)
aMEMBER (1D)
subpartBuilderNamed: ′ partName′
put: (self addClassNamePartBuilder: aMEMBER);
:
:
subpartBuilderNamed: ′ tearOffName′
put: ((AbtTearOffAttributeSpec new attributeName:
′ attributeName′ ) newVariableBuilder);
aMEMBER (1E)
attributeSettingNamed: #primaryPart put:
(aMEMBER subpartBuilderNamed: ′ primaryPartName′ ) .
ÁaMEMBER! (1G)
Figure 56. Internal Structure Section of an ESF File for a GUI Application
aTopLevelPartBuilder
connectionBuilderAt: 0
put: (AbtAttributeToAttributeConnectionBuilder new
sourceBuilder: (aTopLevelPartBuilder subpartBuilderNamed:
′ sourcePartName′ ) ;
sourceAttributeName: #sourceAttributeName;
targetBuilder: (aTopLevelPartBuilder subpartBuilderNamed:
′ targetPartName′ ) ;
targetAttributeName: #targetAttributeName);
Figure 57. Method to Create Connections from an ESF File for a GUI Application
Visual layout
This section (see Figure 58 on page 356) defines the placement,
connections, and initial attribute values of parts on the free-form
surface. AbtShellView is the VisualAge Smalltalk name for the window
part.
anAbtShellView
subpartBuilderNamed: ′ partName′
put: (anAbtVariableIconView := AbtVariableIconView newSubpartBuilder);
:
:
anAbtShellView
attributeSettingNamed: #initWidgetSize put:
(Rectangle origin: (Point x: 0 y: 38) corner: (Point x: 640 y: 480)).
anAbtVariableIconView
attributeSettingNamed: #graphicsDescriptor put: (AbtIconDescriptor new
moduleName: ′ AbtBmp##′ ; id: 903; shading: AbtNormalGraphic);
attributeSettingNamed: #framingSpec put: (AbtViewAttachmentSpec new
leftEdge: (AbtEdgeConstant new
offset: 356);
rightEdge: (AbtEdgeConstant new
offset: 54);
topEdge: (AbtEdgeConstant new
offset: 246);
bottomEdge: (AbtEdgeConstant new
offset: 65));
attributeSettingNamed: #label put: ′ employees′ ;
:
:
anAbtCwConnectionView (2D)
attributeSettingNamed: #midPoints put: ((Array basicNew: 1)
at: 1 put: (Point x: 491 y: 340);
yourself).
ÁanAbtShellView! !
Figure 58. Visual Layout Section of an ESF File for a GUI Application
converterPartBuilder: aParentPartBuilder
″Create the edit time part tree for the AbtStringConverter.″
] anAbtStringConverter ]
ÁanAbtStringConverter!
Public interface
This section (see Figure 59) defines the features that are added to the
interface ( 3A) of the GUI application. This section is optional. Its
inclusion depends on the fact that no features other than those of the
primary part are part of the interface.
calculateInterfaceSpec
″Create the interface specification for the MEMBER.″
″ MEMBER reinitializeInterfaceSpecFromMethod. ″
ÁAbtInterfaceSpecBuilder new
featureBuilderNamed: #featureName put: (AbtSubpartActionSpec newFeatureBuilder
attributeSettingNamed: #subpartFeatureName put: #promotedfeature; (3A)
attributeSettingNamed: #selector put: #partName;
attributeSettingNamed: #subpartName put: ′ classNameOfPart′ ) ;
:
:
Figure 59. Public Interface Section of an ESF File for a GUI Application
This method returns (Á) the interface specification built up with the
featureBuilderNamed:put: method. It indicates the name of the feature,
the feature that was promoted, the part from which it was promoted,
and the class of that part.
At the end of the file, before the escript tag, it also states the version of the
product with which the .ESF was created:
The .ESF is a readable file and could therefore be parsed with a REXX
program.
Just like the .ESF file, the print file can be used as the input for a REXX
program that analyzes and uses its contents.
C.3 Summary
VisualAge Generator provides two sources of information that can be used to
build tools that allow you to analyze or document GUI applications in more
detail.
The .ESF file can be interpreted using a program such as REXX that parses
the output. The same can be done with the print output of a GUI application
that is written to a file instead of to a printer.
Hint
D.1 Self
Every part in VisualAge Generator has a self attribute. This attribute holds
the memory location of the part. This attribute is only used when the
attribute you are connecting to requires the memory location of the part. The
main examples are:
• self of a variable part. This allows you to act in the variable part just like
it is the part to which it is connected.
The memory location of a part also comes back in other attributes. Data
items in a working storage record for instance have two attributes,
DATAITEM and DATAITEM data . The first attribute contains the memory
location and can be used as a pointer to the data item. You can see this
when you tear off this data item. The connection that is created is between
The difference also comes back in some actions. For instance, the
getFieldAtIndex: action of an occurring data item contains the pointer to the
data item in the result attribute of the connection. The associated
getValueAtIndex: contains the value of the data item in the result attribute of
the connection.
D.2 Object
The object attribute of a part is found in all parts that have a data type
associated with them and can contain only one element of data. object
contains the value of the part. The part can only have a value that does not
violate its data type and data type settings. If the latest value given to the
part does, the part shows “** error **” to indicate an incorrect value. Also
the object attribute contains the last value that did not violate the data type
and data type settings.
Data type is the most common attribute used to make sure data is shown in
a part. The object attribute is also used for the default connection created by
the Quick Form facility of VisualAge Generator.
D.3 String
In contrast to object , the string attribute contains a value even if the value
provided is incorrect and does not pass the validation. It contains the
incorrect value, exactly as typed by the user or provided by the system.
The exact name of this attribute can differ according to the part in which it is
used. In an entry field it is string and in a label, labelString .
D.4 Items
Lists of data, like a list box and a container details, have an attribute called
items . In general this indicates that the part contains a list of data. If the
items attribute is torn off, it results in an ordered collection, a clear list of
data.
D.5 Menu
A lot of parts have a menu attribute. This attribute allows you to connect a
menu to the part. The attribute requires the pointer ( self ) to the menu to be
connected to it. If the part is a window, it shows the menu as part of the
window. In all other cases the menu becomes a pop-up menu for the part to
which the menu is connected.
Licensees of this program who wish to have information about it for the
purpose of enabling: (i) the exchange of information between independently
created programs and other programs (including this one) and (ii) the mutual
use of the information which has been exchanged, should contact IBM
Corporation, Dept. 600A, Mail Drop 1329, Somers, NY 10589 USA.
The information contained in this document has not been submitted to any
formal IBM test and is distributed AS IS. The information about non-IBM
DB2 DB2/2
IBM OS/2
VisualAge VisualGen
This information was current at the time of publication, but is continually subject to change.
The latest information may be found at URL [Link]
[Link]
[Link]
• Internet Listserver
With an Internet E-mail address, anyone can subscribe to an IBM Announcement
Listserver. To initiate the service, send an E-mail note to
announce@[Link] with the keyword subscribe in the body of the note (leave
the subject line blank). A category form and detailed instructions will be sent to you.
• Online Orders (Do not send credit card information over the Internet) — send orders to:
IBMMAIL Internet
In United States: usib6fpl at ibmmail usib6fpl@[Link]
In Canada: caibmbkz at ibmmail lmannix@[Link]
Outside North America: dkibmbsh at ibmmail bookshop@[Link]
• Telephone orders
• 1-800-IBM-4FAX (United States) or (+1) 415 855 43 29 (Outside USA) — ask for:
• Internet Listserver
Company
Address
We accept American Express, Diners, Eurocard, Master Card, and Visa. Payment by credit card not
available in all countries. Signature mandatory for credit card payment.
Index 375
GUI programming example (continued) GUI programming example (continued)
GUITST6 133 VSLTST5 175
GUITST7 139 VSLTST6 179
GUITST8 141 VSLTST7 179
GUITST9 142 WINTST1 51
HOVERHLP 39
ITMTST1 110
MEGADATA 270
H
MSGFUN 242 hierarchy 309
MSGRCD1 131
hover help 38
MSGRCD2 131
MSGWIN 174, 175
OFWIN 210, 213
OPENWIN1 210 I
OPENWIN2 210 inheritance 310, 318
OPENWIN3 211 iterator 177
OPENWIN4 213 ITF 12, 14, 59
PRCTST1 157 bind 13
RBBBDDC 297 calling generated server applications 17
RBBBDDR 294 database preferences 13
RBBBZDB 291 [Link] 13
RCDTST1 113, 117, 121 EZERDEBUG 73
RCDTST2 113 interrupting 71
RCDTST3 125, 128, 130 LUW 12
RVOCTEST 320 profile 13
SORTESF 326 stopping 71
SORTOF 325 test monitor 13
TGRGUI1 259, 260, 261 testpoints 59
TGRGUI2 259, 260, 261 trace entry filter 70
TGRTAB1 262 trace log 65
TGRTAB2 262 ITF monitor 61
VALCONV 225 bypass 60
VALFCHK 227 leap 60
VALLOG 247 return 60
VALMASK 222 run 60
VALREUSE 234 stack monitor 61
VALRTST 234 statement monitor 61
VALTAB 229 step 60
VALTST2 237 stop 60
VGTBLE 134 watchpoint monitor 61
VRTCDV 323
VRTCDVT 323
VSLTST1 166 L
VSLTST2 171 layout 49
VSLTST3 172 level-77 165, 275
VSLTST4 174
P
parameters 94, 170
N
part
nesting 9
position 48
settings 7
parts 4
O architecture 285
object factory become primary part 9
dynamic programming 256 building 195
part 209 communication 199
using 210 composite 29, 50
object menu 7, 9 context menu 7, 9
objects data type 29
abstraction 308, 317 delete 22
aggregation 309, 316, 317 description 23
building 316 embedded 195
characteristics 307 member parts 29
class tree 312 object factory 209
classes 315 parts list 41
communication 323 parts palette 21, 23, 198
delegation 310
Index 377
parts (continued) procedural 153
performance 253 profile
pop-up menu 7, 9 database preferences 13
procedural 153 promoting 143
proportional 49 proportional 49
public interface 6 public interface 6
settings 30
sharing data 202
sizing 50 Q
tool bar 22 quick form 120
types 28
using 35
variable parts 204
window 35 R
parts list 41 representation
parts palette building 292
adding parts 198 checklist 293
description 23 interaction 299
GUI application builder 21 introduction 292
sticky 22 running GUI applications 17, 18
perform request 155, 173 calling generated server applications 17
performance 265 ITF 17
performance 251 runtime 18
array dimensions 275 trace 84
client/server 265 [Link] 84
connections 257
data considerations 268
design considerations 266 S
generation options 276 scrolling 186
GUI size 256 security 296, 328
level-77 275 server database errors 219
load time 251 settings 7
logic 257 child placement rules 50
megadata 270 data type 149
parts 253 descriptions 30
perform request 265 layout 49
preloading 253 parts 30
tuning 276 window 36
VisualAge Generator table 273 sharing data 202
persistence 311 variable parts 204
pop-up menu 7, 9 VisualAge Generator table 208
position 45 working storage record 202
primary part sizing
become primary part 9 proportional 49
default 4 sorting 324
V
validation 223
converter 223
Form Input Checker 226
options 231
VisualAge Generator table 228
variable parts 204
virtual class
defining 322
Index 379
IBML
Printed in U.S.A.
SG24-4238-00