Pragana's Tcl Guide

Old notes

Skinable tk widgets

"It is tcl/tk code, so it must be ugly". How many times I've heard people saying that without even complaining. If at least they really know what they are saying... Well, time to prove they are wrong!
Tcl/tk can help us to build beautiful widgets, and with custom skins, as many other toolkits. Better yet, in tcl you can write those things with small code. Do you know what smaller code means? It means less bugs to be fixed, more maintainability, less time to develop. Let they do in Java or C++ and fix later. We are going to write it once, small and elegant. We'll write in tcl  :^)

What's in a skin

Let us first explain what is a skin, anyhow. A skin is just a collection of bitmaps, generally placed together in a single file for economy. We will borrow skins from Xmms, as there are many of them and I'm too lazy to draw fancy widgets. We are going to create skinable buttons and later skinable scales (volume-like controls in tk's nomenclature).

Here is a image of the main Xmms button bar:

Each button is represented twice, first in its normal state, then in the pressed down state.
We will need to get this image and break it in the several small images that we will need for our "simulated buttons". Why simulate a button, if tk already have good customizable buttons? Because with the regular button, we have no way to change the image when it is pressed down (except by using bindings), so it is easier to just place the image in a simple label widget.
      # Img is optional, if you want to read .bmp files
    package require Img
    image create photo btns -file cbuttons.bmp
    set btnw 23
    set btnh 18
for {set i 0} {$i < 5} {incr i} {
        for {set j 0} {$j < 2} {incr j} {
            set img ib${i}_$j
            image create photo $img
            $img copy btns -from [expr $i * $btnw] [expr $j * $btnh] \
                [expr ($i+1) * $btnw] [expr ($j+1) * $btnh - 1]

You may need the original cbuttons.bmp to do it yourself.
What does that code do? It creates lots of images (total of 10), for the first five buttons we have in our skin. I left out the sixth button as it is smaller and don't brings much novelty to our reasoning. Each button will have two images, ib${i}_0 and ib${i}_1, where ${i} is in the range 0..4. If you have the Img extension installed, you may read directly .bmp files, otherwise, you first convert cbuttons.bmp to a .gif file that may be read by standard tk.

Bind to make your code live

Now let's discuss the bindings needed. When a button is pressed, its image change to the lower image (in the picture above) and its attached command is executed. When the mouse button is released the button simply returns to its normal state again.
We may create all buttons at once:

    frame .bts

    for {set i 0} {$i < 5} {incr i} {
        label .lb$i -image ib${i}_0 -highlightthickness 0 -border 0
        bind .lb$i <ButtonPress-1> \
            [list .lb$i config -image ib${i}_1]
        bind .lb$i <ButtonRelease-1> \
            [list .lb$i config -image ib${i}_0]
        pack .lb$i -in .bts -side left

Notice we need to set highlightthickness and border to zero, so the buttons stack nicely.
How to bind comands to those buttons? Easy. Just remember to begin the binding with {+ to not replace the default binding, or the button image will not change.
To quick check your nice butttons,  insert this binding:

    bind all <1> {+puts "button %W pressed"}

You may now pack .bts where you need it. If you want to go further and duplicate Xmms' face, add the following code:

    image create photo imain -file main.bmp
    frame .main
    label -image imain
    place .bts -in .main -x 18 -y 90
    pack .main

The values -x 18 -y 90 fits the buttons at the right place in Xmms main frame. Get the main.bmp image too.

tk buttons with a skin

I'm sorry the image above is not a tclet, or you would see how nice those buttons are.
The images of this skin are from NeXTAmp2.4 by gLaNDix ( You may grab thousands of skins from Xmms and Winamp sites. And you now don't have excuses for making ugly tcl/tk GUIs.
Next time, I'll show you a little more complex example: a skinable tk scale widget, borrowing more bitmaps from Xmms skins. Don't miss it!

That's all fellows. Happy hacking!

Back Home