Sunday, February 21, 2021

Learning Clarion (Part 5)

SoftVelocity Clarion

This follows on from Learning Clarion (Part 4). In the lesson below, we’ll create the procedures that will maintain the "Product" data table

Lesson 9: Copying Procedures

Now that we’ve created the Customer browse procedure, we can reuse much of that work for the next procedure by copying the procedure, then changing its columns. In this lesson, we’ll copy the BrowseCustomers procedure to create the BrowseProducts procedure.
We will also use "Embed points" to write "embedded source code" to call the BrowseProducts procedure from your application’s menu and toolbar. This will introduce you to the numerous points at which you can add a few (or many) lines of your own source code to add functionality to any procedure.
As you recall, when we created your "Browse", "Products" menu item, and the toolbar button labelled "Products," we didn’t specify a procedure to call when the end user executed them. We’ll start by creating the procedure to call. Highlight the "BrowseCustomers" procedure in the Application Tree dialog because we want to copy it. From the main IDE menu, click on "Application" and choose "Copy Procedure".
Change the text in the "New Procedure" dialog box to read "BrowseProducts" and click "OK".
Because the "UpdateCustomer" procedure is nested under the "BrowseCustomers" procedure (the one you are copying), the "Procedure name clash dialog appears". This offers you options on how to handle the clashing procedures. Press the "Prompt" button. By doing this, you tell the Application Generator to let you have the opportunity to rename all the clashing procedures, or not.
We want our new "BrowseProducts" procedure to call a procedure to update "Product" rows, not "UpdateCustomer", so click on "Rename" so we can specify the correct name.
Type in the new procedure name, "UpdateProduct" and click "OK".
Notice how the Application Tree now has the copied "BrowseProducts" procedure, and its associated (empty) "UpdateProduct" procedure. They look "disconnected" from the other procedures because no other procedure calls them (yet). We’ll do that next.

Working with Embed Points

The Clarion templates allow you to add your own customized code to many predefined points inside the standard code that the templates generate. It’s a very efficient way to achieve maximum code reusability and flexibility. The point at which your code is inserted is called an Embed Point. Embed points are available at all the standard events for the window and each control, and many other logical positions within the generated code.
In this lesson you add embedded source code (using a Code template that will write the actual source for you) at the points where the end user chooses the "Browse", "Products" menu item, and at the point where the end user presses the "Products" button on the application’s toolbar.
Right-click on the "Main" procedure in the Application Tree. There are several ways to access the embedded source code points within a procedure. Two of them appear on the popup menu that you now see.
The first is the Embeds selection, which calls the Embedded Source dialog to show a list of all the embed points within the procedure.
The second is the Embeditor Source selection, which actually generates source code for the procedure and calls the "Embeditor" (the Text Editor in embed point edit mode) to allow you to directly edit all the embed points within the context of generated source. The generated source code is "greyed out" to indicate that you cannot edit it, and every possible embed point in the procedure is identified by comments, following which you may type your code.
There are advantages to each method of working in embed points, so we’ll cover both methods during this lesson. First, we’ll use the Embedded Source dialog. Choose "Embeds" from the popup menu.
The Embeds Tree dialog appears, allowing access to all the embed points in the procedure. (You can also get here from the "Embeds" button on the Procedure Properties window, but the popup menu is quicker.) This list is either sorted alphabetically or in the order in which they appear in the generated source, depending on whether you have the Sort Embeds Alphabetically box checked in "Setup", "Application Options". Press the "Contract All" button on the toolbar. This will make it easier to locate the specific embed point you need.
Type in "BrowseProducts" in the search bar. This is a quick way to find a particular procedure. Or you can click on the "+" sign next to "Control Events" and scroll down to "?BrowseProducts".
Click on the "+" sign next to "?BrowseProducts" and select "Accepted". The "Accepted" event for this menu selection marks the point in the generated code that executes when the user chooses the menu command. Click on the "Insert" button.
The Select embed type dialog appears to list all your options for embedding code. You may simply Call a Procedure, write your own Clarion language Source in the Text Editor, or use a Code template to write the source code for you. This is one advantage to editing embed points from within the Embedded Source dialog: you can use Code templates to write the code for you instead of writing it yourself.
Scroll down to the "Initiate Thread" template. Click on it and click "Select".
A Code template usually provides just a few prompts and instructions on its use. It gathers the information it needs from you to write its executable code, which it then inserts into the standard generated code produced by the Procedure template directly into this embed point. This Code template is designed to start a new execution thread by calling the procedure you name using the START procedure (as shown in the window).
Choose the "BrowseProducts" procedure from the drop-down list of available procedure names, and click "OK". This names the procedure to START when the user chooses the menu item. This is the name of the procedure you previously copied.
Notice that there are some up and down buttons and a spin box on the right side of the window that allow you to select a Priority. These are important. The templates generate much of the code they write for you into these same embed points. Sometimes, the code you want to write should execute before any template-generated code, and sometimes it should execute after, and sometimes it should execute somewhere between various bits of generated code.
The exact placement of your code within the embed point is determined by the Priority number. This provides you with as much flexibility in placing your embed code as possible. The Priority numbers themselves do not matter, but the logical position within the generated code does, and that’s why this dialog also shows comments which identify the embed priorities. Don’t worry, there’s more coming on this issue later that’ll help make it clearer.
At this point, you could do the same thing to call the BrowseProducts procedure from the Product button. However, there’s an easier way to write this code again: just Copy and Paste it from one embed point to another. So, with the BrowseProducts menu embed point still highlighted, click on the "Copy" button as shown.
Search for the "ProductButton" in the search bar, or just scroll down until you find it. Click on the "Accepted" embed point and press the "Paste" button. When the "Procedure name clash" dialog appears to warn you that the same procedure has already been used, click on "Same" because we want to use the same procedure. Now click on the green "Save and Close" button.
The BrowseProducts procedure now "connects" to the Main procedure. Now you can customize the copied procedures for the Product table, which we copied from the BrowseCustomer procedure.

