Tcl/Tk GUI Programming 
Lesson #3: creating our own Tcl/Tk commands

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

Let us illustrate our lesson by way of an example.   Using the editor you used in lesson #2 create the following program by typing in these statements:
 
#=======================================
#      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

Let's go ahead now and make our little example more useful.
 
#=======================================
#      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

  1. Try extending your little program to add a third color ... say yellow into the sequence that the button rotates through.  ie. have the red button change to green and have the green button change to yellow and have the yellow button change to red.
We will provide the answer to this exercise as part of lesson #4.

End of Lesson 3.


Copyright of iCanProgram Inc. 2002