16—
Methods for Any Widget
So far, most of the chapters in this book have concentrated on specific widgets. This chapter covers the methods that apply to all widgets. You'll probably never need most of these methods, but there are a few that you'll use frequently.
Many times, you'll use a MainWindow reference (usually $mw in our examples) to call these methods, but you can also call them from other widgets, such as $button, $checkbutton, and so on. Most of the methods are informational only, meaning you pass no arguments to them; you only get a value back.
We'll use the generic $widget here instead of a specific widget type. This will help you to remember that these are multipurpose methods.
Building a Family Tree
The following methods deal with the ancestors or children of widgets and how they were created: children, name, parent, toplevel, manager, and class.
Widget's Children
To determine the children of a widget (usually a toplevel or a frame), use the children method:
@kids = $widget->children();
# i.e. Tk::Button=HASH(0×85e3a0) Tk::Button=HASH(0×85e4a8)
The list returned contains scalars that are the children of $widget. You can then use those references to perform actions such as setting a background color or font.
Name of a Widget
To determine what the parent calls the widget use the name method:
$name = $widget->name();
You can combine the name and children method like this:
@kids = $widget->children();
foreach (@kids) {
  print "Name: ", $_->name(), "\n";
}
Here is example output from that code:
button
button1
Parent of a Widget
To get a reference to the parent of a widget, use the parent method:
$parent = $widget->parent();
The Widget's Toplevel
To get the toplevel widget that contains a widget, use toplevel:
$path = $widget->toplevel();
The $path returned is a number (that is, 8606484) that you can compare to another number that was returned from another call to toplevel to see if they are equal.
Widget's Manager
You can find out which geometry manager $widget used by calling manager:
$manager = $widget->manager();
It returns a string that describes the geometry manager; for instance, if it is a toplevel widget, it will return "grid", "pack", "place", or "wm". The manager method doesn't seem to work correctly on Windows 95, but it works on Unix and Windows NT.
The Widget's class
The class method returns a string that indicates which class it belongs to. For example, $listbox->class() returns "Listbox", and $menu->class() returns "Menu".
Widget's ID
You can get an ID string for a widget by using the id method:
$id = $widget->id();
print "$id\n";
# Prints 0×9c944c
The value returned is a hex value. This method does not work under Windows 95.
Widget's Path
You can get the pathname of the window by calling pathname and using the ID you retrieved with the id method:
$path = $widget->pathname($id);
There is also the PathName method:
$path = $mw->PathName();
This method prints out the path of the widget that is calling it. For example, my $mw would have a PathName of ".".
Color-Related Methods
There are four methods that deal with color: colormapfull, rgb, cells, and depth.
Is the Colormap Full?
To determine if the colormap for the widget is full, use colormapfull:
$isfull = $widget->colormapfull();
The colormapfull method returns a 1 if the colormap is full and 0 if it is not full.
Cell Count
The number of cells in the colormap can be obtained by using the cells method:
$count = $widget->cells();
The value returned is a number indicating the number of colors; for example, 64.
Color Depth
You can get the number of bits per pixel by using the depth method:
$depth = $widget->depth();
# $depth might contain "16"
Translate to RGB Value
You can translate a color name to the red, green, and blue values by using the rgb method. Send rgb a color name (valid color names were covered in Chapter 3) and it returns a list containing three items that represent the red, green, and blue numbers.
($red, $green, $blue) = $widget->rgb("color");
Now $red, $green, and $blue each contain an integer from 0 to 255.
Setting Colors
You can have your entire application based on one color automatically by using the setPalette method:
$widget->setPalette(color);
The background color of $widget is set to the specified color, and the colors for all other widgets are calculated based on that color. So if a button's edge is a lighter color than the background, it will show up a lighter shade of whatever color you picked. This method affects the entire application even if you only call it on a widget instead of a toplevel.
You can set colors for explicit options by specifying the name and then the color to associate with it. For instance, the following code will set all foreground items in the application to red and all backgrounds to blue:
$b->setPalette("background" => "blue", "foreground" => "red");
Predefined Color Scheme
The bisque method sets the entire application to use a bisque scheme. Calling $widget->bisque() is the same as calling $widget->setPalette("bisque").
Option Databases
Under the X Window System, a file named .Xdefaults in the user's home directory contains configuration information for X applications, including the colors and fonts an application should use. You can create the same type of file for Win32 systems and call it whatever you want. You might use a file like this to let your users change the application's color settings.
Typically the lines in this file look something like this:
screen*background: yellow
screen.button.foreground:green
screen*font: {Arial} 24 {normal}
The first item in each line should be the name of your application unless the options are for your application only. My test application was in a file named screen, so that is what I used as the first keyword in each line. The second keyword (if specified) is a widget type or name (you can specify a name for any widget by adding the -name option to the creation command of that widget). The third keyword is the "class" for which you want to set a default. You can set a default value for any of the options associated with a widget. See Appendix A to find out which class is associated with each widget type.
To read in this file, call optionReadfile with the location of the file (for example, "color_options" or "C:/ .Xdefaults" or ".Xdefaults"):
$widget->optionReadfile("filename");
Make sure to include a newline on the last line of this file or you'll get an error that says, ''missing newline on line 2 at C:\PERL\lib\site\Tk\Submethods.pm line 16." This error doesn't make much sense except that the first line number it gives you matches the number of lines in the option file you are trying to read in. If you use $widget->option("readfile", ...) to call the method, you'll get a more sensible error message.
As the second argument to optionReadfile you can specify an optional priority, which should be one of "widgetDefault", "startupFile", "userDefault", or "interactive". The default priority is "interactive", which is the highest priority.
$widget->optionReadfile("filename", "widgetDefault");
You can add an option type in the program dynamically by using the optionAdd method (whether or not you have used optionReadfile):
$widget->optionAdd(pattern => value);
For example, we can change the font for the entire program like this:
$widget->optionAdd("screen*font", "{Arial} 24 {normal}");
The optionClear method should clear out any current option settings and reread the file (or retrieve them from the resource manager):
$widget->optionClear();
To determine the current setting for the value associated with a specified name and class, call optionGet:
$widget->optionGet (name, class);
The Application's Name
The name of the application that is used in the option file discussed earlier is by default the name of the file from which the script is run. You can use the appname method to change the name of the file:
$mw->appname("newname");
You can find out the current name of the application by calling appname with no arguments:
$name = $mw->appname();
Widget Existence
To determine if a widget has been created, use Exists($widget):
if (Exists($widget)) {
   ...
}
Note the uppercase "E" on this method. The Exists method is different from the built-in Perl exists method. Make sure you don't confuse the two.
Is the Widget Mapped?
To find out if the widget has been mapped to the screen, use the ismapped method:
if ($widget->ismapped())
  # Do something
} else {
  # map the widget
}
The ismapped method returns 1 if the widget is currently mapped to the screen and 0 if it is not.
Converting Screen Distances
If you prefer to use inches as a screen distance but you want to print out pixels, you can use the pixels method to convert any valid screen distance string into a pixel value; for example:
$pixels = $widget->pixels("2i");
# What is 2 inches in pixels?
$pixels = $widget->pixels("2m");
# What is 2 millimeters in pixels?

