Application Development


Chapter 23 . Using Widgets

Panther lets you access and manipulate most widgets at runtime, get and modify their data and properties, ascertain the current selection within a radio button group or list box, and determine whether data has changed or passed validation. Panther differentiates between data entry widgets that can be thus accessed and manipulated, and other widgets that are static in nature, like lines, boxes, and static labels.

In order to access widgets, you must know how widgets are identified; for information on widget naming and array/occurrence numbering, refer to Chapter 14, "Identifying Screen Widgets."

Functions described in this section are documented in the Programming Guide; refer to that manual for the syntax and specific behavior of each function.


Changing Widget Display

Widget display is determined by the setting for the Hidden property. By default, this property is set to No. You can change the setting to:

For tab decks, the topmost_card runtime property sets the topmost card in the deck or returns the object id of the card that is topmost in the tab deck.


Controlling Input

You can control what type of input in allowed for the widget by setting the widget's properties in the screen editor and, if necessary, changing those properties at runtime.

Setting Data Entry Formats

The Keystroke Filter property sets the criteria for data entry: the keys that can be used (numbers, letters, or a combination) and the format of the entered data.

For example, the following entry in the Edit Mask subproperty would force the user to enter three digits followed by six letters:

ID#\9\9\9-\X\X\X\X\X\X

ID# and the hyphen are only display characters. Display characters are stripped before sending the value to a database or copying the value with sm_getfield§. For more information, refer to "Edit Masks" in Using the Editors.

The Regular Expression property can also enforce a specific pattern of letters or numbers, and in addition, it can restrict the range of characters available. For example, the following expression defines a code of three digits ranging from 1-5, followed by a hyphen and minimum of three letters, but no more than six.

[1-5]\{3\}-[a-zA-Z]\{3,6\}

For more information, refer to "Regular Expressions" in Using the Editors.

If you want to suggest a format pattern and have that format pattern saved to the database, you can use the Keystroke Filter property in combination with the Initial Text property. For example, an initial text entry of - - in combination with a setting of Numeric in the Keystroke Filter property would allow the user to enter groups of numbers separated by hyphens.

Other properties in the Input category determine if entry in the widget is required and if data in the widget is protected. For more information, refer to Chapter 14, "Data Entry Widgets," in Using the Editors.

Setting Date and Currency Formats

Under Format/Display, properties determine if a widget's contents are right or left justified, a password, a date format, or a currency format. You can also specify the date or currency format which will be used to enter data. For a description of properties in the Format/Display category, refer to Chapter 10, "Controlling the Way Things Look," in Using the Editors.


Traversing Widgets

You can traverse widgets on the screen using the mouse or the TAB key.

Traversing Sets of Widgets

Panther provides a set of library functions that enable you to traverse the contents of a given container objectscreen (including one used as an LDB), grid widget, box widget, selection group, synchronized scrolling group, tab deck, tab card, or table view widget. Follow these steps:

  1. Obtain the container object's id property through JPL or by calling sm_prop_id.
  2. Call sm_list_objects_start to create a list of all widgets that are currently contained by the specified object. This function returns a handle to the list so you can access its contents.
  3. reverse the list of objects created by sm_list_objects_start through repeated calls to sm_list_objects_next. This function, when first called, on a given list returns the object ID of the first widget in the list; each subsequent call returns the object ID of the next widget in the list.

    When the list is completely traversed, the function returns PR_E_ERROR. You can use this error code to test whether a list is fully traversed; or use sm_list_objects_count to set a counter within a for loop.

  4. Call sm_list_objects_end to destroy the object contents list and deallocate the memory associated with it.

For example, the following procedure creates an objects contents list for all members in a grid and traverses the list:

proc traverse_grid( grid_name ) 
vars grid_list, ct, member_ct, member_id
// create list of all members in grid
grid_list = sm_list_objects_start( sm_prop_id( grid_name ) ) 
if grid_list > 0
{
// get count of listed object IDs
member_ct = sm_list_objects_count( grid_list )

for ct = 1 while ct <= member_ct
// traverse list
{
member_id = sm_list_objects_next( grid_list )
// use member's object ID to perform some action on it
}
call sm_list_objects_end( grid_list )
return 1
}
return 0

The following example hides a box widget and the widgets positioned within its borders:

proc hide_box (name) 
{
vars box_list, count, i, item_id
@widget(name)->hidden = PV_YES
box_list = sm_list_objects_start ( sm_prop_id (name) )
if box_list >0
{
count = sm_list_objects_count ( box_list )
for i = 1 while i <= count
{
item_id = sm_list_objects_next ( box_list )
// don't try to hide static labels
if @id(item_id)->widget_type != PV_STATIC_LABEL
{
// don't try to hide always-hidden widgets
if @id(item_id)->hidden != PV_ALWAYS
{
@id(item_id)->hidden = PV_YES
}
}
}
call sm_list_objects_end (box_list)
return 0
}
return -1
}

In JPL, the member property can be used to find the members of a container. The following example cycles through the cards in the specified tab deck:

for i = 1 while i <= my_deck->number_of_cards 
{
a = my_deck->member[i]
@id(a)-> ...

//some JPL programming

}

Getting Widget Data

Panther library functions let you obtain the data in a widget or its occurrences; they also let you ascertain the widget's current property settings.

Getting Widget and Array Data

The following functions copy data from widgets and arrays:

You can also get information about the data in a widget with these functions:

Getting Properties

You can access all widget properties at runtime through JPL or the property functions: sm_prop_get, sm_prop_set, and sm_prop_id. For example, this JPL if statement conditionally unhides a widget at runtime by changing its hidden property to PV_NO:

if (login == "super")
emp_salary ->hidden = PV_NO

For more information about getting and setting widget properties in JPL, refer to Chapter 19, "Programming in JPL."


