Packing some Simple Widgets
A single window with a single label is not very much. We will start with
packing five, basic widgets. The second part of this page looks at placing
widgets in a regular grid.
require 'tk'
root = TkRoot.new() { title "Packing Example" }
button = TkButton.new(root) { text "First, rightmost" }
button.pack("side"=>"right", "fill"=>"y")
entry = TkEntry.new(root).pack("side"=>"top", "fill"=>"x")
entry.insert(0, "Entry on the top")
label = TkLabel.new() { text "to the right" }
label.pack("side"=>"right")
image = TkPhotoImage.new('file'=>"background.gif", 'height'=>50)
img_label = TkLabel.new(root) { image image }.pack("anchor"=>"e")
text = TkText.new(root) { width 20; height 5 }.pack("side"=>"left")
text.insert('end', "Left in canvas")
TkMessage.new(root) { text "Message in the Bottom" }.pack("side"=>"bottom")
Tk.mainloop()
That's not too daunting, is it? Let's walk through the source:
Button
- We stuff a TkButton in the root window,
- Then we pack it, telling it to put itself
as far to the right as possible,
- at the same time, we tell it to fill up all vertical space assigned to it
by its packer,
- The packer is the parent, usually, so the root window in this case; if
required you can set another packer with in,
Entry
- A TkEntry widget can be used to get input
from the user (though we put some text into it right here beforehand),
- The entry is told to pack itself on top, but since it is the
second widget to pack, it has fewer space left to do so than the
button,
- In other words, each pack divides the free
space in two: the packer assigns one part for the widget and leaves the rest
as free space for subsequent widgets.
- Like all editable widgets, TkEntry does not
accept the command text,
- So we use insert instead, which accepts a
position and a string; the position can be an index (number from 0 to n, when
there are n characters in the entry) or a special value like 'insert' and 'end',
- A TkEntry has quite sophisticated selection
and edit capabilities, but you may look those up yourself.
Label
- Well, the stuff concerning the Label is too easy to explain by now,
- When you omit the parent, Tk will take the root window for it. The
advantage is that there is always a root, even if you do not explicitly
create it; you can also pass nil to achieve
this, which is useful when more parameters are required in new(),
- It doesn't matter whether you pack first, or set the text first.
Image
- For an image, some very few formats are recognized,
- An image can not display itself, but needs a TkLabel, TkButton or a
TkCanvas for that,
- We restrict the label to only 50 pixels for its height,
- We tell the label to settle as far East (right) as possible in the area
assigned to it by the packer; enlarge the window to see the effect (in
comparison, the label centers itself vertically),
- In dire need (when you have a black and white bitmap), you can use a TkBitmapImage instead of a photo image,
Text
- A TkText widget is multiline text,
- We specify its size with width and height in number of characters; this TkText is 20 characters wide and 5 lines high; for
proportional fonts, the width will be based on some average.
- The insert has some extra special indexes,
of which the @line,char is used here
Message
- a TkMessage is a multiline label.
Resizing the Window
If you now resize the window, you see that the widgets
are automatically repacked. When you enlarge the window, you can see better
where widgets are placed by the packer.
When you shrink the window, you will see widgets gradually disappearing.
The widgets that were added last, are packed last and find no space left. The
message and text are bound to go first. Notice that the text widget spreads all
text over multiple lines when you shrink it (yes, you can tell it to wrap on
word boundaries with wrap "word").
Finally, if you do like the order in which you construct the widgets, but do
not like them to be packed in that order, you can use before before otherWidget and after
otherWidget as options for pack.
Gridding some Simple Widgets
As alternative, when packing seems to be rude, there is grid. Gridding allows you to align widgets, which is
troublesome when packing. The OO nature of Ruby makes gridding a bit
cumbersome, since you can not grid a set of widgets by calling a method of just
one of them.
Here is some code:
require 'tk'
root = TkRoot.new() { title "Gridding Example" }
br = ["one", "and", "one"].collect { |c|
TkButton.new(root, "text"=>c)
}
TkGrid.grid(br[0], br[1], br[2], "columnspan"=>2 )
TkButton.new(root, "text"=>"is").grid("columnspan"=>3, "sticky"=>"ew")
TkButton.new(root, "text"=>"two").grid("row"=>1, "column"=>3, "columnspan"=>3)
Tk.mainloop
First, we construct three buttons, then we add them in a single row of the
grid. Due to the columnspan, we now have six
columns in our grid.
The fourth button is automatically added to the next row, since we do not
mention any row. In much the same way, it is
added to the first column. It demands three columns and due to sticky, the button is assigned the entire width of
those three columns. Sticky delivers a combination of the anchor and fill
when packing.
The last button is added explicitly to its row and column, because
otherwise it would be added to the third row, first column (it is a new grid command).
The options ipadx, pady and in work the
same as when packing.
widget.grid_columnconfig and widget.grid_rowconfig do not work in current
Ruby/Tk, but I sent a fix to the ruby-dev mailinglist.
Resizing the Window
When you resize the window, there is nothing interesting to see. For more
resizing issues, see the chapter on combining more
widgets.
Kero