Whenever you interact with Paradox, you generate either an Action or MenuAction constant. For example, when you select a menu item, a constant is sent to the built-in menuAction event. If the constant maps to an Action constant, an equivalent Action constant then is sent to the built-in action event. For example, when you select File | Print, the constant MenuFilePrint is sent to the form’s menuAction event. Since MenuFilePrint maps to the action constant DataPrint, DataPrint is sent to action. In the events action and menuAction, you can trap for nearly every user interaction. In addition, using the action() and menuAction() methods you can invoke or imitate nearly any user interaction by sending Action and MenuAction constants to the built-in action and menuAction events.
Action() and PostAction()
Both action() and postAction() performs a specified action. The difference is that action() executes the action right away and postAction() posts an action to an action queue for delayed execution. With postAction(), the action is posted to an action queue at the time of the method call; Paradox waits until a yield occurs—for example, by the current method completing execution or by a call to sleep(). This is an important distinction to keep in mind while executing actions from within your code.
Using the action() and postAction()
These methods open up a whole bunch of commands. As an ObjectPAL programmer, you’re interested in five action constant classes: ActionDataCommands, ActionEditCommands, ActionFieldCommands, ActionMoveCommands, and ActionSelectCommands. Use these commands with the action() method. The syntax for action constants is as follows:
ObjectName.action(ActionConstant)
ObjectName
is the name of the object on which you want the action to occur, such as theBox or Last_Name. The actionConstant can be any constant category whose name starts with action. If you want, you can precede this expression with an object path, as in the following:
1: f.pge3.tf.action(DataNextRecord)
In the above, f
is a handle to another form, and pge3 and tf are the names of two objects contained in the form (the third page and its table frame). The constant DataNextRecord moves the cursor forward one record (if possible).
Using Action Constants
The constants in the ActionDataCommands category deal with data in a table as a whole, as shown here:
Illustration 1
They are used for navigating the pointer in a table, locking a record, posting a record, toggling Edit mode, and positioning the record pointer. Following are three examples:
action(DataPrint) ;Prints a form or table view. action(DataTableView) ;Open the master table in a window. action(DataSaveCrosstab) ;Writes the crosstab data ;to :PRIV:CROSSTAB.DB.
In general, the constants in the ActionEditCommands category are used for altering data within a field, as shown here:
Illustration 2
With these constants, you can copy text to the Clipboard, enter persistent field view, access the help system, and search your text. Following are three examples:
1: action(EditDropDownList) ;Drops down pick list. 2: action(EditEnterMemoView) ;Enters memo view. 3: action(EditPasteFromFile) ;Pastes from file into ;current field.
The constants in the ActionFieldCommands category are used for moving between field objects, as shown here:
Illustration 3
With these constants, you can invoke and control tab order. You can move the focus forward or backward in the tab order. You can ignore the tab order and move up, down, left, or right. You can even move from one table frame to another. Following are three examples:
1: action(FieldRotate) ;Rotates columns in a table frame 2: action(FieldNextPage) ;Moves to the next page in a form 3: action(FieldForward) ;Moves one field forward
The constants in the ActionMoveCommands category are used for positioning within a field object, as shown here:
Illustration 4
With these constants, you can move to the beginning or end of a field, move left one word, or scroll a field up or down. In general, these commands behave differently in a Memo field than they do in a set of fields. Following are three examples:
action(MoveEnd) ;Moves to the end of the document or ;to last field. action(MoveLeftWord) ;Moves cursor to word on the left. action(MoveScrollPageDown) ;Scrolls the page image down.
The ActionSelectCommands constants are similar to the ActionMoveCommands constants, but you use them to select data within a field object, as shown here:
Illustration 5
With these constants, you can select from the current position to the beginning of the document. Following are three examples:
1: action(SelectEnd) ;Select to the end. 2: action(SelectLeft) ;Selects one character to the left. 3: action(SelectSelectAll) ;Selects the entire document.
Browse through the online constants section by selecting View | ObjectPAL Quick Lookup and selecting the Constants tab. Select the categories whose names start with action. These constants are your gateway to more powerful data manipulation and, therefore, to more powerful applications.
Tip: If you find a constant that is not self-explanatory, search in the help for types of constants for a complete list of the constants along with a description for each.
In addition to executing action constants, you can trap for them. The basic idea is to use the action event and inspect the eventInfo variable. For example, to trap for when the form enters Edit mode, type lines 3–6 in the page’s action event.
1: ;Commands :: Pge1 :: action 2: method action(var eventInfo ActionEvent) 3: if eventInfo.id() = DataBeginEdit then 4: DoDefault ;Finish moving into edit mode. 5: beep() 6: msgInfo("Careful", "You are now in edit mode.") 7: endIf 8: endMethod
Another method in ObjectPAL that opens up a whole world of power is menuAction(). The menuAction() method enables you to execute any of the MenuCommand constants, shown next. Any time you want to execute or trap a menu-equivalent task, consider using the menuAction() method or menuActionevent.
Illustration 6
To display the Form Open dialog box, for example, add line 3 to the pushButton event of a button.
Just as you can trap for action constants, you can trap for MenuCommand constants. For example, to trap for the user pressing the Form Maximize button, add lines 3–5 to the menuAction event of a page.
The following table lists the action classes. As you can see, most action events do not bubble. In fact, only ActionDataCommands bubble. You can use eventInfo.actionClass() to return the class of an action event.
ActionEvent
Bubble?
Description of Action
ActionDataCommands
Yes
Deal with the whole form
ActionEditCommands
No
Deal with editing data
ActionFieldCommands
No
Move from field to field
ActionMoveCommands
No
Move the cursor within a field
ActionSelectCommands
No
Select data within a field
Identifying Action and Error Constants
Sometimes it is necessary to identify a constant. Either you need to trap for it or you want to execute it. Either way, finding the action constant that maps to a specific task can be daunting. Using constantValueToName() enables you to extract the name of a constant from a number. The syntax for constantValueToName() is as follows:
constantValueToName ( const groupName String, const value AnyType, var constName String ) Logical
This method is very helpful in developing an application when you want to know which actions are being triggered. The one weakness of this method is that you have to specify the group type. For example, you have to specify ActionDataCommand, ActionMoveCommand, Error, and so on.
The following code snippet from http://prestwood.com/forums/paradox/books/official/files/ID_Actions.fsl demonstrates how to extract the name of an action or error constant from eventInfo, as shown next. For demonstration purposes, this code is called from the action event of the form; this code displays every action generated and every error generated. It uses actionClass() to extract the class of action constant. It also demonstrates using a list object to scroll values. It uses a private custom procedure, which helps make it structured. (For more on structured programming, refer to Appendix A.)
Illustration 7
You can follow the actions I took in the illustration above. I first tried to insert a record and couldn’t because I wasn’t in Edit mode. This generated a peNotInEditMode error. I then toggled into Edit mode, moved to the Customer No field, entered a number, moved to the Name field and pasted a name in. Read through the code and see whether you can follow the logic; start from the method prototype line.
1: ;ID_Actions :: Form :: cmIdentifyConstant 2: proc cpDisplayConstant(sConstantType String, sConstant String) 3: ;Display constant class & constant in list field. 4: ;This procedure is used by cmIdentifyConstant. 5: beep() 6: ;lstConstant is a list object of a list field placed on the form. 7: lstConstant'list.selection = lstConstant'list.count + 1 8: lstConstant'list.value = sConstantType + " :: " + sConstant 9: endProc 10: 11: method cmIdentifyConstant(var eventInfo ActionEvent) 12: ;Identify constant. 13: var 14: sConstant String 15: siConstantType SmallInt 16: sConstantType String 17: siID SmallInt 18: endVar 19: 20: ;Check for an error. 21: if eventInfo.errorCode() <> peOk then 22: constantValueToName("Errors", eventInfo.errorCode(), sConstant) 23: cpDisplayConstant("ErrorCode", sConstant) 24: return 25: endIf 26: 27: ;Identify action constant. 28: siConstantType = eventInfo.actionClass() 29: siID = eventInfo.id() 30: switch 31: case siConstantType = DataAction 32: : sConstantType = "DataAction" 33: constantValueToName("ActionDataCommands", siID, sConstant) 34: case siConstantType = EditAction 35: : sConstantType = "EditAction" 36: constantValueToName("ActionEditCommands", siID, sConstant) 37: case siConstantType = FieldAction 38: : sConstantType = "FieldAction" 39: constantValueToName("ActionFieldCommands", siID, sConstant) 40: case siConstantType = MoveAction 41: : sConstantType = "MoveAction" 42: constantValueToName("ActionMoveCommands", siID, sConstant) 43: case siConstantType = SelectAction 44: : sConstantType = "SelectAction" 45: constantValueToName("ActionSelectCommands", siID, sConstant) 46: otherwise 47: : ;This should never get called. 48: sConstantType = "unknown" 49: sConstant = "unknown" 50: endSwitch 51: 52: cpDisplayConstant(sConstantType, sConstant) 53: endMethod
The following code calls the custom method. Notice that doDefault is called before eventInfo is passed to the custom method.
1: ;ID_actions.fsl :: Form :: action 2: method action(var eventInfo ActionEvent) 3: 4: if eventInfo.isPreFilter() then 5: ;// This code executes for each object on the form 6: ;// 7: DoDefault 8: cmIdentifyConstant(eventInfo) 9: else 10: ;// This code executes only for the form 11: ;// 12: 13: endIf 14: 15: endMethod
You might want to put a variation of the preceding custom method into your standard library—perhaps alter it to return the action constant. After you do this, you can use it from time to time when you code to determine an action constant name that is giving you problems.
Tip: To send a list of all the constants to a table, create and run the following one-line script: enumRTLConstants("CONST.DB") This script creates a table that has all constants, including all the error constants. Use this table to create reports in any order you like.
To manipulate the font attributes and text of a Memo field use the action() method. The basic technique is to pass the action() method an action constant:
object.action( ActionConstant )
For example, the following selects all the text in a Memo field:
Put the constant or number in the MenuAction field (the constant is always preferred). You can just click on the constant displayed below the Execute Menu Constant button.
Press the button to make sure it works.
Illustration 8
The interesting bit of code is in the page’s menuAction event and in the pushButton event of the button. The following is the code in menuAction that traps the menu constants:
1: ;MENUID :: page :: menuAction 2: method menuAction(var eventInfo MenuEvent) 3: var 4: s String 5: endVar 6: 7: if eventInfo.isPreFilter() then 8: ;// This code executes for each object on the form: 9: 10: else 11: ;// This code executes only for the form: 12: switch 13: case eventInfo.id() = MenuInit 14: : ;Occurs when the menu option is selected. 15: ;Do nothing. 16: case eventInfo.id() = MenuBuild 17: : ;Occurs when the menu is first built. 18: ;Do nothing. 19: case eventInfo.id() = MenuControlKeyMenu 20: : ;Menu selected via a key press. 21: ;Do nothing. 22: otherwise 23: : if fldDisplay.value = "Yes" then 24: constantValueToName("MenuCommands", eventInfo.id(), s) 25: msgInfo(eventInfo.id(), s) 26: endIf 27: endSwitch 28: constantValueToName("MenuCommands", eventInfo.id(), s) 29: fldStatus.value = s 30: endMethod
The following is the code in the pushButton event of the button that uses a try block to first try to execute a MenuCommand number and then uses a constant.
In this chapter, you learned you can imitate nearly any user interaction by sending action and menuAction constants to the action and menuAction events using the action() and menuAction() methods. In addition, you learned how to trap for most user interactions in the action and menuAction events. Finally, you learned how to use the ID_Action and MenuID forms to identify action and menuAction constants.