The pixels method rounds to the nearest whole pixel. You can get a fractional pixel result by using fpixels:
$pixels = $widget->fpixels("2i");
# What is 2 inches in pixels?
$pixels = $widget->fpixels("2m");
# What is 2 millimeters in pixels?

Size of Widget
You can use the following methods to find out the size of a widget in several different ways.
Widget's Geometry
The geometry method returns the geometry string for the widget in the form of widthxheight+x+y.
$geom = $widget->geometry();
The geometry string was discussed in detail in Chapter 13. Geometry values are specified in pixels.
Requested Height
The height of the widget is returned by the reqheight method:
$height = $widget->reqheight();
The widget itself determines the appropriate height.
Requested Width
The width of the widget can be determined by using the reqwidth method:
$width = $widget->reqwidth();
Actual Width
To get the width of the widget as it currently is drawn, use the width method:
$cur_width = $widget->width();
When the widget is first created, width will return a 1 until the application has finished drawing everything. After that, it will return the actual width of the widget.
Actual Height
To get the current height, use the height method:
$h = $widget->height();
Just like the width method, height returns a 1 when the widget is first created. You can use the update or the afterIdle method to force everything else to happen and then call height or width to get the finished values.
Widget Position
The methods in this section all deal with the position of a widget.
Position Relative to the Root Window
To determine which widget is at the point x,y;, use the containing method:
$which = $widget->containing($x, $y);
The $x and $y coordinates must be relative to the root window (or on a Microsoft Windows system, the desktop). An empty string is returned if there is no widget found at those coordinates. If there are several widgets located at those coordinates, the one closest to the front is returned.
Coordinates Relative to Parent
You can get the coordinates of the upper-left corner of a widget by using the x and y methods. The coordinates they return are relative to the parent of the widget:
$x = $widget->x();
$y = $widget->y();
Coordinates Relative to Root Window
To get the coordinates relative to the root window, you can use rootx and rooty on the widget:
$x = $widget->rootx();
$y = $widget->rooty();
The coordinates refer to the upper-left corner of the widget.
Virtual Desktop Coordinates
If you have a virtual desktop, there are special methods that will give coordinates relative to the virtual desktop. Virtual desktops are very common on the X Window System (such as the fvwm and tvtwm window managers), but they exist on Microsoft Windows as well.
To determine the height and width of the virtual desktop, use the vrootheight and vrootwidth methods:
$height = $widget->vrootheight();
$width = $widget->vrootwidth();
To get the coordinates of the widget's upper-left corner relative to the virtual desktop, use vrootx and vrooty:
$x = $widget->vrootx();
$y = $widget->vrooty();
All four of these methods return an empty string if a virtual desktop is not found.
Cursor Coordinates Relative to Desktop
You can use pointerx, pointery, and pointerxy to determine where the user clicked on the screen in a widget:
$x = $widget->pointerx();
$y = $widget->pointery();
($x, $y) = $widget->pointerxy();
All the coordinates returned are relative to the desktop (even if it is a virtual desktop).
Screen Information
The following methods all return information based on the screen (which can be a virtual desktop or a normal desktop) and the colors of the desktop.
Screen Name
Each screen you use has a name associated with it. To get the name, use the screen method:
$name = $widget->screen();
The name returned will be formatted as "displayName.screenIndex". My Windows 95 machine returned ":0.0" as the screen name.
Screen Height and Width
The screen height and width is really just the resolution of the screen. Sometimes you might need information to determine how large a window can fit on a user's display. To get the height and width of the screen in pixels, use the screen-height and screenwidth methods:
$height = $widget->screenheight();
$width = $widget->screenwidth();
If my resolution is 768×1024, then screenheight returns 768 and screenwidth returns 1024. If you prefer to get the size of the screen in millimeters, then use screenmmheight and screenmmwidth:
$heightmm = $widget->screenmmheight();
$widthmm = $widget->screenmmwidth();
The same resolution, 768×1024, returns 203 millimeters as the height and 270 millimeters as the width for my monitor.
Cell Count
The number of cells in the default colormap is retrieved by using screencells:
$count = $widget->screencells();
My Windows 95 machine has 64 cells in its default colormap.
Screen Depth
To determine the number of bits per pixel your screen has, use the screendepth method:
$depth = $widget->screendepth();
The depth of my Windows 95 machine is 16 bits per pixel.
Color Type
The type of color is defined by class, and it will be "directcolor", "grayscale", "pseudocolor", "staticcolor", "staticgray", or "truecolor". To determine the class for the screen that contains the widget, use screenvisual:
$type = $widget->screenvisual();
To determine the class of color for the widget itself, use visual:
$type = $widget->visual();
To find out the entire list of classes available for the current setup, use the visualsavailable method:
@list = $widget->visualsavailable
Each element in @list describes the visual and the color depth for that visual. For instance, on my Windows 95 machine, @list contained only one item: "truecolor 16".
Server Type
The type of server is available through the server method:
$servert_type = $widget->server();
My Windows 95 has a server type of "Windows 4.0 67109975 Win32".
Is the Widget Viewable?
A widget is determined viewable if the widget and all of its ancestors are mapped. You can ask the widget itself if it is viewable by using the viewable method:
$isviewable = $widget->viewable();
viewable returns 1 if the widget can be viewed and 0 if not.
Atom Methods
Each widget is assigned a name, which is called an atom. The atom has a string name (you can get it for each widget by using the name method) and a 32-bit ID. These methods are used internally to handle things such as the selection mechanism.
To get the 32-bit ID for a given widget, send the name of the widget to the atom method:
$id = $widget->atom($widget->name());
You can do the opposite and use the ID to get the name of the atom back. To do so, use the atomname method:
$name = $widget->atomname($id);
Ringing a Bell
To make the computer beep at the user, call bell:
$widget->bell();
Clipboard Methods
The following methods manipulate the internal Tk clipboard and also the Windows clipboard (either Unix or Win32).
To add data to the clipboard, use the clipboardAppend method:
$widget->clipboardAppend("data to add");
When you call clipboardAppend, you can specify a format by using the -format option with a value. The -format by default is "STRING", but it can
also be "ATOM". Another option can be specified, -type, which takes a string such as "STRING" or "FILE_NAME".
To clear out the clipboard, use clipboardClear:
$widget->clipboardClear();
Any data in the clipboard will be removed.
To find out what is in the clipboard, see the selectionGet method in the section entitled "Getting the Selection."
Selection Methods
Some widgets allow the user to make a selection. For example, the user can make a selection in the text, entry, and listbox widgets. You can manipulate the selection by using the following methods.
Clearing the Selection
To cleat the current selection from any widget (this will also clear an X selection) use SelectionClear:
$widget->SelectionClear();
You can specify a -selection option, which takes either "PRIMARY" or "CLIPBOARD". The default is "PRIMARY". Using "CLIPBOARD" clears out the clipboard as well.
Getting the Selection
To determine what the current selection for the application is, use SelectionGet:
$selection = $widget->SelectionGet();
You can also specify the -selection option with the SelectionGet method:
$clipboard = $widget->SelectionGet(-selection => "CLIPBOARD");
The -selection method takes either "PRIMARY" or "CLIPBOARD". The default is "PRIMARY", so if you don't specify -selection, you will get back the value that represents thecurrent selection in the application. Using "CLIPBOARD" will return the value in the clipboard.
Assigning a Callback
You can call SelectionHandle to assign a callback that will automatically be invoked when the selection associated with $win changes:
$widget->SelectionHandle($win => \&subroutine);
When $win owns the selection, the callback will be invoked (in this example, subroutine). You can specify the options -format, -type, and-selection with the same possible values shown in the preceding code example. If you call SelectionHandle with an empty string as the callback, the previously assigned callback is removed.
Determining Owner
You can find out which widget on the screen currently owns the selection by calling SelectionOwner (a widget owns the selection if it has something selected in it):
$widget = $widget->SelectionOwner ();
You can also specify the -selection option with either "PRIMARY" or "CLIPBOARD" as the value to determine who owns the selection, or the current clipboard value, respectively.
Setting the Owner
To force a widget to own the selection, call SelectionOwn:
$widget->selectionOwn ();
You can also specify which type of selection to force by using the -selection option with "PRIMARY" or "CLIPBOARD". Finally, you can specify a -command option with an associated callback that will be invoked when that widget's selection is forced away.
Destroying a Widget
You can destroy a widget by calling destroy on the widget (using if Tk: :Exists is recommended):
$widget->destroy () if Tk: :Exists ($widget);
If the widget is a parent of any other widgets, the other widgets are destroyed as well.
Focus Methods
When your application is running, you can force a widget to have the keyboard focus by calling focus on that widget:
$widget->focus ();
You might want to do this if you have an entry widget into which the user should start typing first. Calling focus right before MainLoop causes the widget to get the
focus right away. If you press the Tab key, the focus automatically changes from one widget to the next (remember that you can tell when a widget has the focus by the highlight rectangle around it). There are several methods that allow you to manipulate the focus.
To make the focus follow the mouse around, use focusFollowsMouse:
$widget->focusFollowsMouse ();
This method is buggy under both Windows 95 and Unix. A patch just recently came out for Tk8, so if you want to use this method and it isn't working, make sure you get the patch.
To find out which widget has the focus, call focusCurrent:
$who = $widget->focusCurrent();
To force a widget to have the focus even if the application isn't currently active, call focusForce:
$widget->focusForce();
This is not a nice thing to do, so try to not use it.
To find out which widget had the focus last, call focusLast:
$which = $widget->focusLast ();
If none of the widgets in the window has the focus, the toplevel is returned.
To find out the order in which the focus will change, you can use the focusNext and focusPrev methods:
$nextwidget = $widget->focusNext ();
$prevwidget = $widget->focusPrev ();
Grab Methods
When a window does a "grab" it means that it holds all of the keyboard and mouse input to itself. That window will not allow any other windows in the application to receive input. There is also a global grab, which means that no applications in the entire system can get input except the one window that has done the global grab. These methods are usually called from a toplevel widget.
To do a local grab for the widget, use grab
$widget->grab ();
A local grab means that you can interact with other windows in the system but not with other windows in the application. To do a global grab, use grabGlobal:
$widget->grabGlobal ();
$widget->grabGlobal ();
To ''ungrab", call grabRelease:
$widget->grabRelease ();
To find out which widget has done a grab, call grabCurrent:
$who = $widget->grabCurrent ();
To find out the current grab state of a $widget, call grabStatus:
$status = $widget->grabStatus ();
The grabStatus method returns a string that is "none", "local", or "global".
To find out all the windows that are currently under the influence of grab, use grabs to get a list back:
@windows = $widget->grabs ();
Interapplication Communication
You can use the send command to have Perl/Tk (and even Tcl/Tk) applications communicate back and forth. The arguments include an application to talk to and the command to execute in that application.
$widget->send ("application" => callback);
You can also specify the option -async, which will return control immediately instead of waiting for the callback to execute.
By default, your application will return an error to another application trying to communicate with it. If you want to actually receive communications from other applications, define Tk: :Receive ($widget, "command") and be very careful with what you do with the command string. Allowing any application to send unknown commands to your application can be dangerous.
When doing interapplication communication, it is a good idea to run your Perl script with the -T switch, which force taint checking.
Waiting for Events to Happen
At certain points in your application, it makes sense to wait until something happens. For instance, if you create a ColorEditor window and want it to assign the color the user selects to a variable, you can use waitVariable to wait until the variable is set.
To have a program wait until a variable's value is changed, call waitVariable:
$widget->waitVariable (\$var);
Processing will continue as soon as the value contained within $var is changed to something different. To wait until a $widget is visible, use waitVisibility:
$widget->waitVisibility ();
To wait until a widget is destroyed, call waitWindow:
$widget->waitWindow ();
When you call these methods, nothing will happen in your program until the requested for event has taken place.
An alternative to waitWindow is OnDestroy, where you specify a callback. The widget methods are still available when you use OnDestory:
$widget->OnDestroy (sub { ... });
File Events
There is a special method in Perl/Tk called fileevent. You can use it to watch and be notified when a file is readable or writable. Here is an example snippet of code that shows how it can used (this code is meant to be executed on a Unix system because we use the Unix tail command):*
use Tk;
open (FH, "tail -f -n 25 text_file|") || die "Could not open file!\n";
my $mw = MainWindow->new ();
my $text = $mw->Scrolled ("Text",
                         -width => 80,
                         -height => 25) ->pack(-expand => 1);
