Summary:
See also: Built-in classes, Interaction Model, Multiple Dialogs, Windows and Forms
The Dialog class is a built-in class that provides an interface to an interactive instruction such as INPUT.
ui.Dialog
Class Methods | |
Name | Description |
setDefaultUnbuffered( v INTEGER ) |
Sets the default of the UNBUFFERED attribute for the next dialogs. |
Object Methods | |
Name | Description |
accept( ) |
Validates all dialog fields. |
appendRow( arrname
STRING ) |
Append a row at the end of the list. |
deleteRow( arrname
STRING, pos INTEGER
) |
Deletes row at position pos. |
getArrayLength( arrname STRING
) RETURNING INTEGER |
Returns the total number of rows in a list. |
getCurrentItem(
) RETURNING STRING |
Returns the current item having the focus. This can be a field, list or action. |
getCurrentRow( arrname STRING
) RETURNING INTEGER |
Returns the current row of a list. |
getFieldBuffer( fieldname STRING
) RETURNING STRING |
Returns the current input buffer of the field identified by fieldname. |
getFieldTouched( fieldname STRING
) RETURNING STRING |
Returns TRUE if the TOUCHED flag of the specified field is set. |
getForm() RETURNING ui.Form |
Returns the current form used by this dialog. |
insertRow( arrname
STRING, pos INTEGER
) |
Inserts a row before position pos. |
nextField(
fieldname STRING ) |
Registers the name of the next field that must get the focus when control returns to the dialog. |
setArrayLength( arrname STRING,
v INTEGER
) |
Sets the total number of rows in a list for paged mode. |
setActionHidden( actname STRING,
v INTEGER
) |
Hides or shows the default action view identified by actname. |
setActionActive( actname STRING,
v INTEGER ) |
Enables or disables the action identified by actname. |
setCurrentRow( arrname STRING,
row INTEGER) |
Change the current row in a list. |
setFieldActive( fieldname STRING,
v INTEGER ) |
Enables or disables the field identified by fieldname. |
setFieldTouched( fieldname STRING,
v INTEGER ) |
Sets the TOUCHED flag of the field identified by fieldname. |
setCellAttributes( attarr ARRAY OF RECORD
) |
Defines decoration attributes for each cell (singular dialogs only). |
setArrayAttributes( arrname
STRING, attarr
ARRAY OF RECORD
) |
Defines decoration attributes for each cell (multiple dialogs). |
This class provides an interface to the interactive instructions INPUT, INPUT ARRAY, DISPLAY ARRAY, CONSTRUCT, and MENU.
The DIALOG keyword is a pre-defined object variable. To get an instance of this class, use DIALOG inside the interactive instruction block:
01
INPUT BY NAME custid, custname02
ON ACTION disable03
CALL DIALOG.setFieldActive("custid",0)04
END INPUT
The dialog object is only valid during the execution of the interactive instruction. Using the DIALOG keyword outside a dialog instruction block results in a compilation error. However, you can pass the object to a function, in order to write common dialog configuration code:
01
INPUT BY NAME custid, custname02
BEFORE INPUT03
CALL setupDialog(DIALOG)04
END INPUT05
06
FUNCTION setupDialog(d)07
DEFINE d ui.Dialog08
IF user_group = "admin" THEN09
CALL d.setActionActive("delete",1)10
CALL d.setActionActive("convert",1)11
ELSE12
CALL d.setActionActive("delete",0)13
CALL d.setActionActive("convert",0)14
END IF15
END FUNCTION
You can use the accept()
method to validate field input and
terminate the dialog. This method is equivalent to the ACCEPT INPUT / ACCEPT
DISPLAY / ACCEPT DIALOG instructions. The method is provided as a
3GL alternative to the ACCEPT control instructions, if you need for
example to terminate the dialog in a function, outside the context of a dialog
block, where control instructions cannot be used.
See ACCEPT DIALOG for more details.
The getArrayLength()
method can be used to retrieve the total
number of rows of an INPUT ARRAY or DISPLAY ARRAY list. You must pass the
name of the screen array to identify the list:
01
DIALOG02
DISPLAY ARRAY custlist TO sa_custlist.*03
BEFORE ROW04
MESSAGE "Row count: " || DIALOG.getArrayLength("sa_custlist")05
...06
END DISPLAY07
INPUT ARRAY ordlist TO sa_ordlist.*08
BEFORE ROW09
MESSAGE "Row count: " || DIALOG.getArrayLength("sa_ordlist")10
...11
END INPUT12
...
The setArrayLength()
method is used to specify the total number
of
rows of an INPUT ARRAY or DISPLAY ARRAY list when using the paged
mode. You must pass the
name of the screen array to identify the list, followed by an integer expression
defining the number of rows. When using a dynamic array
without ON FILL BUFFER you don't need to
specify the total number of rows to the DIALOG instruction: It is
defined by the number of elements in the array. However, when using the paged
mode in a DISPLAY ARRAY, the total number of rows does not
correspond to the elements in the program array, because the program array holds
only a page of the whole list. In any other cases, a call to this method is just
ignored.
The nextField()
method can be used register the name of the next
field that must get the focus when control goes back to the dialog. This method
is similar to the NEXT FIELD
instruction, except that it does not implicitly break the program flow. If
you want to get the same behavior as NEXT FIELD, the method call must
be followed by a CONTINUE DIALOG / INPUT / CONSTRUCT instruction.
Since this method takes an expression as parameter, you can write generic
code, when the name of the target field is not known at compile time. In the
next example, the check_value()
function returns a field name where
the value does not satisfy the validation rules:
01
DEFINE fn STRING02
...03
ON ACTION save04
IF ( fn := check_values() ) IS NOT NULL THEN05
CALL DIALOG.nextField(fn)06
CONTINUE DIALOG07
END IF08
CALL save_data()09
...
The getCurrentRow()
method can be used to retrieve the current
row of an INPUT ARRAY or DISPLAY ARRAY list. You must pass the
name of the screen array to identify the list:
01
DIALOG02
DISPLAY ARRAY custlist TO sa_custlist.*03
BEFORE ROW04
MESSAGE "Current row: " || DIALOG.getCurrentRow("sa_custlist")05
...06
END DISPLAY07
INPUT ARRAY ordlist TO sa_ordlist.*08
BEFORE ROW09
MESSAGE "Current row: " || DIALOG.getCurrentRow("sa_ordlist")10
...11
END INPUT12
...
If you want to change the current row in an INPUT ARRAY or DISPLAY
ARRAY list, you can use the setCurrentRow()
method. You must
pass the name of the screen array to identify the list, and the new row number:
01
DEFINE x INTEGER02
DIALOG03
DISPLAY ARRAY custlist TO sa_custlist.*04
...05
END DISPLAY06
ON ACTION goto_x07
CALL DIALOG.setCurrentRow("sa_custlist", x)08
...
Note that moving to a different row with setCurrentRow()
will
not trigger control blocks
such as AFTER ROW. This method will not set the focus either; You need
to use NEXT FIELD to set the focus to a list (this works with DISPLAY
ARRAY as well as with INPUT ARRAY).
The getCurrentItem()
method returns the name of the current form
item having the focus. This can be a simple field, a list or an action view.
getCurrentItem()
returns the name of the
corresponding action. Note that if several action views a bound to the same
action handler with a unique name, there is no way to distinguish which
action view has the focus.getCurrentItem()
returns the field-name of that
current field.getCurrentItem()
returns the screen-array
name identifying the list.getCurrentItem()
returns screen-array.field-name,
identifying both the list and the current field.The getFieldBuffer()
method returns the current input buffer of
the specified field. The input buffer is used by the dialog to synchronize form
fields and program variables. In some situations, especially when using the BUFFERED
mode or in a CONSTRUCT, you may want to access
that input buffer.
The fieldname is a string containing the field qualifier, with an
optional prefix ("[table.]column
").
01
LET buff = DIALOG.getFieldBuffer("customer.cust_name")
The input buffer can be set with:
The getFieldTouched()
method returns TRUE if the TOUCHED
flag of the specified field is set.
The fieldname is a string containing the field qualifier, with an
optional prefix ("[table.]column
"), or a table
prefix followed by a dot and a start ("table.*
").
01
AFTER FIELD cust_name02
IF DIALOG.getFieldTouched("customer.cust_address") THEN03
...
If the parameter is a screen record following by dot-star, the method checks the touched flags of all the fields that belong to the screen record:
01
ON ACTION quit02
IF DIALOG.getFieldTouched("customer.*") THEN03
...
The setFieldTouched()
method can be used to change the TOUCHED
flag of the specified field(s).
The fieldname is a string containing the field qualifier, with an
optional prefix ("[table.]column
"), or a table
prefix followed by a dot and a start ("table.*
").
You typically use this method to set the touched flag when assigning a
variable, to emulate a user input. Remember when using the UNBUFFERED
mode, you don't need to DISPLAY
the value to the fields. The setFieldTouched()
method is provided
as a 3GL replacement for the DISPLAY
instructions to set the touched flags.
01
ON ACTION zoom_city02
LET p_cust.cust_city = zoom_city()02
CALL DIALOG.setFieldTouched("customer.cust_city", TRUE)03
...
If the parameter is a screen record following by dot-star, the method checks the touched flags of all the fields that belong to the screen record. You typically use this to reset the touched flags of a group of fields, after modifications have been saved to the database, to get back to the initial state of the dialog:
01
ON ACTION save02
CALL save_cust_record()03
CALL DIALOG.setFieldTouched("customer.*", FALSE)04
...
Note that the touched flags are reset to false when using an INPUT ARRAY list, every time you leave the modified row.
The getForm()
method returns a ui.Form
object as a handle to the current form used by the dialog. Use this form object to
modify elements of the current form. For example, you can hide some parts of the
form with the ui.Form.setElementHidden() method.
The runtime system is able to detect hidden fields and exclude them from the
input list. See Example 2.
Dialog actions can be enabled and disabled with the setActionActive()
dialog method:
01
BEFORE DIALOG02
CALL DIALOG.setActionActive("zoom",FALSE)
In GUI applications,
push-buttons triggering actions should normally be disabled if the current
context / situation makes the corresponding action invalid or unusable. For
example, a "print" button should be disabled if there is nothing to
print. The setActionActive()
method is typically used to
enable/disable actions according to the context.
The action name must be passed in lowercase letters. Note that sub-dialog
actions can be qualified with the sub-dialog prefix within a DIALOG
instruction. When the setActionActive()
method is called in the
context of the sub-dialog, the prefix can be omitted.
The second parameter of the method must be a boolean expression that evaluates to 0 (FALSE) or 1 (TRUE).
To simplify action activation, you can write a common "setup" function which centralizes all rules to enable/disable actions. This function can then be called from any place in the DIALOG instruction, passing the DIALOG object as parameter. See Example 3.
In the DIALOG instruction,
actions can be prefixed with the sub-dialog identifier. The setActionActive()
method can be take a full-qualified action name as parameter.
Form fields used by the dialog can be enabled/disabled with the setFieldActive()
method. The fields are identified by the field name used in the dialog, with an
optional table prefix ("column
", "table.column
"
or "formonly.field
"). When a
field is disabled, it is still visible, but the user cannot edit the value.
01
ON CHANGE cust_name02
CALL DIALOG.setFieldActive( "customer.cust_addr", (rec.cust_name IS NOT NULL) )
See also Example 1.
The insertRow()
method is
just a basic row creation function, to insert a row in the list at a given
position. It does not set the current row or raise any
BEFORE ROW / BEFORE INSERT / AFTER INSERT / AFTER
ROW control blocks. It is quite similar to inserting a new element in the
program array, except the internal registers are automatically updated (like the
total number of rows returned by getArrayLength()).
If the list was decorated with cell attributes, the program array defining the
attributes will also be synchronized.
Warning: This method should not be called in control blocks such as BEFORE ROW, AFTER ROW, BEFORE INSERT, AFTER INSERT, BEFORE DELETE, AFTER DELETE, but it can safely be used in an ON ACTION block.
TO REMOVE: Default values defined in the form file with the DEFAULT attribute are applied when calling this method.
After the method is called, a new row is created in the program array, so you
can assign values to the variables before the control goes back to the user. The
getArrayLength()
method will return the new row count.
Note that the method does not set the current row and does not give the focus to the
list; you need
to call setCurrentRow()
and execute NEXT FIELD
if you want to give the focus.
The method takes two parameters:
If the index is greater as the number of
rows, a new row will be appended at the end or the list. This will be equivalent
to call the appendRow()
method.
Warning: If the list is empty, getCurrentRow() will return zero. So you must test this and use 1 instead to reference the first row otherwise you can get -1326 errors when using the program array.
Following code example shows a user-define action to insert ten rows in the list at the current position:
01
ON ACTION insert_some_rows02
LET r = DIALOG.getCurrentRow("sa")03
IF r == 0 THEN LET r = 1 END IF04
FOR i = 10 TO 1 STEP -105
CALL DIALOG.insertRow("sa", r)06
LET p_items[r].item_quantity = 1.0007
END FOR
The appendRow()
method is
just a basic row creation function to append a row to the end of the list. It does not set the current row or raise any
BEFORE ROW / BEFORE INSERT / AFTER INSERT / AFTER
ROW control blocks. It is quite similar to appending a new element to the
program array, except the internal registers are automatically updated (like the
total number of rows returned by getArrayLength()).
If the list was decorated with cell attributes, the program array defining the
attributes will also be synchronized.
Warning: This method should not be called in control blocks such as BEFORE ROW, AFTER ROW, BEFORE INSERT, AFTER INSERT, BEFORE DELETE, AFTER DELETE, but it can safely be used in an ON ACTION block.
TO REMOVE: Default values defined in the form file with the DEFAULT attribute are applied when calling this method.
After the method is called, a new row is created in the program array, so you
can assign values to the variables before the control goes back to the user. The
getArrayLength()
method will return the new row count.
Note that the method does not set the current row and does not give the focus to the
list; you need
to call setCurrentRow()
and execute NEXT FIELD
if you want to give the focus.
The appendRow()
method does not create a temporary
row as the implicit append action of INPUT ARRAY; The row is
considered as permanent once it is added.
The method takes only one parameter:
Following code example implements a user-defined to append ten rows at the end of the list:
01
ON ACTION append_some_rows02
FOR i = 1 TO 1003
CALL DIALOG.appendRow("sa")04
LET r = DIALOG.getArrayLength("sa")05
LET p_items[r].item_quantity = 1.0006
END FOR
The deleteRow()
method is
just a basic row deletion function. It does not reset the current row or raise
any BEFORE DELETE / AFTER DELETE / AFTER ROW / BEFORE
ROW control blocks (except in some particular situation as described
below). It is quite similar to deleting an element to the
program array, except that internal registers are automatically updated (like
the total number of rows returned by getArrayLength()).
If the list was decorated with cell attributes, the program array defining the
attributes will also be synchronized.
Warning: This method should not be called in control blocks such as BEFORE ROW, AFTER ROW, BEFORE INSERT, AFTER INSERT, BEFORE DELETE, AFTER DELETE, but it can safely be used in an ON ACTION block.
After the method is called, the row does no more exist in the program array,
and the getArrayLength()
method will return the new row count.
If the deleteRow()
method is called during an INPUT
ARRAY, and after the call no more rows are in the list, the dialog will
automatically append a new temporary
row if the focus is in the list, to let the user enter new data.
When using AUTO APPEND = FALSE attribute, no temporary row will be created
and the current
row register will be automatically changed to make sure that it will not be greater as
the total number of rows.
If deleteRow()
method is called during an INPUT
ARRAY or DISPLAY ARRAY that has the focus, the BEFORE ROW
control block will be executed if you delete the current row. This is required
to reset the internal state of the dialog.
The method takes two parameters:
If you pass zero as row index, the method does nothing (if no rows are in the
list, getCurrentRow()
returns zero).
Following code example implements a user-defined action to remove the rows that have a specific property:
01
ON ACTION delete_invalid_rows02
FOR r = 1 TO DIALOG.getArrayLength("sa")03
IF NOT s_orders[t].is_valid THEN04
CALL DIALOG.deleteRow("sa",r)05
LET r = r - 106
END IF07
END FOR
The deleteAllRows()
method removes all the rows of a list driven by a DISPLAY ARRAY or INPUT
ARRAY. This is equivalent to a deleteRow()
call, but instead
of deleting one particular row, it removes all rows of the specified list.
Warning: This method should not be called in control blocks such as BEFORE ROW, AFTER ROW, BEFORE INSERT, AFTER INSERT, BEFORE DELETE, AFTER DELETE, but it can safely be used in an ON ACTION block.
After the method is called, all rows are deleted from the program array,
and the getArrayLength()
method will return zero.
The method takes the name of the screen-array as parameter.
If the deleteAllRows()
method is called during an INPUT
ARRAY, the dialog will automatically append a new temporary
row if the focus is in the list, to let the user enter new data.
When using AUTO APPEND = FALSE attribute, no temporary row will be created
and the current
row register will be automatically changed to make sure that it will not be greater as
the total number of rows.
If deleteAllRows()
method is called during an INPUT
ARRAY or DISPLAY ARRAY that has the focus, the BEFORE ROW
control block will be executed if you delete the current row. This is required
to reset the internal state of the dialog.
In order to execute NOT NULL, REQUIRED
and INCLUDE validation rules defined
in the form specification files, you can call
the validate()
method by passing a list of fields or screen records
as parameter. The method returns zero if success and the input error code of the
first field which does not satisfy the validation rules.
Note that the current field is always checked, even if it is not part of the validation field list. This is mandatory, otherwise the current field may be left with invalid data.
If an error occurs, the validate()
method automatically displays
the corresponding error message, and registers the next
field to jump to when the interactive instruction gets the control back.
Warning: The validate() method does not stop code execution if an error is detected. You must execute a CONTINUE DIALOG or CONTINUE INPUT instruction to cancel the code execution.
A typical usage is for a "save" action:
01
ON ACTION save02
IF DIALOG.validate("cust.*") < 0 THEN03
CONTINUE DIALOG04
END IF05
CALL customer_save()
The Default View on an
action can made visible or invisible with the setActionHidden()
dialog method:
01
ON ACTION hide02
CALL DIALOG.setActionHidden( "confirm", 1 )
Values of the second parameter can be 1 or 0.
By default dialogs are not sensitive to variable changes. To make a dialog
sensitive, use the UNBUFFERED attribute in the dialog
instruction definition. However, you can define the default for all subsequent dialogs
by using the setDefaultUnbuffered()
class method:
01
CALL ui.Dialog.setDefaultUnbuffered(TRUE)
In an INPUT ARRAY or DISPLAY
ARRAY instruction, the setArrayAttributes()
method can be used to specify display attributes for each cell. You must define
an array with the same number of record elements as the data array used by the INPUT
ARRAY or DISPLAY ARRAY. Each element must have the same name as in
the data array, and must be defined with a character data type (you typically
use STRING).
Fill the display attributes
array with color and video attributes. These must be specified in lowercase
characters and
separated by a blank (ex: "red reverse"). Then, pass the
array to the dialog with the setArrayAttributes()
method, in a BEFORE INPUT or BEFORE DISPLAY block. Display
attributes can be changed dynamically during the dialog:
01
ON ACTION set_attributes02
CALL DIALOG.setArrayAttributes( "sr", attarr )
For a complete example, see Example 4.
An equivalent method called setCellAttributes()
,
takes only the program array as argument. The setCellAttributes()
method is designed for singular dialogs, where only one screen array is
used.
01
FUNCTION input_customer()02
DEFINE custid INTEGER03
DEFINE custname CHAR(10)04
INPUT BY NAME custid, custname05
ON ACTION enable06
CALL DIALOG.setFieldActive("custid",1)07
ON ACTION disable08
CALL DIALOG.setFieldActive("custid",0)09
END INPUT10
END FUNCTION
01
FUNCTION input_customer()02
DEFINE f ui.Form03
DEFINE custid INTEGER04
DEFINE custname CHAR(10)05
INPUT BY NAME custid, custname06
BEFORE INPUT08
LET f = DIALOG.getForm()09
CALL f.setElementHidden("customer.custid",1)10
END INPUT11
END FUNCTION
01
FUNCTION input_customer()02
DEFINE custid INTEGER03
DEFINE custname CHAR(10)04
INPUT BY NAME custid, custname05
BEFORE INPUT06
CALL setup_dialog(DIALOG)07
END INPUT08
END FUNCTION09
10
FUNCTION setup_dialog(d)11
DEFINE d ui.Dialog12
CALL d.setActionActive("print",user.can_print)13
CALL d.setActionActive("query",user.can_query)14
END FUNCTION
01
FUNCTION display_customer()02
DEFINE i INTEGER03
DEFINE arr DYNAMIC ARRAY OF RECORD04
key INTEGER,05
name CHAR(10)06
END RECORD07
DEFINE att DYNAMIC ARRAY OF RECORD08
key STRING,09
name STRING10
END RECORD11
12
FOR i=1 TO 1013
CALL arr.appendElement()14
LET arr[i].key = i15
LET arr[i].name = "name " || i16
CALL att.appendElement()17
IF i MOD 2 = 0 THEN18
LET att[i].key = "red"19
LET att[i].name = "blue reverse"20
ELSE21
LET att[i].key = "green"22
LET att[i].name = "magenta reverse"23
END IF24
END FOR25
26
DIALOG ATTRIBUTES(UNBUFFERED)27
DISPLAY ARRAY arr TO sr.*28
ON ACTION att_set29
CALL DIALOG.setArrayAttributes("sr", att)30
ON ACTION att_clear31
CALL DIALOG.setArrayAttributes("sr", NULL)32
END DIALOG33
34
END FUNCTION