Changing Widget Data

Writing Data to Widgets

The following library functions let you move data directly into widgets:

Clearing Widget Data

To clear widget data:

Inserting and Deleting Occurrences

You can insert rows in using the logical key INSL and delete rows using DELL.

Two functions let you delete and insert occurrences from arrays:

If other arrays are synchronized with the one specified, sm_doccur and sm_ioccur perform the same operation on them, provided their Clearing Protect property is set to No. If a synchronized array is protected from clearing, Panther leaves it unchanged. Thus, you can synchronize a protected array that contains an unchanging sequence of numbers with an adjoining unprotected array whose data grows and shrinks.

Both functions ignore the target array's Clearing Protect setting.


Making Widget Selections

Panther has a set of functions that let you check the current selection or selections within a selection group, and change the selections.

Getting Selections

Two functions, sm_isselected and sm_getfield, let you determine whether a selection has been made within a selection group and what those selections are.sm_isselected checks whether a selection has been made in a selection group. The selection is referenced by the group name and occurrence number.

If you call sm_n_getfield on a radio button group that allows one selection, the buffer that you pass into this function gets the group occurrence number of the selected item. For example, the radio button group rating has the third occurrence, PG-13, selected:

Given this selection, the following call to sm_n_getfield puts the string "3" into the string buffer pointed to by buffer:

ret = 
sm_n_getfield (buffer, "rating");

If you call sm_n_getfield on a group of widget types that allows multiple selections, for example, a check box group. Panther puts the numbers of the selected occurrences into buffer. For example, the genre check box group has occurrences 1, 3, and 4 selected:

If you call sm_n_getfield on genre, buffer gets the string 1 3 4.

Panther sees a group's value as an array whose elements contain the offsets of the selected items. Thus, Panther stores the value of genre as follows:

genre[1] = "1"
genre[2] = "3"
genre[3] = "4
genre[4] = " "

sm_i_getfield gets the specified selection in the group. For example, this call gets the second-selected item in genre and puts its value, 3, into buffer:

retvar = sm_i_getfield (buffer, "genre", 2);

Changing Selections

sm_select lets you select an occurrence within a selection widget group. If the group's # of Selections property allows no more than one selection, Panther first deselects the current selection before it selects the specified group occurrence. For more information about selection widgets, refer to Chapter 20, "Selection Widgets," in Using the Editors.

To deselect an occurrence, call sm_deselect.

The selected runtime property specifies whether a selection-type widget is selected.

Manipulating Grids

For grid widgets, the grid_current_occ runtime property contains the grid widget's current (or selected) occurrence. The following JPL procedure uses this property to delete the selected row.

proc delete_selected_row(fld) 
vars grid_name occ
{
grid_name = @widget(fld)->grid
occ = @widget(grid_name)->grid_current_occ
call sm_i_doccur(fld, occ, 1)
return 0
}

Making Selections in List Boxes

Inside a list box, you can select multiple occurrences or change the application behavior to only allow a single choice. The LISTBOX_SELECTION behavior variable determines the behavior of list boxes in your application with its settings of SIMPLE_SELECTION and EXTENDED_SELECTION (default). The value for LISTBOX_SELECTION must remain constant during the running of the application.

For extended list boxes, the Listbox Type property must be set to Select Any. If it belongs to a selection group, the # of Selections property must also be set to Any. Extended selections pertain to selections within the list box, not the selection group. Therefore, if you have two list boxes in the group, the selection within one list box will have no effect on the other.

One of the field function arguments, K_EXTEND, can determine if the widget is an extended list box. Another field function argument, K_EXTEND_LAST, can determine if the cursor is in the last item of an extended selection list box.

The ADDM logical key toggles in and out of add mode within the list box.


Accessing Tab Controls

A tab control, available for Windows and Motif applications, consists of a tab deck and its associated cards. The tab deck is like a box; any widget within its boundaries is assigned to one of its cards. The number_of_cards read-only property gets the number of cards in the deck, including hidden ones.

Each tab card can have widgets which can be grouped as needed. The card property of each widget appearing on a tab card is set to the object ID of that card.

Tab cards are numbered sequentially within the tab deck. The Card Number property (card_number) determines the sequence of the cards. You can move to another card by clicking on its index tab or with the NCARD and PCARD logical keys.

The tab card currently on display in the screen is the topmost card. At runtime, you can set which card is topmost using the tab deck's topmost_card property. The following JPL statement set a new topmost card:

//  my_deck has three cards named card1, card2, and card3. 
// This call sets the second card as topmost card.

my_deck->topmost_card="card2"

Accessing ActiveX Controls

Active X controls, available for Windows and Web applications, are considered separately since the ActiveX control itself is not a Panther' widget, only the ActiveX container is. However, Panther can access the ActiveX control's properties, events, and methods. This allows you to manipulate the ActiveX control at runtime.

The Active X container's CLSID property (clsid) determines which ActiveX control is located inside the container. If the ActiveX control specified in that CLSID property is registered on your system, the control will be displayed in the screen editor and the Properties window will display the control's property names and settings.

To get and set property values at runtime:

The author of an ActiveX control specifies what methods can be used to access the control, the arguments needed for those methods, and the events that are applicable to the control. Those methods can then be called in Windows applications using sm_obj_call and in Web applications using VBScript or JavaScript. An event handler can then be written for those events using sm_com_set_handler in Windows applications and VBScript functions in Web applications.

For more information and an example of an ActiveX control, refer to Chapter 18, "ActiveX Controls," in Using the Editors.


Checking Validation

Panther maintains two runtime properties that can be checked to determine the validation and modification status of a widget or group:

valided
Indicates whether or not the widget or group has passed validation:

mdt
Indicates whether the data of a widget or group have been modified: