Global training solutions for engineers creating the world's electronics

Tcl/Tk Buttons

Here is a short example showing how to use Tcl/Tk to create toplevel windows containing frequently used buttons. Mostly there are just three things we need to know about buttons:

  • What does the label say?
  • What Tcl command should be executed when clicked?
  • Where does the button appear in its window?

 

Here, button creation is wrapped up in procedure add_button. It takes two arguments, what the label should say and what Tcl commands should be executed when the button is clicked. Buttons are arranged in a single column.

# A Tcl/Tk gadget to construct a window of buttons
# SD 20 Nov 2002


#######################################
####                               ####
#### Leave these lines unchanged   ####
####                               ####
#######################################
destroy  .buttons
toplevel .buttons
wm title .buttons "Buttons"
set count 0
proc add_button {title command} {
  global count
  button .buttons.$count -text $title -command $command
  pack   .buttons.$count -side top -pady 1 -padx 1 -fill x
  incr count
}

#######################################
####                               ####
####     Change these lines to     ####
####     add your own buttons      ####
####                               ####
#######################################
add_button "Resize Main" { wm geometry . 464x650+0+0  }
add_button "Hello"       { puts "Hello there"         }
add_button "Goodbye"     { puts "Cheerio"             }
add_button "Exit"        { exit                       }

The four add_button commands in this example produce a window like this one. You can replace them with any commands appropriate for your EDA tools. Any Tcl commands may be used for the second arguments.

 

Multiple Frames of Buttons

You may want a dozen buttons or more organised in columns. Here's one way to do it:

# A Tcl/Tk gadget to construct a window of buttons
# SD 8 Aug 2003


#######################################
####                               ####
#### Leave these lines unchanged   ####
####                               ####
#######################################
destroy  .buttons
toplevel .buttons
wm title .buttons "Doulos Buttons"
set count 0
proc add_frame title {
  global frame count
  set frame .buttons.frame$count
  frame $frame -border 2 -relief groove
  label $frame.label -text $title
  pack  $frame       -side left -padx 2 -pady 2 -anchor n -fill both
  pack  $frame.label -side top  -padx 2 -pady 2
  incr count
}
proc add_button {title command} {
  global frame count
  button $frame.$count -text $title -command $command
  pack   $frame.$count -side top -pady 1 -padx 1 -fill x
  incr count
}

#######################################
####                               ####
####  Change these lines to add    ####
####  your own frames and buttons  ####
####                               ####
#######################################
add_frame  "Control"
add_button "Window Size"     {wm geometry . 464x692+0+0}
add_button "Create Library"  {vlib mylib; vmap work mylib}
add_button "Compile"         {  vcom counter.vhd
                                vcom countertb.vhd
                                vcom countercf.vhd }
add_button "Load Simulation" {vsim mylib.cfg_countertb}
add_button "Wave Window"     {source wave.do}
add_button "Quit"            {quit -force}

add_frame  "Simulate"
add_button "Run 10"   {run 10}
add_button "Run 100"  {run 100}
add_button "Run 1000" {run 1000}
add_button "Run all"  {run -all}
add_button "Restart"  {restart -force}

add_frame  "Zoom"
add_button "Full"     {.wave.tree zoomfull}
add_button "2x"       {WaveZoom .wave out 2.0}
add_button "4x"       {WaveZoom .wave out 4.0}
add_button "1/2x"     {WaveZoom .wave in 2.0}
add_button "1/4x"     {WaveZoom .wave in 2.0}

 

There is now an add_frame procedure. Each group of add_button commands must be preceded by a call to add_frame. Frames are packed left to right and buttons are still packed in columns.

Once again you can change the add_frame and add_button commands for your own buttons. This example is taken from a ModelSim SE project so the commands are EDA tool specific.



How To Use

These examples are useful for EDA tools that support Tcl and the Tk package. Copy and paste one of the above examples into a file, maybe called buttons.tcl. Edit your copy changing add_button commands to suit your project. From inside the Tcl command window of the EDA tool type:

   source buttons.tcl

Commands issued by button clicks are directly interpreted by the EDA tool.

Does Your EDA Tool Support Tk?

Try typing this into the Tcl command window:

   package require Tk

If the tool responds with a version number like 8.4 then it does. If the tool responds like this can't find package Tk then it doesn't and it might be quite tricky or impossible to support Tk directly. Check the manual. If your EDA tool doesn't support Tk then you can still add Tk functionality to it indirectly.

