motifdeveloper.com
Sponsored by IST Limited
Formerly MW3: Motif on the World Wide Web [MW3 Logo]
Last Updated
November 18, 2002
 


X-Designer - The Leading X/Motif GUI Builder - Click to download a FREE evaluation
 

motifdeveloper.com
Home
About the site
Bulletin Board
News Archive
OpenGroup News
Events
Search
Frequently Asked Questions
The Motif FAQ
X/Motif FAQs
General FAQs
Ask Antony
Latest Q & A
All Q & As
Submit Question
Tips & Pointers
Code Examples
Software
OpenMotif
Widget Sets
GUI Toolkits & Libraries
Motif suppliers
Non-commercial S/W
Commercial Software
Multimedia
Miscellaneous
Organizations
Docs & Pubs
X/Motif Newsgroups
Security
Internationalization
Feedback
Feedback Form
Contributors
 

How do you use the SpinBox and SimpleSpinBox widgets?

21-Mar-01 16:00 GMT

Introduction

A SpinBox is a component which allows the user to cycle through a set of choices. The component is usually presented to the user through a TextField component, with a pair of ArrowButtons which are used for selecting the previous or next item from the choice set. Figure 1 shows a SpinBox configured for selecting from the months of the year.

Figure 1 - A SpinBox

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.

When to use a SpinBox

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.

The Motif SpinBox Components

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.

Figure 2 - the XmSpinBox 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

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.

Creating an XmSpinBox widget

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) ;

Adding XmSpinBox Children

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:

XmSpinBox Resources

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.

    Figure 3 - the XmNarrowLayout resource and its effects

  • 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 relevent TextField child. For example:

	extern Widget text_child ;

	XtVaSetValues(text_child, XmNarrowSensitivity, XmARROWS_SENSITIVE, NULL) ;

XmSpinBox Constraint Resources

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:

    • XmPOSITION_VALUE

      The position is an absolute value between the minimum and maximum bounds.

    • XmPOSITION_INDEX

      The position is an index into the set of possible values for the TextField.

  • 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.

XmSpinBox Callbacks

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.

XmSpinBox Convenience Routines

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.

An XmSpinBox Example

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) ;
	...

Another XmSpinBox Example, using Callbacks

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.

Figure 4: A SpinBox displaying the time

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

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.

Creating an XmSimpleSpinBox widget

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) ;

XmSimpleSpinBox Resources

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.

XmSimpleSpinBox Callbacks

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.

XmSimpleSpinBox Convenience Routines

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.

An XmSimpleSpinBox Example

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) ;
	...

Quirks

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.

Bibliography

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

 

[IST Limited]
IST Limited is the
proud sponsor of motifdeveloper.com.
 

Thanks to all the contributors to these pages.

Privacy Policy

 
"Motif" is a registered trademark of The Open Group. All other trademarks are the property of their respective owners.

Some articles/papers here have their own copyright notice. All other information is copyright ©1999-2008 IST Limited

[CommerceOne] MW3 site originally by Ken Sall of Commerce One (formerly Century Computing).