Application Development |
Almost everything that happens during the life span of a Panther application is identified by Panther as one type of event or another. At one level, events occur as the result of user interaction with the interface—for example, pressing a push button widget, or double-clicking on a dynamic label. These events and the control strings that determine the application's response are discussed in Chapter 18, "Programming Control Strings."
This chapter initially focuses on application events that are not always connected to user actions. For example, a Panther application always starts by opening a screen. Whenever a screen opens, the same sequence of events occurs, such as initialization of the transaction manager and execution of the screen's entry function. Functionality can be associated with an event, such as screen opening, by means of various properties or by installing C or Java functions.
Your ability to control application behavior largely depends on knowing the order in which events occur and what options, or hooks, are available that allow you to intervene. This chapter describes events that typically occur during a Panther application, and the hooks that are available for each one. For purposes of this discussion, events are broadly grouped according to the following application components:
The final section of the chapter discusses these event categories in relation to user-initiated actions.
This chapter assumes that you are already familiar with the basics of Panther application development, as covered by Chapter 1, "Building a Panther Application" and the tutorial in Getting Started 2-Tier or Getting Started JetNet/Oracle Tuxedo.
Screen and Widget Events |
Screens and widgets provide the foundation of a Panther application. All user interaction takes place via a client screen and its widgets; and application code is typically accessible, either directly or indirectly, through client screens or, in three-tier applications, the service components that they invoke. Thus, much of the processing that takes place in a Panther application occurs at the screen and widget level, and can be decomposed into distinct screen and widget events.
The following drawing schematically depicts screen and widget events as they occur in an application that consists of two screens, Screen1 and Screen2:
Application workflow and accompanying events consist of these steps:
Most screen and widget events can be monitored and controlled programmatically and through Panther properties. Functions that execute on events are called event functions. An event function can be installed in the application as an automatic function, which executes on all events of a given object type (screen or widget); or it can be named in an event-specific property of a given screen or widget, so it executes only for that object on a specific event. For example, an automatic screen function executes on all entry and exit events for every screen in the application; however, a function that is named in a screen's Entry Function property executes only when that screen opens or regains focus.
Properties can also be used to control validation processing or check a widget's status. For example, you can set a widget's required property to force user input; and you can check whether a widget's data has changed through its runtime mdt property.
Getting your application to behave as you wish depends on knowing the sequence in which screen and widget events occur and what options are valid for each one. The following sections discuss these events in the order of occurrence. In addition, the Panther debugger can be used to determine the sequence of events for a particular screen.
Screen entry occurs when a screen opens or regains focus. Because an application begins by opening a screen as its base form, the processing that is associated with screen open provides the first—and, often, the most important—set of opportunities to determine an application's behavior. Screen exposure occurs when a screen regains focus from a screen that previously overlay it. The set of events that occur on screen exposure is a subset of the set of events that occur on screen open.
When a screen opens, events occur in the following order:
valided
and mdt
properties are cleared (set to PV_NO
) for all data input widgets.All processing that should occur before the user sees the screen must take place during these steps. The nature of the processing itself dictates the specific step at which it should occur. For example, transaction manager commands can be issued only after the transaction manager is initialized (step 2).
Always allow all steps on this list to complete. Specifically, avoid opening a screen while opening another screen; doing so can prevent the original screen from completing its open processing and yield unpredictable results.
At different times during an application, the active window can open another screen as a sibling or stacked window; the newly opened window overlays its caller. When the original window regains focus, screen exposure processing takes place. Screen exposure processing also occurs when a report returns to the invoking screen (refer to the runreport command).
Screen exposure processing is a subset of open processing, and consists of these steps:
When a screen is exposed, focus returns to the last field on the screen to have had focus. If this field is in a group, grid or tab control, there will be entry events associated with the container prior to the automatic field function.
A screen's unnamed procedure executes and the transaction manager is initialized only once for a given screen, when it opens. Also, the valided
and mdt
properties for the screen's data input widgets are cleared (set to PV_NO
) only when a screen opens. Subsequent exposures of the screen leave these properties unaffected.
A screen's JPL (accessed through its JPL Procedures property) is accessible to the entire screen. When the screen initially opens, its unnamed procedure—the code that precedes the first proc statement—executes first.
A screen executes its unnamed procedure only when it opens; subsequent exposures of the screen ignore this code. Thus, the unnamed procedure of an application's opening screen is the appropriate place to make public those JPL library modules that are required by the entire application or make other JPL modules available for this screen.
The public command makes these modules' procedures accessible to this and other application screens and their widgets. A public module's procedure can be named in screen or widget properties—for example, in a widget's Entry Function property—or called from other JPL procedures with the call command.
When Panther loads a public module, it loads the module's procedures into memory and executes its unnamed procedure, if any. During its life span, an application can call any named procedure in a public module, unless the module is explicitly removed from memory with the unload command.
A public module's unnamed procedure executes only once; and a module can be made public only once. (Panther ignores any public command that is issued on a module that is already public.) Thus, any code in a public module's unnamed procedure is virtually guaranteed to execute only once during the life span of an application.
The include command makes a modules' procedures accessible to the current application screen.
In general, it is good programming practice to public only the procedures that you need to be global to the entire application. Procedures specific to individual screens should be in modules that are included by the screens to which they refer.
It is suggested that you maintain JPL code in libraries for the following reasons:
The transaction manager is initialized only once for a given screen. You can issue transaction manager commands such as SELECT (via sm_tm_command) only after this step is complete. Thus, it is an error to issue this or any other transaction manager command in a screen's unnamed procedure. Use a later stage of screen open processing to issue these commands—for example, the screen's entry function.
To disable transaction manager initialization, set the screen's Root property to A screen's automatic function and entry function are called successively on screen entry:
Transaction Manager Initialization
None
.
Screen Automatic and Entry Functions
funclist.c
. This function is called automatically on all screen entry and exit events. For more information about installing automatic screen functions, refer to "Installation of an Automatic Screen Function."
If the screen function is written in Java, the Java Tag property must specify either a screen-specific Java class, which would access a corresponding Java function, or the default screen Java class, which would access the screen entry processing in the current class factory. For more information about writing Java functions, refer to Chapter 21, "Java Event Handlers and Objects."
Panther always executes the automatic and named entry functions on screen open. It also executes these functions on screen exposure if the setup variable EXPHIDE_OPTION is set to Panther automatically supplies two arguments to screen functions: the screen's name; and an integer bitmask that indicates the screen's current state and why the function was called. (For information on using these arguments in a JPL procedure, refer to "Passing Standard Arguments to JPL Procedures.") Screen functions can use these arguments to control execution that is specific to a given screen; or (more typically) to distinguish between screen event types.Panther provides three mnemonics that can be bit-wise AND'ed with the context argument to determine which screen event caused the screen function to be called:
ON_EXPHIDE
(the default). If so, the screen's automatic and entry functions are the first events to occur on screen exposure.
context & K_ENTRY
— screen entry
context & K_EXIT
— screen exit
For example, the following screen function code tests whether the function is called on screen open or screen exposure:
The following example tests if the screen is being opened for the first time, instead of just being exposed:
Panther screens can be used as vehicles for initializing and saving values on other screens. A screen that performs this background role is called a local data block, or LDB. When a screen serves as an LDB, Panther uses its data input widgets, or LDB entries, to transfer data to and from corresponding widgets on the current screen. Panther matches LDB entries and screen widgets by name. By using LDBs, applications can transfer data between screens automatically.
LDB write-through occurs on both screen open and expose events. No hook is provided to intervene in this process; however, it is important to know that any attempt before this step to set a screen widget's value is actually written to the corresponding LDB entry and so might overwrite any previous value in it. Note also that on screen open, the LDB respects initial widget data that is specified through the screen editor—for example, the value set in a push button's Label property. Initial widget data also is written to the corresponding LDB entry.
For more information about LDB processing, refer to "Using Local Data Blocks."
Panther provides two widget-level runtime properties, A widget's A widget's No hook is provided to intervene in this processing; however, it is important to know that Panther sets these properties after the screen's automatic and entry functions execute and LDB write-through occurs—in other words, after the stages in which widget data is typically initialized, either from a database or LDBs. So, Panther marks as potentially invalid widgets whose initial data is probably valid. By testing both the For more on using the The automatic field function and a field's own entry function are called successively on field entry. The automatic field function is called on all field events; a field's entry function is named in the field's Entry Function property and is there fore specific to that field and event. Field entry functions are typically used for processing that should occur every time a given field gains focus.
For more information about automatic field functions, refer to "Field Functions"; for more about field event functions, refer to "Event-specific Functions and Arguments" .
Just after Panther opens the keyboard and before it displays the screen to the user, it checks the input stack for unprocessed keys; if any are found, it pops them off the stack and processes them. You can push keys onto the input stack earlier during screen entry by calling For example, on application startup you might want to display a login screen that appears simultaneously with the application's base screen and overlays it. As noted earlier, a screen should never try to open another screen until its own open processing is complete. You can implement this behavior in two steps:
int scr_entry_func( char *scr_name, int context )
{
if( context & K_ENTRY )
{
if( context & K_EXPOSE )
{
// expose processing
}
else
{
// open processing
} } }int scr_entry_func( char *scr_name, int context )
{
if !( context & K_EXPOSE )
{
// only the first screen open processing
} } LDB Write-through
Clearing of Valided and Mdt Properties
valided
and mdt
, which are automatically cleared (set to PV_NO
) on screen open for all data input widgets. In other words, when the screen first opens, all data input widgets are regarded as requiring validation and as unmodified.
valided
property remains clear until it passes validation. This sets the valided
property to PV_YES
until the widget's data changes again.
mdt
property remains clear until its data changes. Thereafter, the widget's mdt
property is set to PV_YES
unless it is explicitly cleared, either individually or with all data input widgets on the screen by a call to sm_cl_all_mdts.
valided
and mdt
properties, you can determine whether a widget actually requires validation.
valided
and mdt
properties, refer to "Field Validation" and "How to Validate All Screen Widgets".
Field Automatic and Entry Functions
Input Stack Processing
jm_keys
. Because application keys can be associated with control strings through a screen's Control Strings property, the input stack can be used to defer any processing that cannot safely be called earlier during screen entry, such as calls to open a screen.
APP1 = &login.scr
call jm_keys APP1
Because a login screen appears only at application startup, this call should be made at a stage of the base screen's entry processing that is not repeated on later exposures of the same screen. The unnamed procedure of a module that the base screen makes public (in its own unnamed procedure) executes only once, so it should issue the call to open the login screen.
Now, when the application starts and opens its base screen, the call to jm_keys
pushes APP1 onto the keystack, where it remains until the keyboard opens; Panther pops APP1 off the keystack and in doing so executes APP1's control string and opens the login screen as a stacked window. This done, Panther draws the display and shows both screens as if they opened simultaneously, with login.scr as the topmost, active window.
Frameset event processing is described in "Cursor Movement and Window Management using Framesets" in Using the Editors.
Fields, or data entry widgets, can undergo three events: entry, validation, and exit. Dynamic labels are the exception to field event processing; since dynamic labels cannot be entered, they only have validation events.
The following widget types are not fields, so other exceptions in event processing apply:
Panther provides various properties that let you control entry, validation and exit processing; properties that are specific to each event are described in later sections. All three events share these features:
All fields initially call the automatic field function if one is installed. The automatic field function must be written in C, and it must be installed via the source file funclist.c. For more information about installing an automatic field function, refer to "Field Functions."
Almost all widgets provide properties that let you name functions to execute on specific events—Entry Function, Validation Func, and Exit Function. Some widget types have a Control String property, which can name a function to execute on validation events.
The functions that you name in these properties can be written in JPL, in C, or in Java. If written in C, the function must be installed either as a demand field function (applicable only to data input widgets or as a prototyped function. Because they are specified using individual properties of a given widget, you can write functions that are tailored to specific widgets or events. For example, a function that should execute every time a widget gains focus should be attached to that widget's Entry Function property. For more information, refer to "Installation of Demand Widget Functions" and "Installing Prototyped Functions".
If written in Java, the Java Tag property must specify the Java event handler. If a widget has both the Java Tag and Entry Function properties specified, both types of processing will occur; first the Java event handler, then the named function. For more information, refer to Chapter 21, "Java Event Handlers and Objects."
Panther automatically supplies four arguments to any event function that is specified for a data input widget:
Automatic Field Function
Event-specific Functions and Arguments
Panther supplies these arguments if the event function property contains only the function's name. The function can use these arguments to control execution that is specific to a given widget, or to identify widget event types—for example, to differentiate between close and hide events.
Panther also supplies arguments for grid widgets, selection groups, and tab cards. For more information, refer to "Calls from Screens and Widgets."
When a screen opens or is exposed, the first field that can gain focus undergoes entry processing. Thereafter, a field gains focus either because of user action such as tabbing or mouse-clicking into it, or through programmatic manipulation—for example, a call to sm_tab or sm_gofield.
Entry processing for a field can comprise two stages: first, the automatic field function (if one is installed) executes; then the field's own entry function executes. A field's entry function is a named function that you set in the field's Entry Function property. This property is available for all data input widgets such as single line text; it is also available for grid widgets and selection groups.
When a field loses focus or it is selected or deselected, it undergoes validation processing unless its Field Entry
Field Validation
no_validation
property is set to PV_YES
; the default is PV_NO
. Field validation can occur as a result of various events or actions, including the following:
PV_YES
.
sm_s_val
or sm_validate
in a screen's exit function, or when you attempt to save screen data.
Field validation always occurs on the aforementioned events regardless of the widget's As mentioned earlier, Panther sets all widgets'
Note:
You can also test a widget's validation and modified states by bit-wise AND'ing the VALIDED and MDT mnemonics with the fourth standard argument received by widget functions, as in this code:
During field validation, Panther tests a field's data against a number of formatting and input property settings, in the order shown in the following table. Some fields are skipped if the field is empty or its valided property is set to
The JPL in a field's Validation Func and JPL Validation property must return 0 to indicate success. Other values indicate failure: a return value of 1 leaves the cursor at its last position; any other non-zero value repositions the cursor at the widget's first position.
Field validation does not typically occur when the user uses a cursor key to move out of the widget, or mouse clicks into another widget. To force validation also to occur on these events, set the application setup variable IN_VALID to Exit processing occurs for a field that has focus when the user moves the cursor out of the field, or the screen closes or is hidden. All methods of moving the cursor out of the field, including mouse clicking, trigger exit processing. If the exit event is also one that requires validation processing, exit processing begins only when the widget's valided property is set to Exit processing for a field can comprise two stages: first, the field's own exit function executes; then the automatic field function (if one is installed) executes. A field's exit function is a named function that you set in the field's Exit Function property. This property is available for all data input fields such as single line text; it is also available for grid widgets and selection groups.
When a widget is a grid member, what happens when its column label is clicked depends on its Click Column Action property, which can be When Click Column Action is When Click Column Action is Events occur for the index tab on a tab card and for the tab card itself; the tab deck has no events. Cards in a tab deck have expose and hide events along with entry and exit events.
A tab card expose event occurs when a card becomes the topmost card in the deck and during screen entry for the topmost card in the deck, even if the tab deck is hidden. A hide event occurs when another card on the deck becomes the topmost card, when the card is deleted, or when the screen is closed.
When moving to a new topmost card, a card exit event will not precede a card hide event if a widget outside the tab deck has focus. The following drawing schematically depicts the events that would occur in this context:
Panther provides three mnemonics that can be bit-wise AND'ed with the context argument to determine which event caused the tab card's function to be called:
Avoid Unnecessary Validation
valided
property setting. You can avoid unnecessary processing by checking the widget's validation state in any function that executes during validation. This JPL function tests the current field's valided
property:
proc wdg_valid_func()
if ( @widget("@current")->valided )
{
return
}
else
{
//do validation processing
}valided
property to PV_NO
on screen open; inasmuch as a screen's entry function might initialize these widgets from database values, the valided
setting might not reliably tell whether a widget's data is valid. In this case, you can also test a widget against its mdt
property setting:
proc wdg_valid_func()
vars valid = @widget("@current")->valided
vars modified = @widget("@current")->mdt
if ( valid || !modified ) //data either valid or unchanged
{
return //no further processing required
}
else
{
//do validation processing
}proc wdg_valid_func( fldno, data, occ, context )
if( context & VALIDED || !context & MDT )... Properties Tested During Validation
PV_YES
—that is, there is no data to verify or the data already passed verification.
Non-validation Events
OK_NOVALID
. Because users expect to move freely within a GUI application screen, validation is typically suppressed until they explicitly submit the screen data—for example, by pressing a Save push button. Therefore, IN_VALID
is by default set to OK_NOVALID
.
Field Exit
PV_YES
.
Grid Column Label Click
None
, Sort
or Custom
.
Sort
, the Sort Order should be set. The order can be Lexicographic
for an alphabetic sort; Numeric
for a numeric value sort; Date/Time
for sort by date and time; and Custom
to allow you to use your own sort function. The Sort Order Func property names this function. It can be written in JPL or can be installed as a prototyped function. The function is passed two strings to compare. The return value should be COMPARE_LESS
if the first string is less than the second, COMPARE_EQUAL
if the two strings are equal, COMPARE_GREATER
if the first string is greater than the second or COMPARE_ERROR
if an error has occurred.
Custom
, a Column Click Func can be specified that will be called when the widget's column label is been clicked. This function can be written in JPL or can be installed as a prototyped function. The function is passed the object ID of the widget. Its return is ignored.
Tab Control Events
If all three bits are clear, the tab card hide event was called. For more information, refer to "Tab Control Functions."
Screen exit occurs when a screen closes or is hidden by another screen. Because an application typically ends by closing the screen that is its base form, exit processing for this screen can perform any cleanup that the application requires, such as closing database or middleware connections. Screen hide events occur when a screen loses focus to another screen, or invokes a report by calling the runreport command. Screen hide events are a subset of close events.
When a screen closes or is hidden, the following events occur:
Screen Exit
The functions that you name in these properties can be written in JPL, in C, or in Java. If written in C, a screen entry function must be installed either as a demand screen function or as a prototyped function. Because they are explicitly named, you can write exit functions that are individually tailored to specific screens.
To write screen functions in Java, you must specify an event handler class for the screen in the Java Tag property. If a screen has both the Java Tag and Entry Function properties specified, both types of processing will occur; first the Java event handler, then the named function. Panther automatically supplies the same two arguments to screen exit functions that it supplies to screen entry functions.
Note:
Panther always executes the screen's automatic screen function and the screen's named exit function on screen close. It also executes these functions on screen expose if setup variable EXPHIDE_OPTION is set to ON_EXPHIDE
(the default).
Screen exit processing often tests widget data, either by forcing validation processing or by testing whether widget data has changed. However, you should not open another screen during screen exit.
Call sm_s_val
or sm_validate
which traverses the screen, testing each widget occurrence and setting its valided property to PV_YES
. If it encounters an occurrence with invalid data, the function returns, posts an error message, and positions the cursor there. The valided property remains unchanged for all untested widgets.
Call sm_tst_all_mdts which checks the
mdt property for each data input widget and its occurrences. When the function encounters an occurrence that contains modified data, it returns with information that identifies the widget and occurrence number. For example, the following function alerts users to changed data on the current screen:
int dataChanged()
{
int fldno, occ, wdg;
char *nm;
fldno = sm_tst_all_mdts( &occ );
if( fldno >= 0 )
{
// get the widget's name
wdg = sm_prop_id( "@field_num(fldno)" );
nm = sm_prop_get_str( wdg, PR_NAME );
if ( sm_message_box
( "New data in "##nm##" field--Continue?",
"", SM_MB_YESNO ) == SM_IDNO )
return sm_o_gofield( fldno, occ );
}
return 1;
}
Because sm_tst_all_mdts
is not callable from JPL, you must either use it in a C function, or write a wrapper function that you install as a prototyped function and call from JPL. Alternatively, you can write JPL code that traverses all screen widgets and test each one's mdt property, as in this example:
proc tst_mdts()
vars nextObj, answer, wdg, ctObjs, occ, wdgOccs, nm
vars objList = sm_list_objects_start( @screen("@current")->id )
if( objList > 0 )
{
// get the number of widgets on screen
ctObjs = sm_list_objects_count( objList )
// start traversal
for wdg = 1 while wdg <= ctObjs
{
nextObj = sm_list_objects_next( objList )
nm = @id( nextObj )-> name
// get all the occurrences of this widget
wdgOccs = @id( nextObj )-> num_occurrences
// test mdt property of each widget occurrence
for occ = 1 while occ <= wdgOccs
{
if( @id( nextObj)[occ]-> mdt )
{
if ( sm_message_box \
("New data in "##nm##" field--Continue?",\
"", SM_MB_YESNO) == SM_IDNO )
{
call sm_o_gofield \
(@id( nextObj )->fldnum, occ)
return 0
} } } } }
return 1
The following actions close a screen:
jm_exit
in a function or control string.
If you call jm_exit
in a JPL procedure, no other JPL programming should follow that statement. Otherwise, this subsequent programming will execute on the underlying screen in the stack.
EXIT
key with its default setting.
You can exit an application by:
Exiting an Application
CLAPP
is the Panther logical key that closes an application. For example, the following control string attached to the final screen calls jm_keys to issue the CLAPP
key and a Y response to the termination message:
^jm_keys CLAPP 'Y'
Programming User-initiated Events |
Table 17-2 lists common user-initiated events and the associated event hooks where application processing can be specified. This table references many widget events described under "Widget Events."
Transaction Manager Events |
The transaction manager generates a series of events in order to fetch database data, track any modifications to that data, and update the database with any modifications. The events are divided into two levels: requests and slices.
When you call a transaction manager command, such as VIEW
or SAVE
, the transaction manager generates that command's requests. For the VIEW
command, the request events would be PRE_VIEW
, VIEW
, and POST_VIEW
. The transaction manager then accesses the transaction model to determine what processing to perform for each request. Since a single request could have several steps, each request can be sub-divided into slices. The transaction model also determines the processing necessary for each slice.
For more information on transaction manager operations, refer to Chapter 31, "Building a Transaction Manager Screen." For descriptions of transaction manager commands and their requests and slices, refer to Chapter 8, "Transaction Manager Commands," in Programming Guide.
Database Interface Events |
Database requests can generate errors that are reported by Panther's database drivers and the database engine itself. Panther provides global variables and hook functions that can help identify and manage these errors. Default error handlers are installed to report errors from Panther's database drivers and from the database engine. You can also write and install your own error handlers. With the JetNet/ Oracle Tuxedo middleware adapter, these errors can be logged to your application server.
For full information about database error handlers, refer to Chapter 37, "Processing Application Errors."
Web Application Events |
The online Web Development Guide describes the events that occur at runtime for a Panther web application. For more information, refer to Chapter 5, "Web Events," in Web Development Guide.
You can also include JavaScript or VBScript programming in your client screens for events occurring in the web browser. For more information, refer to Chapter 9, "Using JavaScript and VBScript," in Web Development Guide.
Middleware Events |
In three-tier applications, the type of middleware determines the specification and type of events.
In JetNet and Oracle Tuxedo applications, events have been defined for service requests and as those events occur, they are forwarded to handlers for processing.
Panther provides built-in event handlers for all middleware event types. You can also write and install your own handlers in JPL or C. These handlers can perform all required processing on their own, or they can call the built-in handlers and overlay these with desired enhancements.
The following table lists event types for JetNet and Oracle Tuxedo applications:
Middleware events in JetNet and Oracle Tuxedo applications occur independently of screen and field events and transaction management events; however, their handlers can initiate actions that themselves precipitate events of these types. For example, an exception handler might respond to an error by aborting a service request, which in turn causes the transaction manager to report an error.
For more information about JetNet/Oracle Tuxedo event types and their handlers, refer to Chapter 6, "JetNet/Oracle Tuxedo Event Processing," in JetNet Guide/Oracle Tuxedo Guide.