Modify the Browse

Click on the BrowseProducts procedure and notice that the description still says, "Browse Customers".
Click on the "Properties" button and change the description to "Browse Products". Click on the green "Save and Close" button. Notice that the description is fixed.
Now we need to change the fields that are displayed. Click on the "Window" button to open the window designer.
Change the window Title to "Browse Products" as shown.
Click on the main List Box, and then right-click and choose "List Box format ..." to open the list box formatter.
Notice that all the fields still refer to the Customer table. Use the "Remove" button to remove all the fields shown.
Now click on the "Add Field" button. It will display the current table and fields, none of which are the ones we want. Click on the "Customer" table and then use the "Delete" button to remove it.
Click on the "<ToDo>" word that replaced the "Customer" table and then the "Add" button. This will open a list of tables. Click on "Product" and click "Select".
Use the "Change" button to change the default sort key to "KEYPRODDESC" and click "Select". The "Select Column" dialog now lists the correct table and columns. Click on "ProdNumber" and then the "Select" button.
Check that the RightBorder and Resizeable properties are both "True", and change the Header Text property to "Prod #". The width should be 24.
Use the Add Field button to select "ProdDesc". Check that the RightBorder and Resizeable properties are both "True". The width should be 120.
Use the Add Field button to select "ProdAmount". Check that the RightBorder and Resizeable properties are both "True". The width should be 32.
Use the Add Field button to select "TaxRate". Check that the RightBorder and Resizeable properties are both "True". Click "OK" to close the list box formatter.
Click to the right of the "by Zip Code" tab to select the entire tab sheet. Confirm this by looking for the phrase "SHEET (Use = '?SHEET1')" in the properties window on the right. Then press the "Delete" key to remove the sheet.
Use the green "Save and Close" button to save your work. Then click on the "Accept changes" button to save your work. Return to the "Browse Products" design window.

Add an Incremental Locator

If the list of Products to display is very long, the user can do a lot of scrolling before finding the specific Product they want. By default, all BrowseBox Control Templates have a "Step" row locator that allows the user to press the first letter of the value in the sort key column to get to the first row that begins with that letter.
Sometimes with large databases, however, the user needs to enter the first several letters to get close to the row they want. An Incremental locator provides that functionality by specifying a string control for the user to see the information they type. As they type, the list scrolls to the first row matching the data the user entered thus far. This works best with STRING keys, such as the Product Description key.
Use the Toolbox, and select the "STRING" control. Drag it to the top left of the list box control.
Use the properties window to set the "IsPicture" property to "True", and use the ellipsis to the right of the "Use" property to choose the "ProdDesc" field from the Product table. Use the green "Save and Close" button to save your work and return to the main window. Click on the "Accept changes" button to save your work.
From the main screen, ensure that the "BrowseProducts" procedure is still highlighted, then click on the "Extensions" button.
In the "Extensions" tab, click on "Browse on Product()" and then click the "properties" button. Change to the "Conditional Behaviour" tab and use the "Delete" button to remove the two SHEET choices that applied to the Customer browse but are no longer relevant to the Product browse. After all, we have also deleted the SHEET control.
Change to the "Default Behaviour" tab, and click on the "Locator Behaviour" button. Change the "Locator" option to "Incremental" and click "OK". This completes the requirements for the Incremental Locator. The key column of the sort order (in this case PRO:ProdDesc) is the default locator control. Click "OK", and then on the green "Save and Close" button.