Add External Support for Tk?

Standard Tcl supports pipelines and events. Pipelines let Tcl-only tools interact with other Tcl applications that can support buttons and other powerful Tk widgets. Tcl is free and you can compile your own Tcl interpreter supporting Tk from source code or just download and install a free binary distribution.

This example was written to work with ModelSim PE which doesn't support Tk. The first procedure, include_these_buttons, contains the only ModelSim specific parts. You can change the add_frame and add_button commands to suit your own EDA tool and project.

#! /usr/bin/wish

proc include_these_buttons {} {

  add_frame   "Control"
  add_button  "Create Library"  {vlib mylib; vmap work mylib}
  add_button  "Compile"         {  vcom counter.vhd
                                   vcom countertb.vhd
                                   vcom countercf.vhd }
  add_button  "Load Simulation" {vsim mylib.cfg_countertb}
  add_button  "Wave Window"     {source wave.do}
  add_button  "Quit"            {quit -force}

  add_frame   "Simulate"
  add_button  "Run 10"   {run 10}
  add_button  "Run 100"  {run 100}
  add_button  "Run 1000" {run 1000}
  add_button  "Run all"  {run -all}
  add_button  "Restart"  {restart -force}

}

proc add_frame title {
  global buttons
  set buttons(frame) .frame$buttons(widget_count)
  frame $buttons(frame) -border 2 -relief groove
  label $buttons(frame).label -text $title -font $buttons(font)
  pack  $buttons(frame)       -side left -padx 2 -pady 2 -anchor n -fill both -expand 1
  pack  $buttons(frame).label -side top  -padx 2 -pady 2
  incr buttons(widget_count)
}

proc add_button {title command} {
  global buttons
  button $buttons(frame).b$buttons(widget_count) -text $title -font $buttons(font) \
                                                    -command "puts \"$command\""
  pack   $buttons(frame).b$buttons(widget_count) -side top -pady 2 -padx 2 -fill x
  incr buttons(widget_count)
}

proc respond_to_buttons {} {
  global buttons
  if [eof $buttons(pipe_id)] {
    catch {close $buttons(pipe_id)}
  } elseif { [gets $buttons(pipe_id) line] >= 0 } {
    puts $line
    eval $line
  }
}

if [string compare $argv buttons_gui] {
  global buttons
  if [catch {set buttons(pipe_id) [open "|wish buttons.tcl buttons_gui" r+]}] {
    puts "Couldn't start wish for the buttons GUI\n"
  } else {
    fconfigure $buttons(pipe_id) -blocking 0 -buffering line
    fileevent  $buttons(pipe_id) readable respond_to_buttons
  }
} else {
  wm title . Buttons
  set buttons(font) [font create -family {Arial Helvetica "Courier New"} -size 12]
  set buttons(frame) {}
  set buttons(widget_count) 1
  include_these_buttons
}

To make this example work, the standalone Tcl/Tk interpreter must be installed. Its command name is usually wish. The line containing this fragment starts the wish interpreter through a pipeline:

   [open "|wish buttons.tcl buttons_gui" r+]

If your system uses another name such as wish84 then you should modify this line.

This script is run twice. First from the EDA tool by typing source buttons.tcl. The script then opens a command pipeline calling the Tcl/Tk interpreter and supplying its own name as the script to execute but this time with buttons_gui command line argument. This tells the Tcl script it's being run as the standalone application to display the buttons specified in the include_these_buttons procedure.

Communication takes place through the pipeline. When a button is clicked it sends the Tcl commands as plain text down the command pipeline to the EDA tool. For example:

   puts {vlib mylib; vmap work mylib}

A file event is set up in the EDA tool to respond to new information from the pipeline:

   fileevent $buttons(pipe_id) readable respond_to_buttons

This executes the procedure respond_to_buttons everytime the buttons application sends commands. It reads from the pipeline and uses the eval command to pass them on to the EDA tool's Tcl interpreter.

This example assumes the EDA tool uses an event loop. If it doesn't, you can easily modify the script to start one with the vwait command. However, the event loop may have to be terminated to pass control back to the EDA tool's command window.

If you have ModelSim PE you may want to Download the complete example.

Need To Know More?

There are many many more powerful Tcl applications for EDA. To find out more consider attending Doulos Tcl/Tk Training.