How can I change the colors in a TextField as characters are typed?
|
7-Feb-01 12:00 GMT
|
Question:
In a TextField widget with white background and black foreground, how can I get the background to change to a
different color as soon as I type in a first new character. Then, when I have finished entering the new data,
and ONLY when I hit the return key, the original background color returns?
Colors in a TextField can be changed as characters are typed
using the following methods:
-
Add an XmNmodifyVerifyCallback which simply changes the Text Colors from the normal background and foreground
-
Add an XmNactivateCallback which reverts the foreground and background back to the normal default
-
For safety, add an XmNfocusOutCallback which also reverts the colors. This is in case the user
moves out of the TextField using the mouse pointer, rather than presses the Activate key.
Firstly, we define a utility routine to change the TextField colors: this routine is
generalized to change both background and foreground, although the question as originally
framed was only concerned with the background. This scheme allows for either both background and
foreground changes, or for a single resource change.
/*
** Motif 1.2 does not define this, but Motif 2.1 does
*/
#ifndef XmUNSPECIFIED_PIXEL
#define XmUNSPECIFIED_PIXEL ((Pixel) (~0))
#endif /* XmUNSPECIFIED_PIXEL */
static void set_text_colors(Widget text, Pixel new_fg, Pixel new_bg)
{
Pixel current_fg = XmUNSPECIFIED_PIXEL ;
Pixel current_bg = XmUNSPECIFIED_PIXEL ;
Arg argv[2] ;
Cardinal argc = 0 ;
if (new_fg != XmUNSPECIFIED_PIXEL) {
XtSetArg (args[argc], XmNforeground, ¤t_fg) ; argc++ ;
}
if (new_bg != XmUNSPECIFIED_PIXEL) {
XtSetArg (args[argc], XmNbackground, ¤t_bg) ; argc++ ;
}
if (argc > 0) {
XtGetValues (text, argv, argc) ;
argc = 0 ;
if ((new_fg != XmUNSPECIFIED_PIXEL) && (new_fg != current_fg)) {
XtSetArg (args[argc], XmNforeground, new_fg) ; argc++ ;
}
if ((new_bg != XmUNSPECIFIED_PIXEL) && (new_bg != current_bg)) {
XtSetArg (args[argc], XmNbackground, new_bg) ; argc++ ;
}
if (argc > 0) {
XtSetValues (text, argv, argc) ;
}
}
}
Secondly, a utility to convert from a color name to a Pixel value. This is not actually
used in the example callbacks below, but is provided for those who require the extra information.
The callbacks below assume that the Pixel values are already allocated.
Pixel convert_color_name_to_pixel(Widget any_widget, char *name)
{
XrmValue from_value ;
XrmValue to_value ;
from_value.addr = name ;
from_value.size = strlen(name) + 1 ;
to_value.addr = (XtPointer) 0 ;
XtConvertAndStore(any_widget, XmRString, &from_value, XmRPixel, &to_value) ;
if (to_value.addr != (XtPointer) 0) {
return (*(Pixel *) to_value.addr) ;
}
return XmUNSPECIFIED_PIXEL ;
}
This routine simply changes the foreground/background colors of the TextField to the
stand-out colors. We assume here that the Pixel values associated with the requirements
are already allocated.
extern Pixel special_foreground ;
extern Pixel special_background ;
void text_modify_verify_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
/* Simple: just call the text color change utility routine */
/* If you only want foreground, pass XmUNSPECIFIED_PIXEL as background, */
/* and vice versa for background-only changes. */
set_text_colors(text, special_foreground, special_background) ;
}
These are identical in effect, so you could add the same callback to each. You need to cache the
original pre-editing TextField foreground and background colors before applying the callback(s).
The following kind of code can be used for this purpose:
Pixel cached_text_foreground ;
Pixel cached_text_background ;
XtVaGetValues (text,
XmNforeground, &cached_text_foreground,
XmNbackground, &cached_text_background,
NULL) ;
The callbacks themselves are therefore as follows:
void text_focus_out_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
/* Again simple: just call the text color change utility routine */
/* but this time using the cached original colors. */
/* if you are only changing the foregrounds, pass XmUNSPECIFIED_PIXEL */
/* as the background parameter (and vice versa). */
set_text_colors(text, cached_text_foreground, cached_text_background) ;
}
void text_activate_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
/* As above */
set_text_colors(text, cached_text_foreground, cached_text_background) ;
}
A simple application which contains a single dialog with two TextFields configured for color change
is given in the following sources. The application has been built using X-Designer for speed,
although you don't need the GUI builder in any way to read, understand, or build the program.
The design file is included with the sample sources, in case anyone is interested or has use of this.
The example consists of the following code:
-
TextColors.c - the code which creates the widget hierarchy
-
TextColors.h - widget declarations
-
TextColors_stubs.c- callback code
-
Makefile - a general purpose Makefile for the application. Its configured for Solaris, but at the top of the file are
rules for various platforms: simply comment out the Solaris section, and uncomment your platform as required.
-
TextColors.xd - the X-Designer design save file. Feel free to ignore this.
Alternatively download a tar archive, TextColors.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 scheme above will perform an XtGetValues() call on every keyboard event in the TextField.
Although there are generally far more expensive things going on in an application which are more
worthy of attention, there are a few slight modifications which could be considered, and which
are left as an exercise for the reader:
-
Don't call the color change routine if the user is deleting characters. At present, if the user
switches into the TextField, and selects characters with the mouse, then deletes these, the contents
changes to the stand-out color only when the delete key is issued. This may or may not be as required.
void text_modify_verify_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
XmTextVerifyCallbackStruct *tp =
(XmTextVerifyCallbackStruct *) call_data ;
if (call_data->text->length > 0) {
set_text_colors(text, special_foreground, special_background) ;
}
}
-
Add an XmNfocusInCallback which sets a flag such that the colors are checked only once,
if and only if a character is typed.
Boolean change_colors = False ;
void text_focus_in_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
change_colors = True ;
}
void text_modify_verify_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
XmTextVerifyCallbackStruct *tp =
(XmTextVerifyCallbackStruct *) call_data ;
if (change_colors && (tp->text->length > 0)) {
set_text_colors(text, special_foreground, special_background) ;
change_colors = False ;
}
}
This scheme ought to work in principle regardless of the number of TextFields involved, provided that
they share the same XmNmodifyVerifyCallback. There should be no need to make sure that
a XmNfocusOutCallback sets the change flag to false, since any subsequent focus-in for any TextField
will simply reset it.
-
The scheme could indeed be modified so that focus-in changes the text to the stand-out mode,
focus-out reverts to normal colors, regardless of whether anything is typed. This would
do away with the need for a modify verify callback. In effect, it simply becomes a kind
of special focus highlighting, and is not related to any typing. This, however, is
not the same as the question requirements as originally stated.
void text_focus_in_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, special_foreground, special_background) ;
}
void text_focus_out_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, cached_text_foreground, cached_text_background) ;
}
-
A combination of effects is also possible, so that the background is changed on focus in,
leaving the original foreground, which is only modified on text change, and the foreground
reverts on activate.
void text_focus_in_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, XmUNSPECIFIED_PIXEL, special_background) ;
}
void text_focus_out_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, cached_text_foreground, cached_text_background) ;
}
void text_modify_verify_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, special_foreground, XmUNSPECIFIED_PIXEL) ;
}
void text_activate_callback
(Widget text, XtPointer client_data, XtPointer call_data)
{
set_text_colors(text, cached_text_foreground, XmUNSPECIFIED_PIXEL) ;
}
Sponsored
by X-Designer - The Leading X/Motif GUI Builder
- Click to download a FREE evaluation
Goto top of page
|