OpenEdge Development: Progress 4GL Handbook
![]() ![]() ![]()
|
Introducing the OpenEdge AppBuilderIn the earlier chapters of this book, you learned how to use the Progress Procedure Editor to write your first Progress 4GL procedure. This chapter introduces you to the OpenEdge™ AppBuilder, a tool for designing visual interfaces and for structuring more complex procedures and the code they contain.
As with the earlier chapters, this is a bit of a snowplow exercise. You’ll use the AppBuilder to generate the 4GL code to define a window and its contents, to give a graphical look to your sample procedure.
This chapter includes the following sections:
Starting the AppBuilder
To bring up the AppBuilder, you need to close down the Procedure Editor if it’s running, then select the AppBuilder icon on the OpenEdge Desktop, as shown in Figure 4–1.
Figure 4–1: The ADE desktop
![]()
Alternately, you can bring up the AppBuilder directly from the Windows desktop, by selecting the AppBuilder menu option under the OpenEdge startup group.
The AppBuilder main window has its own menu and toolbar:, as shown in Figure 4–2.
Figure 4–2: The AppBuilder main window
![]()
In addition, the AppBuilder has a separate Palette window where you can select various kinds of both visual objects and nonvisual data management objects to add to your application. You’ll look at just a few of these objects in this chapter. You can learn all about the AppBuilder in OpenEdge Development: AppBuilder.
Figure 4–3 shows the icons for the Palette objects you’ll be using in this chapter. You can learn some of the others by floating the mouse over an icon and looking at its tooltip.
Figure 4–3: The AppBuilder Palette
![]()
You can reshape and reposition the Palette window as you like. To save the Palette window’s position, select Menu
Options
Save Palette from the Palette window.
In addition to the Palette window, the Pro*Tools window also comes up when you start the AppBuilder.
In this chapter you’ll build a window that displays some fields from the Customer table, as well as a browse that shows the Orders for the current Customer. So this is like the example you built in the first chapter, except for two differences:
- By choosing graphical objects to build your window, you get a much better interface than you got using the defaults provided by the
DISPLAYstatement in the previous chapters, one that looks more like a real application window.- Because the AppBuilder generates most of the supporting 4GL code for you, you actually have to write even less code than you did in previous chapters.
Creating a new procedure and window
This section describes how to create a new sample procedure and window.
To create the window that holds all the other objects:
You can resize the design window by grabbing one corner with the mouse and moving it.
Think of this window as corresponding to the new Progress 4GL procedure you will write. The code in that procedure, most of it generated by the AppBuilder, creates the window at run time, along with all the other objects it contains. A single 4GL procedure could certainly create multiple windows, but it is good to begin thinking in terms of a single procedure creating and managing a single visual object, whether it is a window or, later on, an intelligent version of one of the objects inside the window. This is the recommended way to structure your applications. It provides the framework you need to manage things easily.
Adding fields to your window
As you add visual objects to the window, the AppBuilder generates code to populate them with data automatically.
To add fields to your window:
- Display some fields from the Customer table by choosing the DB Fields icon
on the Palette, and then double-click on your design window. The AppBuilder doesn’t support true drag and drop between the Palette and the design window, so use two distinct clicks.
Because you’ve requested database fields, the Table Selector dialog box appears to let you select the database table that contains the fields.- Select Customer from the table list for the Sports2000 database, then choose OK:
The Multi-Field Selector dialog box appears, showing all the fields in the Customer table.- Select some fields by double-clicking on them in the Available Fields list or by selecting one or more fields and choosing the Add button. For example, select the CustNum, Name, Address, City, and State fields:
![]()
- Choose OK. All the fields appear in your design window in a default layout:
![]()
- To arrange the fields in a more useful way, first click in the window background to deselect the fields, and then click on each individual field and drag it to a more visually sensible location:
![]()
In "Using Basic 4GL Constructs," you saw how Progress displays objects in frames. When you create a window in the AppBuilder, it creates a default frame for you that fills the whole design window, and all the other objects, such as your Customer fields, are contained in this frame. If you click on the background of the design window, that is, in any part of the window that shows the layout grid, then you’re selecting that default frame, and it appears in the AppBuilder main window as the selected object. Logically enough, its name is
DEFAULT-FRAME.Changing object names and titles
This section describes how to change the names and titles of objects in your window.
To change the name and title of the default frame:
- Click on the frame, then change the value of the Object field in the AppBuilder main window to CustQuery:
The name CustQuery is appropriate because the AppBuilder, by default, creates a database query for the fields in the frame, and gives it the same name as the frame. You’ll see just ahead what this default query does for you.- If you want to select another object such as a field, click on it.
- To make a change to the window itself (for example, to edit its title), press CTRL-Click (that is, hold the CTRL key down and click the left mouse button).
The AppBuilder has defined a default name for the window of C-Win, which you can see in the Object field. Change this to CustWin. As you’ll see later, the object name is the name of the Progress 4GL variable that holds the handle or pointer to the window’s definition.- Modify the title in the Title fill-in field in the AppBuilder main window, to change it from the default window title of <insert window title> to something meaningful, such as Customers and Orders. The text in the Title field is what displays in the user interface of the window.
Saving a procedure from the AppBuilder
Before moving on, you should save your procedure.
To save your sample window:
You can save it into the same directory as your
h-CustSample.pprocedure. The AppBuilder automatically gives the procedure a filename extension of.winstead of.p. For historical reasons, thewstands for window, even though you can create much more in the AppBuilder than windows. Although there is no absolute requirement that you observe this naming convention, it is strongly recommended that you do. The AppBuilder gives a default.wextension to any procedure it generates that has any user interface element at all, and also to some nonvisual procedures that can be selected and added to a window as part of its logic. Thus the.wextension can be taken to mean any user interface or other window procedure generated by, and therefore readable by, the AppBuilder. This designation can help you to keep your source procedures straight. Note that all Progress source procedures, regardless of their extension, compile into a file with a.rextension.You should get into the habit right now of creating every procedure you write, except for the most trivial, in the AppBuilder rather than the Procedure Editor. This is part of the snowplow again. "Introducing the Progress 4GL," showed you the Procedure Editor to get you started, but now you shouldn’t generally use it. There are templates available from the AppBuilder’s New dialog box for many kinds of procedures, including a structured procedure template that organizes code that doesn’t define any visual elements. By the end of this chapter the advantages of the AppBuilder format should be clear.
Running your procedure
You can already run your window to see what it looks like.
To run your procedure as you did from the Procedure Editor, press F2 or select Compile
Run. You can also choose the Run icon in the AppBuilder main window:
![]()
Here’s what you see when you run (and resize) your window:
![]()
Not only do you get your window with its title and the Customer fields, but the AppBuilder has already generated code to open a query on the Customer table, retrieves the first Customer, and displays it for you. You’ll look at the code that does this just a little later. But first, you need to complete the window.
To stop the window, click the Stop icon, which replaced the Run icon:
![]()
Using the Query Builder
You can easily customize this default data retrieval by using a tool called the Query Builder, where you can define a
WHEREclause and other elements of a query much as you defined theFOR EACHstatement in "Using Basic 4GL Constructs."To bring up the Query Builder for the CustQuery frame:
- Double-click on the frame background. Alternatively, select the Object Properties button from the toolbar:
The property sheet for the frame appears, where you can define various frame properties:
![]()
- Choose the Query button to bring up the Query Builder.
- To define a
WHEREclause ofState = “NH”, select the Where radio set button from the set of options at the top of the Query Builder.- Select State from the list of Customer fields:
![]()
- Choose the equal sign button
.
This brings up the Enter Constant dialog box where you can enter the State value NH. The Query Builder provides the quotation marks for you:
![]()
- Choose OK to return to the Query Builder.
- To add a sort clause
BY Cityto your query, select the Sort radio set button.- Select the City field by double-clicking on it or by selecting it and choosing the Add>> button:
![]()
- Choose OK to leave the Query Builder.
- Choose OK again to leave the frame’s property sheet.
- Run your window again.
The first Customer is displayed again, but this time it is the first Customer in the State of New Hampshire, sorted by City:
![]()
Adding a browse to your window
Next you’re going to add a browse control to the window that displays Orders.
To add a browse to your window:
- If you resized the window to make it smaller, expand it again to make room for the browse.
As you do this, the window’s frame, which displays as a layout grid, should expand automatically with the window. It’s possible that the frame and the window can get out of sync if you inadvertently resize the frame alone (by grabbing its resize handles) rather than the window (by grabbing the corner of the window). If this happens, the layout grid lines won’t fill the whole window, like this:
To correct this, grab the frame’s lower-right resize handle and drag it down so that it fills the window. If you inadvertently try to drop any visual objects directly onto the window itself, the AppBuilder won’t let you, because all the objects must be contained in, or parented to, the frame.- Choose the Browse icon
on the Palette and then click in the space under the Customer fields.
The Query Builder dialog box appears again to help you define a database query to populate this browse. You’ll see that the Customer table has already been selected and marked as <external>, because by default the AppBuilder expects you to display Orders of the current Customer, and the Customer fields and their query are external to your browse.- Select Order from the Available Tables by double-clicking on it or by selecting it and choosing the Add>> button:
The Query Builder has constructed a queryFOR EACH Order OF Customer. This is the same query you created in the sample procedure in "Introducing the Progress 4GL."Next you need to select some fields to display in the browse.- Choose the Fields button. This brings up the Column Editor.
- Choose the Add button to bring up the Multi-Field Selector dialog box.
This dialog box displays fields from both the Customer table and the Order table. It doesn’t make much sense to put Customer fields into the browse, because they always have the same value for every Order of a given Customer.- Scroll down to the Order fields and select some:
![]()
- Choose OK when you’re done.
Back in the Column Editor, there are various field attributes you could set to enable fields or change their label, and so forth.- For now just choose OK again. This returns you to the Query Builder.
- Choose OK once more. This brings you back to the design window, where the AppBuilder has added the browse for you.
- Resize the browse so that all the fields you selected appear. You can also make it taller to display as many rows as you wish.
- Press F2 again to rerun your window:
Now the AppBuilder has constructed another query to select just those Orders for the current Customer, opened it, and used it to populate your browse. And you haven’t written a line of 4GL code yet. This is an example of the power of the OpenEdge development tools.Using property sheets
Every type of object you place onto a window has a property sheet where you can set various property values for it. This section does not describe property sheets in detail, but shows you how to bring up just one so that you know how they work.
To set a property value for the browse:
- Double-click on the browse control in your design window. Alternatively, select the browse and then click on the Object Properties button in the AppBuilder toolbar.
The property sheet for the object comes up, in this case for the browse.- Change the Object name from Browse-1 to OrderBrowse. This will make some of the generated code you look at later a little more readable:
![]()
- Choose OK to exit the property sheet.
Using the Section Editor
Now you’re ready to look at some of the code the AppBuilder has generated for you.
To view the code the AppBuilder created:
- Stop your window, and then choose the Edit Code icon in the main window:
The Section Editor appears. This is where you examine and write all your 4GL code when you’re using the AppBuilder. If you drop down the Section list, you see that there are five types of sections the Section Editor maintains for you:
- Definitions — A section at the top of your procedure where you can write variable definitions and other statements that are needed by the whole procedure.
- Triggers — Blocks of code that execute when an event occurs (for example, when a user chooses a button). You’ll write some triggers of your own just ahead.
- Main Block — The part of the 4GL code that is executed as soon as the procedure starts up. You’ll look at the main block of this sample procedure below and see what it does for you.
- Procedures — Internal procedures, exactly like the one you wrote in "Running Progress 4GL Procedures."
- Functions — User-defined functions are like internal procedures, but they return a value to the statement that uses them, just as the built-in 4GL functions you used in "Using Basic 4GL Constructs" do.
- Select Procedures from the list of section types:
![]()
- From the list of internal procedures (the Name drop-down list), select enable_UI:
The AppBuilder generates this code to get your window started. This code does all the things that make the window, and then the data, appear.Note that the AppBuilder has generated the header statement
PROCEDURE enable_UIfor you, but doesn’t show it except to show the procedure name. Also note that the procedure is marked Read-Only. That’s because the AppBuilder created it and doesn’t want you to make any changes to it directly. If you change any objects in the design window, it changes the code for you.When you create new procedures of your own, you can edit them in the Section Editor just as you did in the Procedure Editor.
Next you take a look at this code to see what it’s doing for you. A word of warning before you start: Because this is AppBuilder-generated code, some of it isn’t as readable as it might be if you wrote it by hand. The whole idea is that you almost never need to look at this code. But you’re going to do that here so that you understand what’s going on behind the scenes.
Looking at preprocessor values in the Code Preview
The first statement already looks pretty strange:
What’s that all about? A name enclosed in braces and preceded by an ampersand tells you this is a Progress preprocessor value. You are probably familiar with preprocessor values from other languages you’ve used. It is nothing more than a substitution string. It’s defined up near the beginning of the procedure file, and everywhere it occurs in the 4GL code, the Progress syntax analyzer replaces it with the string it’s been defined to represent. That way, you (or the AppBuilder) can define a commonly used string of code once and use it multiple times in your procedure.
The AppBuilder generates the definition of this preprocessor value. Normally you don’t need to look at it, so it’s in a special section that isn’t displayed along with the rest of your code sections.
To look at the preprocessor definition:
Figure 4–4: Preprocessor definition in the Code Preview window
- Return to the AppBuilder main window and press F5 or select Compile
Code Preview from the menu. The Code Preview dialog box appears and shows all the code for the whole procedure.
- Scroll down in this dialog box to the section marked Preprocessor Definitions to find the definition of
OPEN-QUERY-CustQuery, as shown in Figure 4–4.
![]()
&Scoped-definemeans that this definition is scoped to just this procedure file, rather than being available to any other source files that are associated with this one. From this line you see that the preprocessorOPEN-QUERY-CustQueryis defined to represent the textOPEN QUERY CustQuery FOR EACH Customer SHARE-LOCK. In later chapters you’ll explore the differences between defining and opening a query on a table and just retrieving the data using aFOR EACHstatement by itself. For now it’s enough to understand that the query namedCustQuerydefines the set of data to be retrieved, theOPEN QUERYstatement starts the retrieval, and then other statements that you’ll see next actually walk through the data row by row. The query definition itself is in another part of the AppBuilder-generated code, and just saysDEFINE QUERY CustQuery FOR Customer.Positioning within the query
The first statement opens that Customer query and sets you up to retrieve and display each of the Customer records in turn. Now look at the next statement:
This statement retrieves the first Customer record using the query
CustQuery.Moving on, you see a
DISPLAYstatement, which should be familiar to you. It has anIF-THENconstruct in front of it that you haven’t seen before, but like most Progress 4GL statements, it’s self-explanatory. If the query turns out to be empty, or if you’ve reached the end of it, then you don’t want to try to display anything. The phraseIF AVAILABLE Customerchecks for that:
IF AVAILABLE Customer THENDISPLAY Customer.CustNum Customer.Name Customer.Address Customer.CityCustomer.StateWITH FRAME CustQuery IN WINDOW CustWin.
Because a field name might occur in more than one table used in the procedure, the AppBuilder puts the table name in front of each field name, as in
Customer.CustNum. This is a good practice for you to follow in the code you write unless your field names are all guaranteed to be unique.The end of the
DISPLAYstatement has a qualifier you didn’t see in previous chapters either,WITH FRAME CustQuery. But you can certainly tell what it does. "Using Basic 4GL Constructs," explains that Progress uses frames to define different display areas, and that each field and block of code is associated with a frame. If you don’t name the frames yourself, you get default frames. If you need to, you can give each frame a name and specify that frame in aDISPLAYstatement. Then Progress knows exactly where each displayed field or other object should go. You renamed your window’s default frameCustQueryearlier, and here you see that name being used. And remember the AppBuilder uses the same name for the frame’s default query.The second qualifier is understandable, too. If your procedure happened to define more than one window, then you would have to tell it which frames go in which window. Here the code makes that explicit, by appending the phrase
IN WINDOW CustWin.So apart from these qualifiers this statement should look familiar. Now look at the next statement:
ENABLE Customer.CustNum Customer.Name Customer.Address Customer.CityCustomer.State OrderBrowseWITH FRAME CustQuery IN WINDOW CustWin.
Not surprisingly, this statement enables each of the fields for data entry, so that you could make changes to a record and then save it. Also it enables the browse control itself so that you can scroll it up and down. At this time, you won’t actually add a Save button to this window to let you save changes (you’ll do that in "Updating Your Database and Writing Triggers").
Next is another preprocessor value:
If you do a Code Preview again (or refer to Figure 4–4) you can see that this value represents the statement
OPEN QUERY OrderBrowse FOR EACH Order OF Customer NO-LOCK INDEXED-REPOSITION. You’ll get to details likeNO-LOCKversusSHARE-LOCKand whatINDEXED-REPOSITIONmeans in "Using the Browse Object." Otherwise, you should recognize this as the query you built in the Query Builder when you dropped the browse control onto the window.The final executable statement is:
This statement tells Progress at run time to make the window visible.
And finally, as you learned in the "Running Progress 4GL Procedures," every internal procedure must end with an
END PROCEDUREstatement:
This is all the code that’s needed to make all the things happen that you saw when you ran the window. It opens two different queries representing a parent-child relationship between Customers and Orders. It displays and then enables the Customer fields and the Order browse. And it views the window itself. All this happens in about ten lines of 4GL code. And you didn’t have to write any of it yourself.
Adding buttons to your window
When your window comes up, it displays the first Customer and its Orders automatically. This is very nice, but of course you’d like to see other Customers as well.You can extend your window so that you can walk through the Customers in sequence and see the Orders for each Customer as you go. To do this, you’ll add some buttons to the window and then define triggers for them. Triggers are blocks of 4GL code that are executed when the user chooses a button.
To make room for some buttons, grab all the fields in your window by clicking with the mouse to the upper-left of the first field, and then dragging the mouse to draw a rectangle around all the fields. Drag them down slightly so that there’s room at the top of the window.
To add a button to your window:
You see that the AppBuilder changes the button label in the design window for you when you tab out of the Label fill-in field.
Defining a CHOOSE trigger for your button
Now you need to write some code for Progress to execute when the user chooses the First button. You can cheat a little here and copy some code you’ve already looked at, because it uses some query syntax that you won’t read about in detail until a later chapter.
To define a
CHOOSEtrigger for your button:
- Choose the Edit Code button to bring up the Section Editor, and go back to the procedure
enable_UI.- Copy the two statements (five lines of code in all) starting with
GET FIRST CustQuery. Select the text by clicking and dragging the mouse over it, then press CTRL-C:
Why do you select just these lines? The preprocessor value in the first line of the procedure opens the Customer query, and since it’s already open when the user chooses a button, you don’t need to do that again. Likewise, the fields and other objects in the window are enabled, so you don’t need to do that again either. (By the way, you might notice that your new BtnFirst button has already been added to the list of things to enable.) And the window has been viewed, so you don’t need that statement either. However, the statement before that, which opens the Order query, you do need, so you’ll go back and get that in a moment.- Drop that same code into the trigger to execute when the user chooses the First button. You can get the Section Editor to move to that place in the procedure in two ways:
In either case you get a starting point for some 4GL code defined within a
DO-ENDblock. You can see that the block of code is defined to executeON CHOOSE OF BtnFirst.Defining user interface events
The
CHOOSEevent is the one you want to capture. An event is an action that happens while the application is running that Progress can intercept for you. Some events are associated with particular kinds of user interface objects, such as theCHOOSEevent for a button. Others are defined for mouse clicks and other mouse events.To define an event for the button:
- Choose the New button in the Section Editor to see a list of all the events that you can define for the current object:
TheCHOOSEevent is the most common event for a button, so that’s the event the Section Editor offers you by default.- Choose Cancel to exit the Choose Event dialog box and return to the Section Editor.
- In the Section Editor, press CTRL-V or select the menu item Edit
Paste to paste the code you copied from the
enable_UIprocedure into your trigger.To go back and get the statement that opens the Order query for you:
- Reselect the
enable_UIprocedure. You can do this by selecting Procedures from the Section type list. Or you can choose the List button, which brings up a list of all editable sections:
![]()
- Copy the statement
{&OPEN-BROWSERS-IN-QUERY-CustQuery}fromenable_UI, go back to your trigger block, and paste it at the end of the block:
This is the code that repositions to the first Customer, displays it, and opens a query to display its Orders.To repeat these steps for a Next button:
- Choose the Button icon on the Palette.
- Drop another button onto your design window next to the First button.
- Rename the button BtnNext and change its label to Next.
- Copy the block of code from the First button and paste it into the same section for the Next button.
- Change the first statement to
GET NEXT CustQuery. This advances to the next record in the set of Customers in New Hampshire when you choose the button.- Save your procedure by selecting File
Save or by choosing the Save icon in the AppBuilder toolbar, and then rerun it.
Now you should be able to walk through the New Hampshire Customers. As you display each one by choosing the Next button, you see that its Orders are displayed in the browse.
To finish adding buttons to your window:
Adjusting the layout of the buttons
Now that you have all your buttons in a row, you can take advantage of the AppBuilder’s layout options to line them up and space them out properly.
To select all four buttons and align them:
- Select all the buttons at once, either by drawing a rectangle around them with the mouse or by selecting each one in turn by pressing CTRL+LEFT-MOUSE-CLICK.
![]()
- Select the Layout menu in the AppBuilder window:
Here you can see a number of methods to adjust the layout of your window.If you select Even Spacing Left-to-Right, for instance, the AppBuilder adjusts the spacing in between the buttons to even it out.- Experiment with some of these options if you like. The Alternate Layout option is rather advanced, and you should leave this one until later. It lets you define different layouts of your window for different user interface types, or even for different user groups or other special customizations.
If you expand the Align item, you see a number of ways in which you can align a group of selected fields, buttons, or other objects in your window:
![]()
- Run your window once again to see all your buttons in action.
This chapter gives you an overview of the OpenEdge AppBuilder. In the next chapter, you’ll examine the code that the AppBuilder generates for you.
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |
![]() ![]() ![]()
|