motifdeveloper.com
Sponsored by IST Limited
Formerly MW3: Motif on the World Wide Web [MW3 Logo]
Last Updated
January 20, 2004
 


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 can I restrict the length of a text field entry?

20-Jan-04 12:30 GMT

Question: How can I restrict the length of a text field entry and then automatically go to the next field?

I'm developing a data entry application consisting of a number of text fields. I need to be able to restrict the number of characters that can be entered by the user into each field and, when that maximum is reached, automatically tab to the next text field. How can I do this?

This can be achieved using the ModifyVerify callback of the XmTextField widget. This callback is triggered before any changes are made to the contents of XmText or XmTextField widgets. Inside this callback we validate the contents of the text field and call XmProcessTraversal to move to the next field when the criteria we have defined are reached.

All the information to we need to evaluate the current length of the text in the widget is available to us in the XmNmodifyVerifyCallback callback structure:

typedef struct {
    int reason;          /* the reason that the callback was called */
    XEvent *event;       /* points to event that triggered callback */
    Boolean doit;        /* do the action (True) or undo it (False) */
    long currInsert;     /* the insert cursor's current position    */
    long newInsert;      /* desired new position of insert cursor   */
    long startPos;       /* start of text to change                 */
    long endPos;         /* end of text to change                   */
    XmTextBlock text;    /* describes the text to insert            */
} XmTextVerifyCallbackStruct, *XmTextVerifyPtr;

The "text" element above points to the XmTextBlock structure which contains additional information we will use in our example:

typedef struct {
    char *ptr;           /* pointer to the text to insert           */
    int length;          /* length of this text                     */
    XmTextFormat format; /* text format (e.g., FMT8BIT, FMT16BIT)   */
} XmTextBlockRec, *XmTextBlock;

As always, this is best explained in some examples. The following example ModifyVerify callback code limits the number of characters in an XmTextField widget to 8 and traverses to the next tab group when that limit is reached. Note that we have to handle special conditions such as mouse pasting, selecting and overwriting text and, of course, character deletion:

The following code is available as modifyverify.c.

#include <Xm/Text.h>

#ifndef   MAX_FIELD_LENGTH
#define   MAX_FIELD_LENGTH   8
#endif /* MAX_FIELD_LENGTH */

void NextFieldAfterEightCharactersCallback(Widget w, XtPointer
			      client_data, XtPointer xt_call_data)
{
    XmTextVerifyCallbackStruct *call_data =
		     (XmTextVerifyCallbackStruct *) xt_call_data ;

    if (call_data != (XmTextVerifyCallbackStruct *) 0) {
	if (call_data->text->length == 0) {
	    /* Deletion - allow this */
	}
	else {
	    /*
	    ** A simple check of current_length +
	    ** call_data->text->length >= MAX_FIELD_LENGTH
	    ** is wrong, because if the user is typing over selected text,
	    ** the overall length can in fact decrease as the new text
	    ** replaces the old selection.
	    */

	    /* This returns the length of text before insertion */
	    XmTextPosition current_length = XmTextGetLastPosition(w) ;

	    /* The length of data to insert */
	    int insertion_length = call_data->text->length ;

	    /* A selection change will have end > start */
	    long change_length = call_data->endPos - call_data->startPos ;

	    /* The final new length of the text after insertion */
	    long new_length = (current_length + insertion_length
					      - change_length) ;

	    if (new_length == MAX_FIELD_LENGTH) {
		XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP) ;
	    }
	    else if (new_length > MAX_FIELD_LENGTH) {
		/* This can happen because of mouse paste */
		/* It can also happen because of a rogue  */
		/* programmatic XmTextSetString,          */
		/* or XtVaSetValues(w, XmNvalue, ...)     */
		/* which apply too much data              */
		call_data->doit = False ;
	    }
	}
    }
}

A more dynamic solution dynamic solution would take into account (and program) the XmNmaxLength resource of the Text, so that the specific upper-bound is not built into the callback, but can be set on a per-widget basis. The following example demonstrates this:

The following code is available as modifyverify2.c.

#include <Xm/Text.h>

static int GetTextMaximum(Widget w)
{
    int maxLength = 0 ;
    XtVaGetValues(w, XmNmaxLength, &maxLength, NULL) ;
    return maxLength ;
}

void NextFieldAfterMaxCharactersCallback(Widget w, XtPointer client_data,
					 XtPointer xt_call_data)
{
    XmTextVerifyCallbackStruct *call_data =
			(XmTextVerifyCallbackStruct *) xt_call_data ;

    if (call_data != (XmTextVerifyCallbackStruct *) 0) {
	if (call_data->text->length == 0) {
	    /* Deletion - allow this */
	}
	else {
	    /*
	    ** A simple check of current_length +
	    ** call_data->text->length >= XmNmaxLength
	    ** is wrong, because if the user is typing over selected text,
	    ** the overall length can in fact decrease as the new text
	    ** replaces the old selection.
	    */

	    int maximum = GetTextMaximum(w) ;

	    /* This returns the length of text before insertion */
	    XmTextPosition current_length = XmTextGetLastPosition(w) ;

	    /* The length of data to insert */
	    int insertion_length = call_data->text->length ;

	    /* A selection change will have end > start */
	    long change_length = call_data->endPos - call_data->startPos ;

	    /* The final new length of the text after insertion */
	    long new_length = (current_length + insertion_length
					      - change_length) ;

	    if (new_length == maximum) {
		XmProcessTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP) ;
	    }
	    else if (new_length > maximum) {
		/* This should not happen from the keyboard by */
		/* definition of XmNmaxLength                  */
		/* But it can happen because of a rogue        */
		/* programmatic XmTextSetString,               */
		/* or XtVaSetValues(w, XmNvalue, ...)          */
		/* which do not respect any setting            */
		/* of the XmNmaxLength resource.               */

		call_data->doit = False ;
	    }
	}
    }
}

 


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