Object Events
Many events are triggered by Alpha Five objects, such as buttons, fields, and forms. The object events are generally triggered in response to the cursors movements into and out of the object (i.e., the changing of focus from one place to another).
Events for Button Objects
A button object can have scripts attached to the following events:
|
Event Name |
Description |
|
The button is pressed. Use to run a script. | |
|
The button gets focus. | |
|
The button looses focus. | |
|
Just before the button gets focus. | |
|
Just before the button looses focus. | |
|
When the mouse is over the object. Use to change the field's colors or display a message. | |
|
When the mouse pointer is no longer over the object. |
Scripts are generally attached to a buttons OnPush event.
The following sequence of events were generated when an operator moved the cursor to a button, clicked it, and moved the cursor off the button.
Sequence of Events for Buttons
|
|
Event Name |
Type |
|
Event Name |
Type |
|
1 |
Control |
5 |
Control | ||
|
2 |
Control |
6 |
Control | ||
|
3 |
Control |
7 |
Form | ||
|
4 |
Control |
8 |
Control |
Events for Type-In Objects
The following events are triggered by all forms of the type-in object: Type-In, List boxes, Drop-Down lists, Radio buttons, Check boxes, Two-state, and Multi-state buttons:
|
Event Name |
Occurs When |
|
The contents of the field object are changed. Use to detect when the field has been changed. | |
|
The field gets focus. | |
|
The field looses focus. | |
|
Just before the field gets focus. | |
|
Just before the field looses focus. | |
|
When the mouse is over the object. Use to change the field's colors or display a message. | |
|
When the mouse pointer is no longer over the object. |
For type-in fields, the OnChange event fires when the control looses focus. For radio button, two-state button, multi-state button, and list box fields, the OnChange event fires as soon as the fields value changes.
For example, assume that you have a form with an Account_Number field. If the user makes a change to the value in this field, you want to be sure that this change was made intentionally, and not by mistake. If the user confirms that the change was intentional, the changed value is retained. Otherwise, the initial value is restored. To do this, scripts must be attached to the fields OnArrive and OnChange events. A flag variable is used to prevent the OnChange script from playing back a second time when the initial value is restored.
The following script is attached to the Account_Number fields OnArrive event:
|
dim flag as L dim SHARED init_valueAS C 'Set a variable to the initial value in account_number init_value= account_number.value 'Set the flag variable to .T. flag = .T. |
The script for the OnChange event is:
|
if flag then code = ui_msg_box("Warning", "You have changed the value in this field. Are you sure you want to change the value? ", UI_OK_SELECTED + UI_QUESTION_SYMBOL) if (code = 2) then 'User selected Cancel button this.value = init_value this.refresh() flag = .F. end if end if |
The following example shows how the forms tab order can be dynamically controlled. In this example, the script is attached to the OnDepart event for the Same_shipping field:
|
If same_shipping.value = .T. then Ship_via.activate() Else Ship_Address.activate() End if |
The following sequence of events were generated when an operator placed the cursor in a type-in field, changed its contents, and moved the cursor to a different field.
Sequence of Events for Type-In Fields
|
|
Event Name |
Type |
|
Event Name |
Type |
|
1 |
Control |
7 |
Field | ||
|
2 |
Control |
8 |
Control | ||
|
3 |
Field |
9 |
Control | ||
|
4 |
Field |
10 |
Field | ||
|
5 |
Control |
11 |
Control | ||
|
6 |
Control |
|
|
|
The following sequence of events were generated when an operator placed the cursor on a check box, clicked it, and moved the cursor off it.
Sequence of Events for Check Boxes
|
|
Event |
Type |
|
Event |
Type |
|
1 |
Control |
7 |
Table | ||
|
2 |
Field |
8 |
Table | ||
|
3 |
Control |
9 |
Field | ||
|
4 |
Field |
10 |
Control | ||
|
5 |
Control |
11 |
Form | ||
|
6 |
Control |
|
|
|
The following sequence of events were generated when an operator moved the cursor to a radio button, selected it, clicked one of the buttons, and moved the cursor off it.
Sequence of Events for Radio Buttons
|
|
Event Name |
Type |
|
Event Name |
Type |
|
1 |
Control |
7 |
Form | ||
|
2 |
Field |
8 |
Field | ||
|
3 |
Control |
9 |
Control | ||
|
4 |
Field |
10 |
Control | ||
|
5 |
Control |
11 |
Field | ||
|
6 |
Control |
12 |
Control |
Events for Image Reference Fields
The following events are triggered by image reference fields:
|
Event Name |
Occurs When |
|
OnChange |
When new images are added |
|
OnArrive |
The field gets focus. |
|
OnDepart |
The field looses focus. |
|
CanArrive |
Just before the field gets focus. |
|
CanDepart |
Just before the field looses focus. |
|
OnFlyover |
When the mouse pointer is over the object. |
|
OnFlyover_leave |
When the mouse pointer is no longer over the object. |
Events for Browse Objects
The browse object triggers the following events:
Note : Placing a browse
on a form creates the browse object. There are no
events for stand alone browse windows, only browse objects on forms.
|
Event Name |
Occurs When |
|
When the browse object is exited. This will occur after the form that encloses the browse object is closed. | |
|
When the browse object is created. This will occur after the form that encloses the browse object is instantiated. | |
|
When the browse is re-synchronized (i.e. when Alpha Five fetches a record). Whenever the user navigates to a new row in the browse, this event and the OnRowChange event will fire. However, the OnFetch event will also fire if the browse is re-synchronized without navigating to a new row. | |
|
Just before you navigate to a new row. | |
|
When you navigate to a new row in the browse. | |
|
When you double click on a row selector. If the browse object is read only, then this event will fire if you double click within the row. | |
|
Before the browse object on the form gets focus. | |
|
Before the browse object on the form can loose focus. | |
|
Before a record in the browse is saved (V8). |
|
|
After the browse object on the form has got focus. | |
|
After the browse object on the form has lost focus. | |
|
After a record in the browse is saved (V8). |
|
| OnChange |
Fires when data in a browse column is changed (V8). Events can be defined for
each column in the browse. Event handlers for this event are defined by creating
specially named functions in the generic 'Events' event. Function name is of the
form <Column>_onChange. For example, here is how to define an event
handler for the 'lastname' column in a browse: 1. Edit the 'Events' event. 2. Define the following function ('this' is an alias that refers to the browse object that contains the browse column): function lastname_OnChange as v () ui_msg_box("On Change Event for Browse. Browse name is: ",this.name()) end function
|
| TitleClick | Fires when a browse column is clicked. To enable this event, you must first set the 'Column title click behavior' to 'Click fires user event' (see Browse properties). Event handlers for this event are defined by creating specially named functions in the generic 'Events' event. Function name is of the form <Column>_TitleClick. See the 'OnChange' event for more information on how to create event handlers. |
In the following example, assume you have a table called Customers. You have a form for this table that shows a browse view of your records. When you double click on a row in the browse, a form called Customer_dlg is opened as a dialog allowing you to edit the record.
|
'Open "customer_dlg" invisibly frm = :form.load("customer_dlg", "dialog") 'Set a variable to the current record's customer Id value cust_id = parent:browse1:cust_id.value 'Set the index on the "customer_dlg" form frm.index_set("cust_id") 'Find the correct record frm.find(cust_id) 'Show the dialog box this also automatically activates it frm.show() 'When the user closes the dialog box, the dialog is not really 'closed. It must be closed with the close() method. frm.close() |
In the following example, a script attached to the CanDepart event causes a calculated field in the parent table to update when focus leaves the embedded browse. Consider the sample Invoice application that ships with Alpha Five. Say you wanted to have a summary field in the invoice_header table that summarized the extended totals in the child invoice_items table. Assume that you had a field in the invoice_header table called summary (numeric 12,2), and had defined the following calculated field rule for this field:
|
dbsum("invoice_items", "invoice_number", INVOICE_NUMBER, "extension") |
While this expression is correct, you would find that the field was not displaying the correct value when you entered new line items into the embedded browse. The reason for this is that calculated fields only evaluate when a record is in change or enter mode, and when you are entering line item records, the invoice_header table is in view mode, not change or enter.
By putting this script on the embedded forms CanDepart event, you can force the calculated fields in the invoice_header table to recalculate:
|
parentform.commit() t = table.current() t.change_begin() t.change_end(.T.) parentform.resynch() |
The following sequence of events were generated when an operator moved the cursor to a embedded browse, selected a row, changed one of the entries, and moved the cursor off the embedded browse.
Sequence of Events for Embedded Browses
|
|
Event Name |
Type |
|
Event Name |
Type |
|
1 |
Control |
11 |
Record | ||
|
2 |
Control |
12 |
Form | ||
|
3 |
Control |
13 |
Record | ||
|
4 |
Form |
14 |
Record | ||
|
5 |
Control |
15 |
Field | ||
|
6 |
Form |
16 |
Control | ||
|
7 |
Control |
17 |
Control | ||
|
8 |
Field |
18 |
Field | ||
|
9 |
Field |
19 |
Record | ||
|
10 |
Record |
20 |
Record |
Events for Forms
The following events are triggered when you display, leave, or work with a form:
|
Event Name |
Occurs When |
|
AskSaveChange |
When the user attempts to close a form before committing changes to a changed record. Allows the programmer to customize the dialog that the user sees when aborting a record. (See AskSaveChange and AskSaveEnter Events below for more details). |
|
AskSaveEnter |
When the user attempts to close a form before committing changes to a new record. Allows the programmer to customize the dialog that the user sees when aborting a record. (See AskSaveChange and AskSaveEnter Events below for more details). |
|
CanChange |
Before a control on a form is edited. The CanChange event only fires if:
The CanChange event will not occur after changes to a record had been saved. |
|
CanExit |
Before the form is closed. You can prevent the form (and therefore Alpha Five as well) from being closed by including the CANCEL()command in the script attached to this event. This event is not fired when you close the form or browse with the .CLOSE() method unless you set its argument to .F. . Note the following limitation: If you have multiple forms open, each of which has a CanExit event, and you click the X on the main window frame, only the CanExit event of the first window that was opened will fire. |
|
CanSave |
Before the record is saved. Note that there is also a CanSaveRecord field rule event. However, if you cancel the CanSaveRecord event, the pending record is lost. If you cancel this event, the record is not saved, but the pending record is preserved, allowing the user to make necessary corrections before trying to save the record again. |
|
The form window is activated (given focus). | |
|
OnDeactivate |
The form window is deactivated (focus is sent to another window). |
|
OnEnter |
The form is put in Enter mode to enter a new record. |
|
OnExit |
The form is closed. |
|
A record is retrieved from the current table or set. | |
|
OnInit |
The form is opened. |
|
OnKey |
Whenever a key is pressed while the form has focus. Variables set:
For example, the following OnKey script will close Alpha Five when the user presses Alt-X: If (A_USER.KEY.VALUE = "{%X}") then If (A_USER.KEY.EVENT = "down") then :a5.close() End if End if TIP : To see how Alpha Five represents different key combinations, define the following OnKey script for a form, then open the trace window and try out different key combinations: trace.writeln("key: " + A_USER.KEY.VALUE + " event: " + A_USER.KEY.EVENT) See Also Script Recorder, Closing a Form with the ESC Key, Running a Script with a Function Key |
|
OnSave |
The record that is being edited is saved. |
|
OnTimer |
The timer interval has elapsed. The timer interval for a form is set by editing the form, selecting Form, Properties and setting a timer interval. For example, if the timer interval is set to 5 seconds, the OnTimer script will execute every five seconds. |
Note : The following
example is obsolete in V5 because you can now select Modal/Modeless data
entry as a property of each Form or Browse layout. The example
is nevertheless still interesting since it describes a use for the OnFetch event.
The following example shows how the OnFetch event can be used to turn off Alpha Fives modeless data entry. Modeless data entry allows the user to just start typing a new value in a field without having to explicitly put the record in change or enter mode. In some applications it may be desirable to turn off modeless data entry, thus requiring the user to press a button before the record can be edited.
Attach this script to the forms OnFetch event:
|
this.allow_change(.f.) |
Note : While the above
example should work in most cases, in some cases, it would be possible
to get a Maximum
Stack Depth Exceeded error message when scrolling through the records
very quickly. This is because the OnFetch event
is fired a second time before the current instance has finished executing.
The current instance is put onto a stack until it can be completed. The
stack has a limited capacity. If enough uncompleted instances of the script
are pushed onto the stack, the stack will eventually overflow. This situation
can be corrected by preventing a second instance of the script from starting
until the first instance is complete. The following code shows how to
do this:
|
dim shared busy as L if (.not. busy) then busy = .T. this.allow_change(.f.) busy = .f. end if |
When the user wants to edit a record, he presses a button with this script attached to the buttons OnPush event:
|
parent.allow_change(.T.) |
Notice that the script attached to the OnFetch event uses the this alias to refer to the form, while the script attached to the button uses the alias parent to refer to the form. This is because the button is a child of the form, whereas the OnFetch event occurs at the level of the form. (Both scripts could also use parentform to refer to the form).
AskSaveChange and AskSaveEnter Events
The AskSaveChange and AskSaveEnter events fire when the user attempts to close a form before committing changes to a new or edited record. They allow the user to custom design the dialog that Alpha Five displays asking the user to confirm the action.
RESULT_CODE Variable
RESULT_CODE is a system variable that is used in conjunction with the AskSaveChange and AskSaveEnter events. For example, if the result_code variable is set to UI_YES_SELECTED, then the record is saved, and Alpha Five does not present its dialog asking the user for confirmation. If you do not define a script for either the AskSaveChange, or AskSaveEnter event, or do not set the numeric result_code, then the default Alpha Five dialog appears.
Examples
Change the wording on the dialog to something specific to the application:
|
result_code = ui_msg_box("Warning","Save invoice change in progress", UI_YES_NO_CANCEL) |
Change the meaning of Yes from save to abort:
|
result_code = ui_msg_box("warning","lose change(s)", UI_YES_NO_CANCEL) if (result_code = UI_YES_SELECTED) then result_code = UI_NO_SELECTED else if result_code = UI_NO_SELECTED result_code = UI_YES_SELECTED end if |
Automatically save the record (i.e. do not ask for confirmation)
|
result_code = UI_YES_SELECTED |
Events for Tab Object on Forms
The following events are triggered when the user changes the active page on a tab control on a form:
|
Event Name |
Occurs When |
|
CanTabChange |
Before the current tab page loses focus and before the target tab page gets focus. |
|
OnTabChange |
After the target tab page gets focus. |
You can use the CanTabChange event to prevent the user from moving off the current tab page.
For example, you might have created a dialog form with a tab control on it. You want the user to complete filling in all of the controls on each page of the tab control before advancing to the next tab page. You could attach the following code to the tab controls CanTabChange event:
|
'Get the current tab page. Page = :customer_dialog:tabbed1.tab_get() select case Page = 1 if (:customer_dialog:last_name = "") then cancel() ui_msg_box("Error", "Fill in last name") end if case Page = 2 if (:customer_dialog:address = "") then cancel() ui_msg_box("Error", "Fill in address") end if end select |
Events for Reports
The following events are triggered when the user a user does a print or print preview of a report:
|
Event Name |
Occurs When |
|
OnPrintInit |
Before the report begins to print and at the beginning of preview. |
|
OnRecord |
After each detail record has printed. |
|
OnPrintExit |
After the report has finished printing. In the case of print preview, when the user closes the print preview window. |
To specify scripts for the OnPrintInit and OnPrintExit events, select Report > Actions. This opens the Script Editor. In the Container drop down box, select the report name. Then select the name of the event you wish to define in the Script drop down box.
To specify a script for the OnRecord event, open the script editor as Defined above, select Detail in the Container drop down box.
You can use the OnPrintInit event to prompt the user for variables by opening a form as a dialog, or by using a UI_GET_TEXT() function, or by running an Xdialog box. These variables might then be used in the report's filter and order expression (defined in the report's Detail properties). IMPORTANT: The variables that you prompt for in the OnPrintInit event must be DIMmed as "shared" or "global". For example, the following Xdialog box prompts for the state. The report filter then has the filter expression: "state = var->whatstate".
|
dim shared whatstate as C Report_vars = ui_dlg_box("What State",<<%dlg% What state: [.50whatstate]; <OK> <Cancel>; %dlg%) 'Check if user clicked the cancel button. 'If so, then cancel the report. If report_vars = "cancel" then Cancel() End if |
You can use the OnRecord event to update records after they have printed. For example, in an invoicing application, you might have a Status field in the invoice_header table. After you print out invoices, you might want to update this field to say Printed. Here is how you could do this:
|
t = table.current() t.change_begin() t.status = "Printed" t.change_end(.T.) |
Events for User Defined Controls
The Form Editor in Alpha Five has a control called User Defined Control that allows an Xbasic programmer to make a custom control.
A user puts a User Defined Control (UDC) on a form using the UDC object on the form editors toolbox. You select the tool and draw the object on the form. Once you have defined the UDC on the form, you can then specify the Xbasic code for its various events.
A UDC allows the user to write custom controls entirely within Xbasic using the Windows API (or other external libraries) to draw the contents, handle key and mouse events, and react to timer events. See User Defined Controls for more information.
The A_USER.HWND variable is used for window control and is always defined.
Events and Associated Variables
|
Source |
Events |
Variables |
Description |
Values |
|
Control |
OnCreate called when window associated with control is created OnDestroy called when window associated with control is destroyed OnDraw called whenever control is repainted OnExit called when the user control is destroyed OnInit called when the user control is created (before window create) |
A_USER.DRAW.HDC |
Display context to paint to. |
|
|
A_USER.DRAW.LEFT |
Left edge of control. |
| ||
|
A_USER.DRAW.RIGHT |
Right edge of control. |
| ||
|
A_USER.DRAW.TOP |
Top edge of control. |
| ||
|
A_USER.DRAW.BOTTOM |
Bottom edge of control. |
| ||
|
Key |
OnKey called when a key is pressed when the control has focus |
A_USER.KEY.EVENT |
|
"down" = key is pressed down |
|
A_USER.KEY.VALUE |
Key that was pressed. |
Example: {F1} = F1 key. | ||
|
Mouse |
OnMouse called when a mouse event occurs |
A_USER.MOUSE.EVENT |
Type of event. |
"left double click" |
|
A_USER.MOUSE.X |
Horizontal location of mouse cursor. |
| ||
|
A_USER.MOUSE.Y |
Vertical location of mouse cursor. |
| ||
|
A_USER.MOUSE.KEYS |
Modification flags can be any combination of the values. |
"l" = left mouse button is down | ||
|
Windows Operating System |
OnMessage catch-all for all other windows messages. |
A_USER.MESSAGE.ID |
Message id passed to window procedure. |
|
|
A_USER.MESSAGE.WPARM |
Word parameter passed to window procedure. |
| ||
|
A_USER.MESSAGE.LPARM |
Long parameter passed to window procedure. |
| ||
|
A_USER.MESSAGE.RESULT |
Result to be returned by the window function. |
| ||
|
A_USER.MESSAGE.HANDLED |
Message id passed to window procedure. |
Set by Xbasic script to TRUE if the event was handled. | ||
|
Application Window |
OnMove called when the window is moved. |
A_USER.MOVE.X |
New horizontal location of window. |
|
|
A_USER.MOVE.Y |
New vertical location of window. |
| ||
|
OnSize called when the window is sized. |
A_USER.SIZE.CX |
New horizontal size of window. |
| |
|
A_USER.SIZE.CY |
New vertical size of window. |
| ||
|
Alpha Five |
OnRefresh called whenever a resynch occurs (i.e. database fields changed). |
|
|
|
|
OnTimer called whenever a timer event occurs (generated by SetTimer windows call). |
A_USER.TIMER.ID |
The ID passed to the SetTimer function. |
|
See Also
CANCEL(), Field Rule Field Events, Field Rule Record Events, Canceling Events, Attaching Scripts to Events