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
|