The TextField displays the current selection from the set of choices. The upwards-pointing arrow selects
the next item in the set of choices, the downwards-pointing arrow selects the previous item. The SpinBox is
thus very similar to a ComboBox in nature; both widgets maintain a set of choices from which the user
may make a single selection, and both widgets present that selection through a TextField. The difference
is that the SpinBox supports the automatic selection of the next choice from the ordered set of choices,
rather than the user being presented with the full set through a popup List.
The notion of an ordered set is very important to the SpinBox. If it is not intuitively obvious what the "next"
or "previous" value means given the current selection, then the SpinBox is probably the wrong choice of interface
component. For example, if the set of values associated with the SpinBox is the names of the days of the week, then
if the current selection is "Monday", it is reasonably obvious what "next" or "previous" means.
On the other hand, if the set of choices consists of arbitrary data such as a list of car parts, then although
the data might well form a set (the complete inventory of all components required to build a car), it would not
necessarily be intuitively obvious what "next" means if the current selection is the exhaust pipe. Unless there
is in this case an imposed order on the choices (for example an alphabetical listing, or associated part numbers
in increasing order) which you can expect the user to intuitively understand, then using a SpinBox in
this context is likely to be entirely inappropriate - the user would not know whether to increment or decrement
to find the required new selection.
If the data is unordered, or if it does not form a closed set, then a List or ComboBox presentation is more
appropriate to the task at hand, because there exists the possibility for the user to see and browse through
all the choices before making a considered selection. If the data does form an ordered, closed set, then the
SpinBox is the natural choice of interface component, because it is more compact than the List-based
alternatives.
Motif supports two SpinBox components, variously introduced in versions 2.0 and 2.1 of the toolkit.
Motif 2.0 saw the introduction of the XmSpinBox widget class. This class is a general purpose constraint manager:
it does not come furnished with any built-in TextField components itself. What it does is lay out any
TextField components which the programmer adds to the widget, defines constraint resources so that a set of
values may be associated with each of the TextField children, and adds two ArrowButtons so that the values of the
TextField may be manipulated by the user (note that the Arrows are drawn, and not real widget sub-components).
The XmSpinBox spins the values associated with the TextField child which currently has the input focus.
In other words, the XmSpinBox class is an enabling technology which provides the mechanisms to rotate through a set
of values; the functionality which it provides is generic in that it supports the addition of multiple TextFields.
The XmSpinBox will accept other kinds of children as well, so that labels can be associated with each of the
TextField children; the XmSpinBox simply lays all of its children out in a horizontal line. Figure 2 is an
XmSpinBox which is configured to display a date.
To create the widget hierarchy of Figure 2, we simply add a Label and a TextField component to the XmSpinBox three times.
The XmSpinBox creates the ArrowButtons for us. These are used to increment or decrement the selection for the
TextField which currently has the input focus. There is thus a single set of ArrowButtons irrespective of the number of
TextField children.
The second SpinBox component in Motif is the XmSimpleSpinBox widget class, introduced in Motif 2.1. Derived
from the generic XmSpinBox, this class packages up the usual requirement, which is for selecting from a set of values
using a single TextField. The XmSimpleSpinBox creates this automatically on behalf of the programmer. It also mirrors
the constraint resources usually applied to TextField children into its own class, so that the set of values associated
with the built-in TextField child can conveniently be applied directly to the XmSimpleSpinBox. Figure 1 is in fact
a snapshot of an XmSimpleSpinBox component.
In Motif, SpinBox TextFields are considered to be of one of two kinds: a numeric field, where the programmer specifies
the set of values by setting upper and lower numerical bounds; and a string field, where the programmer supplies an
array of compound strings. The SpinBox supports both a
modify verify callback and a value changed callback, so that the programmer is notified when
the user requests a change to the current selection.
The XmSpinBox widget is a constraint manager. That is, it defines a set of extra resources for
each of its children, which control the set of values associated with each TextField child.
An XmSpinBox widget is created either through the Motif convenience routine XmCreateSpinBox(), or
via the various generic Toolkit Intrinsic routines such as XtCreateWidget(), as outlined
in the following code fragments:
/* Include the XmSpinBox widget class public header */
#include <Xm/SpinB.h>
extern Widget parent ;
Widget spinbox ;
Arg argv[10] ;
Cardinal argc = 0 ;
/* Create some arguments for the XmSpinBox */
/* The resources of the XmSpinBox are described below */
XtSetArg(argv[argc], XmNarrowLayout, XmARROWS_BEGINNING) ; argc++ ;
/* Create the XmSpinBox */
spinbox = XmCreateSpinBox(parent, "spinbox", argv, argc) ;
...
/* Alternative: X Toolkit mechanisms */
spinbox = XtCreateWidget("spinbox", xmSpinBoxWidgetClass, parent, argv, argc) ;
Since the geometry management which the XmSpinBox performs on behalf of its children is
fairly simplistic, the widget could be created in the managed state without excessive
performance overheads. For example:
spinbox = XtVaCreateManagedWidget("spinbox",
xmSpinBoxWidgetClass,
parent,
XmNarrowLayout,
XmARROWS_BEGINNING,
NULL) ;
XmSpinBox children are added in the normal manner consistent with any other
Xt Manager-derived widget. The XmSpinBox does not restrict the type of
child which can be added, although clearly some combinations are more sensible than others.
The typical arrangement is to add Label and TextField children. For example, ignoring the
problem of setting value resources for the moment, the
widget hierarchy associated with Figure 2 can be created as follows:
/* Include the XmSpinBox widget class public header */
#include <Xm/SpinB.h>
extern Widget parent ;
Widget spinbox ;
Widget label ;
Widget days ;
Widget months ;
Widget years ;
Arg argv[4] ;
Cardinal argc = 0 ;
XmString xms ;
/* Create the XmSpinBox itself */
spinbox = XmCreateSpinBox(parent, "date", argv, argc) ;
...
/* Add a "Date" Label */
argc = 0 ;
xms = XmStringCreateLocalized("Date") ;
XtSetArg(argv[argc], XmNlabelString, xms) ; argc++ ;
label = XmCreateLabel(spinbox, "date_label", argv, argc) ;
XtManageChild(label) ;
XmStringFree(xms) ; /* The widget takes a copy */
/* Add the "Days" TextField */
...
days = XmCreateTextField(spinbox, "days", argv, argc) ;
XtManageChild(days) ;
/* Add the first "/" separator Label */
...
xms = XmStringCreateLocalized("/") ;
XtSetArg(argv[argc], XmNlabelString, xms) ; argc++ ;
label = XmCreateLabel(spinbox, "day_separator", argv, argc) ;
XtManageChild(label) ;
XmStringFree(xms) ; /* The widget takes a copy */
/* Add the "Months" TextField */
...
months = XmCreateTextField(spinbox, "months", argv, argc) ;
XtManageChild(months) ;
/* Add the second "/" separator Label */
...
xms = XmStringCreateLocalized("/") ;
XtSetArg(argv[argc], XmNlabelString, xms) ; argc++ ;
label = XmCreateLabel(spinbox, "month_separator", argv, argc) ;
XtManageChild(label) ;
XmStringFree(xms) ; /* The widget takes a copy */
/* Add the "Years" TextField */
...
years = XmCreateTextField(spinbox, "years", argv, argc) ;
XtManageChild(years) ;
/* Display the XmSpinBox */
...
XtManageChild(spinbox) ;
Before turning to the constraint resources associated with the XmSpinBox, which are used to configure
the values associated with each TextField child, let us first look at
the general resources which can be configured for the widget class. The following table lists
the normal non-constraint resources for the widget, together with the default values and access
associated with each:
Name | Class | Type | Default | Access |
XmNarrowLayout | XmCArrowLayout | unsigned char | XmARROWS_END | CSG |
XmNarrowOrientation | XmCArrowOrientation | unsigned char | XmARROWS_VERTICAL | CSG |
XmNarrowSize | XmCArrowSize | Dimension | 16 | CSG |
XmNdefaultArrowSensitivity | XmCDefaultArrowSensitivity | unsigned char | XmARROWS_SENSITIVE | CSG |
XmNdetailShadowThickness | XmCDetailShadowThickness | Dimension | dynamic | CSG |
XmNinitialDelay | XmCInitialDelay | unsigned int | 250 | CSG |
XmNmarginHeight | XmCMarginHeight | Dimension | 2 | CSG |
XmNmarginWidth | XmCMarginWidth | Dimension | 2 | CSG |
XmNrepeatDelay | XmCRepeatDelay | unsigned int | 200 | CSG |
XmNspacing | XmCSpacing | Dimension | 2 | CSG |
-
XmNarrowLayout
Specifies the location of the SpinBox arrows. Possible values are:
-
XmARROWS_END
Both increment and decrement arrows are placed at the end of the SpinBox. The interpretation
of "end" depends upon the current XmNlayoutDirection: a right-to-left layout will place
the arrows at the beginning (before any children).
-
XmARROWS_SPLIT
The increment and decrement arrows are placed at each end of the SpinBox children. Again,
this resource is sensitive to the layout direction: a right-to-left layout places the
increment arrow on the left of any children.
-
XmARROWS_BEGINNING
Both arrows are placed before any children. A reversed right-to-left layout places them afterwards.
-
XmARROWS_FLAT_BEGINNING
Similar to XmARROWS_BEGINNING, excapt that the arrows are horizontally aligned, rather than one
above the other.
-
XmARROWS_FLAT_END
As XmARROWS_END, except the arrows are horizontally aligned.
Figure 3 illustrates the various effects of the XmNarrowLayout resource. The figure assumes a layout
direction of left-to-right.
-
XmNarrowOrientation
Specifies the orientation of the arrows. Possible values are:
-
XmARROWS_VERTICAL
The arrows point vertically, with the increment arrow pointing upwards, and the decrement arrow
pointing downwards. This is not affected by any layout direction.
-
XmARROWS_HORIZONTAL
The arrows point horizontally, with the increment arrow pointing to the right and the decrement
arrow pointing to the left. This is reversed if the layout direction is right-to-left.
-
XmNarrowSize
Specifies the width and height of the arrows, measured in pixels.
-
XmNdefaultArrowSensitivity
Specifies the default sensitivity of the arrow buttons to user input. Each TextField child of the
XmSpinBox can override this through the XmNarrowSensitivity constraint resource for the child;
further details of this will be given below. The possible values for XmNdefaultArrowSensitivity
are as follows:
-
XmARROWS_DECREMENT_SENSITIVE
The decrement arrow is insensitive (the user may not increment the current TextField value).
-
XmARROWS_INCREMENT_SENSITIVE
The increment arrow is insensitive (the user may not decrement the current TextField value).
-
XmARROWS_INSENSITIVE
Both arrows are insensitive (only the program may modify the current TextField value).
-
XmARROWS_SENSITIVE
Both arrows are sensitive (the user may increment or decrement at will).
-
XmNdetailShadowThickness
Specifies the thickness of the shadow used for drawing the ArrowButtons.
The toolkit accepts 0, 1, 2 as possible values. Note that the default
varies between Motif 2.0 and 2.1; the former has a default of 2, the latter
depends upon the XmDisplay object XmNenableThinThickness resource: if true,
the default is 1, otherwise 2.
-
XmNinitialDelay
Specifies a time interval, in milliseconds, which is to elapse after the user has first
pressed the mouse on an ArrowButton before automatic spinning comes into effect. What this
means is that the XmSpinBox will repeatedly increment (or decrement) the value associated
with the TextField which has the input focus until such time as the user releases the mouse.
how often it modifies the value whilst the mouse is pressed will depend on the XmNrepeatDelay
resource, discussed below.
-
XmNmarginHeight
Specifies the space between the top edge of the XmSpinBox and the topmost child, and the bottom edge of
the XmSpinBox and its bottommost child.
-
XmNmarginWidth
Specifies the space between the left edge of the XmSpinBox and the leftmost child, and the right edge of
the XmSpinBox and its rightmost child.
-
XmNrepeatDelay
Specifies a time interval (in milliseconds) between automatic increment/decrement of the current child TextField
value. If the resource is zero, automatic spinning of the current TextField value whilst the mouse is held
down is effectively disabled.
-
XmNspacing
Specifies the distance between children of the XmSpinBox in both the
horizontal and vertical directions.
In addition to the normal XmSpinBox resources, the widget defines the following constraints, used amongst
other things to specify the range of values associated with each TextField child. In other words,
although these resources are defined by the XmSpinBox, they should be applied to the relevant TextField
child. For example:
extern Widget text_child ;
XtVaSetValues(text_child, XmNarrowSensitivity, XmARROWS_SENSITIVE, NULL) ;
Name | Class | Type | Default | Access |
XmNarrowSensitivity | XmCArrowSensitivity | unsigned char | XmARROWS_DEFAULT_SENSITIVITY | CSG |
XmNdecimalPoints | XmCDecimalPoints | short | 0 | CSG |
XmNincrementValue | XmCIncrementValue | int | 1 | CSG |
XmNmaximumValue | XmCMaximumValue | int | 10 | CSG |
XmNminimumValue | XmCMinimumValue | int | 0 | CSG |
XmNnumValues | XmCNumValues | int | 0 | CSG |
XmNposition | XmCPosition | int | 0 | CSG |
XmNpositionType | XmCPositionType | unsigned char | XmPOSITION_VALUE | CSG |
XmNspinBoxChildType | XmCSpinBoxChildType | unsigned char | XmSTRING | CSG |
XmNvalues | XmCValues | XmStringTable | NULL | CSG |
XmNwrap | XmCWrap | Boolean | True | CSG |
-
XmNarrowSensitivity
Specifies the sensitivity of the XmSpinBox arrows when the TextField to which this constraint resource
is applied has the input focus. Possible values for the constraint resource are:
-
XmARROWS_DEFAULT_SENSITIVITY
The TextField is to inherit whatever default sensitivity (XmNdefaultArrowSensitivity) has been applied
to the XmSpinBox parent.
-
XmARROWS_DECREMENT_SENSITIVE
Only the decrement ArrowButton of the XmSpinBox will be sensitive if this TextField
has the current input focus.
-
XmARROWS_INCREMENT_SENSITIVE
Only the increment ArrowButton of the XmSpinBox will be sensitive if this TextField
has the current input focus.
-
XmARROWS_SENSITIVE
Both the decrement and the increment ArrowButton of the XmSpinBox will be sensitive if this TextField
has the current input focus.
-
XmARROWS_INSENSITIVE
Neither the decrement nor the increment ArrowButton of the XmSpinBox will be sensitive if this TextField
has the current input focus.
-
XmNdecimalPoints
Specifies the number of decimal points to use when displaying numeric data.
-
XmNincrementValue
Specifies by how much to increment (and, indeed, decrement) the value of the TextField which
has the input focus, if the user presses one of the ArrowButtons.
-
XmNmaximumValue
Specifies the upper bound allowed in a numeric TextField child of the XmSpinBox.
-
XmNminimumValue
Specifies the lower bound allowed in a numeric TextField child of the XmSpinBox.
-
XmNnumValues
Specifies the size of the compound string table associated with the XmNvalues resource.
-
XmNposition
Specifies the current value of the TextField. An unnecessarily complex resource, because its interpretation
depends on several factors, and it is sensitive to the values of the XmNpositionType and
XmNspinBoxChildType resources.
In essence, the position can either represent an index into the set of values associated with this
TextField, or it can be an absolute value between the maximum and minimum bounds.
In a string-based TextField, the position will always be an index into the set of compound string values.
In a numeric TextField, and if XmNpositionType is XmPOSITION_VALUE, the position will be
an absolute value between the maximum and minimum bounds. If XmNpositionType is XmPOSITION_INDEX,
the position is calculated according to the formula:
minimum + (n * increment)
That is, position zero is the minimum bound, position 1 is the minimum plus one increment, position 2
is the minimum plus two increments, and so forth.
-
XmNpositionType
Specifies how the position is to be interpreted. The possible values are:
-
XmNspinBoxChildType
This is the resource which controls whether a TextField child of the XmSpinBox
is numeric or string-based in nature. Possible values are:
-
XmSTRING
The TextField is string-based; it uses the XmNvalues and XmNnumValues resources
to provide the set of values associated with this component.
-
XmNUMERIC
The TextField is numerical; it uses the XmNmaximumValue, XmNminimumValue, and
XmNincrementValue resources to calculate the set of values associated with this component.
-
XmNvalues
For a string-based TextField, this will specify the set of values, expressed through
an array of compound strings. It should be manipulated in conjunction with the XmNnumValues
resource.
-
XmNwrap
Specifies whether the XmSpinBox allows the values associated with this TextField child to wrap
around. That is, if the current position is at the maximum and the user presses the increment
arrow, the new position wraps round to the minimum. Similar logic holds if the current position
is at the minimum and the user presses the decrement arrow. If XmNwrap is True, wrapping
is allowed; False, and the bell is rung and the position stays at the current value.
The XmSpinBox defines two callback resources which can be used to intercept, validate, or
generally receive notification of changes to the current value associated with any TextField child.
They are as follows:
-
XmNmodifyVerifyCallback
Callbacks associated with this resource are invoked when an attempt is made by the user to modify
the position associated with a TextField child. The callbacks are invoked before
the position is actually modified, and the programmer may accept, modify, or reject the requested
new position by suitable alteration of data passed by the toolkit to the callback. The data
structure associated with callbacks of this type is given below.
-
XmNvalueChangedCallback
This resource specifies a list of callbacks which are to be invoked after the position associated
with any TextField child is changed.
Each callback is passed the following structure when invoked:
typedef struct
{
int reason ;
XEvent *event ;
Widget widget ;
Boolean doit ;
int position ;
XmString value ;
Boolean crossed_boundary ;
} XmSpinBoxCallbackStruct;
The reason element indicates why the callback has been triggered. This can have one of
the following values:
-
XmCR_SPIN_FIRST
The position associated with the current focused TextField is either at the minimum value,
or the first item in the array of values, depending on whether the TextField is set numeric
or string-based.
-
XmCR_SPIN_LAST
The position associated with the current focused TextField is either at the maximum value,
or the last item in the array of values, depending on whether the TextField is set numeric
or string-based.
-
XmCR_SPIN_NEXT
The increment arrow has been armed.
-
XmCR_SPIN_PRIOR
The decrement arrow has been armed.
-
XmCR_OK
The previously-armed arrow has been disarmed.
The event element is a pointer to a structure which describes the event
which triggered the callback.
The widget element is set to the TextField child affected by the callback:
it will be the widget which currently has the keyboard/input focus.
The doit element is a Boolean flag which indicates whether the requested action is
to be allowed. By default, this will be True, but the programmer may set this False
to prevent the requested modification to the current value of the TextField widget.
The position element specifies the requested new position for the TextField child which
has the input focus. The programmer can in fact modify this element in an XmNmodifyVerifyCallback
to force an alternative new position for the widget.
The value element is a compound string representing the new value to display in the TextField
widget. The element is temporarily allocated solely for the purposes of the callback - the
programmer should take a copy if this is to be stored and manipulated outside the scope of the current
callback.
The crossed_boundary element specifies whether the position associated with the TextField
widget has crossed the upper or lower boundary specified by the XmNminimumValue or
XmNmaximumValue constraints (for a numeric TextField), or the first or last item in the
XmNvalues array (for a string-based TextField). This will tell the programmer that a
request has been made to wrap around to the start (end) of the valid set of values.
The following convenience routine is defined for the XmSpinBox class:
int XmSpinBoxValidatePosition(Widget text, int *position_value)
XmSpinBoxValidatePosition() checks that the text child of
an XmSpinBox has a valid position and value. If the current position is valid,
it is returned into the address specified by position_value. The function also returns
an integer representing the status of the check, as follows:
-
XmCURRENT_VALUE
This is returned if the XmNspinBoxChildType of text is not XmNUMERIC.
-
XmMINIMUM_VALUE
The current XmNposition resource of text is less than the XmNminimumValue
resource of the widget.
-
XmMAXIMUM_VALUE
The current XmNposition resource of text is greater than the XmNmaximumValue
resource of the widget.
-
XmINCREMENT_VALUE
The current XmNposition resource of text falls between
the minimum and maximum bounds set for the widget. In addition, the position
should not fall on an increment boundary. That is, it is not defined by:
minimum + (n * increment)
The nearest value (not less than the current value) which does fall on an increment is calculated,
and returned in the position_value parameter of the function.
-
XmNVALID_VALUE
The current XmNposition resource of text falls between
the minimum and maximum bounds set for the widget. In addition, unlike
the case for XmINCREMENT_VALUE, the position does fall on an increment boundary.
Note that this routine does not modify the current position associated with text.
The following code adds a Label and TextField to an XmSpinBox, and configures the TextField
to display the names of the months.
/* Include the XmSpinBox widget class public header */
#include <Xm/SpinB.h>
extern Widget parent ;
Widget spinbox ;
Widget label ;
Widget text ;
Arg argv[12] ;
Cardinal argc = 0 ;
XmString *xmtable ;
XmString xms ;
int i ;
/* Create the XmSpinBox */
argc = 0 ;
spinbox = XmCreateSpinBox(parent, "spin", argv, argc) ;
...
/* Create the Label */
argc = 0 ;
xms = XmStringCreateLocalized("Month") ;
XtSetArg(argv[argc], XmNlabelString, xms) ; argc++ ;
label = XmCreateLabel(spinbox, "months_l", argv, argc) ;
XmStringFree(xms) ;
XtManageChild(label) ;
/* Create the TextField */
argc = 0 ;
XtSetArg(argv[argc], XmNspinBoxChildType, XmSTRING) ; argc++ ;
XtSetArg(argv[argc], XmNarrowSensitivity, XmARROWS_SENSITIVE) ; argc++ ;
XtSetArg(argv[argc], XmNwrap, True) ; argc++ ;
/* Specify the Values */
xmtable = (XmString *) XtMalloc((unsigned) 12 * sizeof(XmString)) ;
xmtable[0] = XmStringCreateLocalized("January") ;
xmtable[1] = XmStringCreateLocalized("February") ;
xmtable[2] = XmStringCreateLocalized("March") ;
xmtable[3] = XmStringCreateLocalized("April") ;
...
xmtable[10] = XmStringCreateLocalized("November") ;
xmtable[11] = XmStringCreateLocalized("December") ;
XtSetArg(argv[argc]. XmNnumValues, 12) ; argc++ ;
XtSetArg(argv[argc]. XmNvalues, xmtable) ; argc++ ;
/* Specify the initial value (March, say) */
XtSetArg(argv[argc], XmNposition, 2) ; argc++ ;
text = XmCreateTextField(spinbox, "months_t", argv, argc) ;
/* The widget takes a copy. Free the utilized space */
for (i = 0 ; i < 12 ; i++)
XmStringFree(xmtable[i]) ;
XtFree((char *) xmtable) ;
XtManageChild(text) ;
/* Display the SpinBox */
XtManageChild(spinbox) ;
The alternative presentation, with integral months, could be created with the following kind of code:
...
/* Create the TextField */
argc = 0 ;
XtSetArg(argv[argc], XmNspinBoxChildType, XmNUMERIC) ; argc++ ;
XtSetArg(argv[argc], XmNarrowSensitivity, XmARROWS_SENSITIVE) ; argc++ ;
XtSetArg(argv[argc], XmNwrap, True) ; argc++ ;
/* Specify the Values */
XtSetArg(argv[argc], XmNminimumValue, 1) ; argc++ ;
XtSetArg(argv[argc], XmNmaximumValue, 12) ; argc++ ;
XtSetArg(argv[argc], XmNincrementValue, 1) ; argc++ ;
/* Specify the initial value (March, say) */
XtSetArg(argv[argc], XmNpositionType, XmPOSITION_VALUE) ; argc++ ;
XtSetArg(argv[argc], XmNposition, 3) ; argc++ ;
text = XmCreateTextField(spinbox, "months_t", argv, argc) ;
...
The following Figure 4 is of a SpinBox configured to display a 24 hour clock. Callbacks have been added
so that if the user presses the increment Arrow when the seconds, or minutes fields are at the maximum,
the corresponding minutes and hours fields are updated automatically. That is, with the time at 10:59:59,
and the user places the focus in the seconds TextField, subsequently pressing the increment Arrow, then
the new time will display 11:0:0. Similar logic holds if the seconds/minutes fields are showing zero, and the user
presses the decrement Arrow. The application also initializes itself to display the current time correctly
on start up.
The example consists of the following code:
- SpinBoxClock.c - the code which creates the widget hierarchy
- SpinBoxClock.h - widget declarations
- SpinBoxClock_stubs.c - the callback code which ensures that values wrap round the various fields correctly as the time is incremented/decremented 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.
- SpinBoxClock.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, SpinBoxClock.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 XmSimpleSpinBox widget is derived from the XmSpinBox widget, which means that it
inherits all of the callbacks, normal resources, and constraint resources from that parent class.
It packages up the most frequent requirement, which is for a SpinBox with a single TextField component.
For this reason, unlike the XmSpinBox, the XmSimpleSpinBox automatically creates a TextField child
on behalf of the programmer. Furthermore, as a convenience, it implements what is known as a mirror.
That is, the resources and constraints which would normally have to be set upon a child or descendant
component can be applied directly to the XmSimpleSpinBox itself, and the widget automatically distributes
the values downwards to the built-in TextField.
An XmSimpleSpinBox widget is created either through the Motif convenience routine XmCreateSimpleSpinBox(), or
via the various generic Toolkit Intrinsic routines such as XtCreateWidget(), as outlined
in the following code fragments:
/* Include the XmSimpleSpinBox widget class public header */
#include <Xm/SSpinB.h>
extern Widget parent ;
Widget simplespin ;
Arg argv[10] ;
Cardinal argc = 0 ;
/* Create some arguments for the XmSimpleSpinBox */
/* The resources of the XmSimpleSpinBox are described below, */
/* although it inherits the XmSpinBox resources, and mirrors */
/* the constraints into the internal TextField child. */
/* For example, the following resource is inherited. */
XtSetArg(argv[argc], XmNarrowLayout, XmARROWS_BEGINNING) ; argc++ ;
/* Create the XmSimpleSpinBox */
simplespin = XmCreateSimpleSpinBox(parent, "simple", argv, argc) ;
...
/* Alternative: X Toolkit mechanisms */
simplespin = XtCreateWidget("simple", xmSimpleSpinBoxWidgetClass, parent, argv, argc) ;
The XmSimpleSpinBox resource set includes a mirror. This means that resources which are usually
applied to child objects can be applied directly to the XmSimpleSpinBox itself, and the widget will distribute
the values downwards on behalf of the programmer. In this instance, the mirror includes the constraint resources
of the XmSpinBox, so that the range of values associated with the built-in TextField can be conveniently
applied to either the TextField or the SpinBox: the effect is the same. This TextField can be accessed either
through the XmNtextField resource of the XmSimpleSpinBox (see table below), or through the routine
XtNameToWidget(). The TextField is called "nnn_TF", where nnn is the name of the parent XmSimpleSpinBox.
Name | Class | Type | Default | Access |
XmNarrowSensitivity | XmCArrowSensitivity | unsigned char | XmARROWS_SENSITIVE | CSG |
XmNcolumns | XmCColumns | short | 20 | CSG |
XmNdecimalPoints | XmCDecimalPoints | short | 0 | CSG |
XmNincrementValue | XmCIncrementValue | int | 1 | CSG |
XmNmaximumValue | XmCMaximumValue | int | 10 | CSG |
XmNminimumValue | XmCMinimumValue | int | 0 | CSG |
XmNnumValues | XmCNumValues | int | 0 | CSG |
XmNposition | XmCPosition | int | 0 | CSG |
XmNpositionType | XmCPositionType | unsigned char | XmPOSITION_VALUE | CG |
XmNspinBoxChildType | XmCSpinBoxChildType | unsigned char | XmSTRING | CSG |
XmNtextField | XmCTextField | Widget | dynamic | G |
XmNvalues | XmCValues | XmStringTable | NULL | CSG |
XmNwrap | XmCWrap | Boolean | True | CSG |
The resource table here is almost identical to the Constraint resource table for the XmSpinBox, and the
interpretation of identically named resources will be the same in each case. The exceptional resources are:
-
XmNtextField
Specifies the widget ID of the TextField which the XmSimpleSpinBox creates automatically. This resource
is strictly read-only.
-
XmNcolumns
Specifies the width (measured in characters) of the built-in TextField. This resource is not available
in the normal XmSpinBox constraint set, but is a natural resource of a TextField. It is only provided
in the XmSimpleSpinBox mirror as a convenience.
The XmSimpleSpinBox defines no new callback resources: it inherits the XmNmodifyVerify
and XmNvalueChanged callbacks from the XmSpinBox widget class. These are described
in the XmSpinBox Callbacks section above.
A small number of convenience routines are defined for the XmSimpleSpinBox widget.
These all happen to assume that the XmNspinBoxChildType is XmNUMERIC;
indeed, they will tend to silently fail if this is otherwise. The exception is
XmSimpleSpinBoxSetItem() which can raise a warning, although this will depend
on various factors associated with whether the current XmNposition value actually
refers to a valid index into the array of items.
void XmSimpleSpinBoxAddItem(Widget spinb, XmString item, int position)
This routine adds an item at the specified position in the array
of values associated with the TextField child of the XmSimpleSpinBox widget spinb.
The first item in the set of values is considered to be at position 1. If position
is zero, or exceeds the current number of items, the item is simply appended.
void XmSimpleSpinBoxDeletePos(Widget spinb, int position)
XmSimpleSpinBoxDeletePos() removes the item at the given position
from the list of values associated with the TextField child of the spinb widget.
The first item is considered to be at position 1. A position of zero will delete the last
item in the set of values.
void XmSimpleSpinBoxSetItem(Widget spinb, XmString item)
This procedure makes item the current value associated with the XmSimpleSpinBox
widget. If item is not found within the set of values associated with the spinb
widget, a warning message is displayed. Otherwise, the XmNposition resource of the widget
is modified to reflect the index of the supplied item within the array of values. Unlike
the previous convenience routines, no internal check is performed to ensure that the XmSimpleSpinBox
is numeric in nature.
Following on from the example given in the XmSpinBox sections, a month field can alternatively be created
out of the XmSimpleSpinBox as follows. Note that the code is extremely similar: the differences are
simply that we apply resources directly to the XmSimpleSpinBox and not to any TextField child (although
we could do so post-create should we so wish).
/* Include the XmSimpleSpinBox widget class public header */
#include <Xm/SSpinB.h>
extern Widget parent ;
Widget spinbox ;
Arg argv[12] ;
Cardinal argc = 0 ;
XmString *xmtable ;
XtSetArg(argv[argc], XmNspinBoxChildType, XmSTRING) ; argc++ ;
XtSetArg(argv[argc], XmNarrowSensitivity, XmARROWS_SENSITIVE) ; argc++ ;
XtSetArg(argv[argc], XmNwrap, True) ; argc++ ;
XtSetArg(argv[argc], XmNcolumns, 15) ; argc++ ;
/* Specify the Values */
xmtable = (XmString *) XtMalloc((unsigned) 12 * sizeof(XmString)) ;
xmtable[0] = XmStringCreateLocalized("January") ;
xmtable[1] = XmStringCreateLocalized("February") ;
xmtable[2] = XmStringCreateLocalized("March") ;
xmtable[3] = XmStringCreateLocalized("April") ;
...
xmtable[10] = XmStringCreateLocalized("November") ;
xmtable[11] = XmStringCreateLocalized("December") ;
XtSetArg(argv[argc]. XmNnumValues, 12) ; argc++ ;
XtSetArg(argv[argc]. XmNvalues, xmtable) ; argc++ ;
/* Specify the initial value (March, say) */
XtSetArg(argv[argc], XmNposition, 2) ; argc++ ;
spinbox = XmCreateSimpleSpinBox(parent, "months_t", argv, argc) ;
/* The widget takes a copy. Free the utilized space */
for (i = 0 ; i < 12 ; i++)
XmStringFree(xmtable[i]) ;
XtFree((char *) xmtable) ;
/* Display the SpinBox */
XtManageChild(spinbox) ;
...
The ConstraintSetValues routine of the XmSpinBox widget only manipulates certain resources
depending upon the XmNspinBoxChildType resource of the current child. For example,
attempting to specify an array of compound strings to represent the values of a TextField
will silently fail if the TextField is currently numeric in nature: the class method simply fails
to take a copy at all. Similarly, setting minimum, maximum, and increment bounds for a TextField
child will also fail to take effectively if the child is currently set to be string-based; in this
case, the value may well be recorded in the constraints of the given component, but the widget
will fail to redisplay the child dynamically, and it will also fail to validate the values.
Since the XmSimpleSpinBox is built on top of the XmSpinBox, this also holds true for
the XmSimpleSpinBox widget: you must ensure that the widget for which you are attempting to
set values (or a range of values) is in the correct mode before applying the required
resources.
This also holds true of the convenience routines associated with the XmSpinBox and XmSimpleSpinBox:
XmSimpleSpinBoxAddItem() fails if the SimpleSpinBox is logically numeric, and similar logic holds for
all the other routines.
Note that the specification originally intended that changing the XmNspinBoxChildType
would be forbidden - it was designed originally as a create-only resource - however
a requirement that the widget remained compatible with the DtSpinBox widget relaxed
the restriction, so that the logical type of a TextField child can indeed be modified
if and when required.
In practical terms, it is unlikely that a SpinBox TextField child is likely to change
from string-based to numeric calculations. Be warned, however, that a certain code order is
required if you want to change the data and type of a TextField component: you must change the
XmNspinBoxChildType before or simultaneously to specifying the new data.
The ConstraintDestroy method of the XmSpinBox does however clean itself up correctly, irrespective
of the mode of the TextField children, and so there is no memory leak associated with changing
a SpinBox from string to numeric in nature: any array of compound strings specified for the XmNvalues
resource will be deallocated regardless. This, however, is only effective on the destruction of a
SpinBox child, so that if a string-based SpinBox is changed to a numerical basis, the compound strings
previously associated with the value remain extant until such time as the widget itself is freed, unless
the programmer takes the trouble to deallocate the items herself before changing mode.
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,
which hopefully will be available in the not too distant future.
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