This document covers the following topics:
Tab controls are created in the dialog editor in the same way as
other standard controls (such as list boxes or push buttons) are. That is, they
are either created statically in the dialog editor via the
menu or by drag and drop from the Insert tool bar, or
dynamically at run-time by using a PROCESS GUI ACTION
ADD
statement with the TYPE
attribute set to TABCTRL
.
Alternatively, dialogs containing tab controls may be generated with the Dialog Wizard. In this case, many of the techniques described in this section are applied automatically by the wizard, and either do not need to be explicitly implemented, or simply need to be extended or "filled-out", whilst retaining the generated structure. This can significantly reduce the programming effort required.
A tab control may have zero or more tabs associated with it. Tabs may be
defined in the dialog editor from within the tab control's attribute window, or
at run-time by performing a PROCESS GUI ACTION
ADD
statement with the TYPE
attribute set to TABCTRLTAB
.
The tab control is a container. However, the individual tabs are not
containers, in the Natural implementation of this control. When controls are
created within the tab control in the dialog editor, the control's
PARENT
attribute is automatically set to the handle of the tab control, and not to the
handle of the currently active tab (if any). In order to associate a child
control with a particular tab, the child control's
OWNER
attribute is set to the handle of the tab with which the control should be
associated. The control is then automatically hidden by Natural when the tab is
deactivated, and automatically re-shown when it is re-activated.
Note, however, that the dialog editor only automatically sets the child
control's OWNER
attribute if the tab control's "UI active (U)"
STYLE
flag
is set, which is the default setting. Otherwise the child control's
OWNER
attribute is left unset (i.e., NULL-HANDLE
). In the latter case,
the child control is not automatically shown and hidden when switching between
tabs. Note that the "UI active (U)"
STYLE
has
no effect at run-time.
As stated above, all child controls within a tab control have a tab control as their parent, regardless of the tab to which they belong. Whilst this is sufficient, it may be preferable to separate the controls on different tabs into separate sub-hierarchies.
The most convenient way of achieving this is to create a child control
box for each tab to represent the tab "pages". All other child
controls are then created as child controls of the respective control box.
Assuming that the tab control's "UI active (U)"
STYLE
flag
is set, the control boxes will be automatically hidden and shown during tab
switching, and thus t heir respective child controls with them (child controls
are automatically hidden if any ancestor window is hidden). Otherwise, the
program must do the page switching explicitly, as described in the next
section.
The control's organization is shown in the following diagram:
As shown in the diagram, each child control box should be transparent,
that the tab control's background texture (if any) shows through, and have the
"size to parent (z)"
STYLE
, so
that the control boxes automatically exactly fill the interior area of the tab
control, both immediately and whenever the size of the tab control is changed.
In addition, each control box should be "exclusive" if the tab
control is not UI active, such that only one child control box is visible at
any time.
Anmerkung:
This section only relates to tab controls that are not UI active.
Otherwise, the control switching is done automatically by Natural.
In the dialog editor, this is performed automatically by the dialog editor when a control belonging to an exclusive control box (or the control box itself) is selected, which is not currently being displayed. The dialog editor makes the currently visible exclusive control box (if any) invisible (thus also hiding any controls placed within it) and makes the control box containing the selected control visible (thus also showing any controls placed within it). This process is independent of how the selection is made (for example, explicitly, from the selection box in the status bar, or implicitly, by simply tabbing through the controls).
Anmerkung:
If the status bar is not shown, set the Status
Bar under the Dialog Editor tab of
the Options dialog opened via the
command.
At run-time, the control boxes must, of course, be shown or hidden in
response to the user selecting the corresponding tab. This can be achieved by
querying the active tab in the tab control's
CHANGE
event
and setting the VISIBLE
attribute of the corresponding control box to TRUE
. One way of
making the tab/control box associations is to store the handle of the control
box in the CLIENT-HANDLE
attribute of the corresponding tab in the
AFTER-OPEN
event of the dialog.
For example:
/* Map control boxes to tabs: #TAB-1.CLIENT-HANDLE := #CTLBOX-1 #TAB-2.CLIENT-HANDLE := #CTLBOX-2 .. #TAB-N.CLIENT-HANDLE := #CTLBOX-N
Then, assuming #CONTROL
is defined as HANDLE OF
GUI
, the CHANGE
event
of the tab control (#TABCTRL-1
) could look like this:
/* Get active tab #CONTROL := #TABCTRL-1.SELECTED-SUCCESSOR /* Switch to control box belonging to active tab: #CONTROL := #CONTROL.CLIENT-HANDLE IF #CONTROL <> NULL-HANDLE #CONTROL.VISIBLE := TRUE END-IF
In some situations, it may be desirable to display controls that remain visible, irrespective of which tab is currently selected.
There are two ways of achieving this:
If control boxes are being used, the control boxes can be made smaller
in order to cover only part of the tab control's interior area, leaving the
remaining space available for controls that should be permanently displayed.
The "size to parent (z)"
STYLE
must
be switched off for the control boxes.
If control boxes are not being used and the tab control is UI active,
permanently displayed controls may be created by ensuring that the
"UI active (U)" STYLE
for
the tab control is temporarily switched off whilst creating the child
control(s) that are to be permanently displayed.
If the tab control is not UI active, a two-layer control box hierarchy can be used, where the child control boxes described above are created as child controls of a transparent top-level control box, which in turn is created as a child of the tab control. The top-level control box (which does not have the "size to parent" flag set), can then be positioned and sized appropriately to define the replaceable region.
Anmerkung:
This is very similar to the technique used for wizard dialogs. See
the section Working with
Control Boxes for more information
There are three methods of navigating between the tabs of a tab control via the keyboard, any combination of which can be applied simultaneously:
If the tab control is assigned the "browsable
(z)" STYLE
flag, the tab control is included in the tab sequence (i.e., can be navigated
to via the TAB key). When the tab control receives the focus,
navigation between the tabs is possible via the arrow keys. There is no
"wrap-around" between the first and last tabs in this case.
The tab captions (STRING
attribute) may contain an ampersand (&), indicating that the following
character is a mnemonic character. The tab is selected when the mnemonic
character is pressed together with the ALT key. This allows for
"direct" keyboard navigation to the desired tab.
If the dialog has the "Property Sheet (p)"
STYLE
set,
the keyboard shortcuts CTRL+TAB and CTRL+SHIFT+TAB may be
used to navigate to the next and previous tab (respectively), with
wrap-around.
Note that the focus does not have to be on the tab control or a dialog
element within it in order for the last technique to work. Starting from the
focus control, Natural examines each container (ancestor), until a container
(if any) is found that contains one or more tab controls. If this container
contains exactly one tab control, the keyboard shortcuts are then applied to
this tab control. If it contains two or more tab controls, these shortcuts have
no effect. If the dialog does not contain a tab control, the shortcuts perform
their usual function, as if the "Property Sheet (p)"
STYLE
had
not been set.
Note that this default usage of the CTRL+TAB and
CTRL+SHIFT+TAB key combinations may be overridden by redefining them
via the ACCELERATOR
attribute.
Whenever a tab switch is performed (either by the user or programmatically), the following sequence of events occurs:
The currently selected tab receives a
LEAVE
event, if not suppressed. This event is typically used for data validation
and/or committing the data on the tab page.
The MODIFIABLE
attribute of the tab control is then examined. If it is set to
FALSE
, the tab switch is not performed. The currently selected tab
remains selected and no further events are raised. This can be useful if data
validation performed during the
LEAVE
event found an error, which should be corrected by the user before
continuing.
All direct child controls (if any) that have currently selected tab as
their OWNER
are
automatically hidden.
The new tab is selected.
All direct child controls (if any) that have the newly-selected tab as
their OWNER
are
automatically shown, if their VISIBLE
attribute is set to TRUE
.
The newly-selected tab receives an
ENTER
event. If not suppressed. This event is typically used for initializing
controls on the new tab page.
The tab control receives a
CHANGE
event.
This is convenient for tracking tab switches and responding to them without
having to modify the event handlers for each tab.
Note that no initial ENTER
event is
raised for the selected tab when the control is created, and that the tab
control does not receive an initial
CHANGE
event
either. Furthermore, when the dialog containing the tab control is closed, the
currently-selected tab does not receive a
LEAVE
event.