Creating a GUI Application with Tk

Credit: Kevin Marshall

Problem

You need to create a program that has a graphical user interface (GUI).

Solution

Use the Tk library. Its language-independent, cross-platform, and best of all, it comes standard with most Ruby distributions.

With Tk you create GUI elements, or "widgets", and then bind code blocks to them. When something happens (like the user clicking a widget), Tk runs the appropriate code block.

Ruby provides a class for each type of Tk widget. This simple Tk program creates a "root" widget (the application window), and a "label" widget within the window. The program then waits for events (although it can respond to any).

	require 	k
	root = TkRoot.new { title "Tiny Tk Application" }
	label = TkLabel.new(root) { text "You are a trout!" }
	label.pack
	Tk.mainloop

When run, it looks like Figure 21-1.

Figure 21-1. You are a trout


Discussion

The simple application above shows most of the basic features of GUI programming in Tk and other modern GUI toolkits. Well use the techniques to build a more complex application.

Tk GUI development and layout take a parent/child approach. Most widgets are children of other widgets: depending on the widget, this nesting can go arbitrarily deep. The exception to this rule is the TkRoot widget: its always the top-level widget, and its represented as the application window.

Child widgets are "packed" inside their parents so they can be displayed. A system called the geometry manager controls where on the screen the widgets actually show up. The default geometry manager is the "placer" manager, which lets you place widgets in relation to each other.

Tk applications are event-driven, so the final step is to start a main event loop which tells our program to listen for events to be fired on our widgets.

To further illustrate, lets make a simple stopwatch program to demostrate a realworld use of Tk.

To start, well create four simple methods that will be bound to our widgets. These are the nonGUI core of the program:

	#!/usr/bin/ruby
	# stopwatch.rb
	require 	k

	class Stopwatch

	 def start
	 @accumulated = 0 unless @accumulated
	 @elapsed = 0
	 @start = Time.now

	 @mybutton.configure(	ext => Stop)
	 @mybutton.command { stop }
	 @timer.start
	 end

	 def stop
	 @mybutton.configure(	ext => Start)
	 @mybutton.command { start }
	 @timer.stop
	 @accumulated += @elapsed
	 end

	 def reset
	 stop
	 @accumulated, @elapsed = 0, 0
	 @mylabel.configure(	ext => 0:00:00.0)
	 end

	 def tick
	 @elapsed = Time.now - @start
	 time = @accumulated + @elapsed
	 h = sprintf(\%02i, (time.to_i / 3600))
	 m = sprintf(\%02i, ((time.to_i % 3600) / 60))
	 s = sprintf(\%02i, (time.to_i % 60))
	 mt = sprintf(\%1i, ((time - time.to_i)*10).to_i)
	 newtime = "#{h}:#{m}:#{s}:#{mt}"
	 @mylabel.configure(	ext => newtime)
	 end

Next, we set up our GUI. This consists of six simple widgets. As before, the TkRoot is our application window, and contains all our other widgets:

	 def initialize
	 root = 
TkRoot.new { title Tk Stopwatch }

The TkMenuBar corresponds to the menu bar at the top of the screen in most modern GUI programs. Its an easy way to group a set of program features and make them available across our application. The menu layout of a TkMenuBar is defined by a nested array containing the menu items, and the code blocks to run when a menu item is selected:

	 menu_spec = [
	 [
	 [Program],
	 [Start, lambda { start } ],
	 [Stop, lambda { stop } ],
	 [Exit, lambda { exit } ]
	 ],
	 [
	 [Reset], [Reset Stopwatch, lambda { reset } ]
	 ]
	 ]

	 @menubar = TkMenubar.new(root, menu_spec, 	earoff => false)
	 @menubar.pack(fill=>x, side=>	op)

The TkFont is used only as a configuration option for our TkLabel, which in turn is only used to display the value of our stopwatch:

	 @myfont = TkFont.new(size => 16, weight => old)

	 @mylabel = TkLabel.new(root)
	 @mylabel.configure(	ext => 0:00:00.0, font => @myfont)
	 @mylabel.pack(padx => 10, pady => 10)

Apart from the menu bar, the TKButton is the only part of the GUI that the user can directly manipulate. The code block passed into its command method is run when the user clicks the button. Recall how the start and stop methods call this method to modify the behavior of the button. This makes the button act like the toggle on a physical stopwatch:

	 @mybutton = 
TkButton.new(root)
	 @mybutton.configure(	ext => Start)
	 @mybutton.command { start }
	 @mybutton.pack(side=>left, fill => oth)

The TkAfter event is an especially interesting widget because it has no direct visual representation in our program. Instead, it runs in the background firing our tick method every millisecond:

	 @timer = TkAfter.new(1, -1, proc { tick })

Finally, well start up the main Tk event loop. This call loads the GUI and starts listening for events:

	 Tk.mainloop
	 end
	end

	Stopwatch.new

Figure 21-2 shows the final product.

Figure 21-2. The stopwatch in action


This recipe only scratches the surface of the Tk library, not to mention GUI design in general. The Tk library includes dozens of widgets with lots of options and features. Entire books have been writen about how to use the library. You should refer to the Ruby Tk documentation or other Tk references for complete details.

See Also

  • If your Ruby distribution doesn include Tk, you can obtain the binary or source from http://www.tcl.tk; you may then need to rebuild Ruby from the source distribution once you have the Tk extension; on Debian GNU/Linux, you can just install the libtk-ruby package
  • Rubys Tk documentation is not very complete; fortunately, its Tk binding is similar to Perls, so you can get a lot of information from the Perl/Tk documentation; one location for this is http://perlhelp.web.cern.ch/PerlHelp/
  • Tcl and Tk by Brent B. Welch and Ken Jones with Jeffrey Hobbs (Prentice Hall)
  • Perl/Tk Pocket Reference by Stephen Lidie (OReilly)
  • The next few recipes (21.13 and 21.15) reproduce the simple GUI application and the stopwatch with the Ruby bindings to various other GUI libraries


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net