$mw->fileevent (FH, 'readable', [\&insert_text]);
MainLoop;

sub insert_text
{
  my $curline;
  if ($curline = <FH>)
  {
    $text->insert ('end', $curline);
    $text->yview ('moveto', 100);
  }
  else
  {
    $mw->fileevent (FH, 'readable', "");
  }
}
* Thanks to my friend Phivu Nguyen for sharing his code with me.
This short program sits around and waits until a file is readable and then does an insert into a text box with the newly read information. You can also use 'writable'.
$mw->fileevent (FH, 'writable', callback);
If you get rid of the callback portion, the callback will be returned. Replace the callback with an empty string ("") and the callback is removed.
Parsing Command-Line Options
In the Unix world, it is standard practice to specify command-line options when you are invoking an application, especially a graphical program. Starting your program as myscript -geometry "80×40" would not be unusual. To have Perl/Tk automatically parse and apply these command-line options for you, just call CmdLine immediately after you create your MainWindow.
$mw->CmdLine ();
in Tk4, if you want to have CmdLine stop processing command-line arguments and leave some for you to deal with, add a double dash (-) before the arguments you want it to leave for you; for instance, myscript -geometry "80×40" --myopt.
In Tk8, the processing of options will stop when the first unknown option is found.
Another way to deal with command-line options is to use the Perl Getopts modules. Take a look in Programming Perl (O'Reilly, 1997) to find out how to use the methods available in Getopts. The methods inside Getopts don't handle the options for you; it just puts them in a structure that's easier to deal with.
Time Delays
There are times when you'll want to be able to delay the program a bit before going on, or maybe you'll want to execute the same command every minute. To have the program sleep for x number of milliseconds, call after with the number of milliseconds:
$widget->after (milliseconds);
To specify a callback that will be called after so many milliseconds instead of waiting, send a callback as the second argument to after:
$id = $widget->after (milliseconds, callback);
# i. e.
$id = $widget->after (1000, \&do_something);
If you want to execute a subroutine after the program has been idle for a while, call afterIdle:
$id = $widget->afterIdle (callback);
To cancel the call to after or afterIdle, use afterCancel with the $id returned by after:
$widget->afterCancel ($id);
# You can also do this:
$id->cancel ();
You can have the program repeatedly call the same callback by using the repeat method:
$widget->repeat (milliseconds, callback);
# i. e.
$widget->repeat (600, \&update_status);
If you destroy $widget, any calls to after and repeat are automatically canceled for you.
cover24213.jpg