Creating the Form Procedure

When you renamed the reference to the UpdateCustomer procedure while copying BrowseCustomers to BrowseProducts, it made the UpdateProduct procedure a "ToDo" procedure. Therefore, we need to create a form to update the Products table.
Click on the "UpdateProduct" procedure and select "Properties". Select the "Defaults" tab, choose "FORM (Add/Edit/Delete)" and then press the "Select" button.
In the "Data / Tables" pad, highlight the "<ToDo>" table, then press the "Add" button (or double-click on "<ToDo>"). Choose the "Product" table and click on the "Select" button.
Set the Description to "Update Product" and click on the ellipsis next to the "Window" button.
Change the WINDOW text to 'Update Product' and add in ",FONT('Segoe UI')" at the end of the first line. Click on the green "Save and Close" button, and then use the "Window" button to enter the Window Designer.
Starting with the "ProdNumber" field, drag and drop each field from the "Data / Tables" pad to the form, as shown.
Spend a few minutes tidying up the form layout, and adjust the form size as shown. Click on the green "Save and Close" button, then the green "Save and Exit" button, and finally the "Accept changes" button to save your work. The Products table update form window is completed.
Make a backup of your work.

OK, What Did I Just Do?

Here’s a quick recap of what you just accomplished:
  • You copied an existing procedure, renaming the subsequent procedures it called.
  • You used a Code Template in the Embedded Source dialog to call the new procedure from the main menu.
  • You modified the copied procedure to display from another table.
  • You added an Incremental Locator to the Browse procedure.
  • You created an entire Form procedure very quickly by just using the Populate Column toolbox.
Now that you’re thoroughly familiar with Procedure Templates, we’ll go on to use some Control and Extension Templates.

Lesson 10: Control and Extension Templates

For the BrowseOrders procedure, you’ll create a window with two synchronized scrolling list boxes. One will display the contents of the Orders table, and the other will display the related rows in the Detail table. You’ll use a generic Window procedure, and populate it using Control templates. The only reason for doing it this way instead of starting with a Browse Procedure Template is to demonstrate another way of building a procedure: using Control templates placed in a generic Window (the same way the Browse Procedure template itself was created).
Control templates generate all the source code for creating and maintaining a single control or related group of controls. In this case, placing a BrowseBox Control template allows the Application Generator to produce the code that opens the tables and puts the necessary data into the structures which hold the data for display in the list box.

Creating the Procedure

Click on the "BrowseOrders" procedure and the "Properties" button. When the "Select Procedure Type" dialog box opens, choose the "Templates" tab, and select "Window - Generic Window Handler".
Type in "Browse Orders" in the Description field, and then click on the ellipsis next to the "Window" button. When the "Select default declaration" dialog appears, choose "MIDI Child Window" and click on "Select".
Change the WINDOW caption to 'Orders' and check that the FONT declaration shows 'Segoe UI'. Then click on the green "Save and Close" button. Then click on the "Window" button to go into the normal Window Designer.
Resize the window to double its height and width. Change the "MaximizeBox" property to "True" and check that the Frame Type is "Resizable". Open the "Control Templates" pad.
Drag the "BrowseBox" control template to the top left corner of the window, and drop. The "Select Column" dialog opens. Click on the "<ToDo>" entry, click the "Add" button, choose the "Order" table and click the "Select" button.
With the "Order" table still selected, click on the "Change" button and select the "KeyOrderNumber" key to sort the data by order number.
Choose the first field "CustNumber" and click "Select".
Right-click on the newly-created list box and choose "List Box format ..." to open the List Box Formatter.
Use the "Insert Field" button to click on and "Select" each of the remaining fields in the Order table.
Adjust the column widths by moving the right border on applicable fields. Set the Header Indent to 1 for the first field. Ctrl-click on each of the fields to select them all. Then Check that the "Resizable" and "RightBorder" properties are "True". Examine the Header text property of each column, and abbreviate them as follows: "Cust#", "Ord#", "Inv Amt", "Date", and "Note". Click "OK" when done.
Set the "Vertical" and "Horizontal" scrollbar properties to "True" and widen the list box to fill most of the width of the form, leaving an equal distance between left, right and top parts of the window. Change the Font "Size" to "8" points so that more of of the Note field can be displayed. Use the green "Save and Close" and "Save and Exit" buttons to save your work and return to the main screen.
Try the "Start Without Debugger" button to see how your application is progressing. Close the application when done, and return to the Window Designer by clicking on the "Window" button.

