![]() |
Tcl/Tk GUI Programming
|
| Course content | Enter chat room | Send email
to mailing list |
Check calendar |
In memory of Linda. Worldwide Cancer sites here. Canadian Cancer donations here.
In this lesson we are going to learn how to extend and create our own Tcl/Tk commands.
We are going to learn about some program control statements and constructs.
Any computer language contains a relatively small set of basic commands. If that is all that the language could do it would not be very useful or practical. It would be better if we could extend existing commands or create entirely new ones as we needed them. Fortunately Tcl/Tk has just that capability.
Before we begin we need to discuss and reinforce the relationship between the "Wish" program and our little programs.
Tcl/Tk is what is known as an "interpreted language". What
this really means is that the statements in our little programs are "digested"
one by one inside the "Wish" program as they execute. This
has no real impact on what we are learning except that phrases such as
"Tcl/Tk interpreter" or "interpreted by Wish" etc. will appear in the lessons
such as this one. Suffice to remember that our programs require
Wish in order to run.
| HINTS:
Remember the time saving "tiling" hint from lesson #2. ie. open your Wish program and editor program and position the resulting three windows in such a way that there is no overlap. It is probably a good idea to print this lesson off and work from the printout ... otherwise you are going to have more clutter on your screen. |
Step 1: first example |
#=======================================
# iCanProgram.com
# Lesson#3: first example
#=======================================
#=======================================
# scott - entry point
#=======================================
proc scott {mycolor} {
puts stdout [format "lastcolor was %s" $mycolor]
return $mycolor
} ;# end of proc scott
#========================================
# main - entry point
#
# These statements will be executed at startup
#
#========================================
set lastcolor red
destroy .hello
button .hello -text "change me to green" -background red \
-command {set lastcolor [scott $lastcolor]}
pack .hello -padx 20 -pady 20
|
The first thing you will notice is the statements which begin with the "#" character. The Tcl/Tk interpreter program (eg. Wish) will simply ignore these statements. This type of statement is used to add some description to a computer program. As such these statements are often referred to as "comments". In addition blank lines are ignored as well with one important exception noted below.
Occasionally Tcl/Tk statements get very long. Long statements are very difficult to read because a portion of those long lines is often "off the visible screen". To make long statements more readable Tcl/Tk has assigned the "\" character a special significance. It is often referred to as the "continuation" character.
What the "\" tells the Wish program is that the line that follows is
really to be treated as part of the same line that the "\" appears on.
As such you can not follow a line ending in "\" with a blank line.
In the example above we have used the continuation character to divide
this line into two lines:
button .hello -text "change me to green" -background red -command {set lastcolor [scott $lastcolor]}
|
Notice that we have also introduced another argument for the button widget. This argument is the "-command" argument. It is probably the single most powerful feature of the Tk part of the Tcl/Tk language.
What we are saying is "whenever you press the button with the mouse jump and execute the statement enclosed by the {} immediately following the -command argument". This is what allows Tk programs to actually interact with us humans.
Before we try to understand the -command we have for our button we need
to understand a couple of other new Tcl/Tk ideas. The
first of these is what is called a variable. Computer
programs, like calculators, would be a lot less useful if we could not
store values for later use. The mechanism for storing
values is to create a named storage area called a variable. In Tcl/Tk
we do this by using the "set" command. An example in our code is:
| set lastcolor red |
In this example our variable is named "lastcolor" and the value we are
assigning to that variable is "red". We can then use
that stored value at other places in our program by adding a "$" symbol
to the front of the variable name. You can see a couple of
examples of this in the program example above. The most interesting
of these statements also merits further explanation:
puts stdout [format "lastcolor was %s" $mycolor] |
In this statement we have introduced the first of our "statement within
a statement" constructs. The inside statement is enclosed in
"[ ]". The way the Wish program handles this is that
it first executes the inside statement. In this case:
| format "lastcolor was %s" $mycolor |
As with any Tcl/Tk statement this produces a result. The Wish program then executes the outer statement
puts stdout "whatever the result was from the format statement"
Compound statements, as these are sometimes called, are very important Tcl/Tk constructs to understand. We will be encountering these many times in future lessons. The format statement itself is a very powerful and important Tcl/Tk statement. The format statement can be viewed as a kind of "text creation statement". It is often desirable in a computer program to display the result of a computation or the value stored in a variable as part of a human friendly phrase. For this purpose we use the Tcl/Tk format statement. If you examine the 1st argument to the format statement:
"lastcolor was %s"
You can readily identify a portion of the "human friendly" phrase. In this case it would be "lastcolor was". We would like to be able to finish this phrase using the contents of the variable that we called "mycolor". We do this by using a special format character called a placeholder. In this case it is "%s". The format statement understands a whole range of placeholder types. The "%s" means that "the variable I'm holding the place for is a text string". The third argument in our format statement identifies the variable value that we wish to have stuffed into the spot held open by the placeholder. In our case that is:
$mycolor
The resulting phrase in our example might be something like:
lastcolor was red
if the value stored in "mycolor" variable was in fact "red".
We now have talked about all the new Tcl/Tk constructs in our little
program example with the exception of the statement:
| proc scott {mycolor} { |
The command "proc" in this statement is informing the Wish interpreter
program that we want to create our very own new Tcl/Tk command.
In this case we are calling our new Tcl/Tk command "scott".
The first matching set of { } tell the Wish program that our new command
will accept a single argument ... and with our command that argument will
be named "mycolor". The single "{" at the end of the
line denotes the beginning of the block of Tcl/Tk code which will constitute
our new command called scott. This logic will continue
until we encounter the "closing brace" "}" as in:
| } ;# end of proc scott |
We have introduced another form of Tcl/Tk comment here as well. If you want to add a comment to the same line as a Tcl/Tk statement is on you must use two characters ";#" together to denote the beginning of this comment string.
The return statement presents the result that we want our new scott
command to give back or return. In this simple example we are
simply returning the same value that we gave in as an argument.
| return $mycolor |
Everything between the opening brace "{" and the closing brace "}" constitute the logic associated with our new command called scott.
In our simple example the puts statement and the return statement are the only statements contained within scott. Our new commands can be as simple or complicated as we need to make them. This capability gives our computer language a huge degree of flexibility and richness. It is as if we can take words in our spoken language and combine them together to create brand new words of our own.
Having defined our new command "scott" we can now have it execute every
time we press the button with the mouse by adding the following to the
"-command" argument:
| set lastcolor [scott $lastcolor] |
Remember how the compound statements execute. Inner part first ... outer part next.
Go ahead and type this program in and execute it as you did in lesson #2. Remember to press the button with your mouse. You should see an output that looks something like this
Step 2: more useful example |
#=======================================
# iCanProgram.com
# Lesson#3: more useful example
#=======================================
#=======================================
# scott - entry point
#=======================================
proc scott {mycolor} {
puts stdout [format "lastcolor was %s" $mycolor]
if {$mycolor == "red" } {
.hello configure -text "change me to red" -background green
set newcolor green
} else {
.hello configure -text "change me to green" -background red
set newcolor red
};#end if else
puts stdout [format "newcolor is %s" $newcolor]
return $newcolor
} ;# end of proc scott
#========================================
# main - entry point
#========================================
set lastcolor red
destroy .hello
button .hello -text "change me to green" -background red \
-command {set lastcolor [scott $lastcolor]}
pack .hello -padx 20 -pady 20
|
What we have done in this enhanced example is added some new statements to our scott command. The first of those new constructs is what is known as the "if ... then ... else" branching construct. Computers excel at this kind of true or false branching decisions. Most of the so called "intelligence" in computer software can be traced back to statements like these in the code. The "if" statement allows our little program to alter its execution path depending on the contents of a variable.
It begins with the statement:
if {$mycolor == "red" } {
|
In English this reads "if the value stored in our variable we have called
mycolor is equal to red then do this". The "this" in
this case is everything between the last { on the if line and the next
closing }. In our little example this code block includes:
.hello configure -text "change me to red" -background green set newcolor green |
Here we have introduced our final Tcl/Tk concept for this lesson ... the ability to alter the attributes on a Tk widget even after it has been drawn on the screen.
This is neat stuff.
We can alter the color of our button. We can alter the text in our button. We can do all these things based on how we code our program logic and flow. The statement which does all this magic is:
.hello configure ...
Recall that when the button was defined it was given the name ".hello".
Thus the .hello configure command construct is saying
"I want to change something about the widget I have called .hello ... in this case a button widget".Notice in this example we are changing the text in the button as well as its background color. When this statement executes that is exactly what will happen on the screen.
The other statement inside our "true" branch of our "if" statement simply allows us to remember the new color we have assigned to our button.
The closing } for our "true" branch is found as part of the else statement
below:
| } else { |
This says "I'm done with the "true" branch and I now want to code the "false" branch".
This is what "if" statements are all about.
If the condition in the if statement itself is false it WILL SKIP OVER THE "TRUE" BRANCH and execute the code contained in the "false" branch as denoted by the opening brace { after the else statement.
It is hard to see from this very simple example, but this is how computers get much of their apparent "intelligence". You can see that it isn't intelligent at all! The intelligence is all supplied by the human programmer in the form of these true and false blocks of code.
Our false branch in our code simply mirrors the true branch in that we will alter the text and color to reflect a "red" button and remember that color in our "newcolor" variable.
.hello configure -text "change me to green" -background red
set newcolor red
The false branch block is ended by the single closing } as below
}; end if else
If you now type in this program and run it you should see the button
toggle between red and green each time you click on it with your mouse.
Summary |
![]() |
Congratulations! You have completed one of the tougher lessons of the bunch. Computer languages are not all dry and boring like this stuff is. Unfortunately, you need to understand this to go forward to the interesting stuff like ... real graphical interfaces. |
You have been introduced to a bunch of new Tcl/Tk statements and constructs in this lesson. Let's review:
Exercises |
End of Lesson 3.