5—
Label and Entry Widgets
There are times you'll want users to type in specific information such as their name, address, or even a serial number. The simplest way to do this is to use entry widgets. You can use a label widget with an entry to clearly communicate to the user what should be typed in the entry. Most often, you'll see the label and entry combination used multiple times in a database entry-type window where there are many different pieces of information the user must enter.
The Label Widget
0102-01.gifSo far, all we have talked about are buttons, buttons, and more buttons. What if we just want to put some informative text on the screen? The label widget does just that. A label is like a button that doesn't do anything. It is a noninteractive widget and by default cannot have the keyboard focus (meaning you can't tab to it) and it does nothing when you click on it.
The label widget is probably the simplest widget. It is similar to a button in that it can show text (or a bitmap), have relief (default is flat), display multiple lines of text, have a different font, and so on. Figure 5-1 shows a simple window, with both a button and label, created with this code:
use Tk;
$mw = MainWindow->new();
$mw->Label(-text => "Label Widget")->pack();
$mw->Button(-text => "Exit", -command => sub { exit })->pack();
MainLoop;
0103-01.gif
Figure 5-1.
A simple window with label and button
Here are some typical uses for a label:
• Put a label to the left of an entry widget so the user knows what type of data is expected.
• Put a label above a group of radiobuttons, making their purpose more clear (e.g., ''Background Color:"). You can do the same thing with checkbuttons if they happen to be related or along the same theme.
• Use a label to tell users what they did wrong: "The number entered must be between 10 and 100." (Typically, you would use a Dialog composite widget to give messages to the user like this, but not always.)
• Put an informational line across the bottom of your window. All the other widgets would have a mapping that displays a string containing information about that widget.
Creating a Label
The command to create a label is, of course, Label. Here's the basic usage:
$label = $parent->Label( [ option => value ... ] )->pack();
Hopefully, you are starting to see a trend in the creation command. As you might expect, when you create a label, you can specify options that will change its appearance and how it behaves.
Label Options
The following list is a comprehensive list of options for labels:
-anchor => 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' | 'center'
Causes the text to stick to that position in the label widget. This won't be obvious unless the label is forced to be larger than standard size.
-background => color
Sets the background color of the label to color.
-bitmap => bitmap
Displays the bitmap contained in bitmap instead of text.
-borderwidth => amount
Changes the width of the edges of the label.
cursor => cursorname
Changes the cursor to cursorname when the mouse is over this widget.
-font => fontname
Indicates that the text in the widget will be displayed with fontname.
-foreground => color
Changes the text of the button (or the bitmap) to be color color.
-height => amount
Sets the height of the label to amount; amount is a valid screen distance.
-highlightbackground => color
Sets the color of the focus rectangle when the widget is not in focus to color.
-highlightcolor => color
Sets the color of the focus rectangle when the widget has focus to color.
-highlightthickness => amount
Sets the width of the focus rectangle. Default is 0 for the label.
-image => imgptr
Displays the image to which imgptr points instead of text.
-justify => 'left' | 'right' | 'center'
Sets the side of the label against which multi-line text will justify.
-padx => amount
Adds extra space inside the edge to the left and right of the label.
-pady => amount
Adds extra space inside the edge to the top and bottom of the label.
-relief => 'flat' | 'groove' | 'raised' | 'ridge' | 'sunken'
Changes the type of edges drawn around the button.
-takefocus => 0 | 1 | undef
Changes the ability of the label to have the focus or not.
-text => text
Displays in the label a text string.
-textvariable => \$variable
Points to the variable containing text to be displayed in the label. Label will change automatically as $variable changes.
-underline => n
Causes the nth character to be underlined. Allows that key to invoke the widget when it has the focus. Default value is -1 (no character underlined).
-width => amount
Causes the label to be width amount.
-wraplength => amount
Indicates that the text in the label will wrap when it gets longer than amount.
This list briefly describes each option and what it does. Some of the options have different defaults for the label widget than we are used to seeing with the buttontype widgets, causing the label to behave a bit differently.
How a Label Differs from Other Widgets
When we created button-type widgets, we could either click them with the mouse or tab to them and then use the keyboard to cause the button to be pressed. A label widget, on the other hand, does not interact with the user. It is there for informational purposes only, so there is no -command option. We also can't tab to a label widget because nothing would happen.
The default value for the -takefocus option is 0, making the label noninteractive. When tabbing between widgets on the screen, the highlight rectangle shows us which widget currently has the keyboard focus. Since we don't allow the label to have the focus (remember, -takefocus is set to 0), it doesn't make sense to have a visible highlight rectangle. The default value for the -highlightthickness option in a label widget is 0. You can make a rectangle appear around a label by setting -highlightthickness to something greater than 0, and setting -highlightbackground to a color such as blue or red.
The label widget also doesn't have a -state option. Since we shouldn't be able to click a label, we should never have to disable it.
Relief
In Figure 5-2, you can see what happens when you change the label's -relief option. Notice that the edges of the widget are very close to the text. Unlike a button, you usually don't want much extra space around the label (space is controlled by the -padx and -pady options). Normally, you want the label widget to sit right next to the widget (or widgets) it is describing.
0105-01.gif
Figure 5-2.
Labels with different relief values. Window on right has a -borderwidth of 10.
You'll notice that I like seeing what widgets look like with the different relief values. This sometimes helps determine where the widget ends, especially with widgets that
have a default value of "flat". Also, I often change the relief of different widgets to make sure I know which widgets are where on the screen. After creating 10 entries and labels with less than creative variable names, it's easy to lose track. Also, changing the borderwidth is bound to make that one widget stand out. Of course, I always change the relief and borderwidth back to something non-obnoxious before I give the program to anyone else to run! Color is also a good way to do a diagnostic message.
Status Message Example
I often use the groove or ridge relief when I'm making a help or status label along the bottom of my window. I make a label that is packed with -side => 'bottom' and -fill => 'x'. There are two different ways you can use a status label:
• Set the variable associated with it so it changes as your program progresses, announcing to the user that it is busy, or something is happening.
• Have the help label give information on each of the different widgets in your application when it gets the focus, using the bind command.
Both types are demonstrated in the following sample code.
This code shows the "What I'm doing now" type of help label:
$mw->Label(-textvariable => \$message, -borderwidth => 2,
           -relief => 'groove')->pack(-fill => 'x',
                                      -side => 'bottom');
$mw->Text()->pack(-side => 'top',
                            -expand => 1,
                            -fill => 'both');

$message = "Loading file index.html...";
...
$message = "Done";
The label is created across the bottom of the screen. We pack it first because we want it to stay on the screen if we resize the window (remember, the last widgets packed will get lower priority if the window runs out of room). As the program executes (represented by the...), it changes the label accordingly.
This code shows an example of using a widget-helper help label:
$mw->title("Help Label Example");

$mw->Label(-textvariable => \$message)
   ->pack(-side => 'bottom', -fill => 'x');

$b = $mw->Button(-text => "Exit", -command => \&exit)
        ->pack(-side => 'left');
&bind_message($b, "Press to quit the application");
 
$b2 = $mw->Button(-text => "Do Nothing")->pack(-side => 'left');
&bind_message($b2, "This button does absolutely nothing!");

$b3 = $mw->Button(-text => "Something",
  -command => sub { print "something\n"; })->pack(-side => 'left');
&bind_message($b3, "Prints the text 'something'");

sub bind_message {
  my ($widget, $msg) = @_;
  $widget->bind('<Enter>', [ sub { $message = $_[1]; }, $msg ]);
  $widget->bind('<Leave>', sub { $message = ""; });
}
This example is a bit longer because we are using the bind method (the bind method is explained in more detail in Chapter 14, Binding Events). For each widget we create, we want to associate a help message with it. We do this by adding bindings to each widget that change the variable $message to a specified string when the mouse enters the widget, and to an empty string if the mouse leaves the widget. We used a subroutine to avoid writing the same two bind lines over and over again. Figure 5-3 shows what our window looks like with the mouse over the center button.
0107-01.gif
Figure 5-3.
Window with label across the bottom
Container Frames
In Figure 5-3, you can see that the example text is centered within the label widget. When using non-multiple line labels, when you fill the widget across the screen, the text remains centered, even if you add the -justify => 'left' option. You can get around this by creating a container frame, giving it the desired relief, filling the frame across the screen (instead of the label), and placing the label widget within the frame:
$f: = $mw->Frame(-relief => 'groove',
 
                -bd => 2)->pack(-side => 'bottom',
                                -fill => 'x');
$f->Label(-textvariable => \$message,)->pack(-side => 'left');
This allows the label to grow and shrink within the frame as necessary, while the text sticks to the left side. If you've typed this short little example in and played with the strings bound to each widget, you might have noticed that the window will resize itself if the text assigned to $message is too long to display in the label. This can get annoying if your window is fairly small to begin with. There are two ways to deal with this: First, you can always use really short text strings, and second, you can tell the window to not resize when the label changes size.
The drawbacks with each approach aren't too bad, and which one you pick just depends on the application you are working on. If you can make really short sentences that make sense, great. Telling the window to not resize is almost as easy, though-it is accomplished by adding one line to your program:
$mw->packPropagate(0);
Using packPropagate will cause your window to not resize when a widget is placed inside the window (we first talked about packPropagate in Chapter 2, Geometry Management). This means that your window might not be showing all your widgets right away. You can deal with this by keeping it on until you get all your widgets in it, figuring out a good starting size for your window and using $mw->geometry(size) to request that size initially. (See Chapter 13, Toplevel Widgets, for info on the geometry method.)
Label Configuration
Label is a pretty boring widget, so there are only two methods available to change or get information on it: cget and configure. Both methods work for Label the same way they work for the Button widget. Please refer to Appendix A for the details on arguments and return values.
The Entry Widget
0108-01.gifUntil now, the only input we know how to get from the user is a mouseclick on a button widget (Button, Checkbutton, or Radiobutton), which is handled via the -command option. Getting input from a mouseclick is useful, but it's also limiting. The entry widget will let the user type in text that can then be used in any way by the application. Here are a few examples of where you might use an entry widget:
• In a database form that requires one entry per field (e.g., Name, Last name, Address)
• In a software registration window that requires a serial number
• In a login window that requires a username and password
• In a configuration window to get the name of a printer
• In an Open File window that requires the path and name of a file
Normally, we don't care what users type in an entry widget until they are done typing, and any processing will happen "after the fact" when a user clicks some sort of Go button. You could get fancy and process each character as it's typed by setting up a complicated bind-but it is probably more trouble than it is worth.
The user can type anything into an entry widget. It is up to the programmer to decide if the text entered is valid or not. When preparing to use the information from an entry, we should do some error checking. If we want an integer and get some alphabetic characters, we should issue a warning or error message to the user.
An entry widget is a much more complex widget than it first appears to be. The entry widget is really a simplified one-line text editor. Text can be typed in, selected with the mouse, deleted, and added. I would classify an entry widget as a middle-of-the-line widget. It's more complicated than a button, but much less complicated than the text or canvas widgets.
Creating the Entry Widget
No surprises here:
$entry = $parent->Entry( [ option => value ... ])->pack;
When the entry widget is created, it is initially empty of any text, and the insert cursor (if the entry had the keyboard focus) is at the far-left side.
Entry Options
The following list contains a short description of each option available for configuring an entry widget. Several of them are discussed in more detail later in this chapter.
-background => color
Sets the background color of the entry widget. This is the area behind the text.
-borderwidth => amount
Changes the width of the outside edge of the widget. Default value is 2.
-cursor => cursorname
Changes the cursor to cursorname when it is over the widget.
-exportselection => 0 | 1
If the Boolean value specified is true, any text selected will be exported to the windowing system's clipboard.
-font => fontname
Changes the font displayed in the entry to fontname.
-foreground => color
Changes the color of the text.
-highlightbackground => color
Sets the color the highlight rectangle should be when the widget does not have the keyboard focus.
-highlightcolor => color
Sets the color the highlight rectangle should be when the widget does have the keyboard focus.
-highlightthickness => amount
Sets the thickness of the highlight rectangle around the widget. Default is 2.
-insertbackground => color
Sets the color of the insert cursor.
-insertborderwidth => amount
Sets the width of the insert cursor's border. Normally used in conjunction with
-ipadx and -ipady options for the geometry manager.
-insertofftime => milliseconds
Sets the amount of time the insert cursor is off in the entry widget.
-insertontime => milliseconds
Sets the amount of time the insert cursor is on in the entry widget.
-insertwidth => amount
Sets the width of the insert cursor. Default is 2.
-justify => 'left' | 'right' | 'center'
Sets the justification of the text in the entry widget. The default is left.
-relief => 'flat' | 'groove' | 'raised' | 'ridge' | 'sunken' | 'solid'
Sets the relief of the outside edges of the entry widget.
-selectbackground => color
Sets the background color of any selected text in the entry widget.
-selectborderwidth => amount
Sets the width of the selection highlight's border.
-selectforeground => color
Sets the text color of any selected text in the entry widget.
-show => char
Sets the character that should be displayed instead of the actual text typed.
-state => 'normal' | 'disabled' | 'active'
Indicates the state of the entry. Default is 'normal'.
-takefocus => 0 | 1 | undef
Allows or disallows this widget to have the keyboard focus.
-textvariable => \$variable
Sets the variable associated with the information typed in the entry widget.
-width => amount
Sets the width of the entry in characters.
-xscrollcommand => callback
Assigns a callback to use when scrolling back and forth.
The following options behave as we expect them to, and aren't worth further discussion: -background, -cursor, -font, -highlightbackground, -highlightcolor, -highlightthickness, -foreground, -justify, -takefocus, and -state. For more detailed information on these how these options affect a widget, see Chapter 3.
Assigning the Entry's Contents to a Variable
The -textvariable option lets you know what the user typed in the entry widget:
-textvariable => \$variable
By now, you should be familiar with this option from several of our button examples. Any text input into the entry widget will get assigned into $variable. The reverse also applies. Any string that gets assigned to $variable will show up in the entry widget.
It is important to remember that no matter what the user enters, it will be assigned to this variable. This means that even though you are expecting numeric input (e.g., "314"), you might get something like "3s14" if the user accidentally (or on purpose!) presses the wrong key(s). Before using any information from an entry widget, it's a good idea to do some error checking to make sure it's the information you expect or, at the very least, in the correct format. Trying to use ''3s14" in an equation would most likely produce undesired results.
The other way you can find out what is in the entry widget is by using the get method:
$stuff = $entry->get();
You can use get whether or not you have used the -textvariable option.
Relief
As with all the widgets, you can change the way the edges are drawn by using the -relief and/or -borderwidth options:
-relief => 'flat' | 'groove' | 'raised' | 'ridge' | 'sunken'
-borderwidth => amount
The default for an entry is 'sunken', which is also a change from what we've seen so far. Figure 5-4 shows the different relief types at different -borderwidth values incrementing from the default, 2, to 4, to 10.
0112-01.gif
Figure 5-4.
Different relief types for an entry widget: -borderwidth of 2 (the default), 4, and 10
This is the code snippet that created the five entry widgets and used the relief name as the entry widget's text:
foreach (qw/flat groove raised ridge sunken/) {
  $e = $mw->Entry(-relief => $_)->pack (-expand => 1);
  $e->insert ('end', $_);  # put some text in the entry
}
Entry Indexes
In order to manipulate the text in the entry widget, you need some way to identify specific portions or positions within the text. The last example actually used an index in it. The line $e->insert('end', $_) uses the index 'end'. Just like the insert method (covered later in the chapter), all of the methods that require information about a position will ask for an index (or two, if the method requires a range of characters). This index can be as simple as 0, meaning the very beginning of the text, or something more complicated like 'insert'.
Here are the different forms of index specification and what they mean:
n (any integer)
A numerical character position. 0 is the first character in the string. If the entry contains  the string
"My mother hit your mother right on the nose" and we used an index of 12, the character pointed to would be the  "t" in the word "hit."
'insert'
Indicates the character directly following the insertion cursor. The insertion cursor is that funny-looking little bar thing that shows up inside the entry widget when text is typed. You can move it around with the arrow keys or by clicking on a different location in the entry widget.
'sel.first'
The first character in the selection string. This will produce an error if there is no selection. The selection string is the string created by using the mouse or shift-arrow. The selected text is slightly raised from the background of the entry.
If our selected text were the word "nose" in this string (shown here in bold)
My mother hit your mother right on the nose
'sel.first' would indicate the "n".
'sel.last'
The character just after the last character in the selection string. This will also produce an error if there is no selection in the entry widget. In the preceding example, this would mean the space after the "e" in nose.
'anchor'
The 'anchor' index changes depending on what has happened with the selection in the entry widget. By default, it starts at the far left of the entry: 0. It will change if you click anywhere in the entry widget with the mouse. The new value will be at the index you clicked on. The 'anchor' index will also change when a new  selection is made-either with the mouse (which means the 'anchor' will be wherever you clicked with the mouse) or by Shift-clicking-and 'anchor' will be set to where the selection starts. Mostly, this index is used internally, and you'll rarely find a case where it would be useful in an application.
'end'
This indicates the character just after the last one in the text string. This value is the same as if you specified the length of the entire string as an integer index.
'@x'
This form uses an x coordinate in the entry widget. The character that contains this x coordinate will be used.
"@0" indicates the leftmost (or first) character in the entry widget. This form of index specification is also one you'll rarely use.
Text Selection Options
You can select the text in an entry widget, and several things happen. The indices 'sel.first' and 'sel.last' point to the beginning and end of the selected text respectively. You can also make the selected text available on the clipboard on a Unix system by using the -exportselection option:
-exportselection => 0 | 1
The -exportselection option indicates whether or not any selected text in the entry will be also be put in the selection buffer in addition to being stored internal to the entry as a selection. By leaving this option in its default value, you can paste selected text into other applications.
The selected text also has some color options associated with it: -selectbackground, -selectforeground, and -selectborderwidth:
-selectbackground => color
-selectforeground => color
-selectborderwidth => amount
The -selectbackground and -selectforeground options change the color of the text and the area behind the text when that text is highlighted. In Figure 5-5, the word "text" is selected.
0114-01.gif
Figure 5-5.
Entry with -selectbackground => 'red' and -selectforeground => 'yellow'
You can change the width of the edge of that selection box by using -selectborderwidth. If you left the size of the entry widget unchanged, you wouldn't see the effects of it. The entry widget cuts off the selection box. To actually see the results of increasing the -selectborderwidth value use the -selectborderwidth option in the entry command and the -ipadx and -ipady in the geometry management command.
0115-01.gif
Figure 5-6.
Entry widget with -selectborderwidth => 5
You might want to change the -selectborderwidth option if you like a little extra space around your text or if you really want to emphasize the selected text. Here's the code that generated the entry widget in Figure 5-6:
$e = $mw->Entry(-selectborderwidth => 10)->pack (-expand => 1,
                                                  -fill => 'x'
                                                  -ipadx => 10,
                                                  -ipady => 10);
$e->insert ('end', "Select the word text in this entry");
Notice the -ipadx and -ipady options in the pack command.
The Insert Cursor
The insert cursor is that funny-looking little bar that blinks on and off inside the entry widget when it has the keyboard focus. It will only show up when the entry widget actually has the keyboard focus. If another widget (or none) has the keyboard focus, the insertion cursor is still there, but it is invisible. In Figure 5-7, the insertion cursor is immediately after the second "n" in the word "Insertion."
0115-02.gif
Figure 5-7.
Default insertion cursor
You can change the thickness, border width, and width of the insertion cursor by using these options:
-insertbackground => color
-insertborderwidth => amount
-insertwidth => amount
The -insertwidth option simply changes the width of the cursor so it looks fatter. The -insertbackground option changes the overall color of the insertion cursor. Figure 5-8 shows an example.
0116-01.gif
Figure 5-8.
Insertion cursor with -insertbackground => 'green' and -insertwidth => 10
No matter how wide the cursor, it is always centered over the position between two characters. The insertion cursor in Figure 5-8 is in the same location it was in Figure 5-7. This can look distracting to users and might just confuse them unnecessarily, so you most likely won't change the -insertwidth option.
You can give the insertion cursor a 3D look by using -insertborderwidth (as in Figure 5-9). Like the -insertwidth option, the -insertborderwidth option doesn't have much practical use.
0116-02.gif
Figure 5-9.
Insertion cursor with -insertborderwidth => 5, -insertbackground => 'green' and
-insertwidth => 10
You can also change the amount of time the cursor blinks on and off by using these options:
-insertofftime => time
-insertontime => time
The default value for -insertofftime is 300 milliseconds. The default for -insertontime is 600 milliseconds. The default values make the cursor's blink stay on twice as long as it is off. Any value specified for these options must be nonnegative.
For a really frantic-looking cursor, change both values to something much smaller. For a relaxed and mellow cursor, double the default times. If you don't like a blinking cursor, change -insertofftime to 0.
Password Entries
There are times when you'll request information from the user that shouldn't be displayed on the screen. To display something other than the actual text typed in, use the -show option:
-show => char
The char is a single character that will be displayed instead of the typed-in characters. For a password entry, you might use asterisks (see Figure 5-10). If you specify a string, just the first character of that string will be used. By default, this value is undefined, and whatever the user actually typed will show.
0117-01.gif
Figure 5-10.
Entry displaying a password
When using the -show option, the information stored in the associated $variable will contain the real information, not the asterisks.
If you use this feature, the user can't cut and paste the password (regardless of the value of -exportselection). If it is cut and pasted to another screen, what the user saw on the screen (the asterisks, for example) is actually pasted, not the information behind it. You might think that if you did a configure on the entry widget such as $entry->configure (-show => "");, the words the user entered would suddenly appear. Luckily, this isn't true. A bunch of \x0s (essentially gibberish) show up instead. Any variable that uses the -textvariable option and is associated with the entry will still contain the correct information. If you perform an $entry->get(), the correct (nongibberish) information will be returned as well. The get method is described later in this chapter.
Using a Scrollbar
If the information requested from the user could get lengthy, the user can use the arrow keys to manually scroll through the text. To make it easier, we can create and assign a horizontal scrollbar to the entry widget by using the -xscrollcommand option:
-xscrollcommand => [ 'set' => $scrollbar ]
For now, I'm going to show you the most basic way to assign a scrollbar to the entry widget. For more details on the scrollbar see Chapter 6, Scrollbars.
To create a scrollbar and associate it with an entry widget, do this:
$scroll = $mw->Scrollbar(-orient => "horizontal"); # create scrollbar
$e = $mw->Entry(-xscrollcommand => [ 'set' => $scroll ])->
  pack(-expand => 1, -fill => 'x'); # create entry
$scroll->pack(-expand => 1, -fill => 'x');
$scroll->configure(-command => [ $e => 'xview' ]); # link them
$e->insert('end', "Really really really long text string");
Figure 5-11 shows the resulting window in two states: on the left, the window as it looked when it was created, and on the right, how it looks after scrolling all the way to the right.
0118-01.gif
Figure 5-11.
Scrollbar and an entry widget
You'll very rarely want to use a scrollbar with an entry widget. The scrollbar doubles the amount of space taken, and you can get the same functionality without it by simply using the arrow keys when the entry widget has the focus. If the user needs to enter multiple lines of text, you should use a text widget instead. See Chapter 8, The Text Widget, for more information on what it can do.
Configuring an Entry Widget
Both cget and configure are the same for the entry widget as they are for any of the other widgets. The default options for the entry widget are listed in Appendix A, Configuring Widgets with configure and cget.
Deleting Text
You can use the delete method when you want to remove some or all of the text from the entry widget. You can specify a range of indices to remove two or more characters or a single index to remove one character:
$entry->delete(firstindex, [ lastindex ])
To remove all of the text, you can use $entry->delete(0, 'end'). If you use the -textvariable option, you can also delete the contents by reassigning the variable to an empty string: $variable = "".
Here are some other examples of how to use the delete method:
$entry->delete(0);         # Remove only the first character
$entry->delete(1);         # Remove the second character

$entry->delete('sel.first', 'sel.last')  # Remove selected text
   if $entry->selectionPresent();        # if present
Getting the Contents of an Entry Widget
There are two ways to determine the contents of the entry widget: the get method or the variable associated with the -textvariable option. Using the get method, $entry_text = $entry->get() will assign the entire contents of the entry widget into $entry_text.
Which way you find out the content depends on what you are going to do with the information. If you only need to reference it once in order to write it to a file or insert it into a database, it doesn't make sense to waste memory by storing it in a variable. Simply use the get method in the print statement (or wherever it would be appropriate). If the information in the entry widget is going to be a frequently used value such as a number for a mathematical calculation, then it makes sense to initially store it in a variable for easy access later.
Moving the Insertion Cursor
The icursor method will place the cursor at the specified index:
$entry->icursor(index);
By default, the insertion cursor starts out wherever the last insert took place. To force the insertion cursor to show up elsewhere, you could do something like this:
$e_txt = "Entry Text";
$e = $mw->Entry(-textvariable => \$e_txt)->pack();
$e->focus;
$e->icursor(1); # put cursor at this index
We use the focus method (which is not specific to the entry widget; it's generic to all widgets) to have the application start with the focus on our entry widget. Then we place the insertion cursor between the first and second characters (indices 0 and 1) in the entry. See Chapter 16, Methods for Any Widget, for more information on focus.
You might want to move the starting position of your cursor if you are starting the text with a specific string. For instance, set $e_txt = "http://" and then do $e->icursor('end')
Getting a Numeric Index Value
The index method will convert a named index into a numeric one:
$numindex = $entry->index(index) ;
One of the uses of index is to find out how many characters are in the entry widget: $length = $entry->index('end'). Of course, if we used the -textvari-
able option, we could get the same result by using $length = length($variable).
As an example of using index to find out where the current selection starts, use this code:
$startindex = $entry->selectionPresent() ?
                $entry->index('sel.first') : -1;
We discuss selectionPresent later in the chapter.
Inserting Text
The insert function will let you insert any text string at the specified index:
$entry->insert(index, string);
Here's a simple application that uses insert:
#!/usr/bin/perl
use Tk;
$mw = MainWindow->new;
$mw->title("Entry");

$e_txt = "Entry Text";    # Create entry with initial text
$e = $mw->Entry(-textvariable => \$e_txt)->pack(-expand => 1,
                                               -fill => 'x');
$mw->Button(-text = > "Exit",
           -command => sub { exit })->pack(-side => 'bottom');

# Create a Button that will insert a counter at the cursor
$i = 1;
$mw->Button(-text => "Insert #", -command =>
            sub {
             if ($e->selectionPresent() ) {
               $e->insert('sel.last', "$i"); $i++;
              }
            })->pack;
MainLoop;
We fill the entry widget with "Entry Text" as a default. Then we create two buttons. The first one is the obvious Exit button that will allow us to quit the application. The second one is a bit more complicated. When pressed, it will check to see if any text is selected in the entry $e. If text is selected, it will insert a number that keeps track of the number of times we have pressed the Insert # button.
In Figure 5-12, we first selected the word "Entry" and then pressed the Insert # button four times. Each time it was pressed, it inserted a number at the index "sel.last". This index didn't change in between button presses, so it looks as if we are counting backward!
0121-01.gif
Figure 5-12.
Using the insert method
Scanning Text
Both ScanMark and scanDragto are used within the entry widget. They allow fast scrolling within the entry widget. A call to scanMark simply records the x coordinate passed in for use later with scanDragto. It returns an empty string.
$entry->scanMark(x);
$entry->scanDragto(x;
The companion function to scanMark is scanDragto, which also takes an x coordinate. The new coordinate is compared to the scanMark x coordinate. The view within the entry widget is adjusted by 10 times the difference between the coordinates.
Working with the Selection
The selection method has several possible argument lists. If you look at the web-page documentation, you'll see that you can use:
$entry->selectionAdjust(index).
You might also see the form $entry->selection('adjust', index), where 'adjust' is the first argument. Be aware that they mean the same thing as you read code written by other people.
You can adjust the selection to a specified index by using selectionAdjust
$entry->selectionAdjust(index);
The selected text is extended toward the index (from whichever end is closest).
To clear out the selection:
$entry->selectionClear();
Any selection indicator will be removed from the entry widget, and the indices 'sel.first' and 'sel.last' are now undefined. The selected text remains.
To reset the 'anchor' index to the specified index, use selectionFrom:
$entry->selectionFrom(index);
This does not affect any currently selected text or the indexes 'sel.first' and 'sel.last'.
The only way to check to see if there is a selection in the entry widget is to use selectionPresent:
if ($entry->selectionPresent()) {
}
It returns a 1 if there is a selection, which means that you can safely use the 'sel.first' and 'sel.last' indices (if there isn't a selection, an error will be printed when you refer to either index). selectionPresent will return a 0 if there is no current selection.
You can change the selection range by calling selectionRange:
$entry->selectionRange(startindex, endindex);
The two indices indicate where you would like the selection to cover. If start-index is the same or greater than endindex, then the selection is cleared, causing 'sel.first' and 'sel.last' to be undefined. Otherwise 'sel.first' and 'sel.last' are defined to be the same as startindex and endindex respectively.
The selectionTo method will cause the new selection to be set from the current 'anchor' point to the specified index:
$entry->selectionTo(index);
Changing the View in the Entry Widget
xview is a method that will change its purpose based on what arguments are passed in.
With no arguments, it will return a two-element list containing numbers from 0 to 1. These two numbers define what currently is visible in the entry widget. The first number indicates how much of the text is off to the left and not visible. If it were .3, then 30% of the text is to the left of the entry widget. The second number returned is how much of the text is not visible on the left side of the entry widget plus the amount that is visible in the widget. In this case, 50% of the text is actually visible in the entry widget (see Figure 5-13).
($left, $right) = $entry->xview();
When passing an index value to xview, the text in the entry widget will shift position so that the text at the specified index is visible at the far-left edge:
$entry->xview(index);
0123-01.gif
Figure 5-13.
What $left and $right mean
The rest of the forms of xview have to do directly with scrolling (and are explained in detail in Chapter 6):
$entry->xviewMoveto(fraction);
$entry->xviewScroll(number, what)
Fun Things to Try
There aren't too many exciting things you can do with label widgets, but it's a good idea to practice using the entry widget.
• Create an entry and label combination and display the same information in both. When you put something new in the entry, the label should display it simultaneously.
• Create a database entry form, labeling each entry with Name, Address, City, State, Zip, Phone. Add an Update button that will perform some error checking on the information in the entry widgets based on the information expected.
• Create a window with an entry widget and several buttons, each of which does something different to the entry widget. Some suggestions: Clear, Delete Selection, or Default (replace with original string).
• Create an entry widget and type something in it. Put a button in the window that will reverse the string in the entry widget when pressed.