▷▷▷▷▷▷ Follow My Threads Account ◁◁◁◁◁◁
手机版
Selected Topics in Tcl/Tk
- by Changhai Lu -
Unless otherwisely stated, this article makes use of Tcl/Tk 8.3.2.
The basic features of Tcl/Tk are fairly stable, therefore
changes made by later versions should have little impact on what we covered here.
The syntax highlight of the code is generated by
Tcl2Html.
0. Contents
-
Default Arguments - Not Just for Convenience
-
Tk Option Database - Look & Feel Goes Global
-
Images on Control Elements
-
Behind the Curtain - Make Use of the Tk Internal Code
1. Default Arguments - Not Just for Convenience
Most C++ programmers are familiar with the concept of default argument,
it is a convenient way to declare a function such that it can be used with less number of
arguments (the compiler will insert default values for the missing arguments).
For instance a function that calculates the total price of an order
may take the unit price of the merchandise and the quantity as arguments. If
most customers only purchase a single unit, you may want to set a default value ("1" in this case) for
the quantity so you don't have to pass it explicitly to the function most of the time.
The technique of doing this is called default argument (even
though we are really talking about the default value assigned
for the argument).
In C++, default argument is nothing but a convenient way to let you call a function with
omitted arguments. If you
want, you can always define multiple functions with same name but different signatures
because C++ supports function overloading.
In Tcl, however, there is no function overloading, so if you write multiple
functions with one name, the last function will overwrite all the previous ones. Therefore
in Tcl, default argument is the only way to achieve the goal.
The following code demonstrates the use of the default argument in Tcl:
proc f {s1 {s2 "world"}} {
puts "$s1 $s2"
}
|
This procedure (the terminologies in programming world is a little messy, function in C/C++,
method in Java and procedure
in Tcl are different names for the exact same concept)
- named f - takes s1
and s2 as arguments and simply prints them out.
The default value of the 2nd argument is
set to the string "world". So f "hello" -
with the 2nd argument missing - will output "hello world", but
f "hello" "Tcl" - with both arguments passed - will output
"hello Tcl".
A function can have more than one default arguments.
The general rule is: put each pair of the argument and default value in a separate curly bracket.
2. Tk Option Database - Look & Feel Goes Global
Suppose you have an application that runs fine, but you want to change the background color of
ALL the buttons to a new value, say yellow. How would you do that?
One way to do it is of course to perform the change for each and every button,
which - depending on the scale
of your application - could become quite tedious. Not only that it may become tedious, what if
you want to try several configuration options before making a decision? Brute force
is certainly not the best way to go. Tcl/Tk stores default values for widget configuration
options in something called the option database and provides you with commands to
modify those options. By modifying the
option database for a widget type, one can change the look & feel for all the
widgets in that type. For instance, to change the background color of all the buttons to yellow,
one can use the following line:
option add *Button.background yellow startupFile
|
The option add is the command to modify the
option database, the argument *Button.background means we want to
modify the background option for all the buttons.
Notice that the first character of the widget name - Button - is capitalized,
which means the modification applies to the whole type of widget. A non-capitalized
name, on the other hand, only applies to a specific widget with that specific name. For instance
*button.background only applies to the background option of
a widget named .button (which may not even be a button).
The next argument
- yellow - in the code specifies the value for that
option. Finally, the argument startupFile assigns a priority to the
option setting. Now if we create two buttons:
button .b1 -text "Button 1"
button .b2 -text "Button 2"
pack .b1 .b2
|
Both buttons will have yellow background. For any specific widget you can overwrite
this option database value by specifying an explicit
value (say a red background) for that widget (similar to the use of
a local stylesheet to overwrite a document-level stylesheet in web design).
3. Images on Control Elements
There are several ways to put images on control elements such as buttons, labels, etc.
We use buttons as an example to describe two most useful methods.
Both methods can be easily applied to other control elements.
The image we use is a mailbox icon
with a transparent background. Both methods
we introduce will preserve the transparency.
The first method makes use of the image file directly, suppose the file is named
icon_email.gif
and placed in the same directory as the Tcl file itself, the following is the code to create a button
with that image on it.
image create photo img -format gif -file "icon_email.gif"
button .b -image img
pack .b
|
Here the first line creates an image based on the file
icon_email.gif, the name of the image is
img. This name is then used in the second line together with
the -image option for the button to draw the image on
the button. If you run this code, a button
will be created. If we add a background option
-background yellow to the button,
due to the transparency of the image background, the new background color
(yellow) will surround the little mailbox seamlessly:
.
Direct use of external image files is not always convenient. Especially if the application
is to run across the network, you may not want to transfer image files separately. In this case
we can use the so-called Base64 encoding to convert images
into character strings and use those strings instead of the external images. I will not explain
Base64 encoding here, do a search on the web and you will find many
introductory materials as well as free utilities to
do the encoding. The following code creates the same button as in the previous
example, but makes use of the Base64 encoded image:
set imgdata "
R0lGODlhIwAjAKL/AP////8AAL+/v4CAgICAAAAAAMDAwAAAACH5BAEAAAYALA
AAAAAjACMAQAPkaLrc/nAVASgFONcq+hhFESmTEAalAIbFYLpuAaxjUxB4uL5h
7ZOt30hm4XhoQkapgGp1NkWTyhQU/UKdrNYJm1qvOIKul3T0juSyWaOxZD9pX+
pZZGNeU1BkGWiyXEVcJUgQZ1pagFx5Jkk3YnN4MHFgOS2TakphY1+YnZ0sl54G
LUZonJgybVCmakR2d6sqhENQtWxRWHp7HTpZthmKMbsmfX++FhMxcLpmvMUqoC
4VydAzoaMi0JA7Ul1jctmHW4uSjVji1DDYjZrn3euomiAr1+w586eijmL4og/3
lvwJbJAAADs=
"
image create photo img -data $imgdata
button .b -image img
pack .b
|
Here the weired magic string imgdata carries the Base64 encoded information
for the mailbox image. The rest part of the code is very similar to the previous method, except that the
image create photo now uses the data string
$imgdata (together with the -data option)
instead of the image file.
4. Behind the Curtain - Make Use of the Tk Internal Code
As your programming experience grows, chances are that you will gradually become
"a person who enjoys exploring the details of programmable systems and how to
stretch their capabilities" (According to «The Jargon Dictionary», such a person is called
a hacker).
In that case, you may want to go beyond what ordinary Tcl/Tk commands let
you do. For instance you may want to create a menubutton, but instead of
using the left button (Button-1) to bring up the menu, you may want to use the
right button (Button-3). This apparently goes beyond the capability of an ordinary
menubutton. We will use this as an example to demonstrate how to probe and use Tk
internal code.
To change the default menu binding from Button-1 to Button-3, you need first
find out the Tk internal code for the Button-1 binding. Open
wish, enter the command bind Menubutton
(notice the first character of widget type name must be capitalized).
This gives you all the bindings available for a menubutton widget:
<Key-F10> <Alt-Key> <Key-space> <ButtonRelease-1>
<B1-Motion> <Motion> <Button-1> <Leave> <Enter>. Obviously
<Button-1> and <ButtonRelease-1>
are the relevant ones here. To find out the Tk internal code for
<Button-1> binding, use the command
bind Menubutton <Button-1>, the output
is:
if {[string compare $tkPriv(inMenubutton) ""]} {
tkMbPost $tkPriv(inMenubutton) %X %Y
}
|
Similarly the command bind Menubutton <ButtonRelease-1> gives the
internal code for <ButtonRelease-1> binding:
Now we paste the code to the Button-3 bindings. The following code creates a
"File" menubutton with a single dummy menu entry "New". The menu can only be brought up using
the right button (you can keep the Button-1 binding if you don't disable it).
menubutton .mb -text "File" -menu .mb.m
menu .mb.m
.mb.m add command -label "New"
# disable the default Button-1 binding
bind .mb <Button-1> { break }
bind .mb <ButtonRelease-1> { break }
# re-produce internal Button-1 binding on Button-3
bind .mb <Button-3> {
if {[string compare $tkPriv(inMenubutton) ""]} {
tkMbPost $tkPriv(inMenubutton) %X %Y
}
}
bind .mb <ButtonRelease-3> {
tkMbButtonUp %W
}
pack .mb
|
We can even simplify those Tk internal code for our example.
Look at the <Button-1> binding, the if-statement
basically checks whether the menubutton is under the mouse cursor.
Since we are talking about binding on the menubutton, the whole binding code will not be
invoked at all if the mouse cursor is not on the menubutton.
Therefore we can remove the if-statement. Next we
use the command info args tkMbPost to query the signature of the
tkMbPost procedure, the result is
w x y which means it takes the path name of the event widget and the
coordinates of the event as arguments. Similar to the use of
%X and %Y to substitute the
x and y
coordinates of the event, we can use %W to substitute the
path name of the event widget. So
the Button-3 binding can be simplied as:
bind .mb <Button-3> {
tkMbPost %W %X %Y
}
|
Finally, for those who want to probe even deeper into the internal code, the command
info body tkMbPost can be used to query the full content
of the tkMbPost procedure. Other procedures can be queried similarly.
posted on November 20, 2002 https://www.changhai.org/
|