Adding the Browse Update Buttons Template

Next add the standard "Insert", "Change" and "Delete" buttons for the top browse list box control. Since there are going to be two list boxes on this window, we’ll leave these buttons visible for the user. Later we’ll add a form procedure for adding or editing an order.
Search in the "Control Templates" pad for "browseupdatebuttons" and locate the "Browse on Order" template. Drag it to the bottom left of the list box as shown. The three buttons will appear.
Select just the "Delete" button, and then right-click and choose "Actions ..." from the pop-up menu.
Type in "UpdateOrder" in the Procedure Name field and click "OK". This names the procedure, in the same way that you named the Update procedure for the Customer browse in its Procedure Properties dialog. Naming the Update Procedure for one button in the Control template names it for all three.

Placing the Second Browse List Box

Next, place a list box with the contents of the Detail table. This will update automatically when the end user changes the selection in the top list box. To do this, you may have to make a bit more space on the form, by shortening the "Order" list box and moving the three buttons up to the middle of the form height.
Drag another "BrowseBox" control template to the point below the "Insert" button. Click on the new '<ToDo>" entry, click "Add" and choose the "Detail" table before you click "Select".
Select the new "Detail" table entry, and click on "Change" to choose the "KeyOrderNumber" sort key, and click "Select".
Click on the "Detail" table, choose the first field and click "Select". This will return us to the Window Designer.
Adjust the shape of the new list box to fit the window, leave some space to the right for a "Close" button which we will add later, and then right-click on it to choose the "List Box format..." command and open the List Box Formatter.
Click on the "Add Field" button, select the "Detail" table and add in the remaining fields as shown, using the "Select" button.
Adjust the headings and widths of each field to make them neater. Then click "OK" when done.
Right-click on the list box again and select "Actions ..."
Click on the ellipsis to the right of the "Range Limit Field" and select "OrderNumber" from the "Detail" table. This is autosuggested for you. Change the "Range Limit Type" to "File Relationship" and use the ellipsis to the right of the "Related file" field to select the "Order" table. These settings will now show only the Detail records for the selected "Order" record in the top browse. Click "OK".
Change the font "Size" property to "8" points so that it matches the size of the first list box, and make sure the "Horizontal" and "Vertical" scrollbar properties are set to "True".

Adding the Close Button Control Template

Finally, you can add a "Close" button that closes the window.
Drag and drop the "CloseButton" control template in the bottom-right corner of the window, as shown. Use the green "Save and Close" button, followed by the "Accept changes" button, to save your work.

Make the window resizable

Select the BrowseOrders procedure, and then click on "Properties" button.
Go to the "Extensions" tab. Click on the "Insert" button. Choose the "WindowResize" extension and click on "Select".
Instead of just accepting the default resizing strategy, we are going to change a few things. First, enable the "Restrict Minimum Window Size" option, to prevent the window being made smaller than the designed size. Next, click on the "Override Control Strategies" button and click on "Insert". Choose the "?Insert" window control and change the "Vertical Positioning Strategy" option to "Fix Bottom". Click "OK". Repeat these steps for the "?Change", "?Delete" and "?List:2" buttons. This ensures that the three buttons and the bottom list box remain a constant distance from the bottom edge of the top list box.
Insert another control strategy for the "?List" control, and set the "Vertical Resize Strategy" to "Constant Bottom Border" and click "OK". This will ensure that the top list box changes its height as the window grows, but the bottom list box stays the same height. Click "OK" and "OK" again to return to the "Extensions" tab. Click on "Accept changes" to save your work.

Set up a Reset Column

In the "Extensions" tab, highlight "Browse on Detail" and press the "Properties" button.
Click on the "Reset Fields" button, then "Insert" and use the ellipsis to "Select" the "InvoiceAmount" field from the "Order" table. Click "OK", "OK", "OK". This specifies that the "Detail" table’s list box should reset itself whenever the value in the "ORD:InvoiceAmount" column changes. This ensures that any changes you make to an existing order are reflected in this dialog when you return from changing the order.
Click on the green "Save and Close" button, followed by the Accept changes" button to save your work.
Make a backup of your work.

OK, What Did I Just Do?

Here’s a quick recap of what you just accomplished:
  • You created a new browse procedure, but did it using the BrowseBox and BrowseUpdateButtons Control Templates instead of the Browse Procedure Template.
  • You created a second, range-limited list box to display related child rows.
  • You used the WindowResize Extension Template and specified individual control resize strategies.
  • You set a Reset Column on the Detail table’s Browse list so its display is always kept current.
Next, we’ll create the UpdateOrder Form procedure to create and maintain the "Order" and "Detail" table rows.

No comments: