Creating a Modal Popup Object
Here is the approach for designing and creating a modal task. First, you define the problem and design an interface to perform the task. Let's say that we need to know if it is proper to accept overtime hours. Our interface might look like the following:
Object Name:
overtime
Function:
ApproveOvertime
returns Boolean
Return:
True if approved, False if denied
This is all we need to know to use this object in our program. The procedure initiating the modal task would look like the following:
Procedure Process_Hours number iTotalHours
Boolean bResponse
Number nOTHours
If (iTotalHours > 40) Begin
Get ApproveOvertime of oOvertime to bResponse
If (bResponse) ;
Move (iTotalHours - 40) to nOTHours // hours approved
Else ;
Move 0 to nOTHours // hours not approved
Move 40 to iTotalHours
End
Send EnterHours iTotalHours nOTHours
End_Procedure
At this point, we only worry about the interface. We have an object named overtime that understands the message ApproveOvertime. It will perform a task and return a result. At this level, this is all we need to know. We do not even know if the task involves user interaction or not. This is the responsibility of the task object. That level of detail should be hidden from the rest of the program (it is encapsulated).
We will look at three completely different methods of handling the task. These are all valid and completely interchangeable.
Option 1: Non-user-interface - Return an answer based on existing data.
Object oOvertime is a cObject // use a simple class
// Do not allow if employee.ot_type = "S" (salaried)
Function ApproveOvertime returns Boolean
If (Employee.ot_type = "S") ;
Function_Return False
Else ;
Function_Return True
End_Function
End_Object
Option 2: Pass the buck chain wait to another program which may or may not perform a UI task.
If it is a UI task, it will be modal since a chain waited program cannot interact with its parent program. This method is not necessarily recommended. It is included because this is a method that procedural DataFlex developers use all the time.
Object Overtime is a cObject
Function ApproveOvertime returns Boolean
Chain_Wait "ot_pgm" export_files
// use some time-honored procedural trick to figure out what happened
// in the chain-waited program and return a status_value.
Function_Return status_value
End_Function
End_Object
Option 3: Require user input - Create and use a modal popup object.
To do this, we must do the following:
- Make sure the object is a modal-popup object. This is simple—we should base the object on the ModalPanel or dbModalPanel class.
- Pop up the object. We send the message
popupto do this. - When finished with the object, send
close_panel. - Figure out what happened and return a status value.
You could do this as follows:
Object Overtime is a ModalPanel
// we use this to track the return value
Property Boolean pbOvertimeOk
Set Label to "Allow Overtime?"
Set Size to .. ..
// note that modal panels will locate automatically
// Let's assume that OT_is_Good and OT_is_Bad should complete the popup
Procedure AcceptOk
Set pbOvertimeOk to True // mark this property as OK
Send Close_Panel // and close the panel
End_Procedure
Object oOTButton is a Button
Set Location to .. ..
Set Label to "OT is OK"
Procedure OnClick
Delegate Send AcceptOk // we define this message
End_Procedure
End_Object
Object oNoOTButton is a Button
Set Location to .. ..
Set Label to "No OT"
Procedure OnClick
Delegate Send Close_Panel // this is understood by ModalPanel
End_Procedure
End_Object
Function ApproveOvertime returns Integer
Boolean bResponse
Set pbOvertimeOk to False // set a default value of no OT
Send Popup // This may change pbOvertimeOk
Get pbOvertimeOk to bResponse
Function_Return bResponse
End_Function
End_Object
This example presents the suggested structure for all modal pop-up objects. Please note the following:
- If the object is modal (based on ModalPanel, dbModalPanel, or the property Modal_State is set to true), the object is invoked when it is sent the message
popup. - Whenever possible, do not send the
popupmessage from outside of the object. Instead, create a public message that performs the desired task. In this sample, our task was not to pop up a modal object; our task was to determine if overtime was allowed. An interface should reflect an object’s purpose, not its function. - A modal panel is closed by sending the message close_panel. This message is also sent automatically by other operations like clicking on the Close button in the panel’s upper right-hand corner.
The best way to determine what happened within a modal panel is to have object data (i.e., a property) which can be inspected after the popup is complete. In this sample, we created a status property which was initialized to 0 upon start-up and is only set to 1 if the Ok button is selected.
Finally, notice that this was designed starting with the interface. The object that started this (invoked the prompt) is not responsible for any of this. It simply asks an object a question through an agreed-upon interface. It has no idea how the response will be generated. It is asking a question of a black box.
If you design your interface first and then worry about implementation, everything becomes much easier.