How do you use the
the XmComboBox Widget?
|
10-May-01 16:00 GMT
|
A ComboBox is a component which combines direct Textual user input with the convenience of List selection.
Generally, the component presents itself to the user as a TextField of some description, with an ArrowButton to the
side of the Text. The user can either type into the Text component, or press the ArrowButton, which results in the
popping up of a List of available items from which the user can select using the mouse.
Figure 1 displays a typical ComboBox, configured to allow the user to select from the days of the week.
ComboBoxes are components which are compact in terms of screen usage. Unlike a simple List, they occupy only sufficient
space on the screen in order to display the current selection.
ComboBoxes are however associated with only a single selection at any given time. If multiple choices may be made from
a set of items, the List remains the correct interface paradigm for the programmer to adopt.
Given the task of presenting a set of choices to the user, whilst at the same time minimizing the screen space required
for the task, the ComboBox is the natural component. Where a ComboBox might not be preferred over other components depends
on the nature of the data. If the set of choices is prohibitively expensive to calculate, or the set is fairly large, it
might be better to simply present a TextField to the user; navigating through a particularly large set of items in a
popup List is not a very pleasant user experience, and should generally be avoided.
A secondary consideration is whether the data to be presented forms a natural, closed and ordered set. If this is the case,
a SpinBox component also comes into consideration; where the data is in any way unordered or arbitrary, the ComboBox
is to be preferred. Where the data forms a small set, there is little to choose between the two components, ordered
or otherwise.
In Motif, there are three logical kinds of ComboBox:
Programmers wishing to use the Motif ComboBox should include the file <Xm/ComboBox.h>
in their sources. The header file declares the XmComboBoxWidget and XmComboBoxWidgetClass
types, as well as providing functional prototypes for all the XmComboBox convenience routines,
which are listed below. The class pointer is xmComboBoxWidgetClass.
The Motif XmComboBox widget class is a sub-class of the XmManager Widget Class; it inherits all of the resources of the class,
although it overrides various default values of the super class, typically margins and shadow thicknesses. The full
class inheritance is as follows:
Core -> Composite -> Constraint
-> XmManager -> XmComboBox
Although the widget inherits via the Constraint class, XmComboBox does not define any new constraint resources.
The widget creates two internal components, a TextField, which is named "Text", and a Scrolled List, known as "List".
The ScrolledList is either directly parented off the ComboBox, or from a special internal popup GrabShell, depending upon
whether the ScrolledList is to be permanently visible. The GrabShell is of no real interest to this discussion: it is simply
a popup shell which grabs the pointer until such time as the shell is popped down. The following code could be used to
fetch the internal components of a ComboBox (although as will be seen below in the Resource tables, there are other means by which the
abstract (built-in) components of the ComboBox can be fetched):
extern Widget combo ;
Widget text = XtNameToWidget(combo, "Text") ;
Widget list = XtNameToWidget(combo, "*List") ;
Note that the wildcard specification (*) is required before the internal List name, because as already discussed, the
ScrolledList may not be an immediate ComboBox child.
Whether fetching the internal components of the XmComboBox is really necessary from the general programming perspective is a moot point:
the XmComboBox implements what is termed a mirror, whereby resources which normally would need to be applied to sub-components
can be applied directly onto the XmComboBox itself.
Note that the ArrowButton which the XmComboBox component creates in order to facilitate popup of the
List is a hand-drawn artifact, and not a real sub-component. So while it is possible to configure the
built-in Text and List components of the ComboBox to whatever style the programmer requires, configuration
of the ArrowButton is strictly limited by the interface which the XmComboBox directly presents to the programmer.
An XmComboBoxWidget can be created in a number of ways, either using generic Xt Intrinsics methods, or by utilizing a Motif
convenience routine defined for the purpose.
Motif defines three convenience routines, one for each of the supported ComboBox styles of presentation:
Widget XmCreateComboBox(Widget parent, char *name, ArgList argv, Cardinal argc)
Widget XmCreateDropDownComboBox(Widget parent, char *name, ArgList argv,
Cardinal argc)
Widget XmCreateDropDownList(Widget parent, char *name, ArgList argv,
Cardinal argc)
The methods simply instantiate an XmComboBox in each of the various supported styles. For example:
#include <Xm/ComboBox.h>
extern Widget parent ;
Arg argv[MAX_ARGS] ;
Cardinal argc ;
Widget combo ;
Widget drop_down_combo ;
Widget drop_down_list ;
/*
** Specimen arguments for the widget. See Resource Table below.
*/
argc = 0 ;
XtSetArg(argv[argc], XmNvisibleItemCount, 12) ; argc++ ;
combo = XmCreateComboBox(parent, "combo", argv, argc) ;
...
drop_down_combo = XmCreateDropDownComboBox(parent, "drop_down_combo",
argv, argc) ;
...
drop_down_list = XmCreateDropDownList(parent, "drop_down_list",
argv, argc) ;
Ultimately, the Motif convenience creators are mapped down onto Xt Intrinsics methods in any case; these Xt methods can always be called
directly as an alternative.
Widget XtCreateWidget(char *name, WidgetClass class,
Widget parent, ArgList argv, Cardinal argc)
Widget XtCreateManagedWidget(char *name, WidgetClass class,
Widget parent, ArgList argv, Cardinal argc)
Widget XtVaCreateWidget(char *name, WidgetClass class,
Widget parent, ...) ;
Widget XtVaCreateManagedWidget(char *name, WidgetClass class,
Widget parent, ...) ;
For example:
#include <Xm/ComboBox.h>
extern Widget parent ;
Arg argv[MAX_ARGS] ;
Cardinal argc ;
Widget combo ;
Widget drop_down_combo ;
Widget drop_down_list ;
/*
** Specimen arguments for the widget. See Resource Table below.
*/
argc = 0 ;
XtSetArg(argv[argc], XmNcomboBoxType, XmCOMBO_BOX) ;
argc++ ;
combo = XtCreateWidget("combo", xmComboBoxWidgetClass,
parent, argv, argc) ;
...
XtSetArg(argv[argc], XmNcomboBoxType, XmDROP_DOWN_COMBOBOX) ;
argc++ ;
drop_down_combo = XtCreateManagedWidget("combo",
xmComboBoxWidgetClass, parent, argv, argc) ;
...
drop_down_list = XtVaCreateWidget("combo", xmComboBoxWidgetClass,
parent, XmNcomboBoxType, XmDROP_DOWN_COMBOBOX, NULL) ;
Note that if you use the generic Xt mechanisms, you must explicitly specify the type of ComboBox if you want a Drop-Down ComboBox or
Drop-Down List style. This is implicitly set if you are using the Motif convenience routines, but must be explicitly stated here.
More information on the various resources supported by the XmComboBox widget is given in the resource table below.
The geometry management associated with an XmComboBox is minimal: its layout of the constituent List and Text components is very basic,
and so there is no reason why an XmComboBox cannot be instantiated in the managed state (XtCreateManagedWidget(), ...). As a
general rule, geometry managers should be managed bottom-up after their children are all managed, in order to avoid explosive geometry
management effects. Here, since the XmComboBox is not acting as a general purpose layout manager, the performance side effects are minimal.
The Following table lists all the resources associated with the XmNcomboBox widget, specifying for each the class, type, default value,
and get/set access status.
Name | Class | Type | Default | Access |
XmNarrowSize | XmCArrowSize | Dimension | dynamic | CSG |
XmNarrowSpacing | XmCArrowSpacing | Dimension | dynamic | CSG |
XmNcolumns | XmCColumns | short | dynamic | CSG |
XmNcomboBoxType | XmCComboBoxType | unsigned char | dynamic | CG |
XmNfontList | XmCFontList | XmFontList | NULL | CSG |
XmNhighlightThickness | XmCHighlightThickness | Dimension | dynamic | CSG |
XmNitemCount | XmCItemCount | int | dynamic | CSG |
XmNitems | XmCItems | XmStringTable | dynamic | CSG |
XmNlist | XmCList | Widget | dynamic | G |
XmNmarginHeight | XmCMarginHeight | Dimension | 2 | CSG |
XmNmarginWidth | XmCMarginWidth | Dimension | 2 | CSG |
XmNmatchBehavior | XmCMatchBehavior | unsigned char | dynamic | CSG |
XmNpositionMode | XmCPositionMode | XtEnum | XmZERO_BASED | CSG |
XmNrenderTable | XmCRenderTable | XmRenderTable | dynamic | CSG |
XmNselectedItem | XmCSelectedItem | XmString | NULL | CSG |
XmNselectedPosition | XmCSelectedPosition | int | 0 | CSG |
XmNtextField | XmCTextField | Widget | dynamic | G |
XmNvisibleItemCount | XmCVisibleItemCount | int | 10 | CSG |
-
XmNarrowSize
Specifies the size of the drawn ArrowButton which the user "presses" to display the popup List of items.
The default value depends on the size of the TextField.
-
XmNarrowSpacing
Specifies the horizontal distance, measured in Pixels, between the drawn ArrowButton and the built-in TextField.
-
XmNcolumns
A "mirrored" resource, this specifies the number of columns to display in the built-in TextField.
-
XmNcomboBoxType
Specifies the logical type or style of ComboBox. Possible values are:
-
XmCOMBO_BOX
The List is permanently visible, and the TextField is editable.
-
XmDROP_DOWN_COMBO_BOX
The List is hidden until required, and the TextField is editable.
-
XmDROP_DOWN_LIST
The List is hidden until required, and the TextField is read-only.
-
XmNfontList
Specifies the font used for the List items, and the TextField. The XmFontList type
is considered deprecated from Motif 2.0 onwards; although maintained for backwards compatibility,
the XmRenderTable is now the preferred way of specifying compound string appearance.
-
XmNhighlightThickness
Specifies the thickness of the rectangle used for highlighting the XmComboBox widget. The default
value depends upon the XmDisplay object XmNenableThinThickness resource. If this is True,
the default is 1, otherwise 2.
-
XmNitemCount
Specifies the number of items in the XmComboBox internal List. The resource must be used in conjunction with the
XmNitems resource.
-
XmNitems
Specifies the set of items in the XmComboBox internal List. This resource is represented by an array of compound
strings (XmString).
-
XmNlist
Specifies the widget ID of the internal List widget associated with the XmComboBox. This resource is read-only: applications
cannot change the List component associated with the XmComboBox. The programmer can however fetch the value in order to
perform direct operations on the internal List when required.
-
XmNmarginHeight
Specifies the minimum vertical spacing between the XmComboBox top and bottom edges and the internal List and Text components.
-
XmNmarginWidth
Specifies the minimum horizontal spacing between the XmComboBox left and right edges and the internal List and Text components.
-
XmNmatchBehavior
Specifies whether keyboard input matching behavior is enabled for the internal List. If enabled, the user can type
the first character of an item in order to select that item, when the internal List is visible. Possible values are:
-
XmNpositionMode
Configures the way in which the selected position is reported in XmComboBox callbacks. XmComboBox callbacks are
considered in a section further down this document. Usually in Motif, List
widgets assume that the first item in the List is at position 1, zero being reserved for the last position. However,
under CDE, a set of desktop components were written which assumed that the first item is at position zero. For reasons
of compatibility, this resource can be set so that callbacks report the position in a manner consistent with the DtComboBox
component in particular. Possible values are:
Note that this resource only affects callback reporting, and the interpretation of the XmNselectedPosition resource.
Inserting or selecting items using the Motif convenience routines XmComboBoxAddItem(), XmComboBoxSelectItem(),
and XmComboBoxSetItem() (see below) always assume that the List has the first item at position 1.
-
XmNrenderTable
Specifies the render table used to render both the internal List and TextField components. If unspecified, this
will be inherited from a BulletinBoard or VendorShell ancestor. Any render table specified will take precedence over
any XmNfontList resource.
-
XmNselectedItem
Specifies the currently selected item associated with the XmComboBox. It is represented by a compound string (XmString).
-
XmNselectedPosition
Specifies the position of the currently selected item within the internal XmComboBox List. Interpretation depends upon
the value of the XmNpositionMode resource.
-
XmNtextField
Specifies the widget ID of the internal TextField component of the XmComboBox. This resource is read-only.
-
XmNvisibleItemCount
Specifies the number of visible items in the XmComboBox internal List. Setting this resource may affect the height
of the List widget, and hence the XmComboBox itself if the List is configured to be permanently visible.
The Motif toolkit defines the following convenience routines for the XmComboBox widget:
void XmComboBoxAddItem(Widget widget,
XmString item,
int position,
Boolean unique)
XmComboBoxAddItem() adds the specific item to the List component of the XmComboBox widget at the
specified position. A position of 1 represents the first item of the List, 2 inserts at the second position,
and so forth. A position of zero appends the item onto the end of the List. If unique is True,
the item is only inserted if it does not already appear in the XmComboBox List.
The item parameter is a compound string (XmString): this should be constructed using a standard XmString routine
such as XmStringCreateLocalized(), XmStringGenerate(), and so forth.
The XmComboBox takes a copy of the supplied item (or rather, the built-in List component does, through the routine
XmListAddItemUnselected()), and so the programmer should reclaim the utilized space associated with the item
by calling XmStringFree() at an appropriate point.
void XmComboBoxDeletePos(Widget widget,
int position)
XmComboBoxDeletePos() removes the item at the specified position from the internal XmComboBox List.
The first item in the List is at position 1, the second item is at position 2, and so forth. The last item in the List
can be removed by specifying zero as the position parameter.
Note that if no item exists in the XmComboBox List at the specified position, the Motif toolkit automatically raises
an error using the XmeWarning() routine, which maps onto XtAppWarningMsg(). By default, this will
write a message to the standard error output, unless the programmer has installed a customized Xt warning handler using the
routine XtAppSetWarningMsgHandler().
void XmComboBoxSelectItem(Widget widget,
XmString item)
XmComboBoxSelectItem() selects the first occurrence of the specified item in the XmComboBox internal List.
If the specified item is found within the List, it also automatically replaces the value in the XmComboBox TextField.
Just as XmComboBoxDeletePos() raises an error if the parameters to the routine are invalid, so does XmComboBoxSelectItem()
if the specified item is not found within the current internal List item array.
The item parameter is a compound string (XmString), which should be constructed through the standard XmString routines
such as XmStringCreateLocalized() or XmStringGenerate(). It is the responsibility of the programmer to reclaim the
utilized space associated with the item by calling XmStringFree() at an appropriate point after XmComboBoxSelectItem()
has been called.
void XmComboBoxSetItem(Widget widget,
XmString item)
XmComboBoxSetItem() is almost identical in behavior to XmComboBoxSelectItem(); the difference is that XmComboBoxSetItem()
also ensures that the given item is also visible in the internal List. If item is at a position greater than the
XmNvisibleItemCount resource of the XmComboBox widget, the item becomes the first visible item in the List.
void XmComboBoxUpdate(Widget widget)
XmComboBoxUpdate() updates the XmComboBox widget so thai it is synchronized with the state of the internal List component.
This would be required where the programmer decides to manipulate the contents of the internal List directly, rather than using XmComboBox
convenience functions and resources. In particular, the XmComboBox XmNselectedPosition, XmNitems, and XmNitemCount are
recalculated from the internal List, and used to reset the XmComboBox selected item where appropriate.
Note that only the routine XmComboBoxUpdate() was defined for Motif 2.0: all the other convenience functions are Motif 2.1 specific.
The XmComboBox defines a single Callback resource, XmNselectionCallback. Each callback on this callback list is passed the
following structure by the Motif toolkit:
typedef struct
{
int reason ;
XEvent *event ;
XmString item_or_text ;
int item_position ;
} XmComboBoxCallbackStruct ;
-
The reason field will always have the value XmCR_SELECT for an XmComboBox callback.
-
The event field is a standard X description of the event which triggered the callback.
-
The item_or_text field is a compound string (XmString) which represents the new selected item
in the XmComboBox widget. This element of the structure is temporarily allocated by the Motif toolkit
for the duration of the callback - if the programmer wants the value cached and utilized outside the scope
of the callback, the application should copy the value using XmStringCopy().
-
The item_position element specifies the index of the selected item within the internal List. The interpretation of the value
depends on the XmNpositionMode resource of the XmComboBox.
If this is XmONE_BASED, the first item in the List is
assumed to be at position one; it is possible for the toolkit to report an item_position of zero in these circumstances,
and this situation corresponds to the case where the user directly typed a new value into the XmComboBox TextField rather than
selecting from the List of choices.
If this is XmZERO_BASED, the first item in the List is at position zero. If we follow on from the previous paragraph,
it means that an item_position of zero is now ambiguous: it is not possible to distinguish between List selection and
TextField direct entry in this mode, just by inspection of the callback data.
As an example, consider the simple task of presenting the user with a set of Month names from which to select.
The example consists of the following code:
- MonthComboBox.c - the code which creates the widget hierarchy
- MonthComboBox.h - widget declarations
- MonthComboBox_stubs.c - selection callback code which prints out the current selection of the ComboBox as it is modified by the user.
- Makefile - a general purpose Makefile for the application. This is configured for Solaris,
although you will need to get hold of something later than Solaris 2.6 as this
is a Motif 1.2 platform. At the top of the file are rules for various platforms: simply
comment out the Solaris section, and uncomment your platform as required.
- MonthComboBox.xd - the X-Designer design save file, created with version 6 of the product.
Feel free to ignore this: the source codes can be read without the use of the GUI builder.
Alternatively download a tar archive, MonthCombopBox.tar, of all the above source files. If you are using Netscape
Navigator you may have to hold down the Shift key when you click on the file name in order to ensure that you
are prompted to save the file.
The XmComboBox style, as indicated by the XmNcomboBoxType resource, is a create-only attribute. This means that
the style of presentation is fixed once the component has been instantiated into the program. Unfortunately, the
default value of XmNcomboBoxType is XmCOMBO_BOX, which is the permanently visible List arrangement.
This means that an XmComboBox, created using default values and standard Xt Intrinsics creation routines, differs from the normal
understanding of how a ComboBox should look and feel. The default XmComboBox is not really a ComboBox at all; for proper ComboBox
behavior, the correct convenience routine must be called, or the style explicitly coded.
This is probably a minor technical mistake; the default style
can already be obtained out of standard components in any case.
The following materials are available for further reading. Firstly, for reference
materials on the Motif 2.1 toolkit, may I be so bold as to suggest:
Motif Reference Manual for Motif 2.1,
Antony Fountain and Paula Fergusson,
O'Reilly and Associates,
ISBN: 1-56592-654-4
Buy it from Amazon.com or Amazon.co.uk
A companion Motif 2.1 Programming Manual has been prepared for O'Reilly.
For a general Xt reference manual, the following is recommended:
X Toolkit Intrinsics Reference Manual,
Edited by David Flanagan,
O'Reilly and Associates,
ISBN: 1-56592-007-4
Buy it from Amazon.com or Amazon.co.uk
A good one-stop general purpose Motif programming manual is:
Advanced Motif Programming Techniques,
Alistair George and Mark Riches,
Prentice Hall,
ISBN: 0-13-219965-3
Unfortunately this book is out of print,
but you may be able to buy it from Amazon.com
This last volume is Motif 1.2 specific, although the general techniques which
are described remain invaluable, irrespective of the version of the toolkit you are using.
Sponsored
by X-Designer - The Leading X/Motif GUI Builder
- Click to download a FREE evaluation
Goto top of page