Hello, World! Simple Widgets Binding Events More Widgets Scrollbars Menus Canvas Make things look Beautiful More Information

We are moving to this wiki

Scrollbars

An important UI widget, which is implemented in Ruby/Tk in a very elegant way. We will repeat the Ruby Book example here, written even shorter.
root = TkRoot.new() { title "(Sc)rolling, (sc)rolling), (sc)rolling..." }
bar = TkScrollbar.new(root).pack('side'=>'right', 'fill'=>'y')
list = TkListbox.new(root).pack('side'=>'left', 'fill'=>'both', 'expand'=>true)
(0..20).each { |i|
  list.insert('end', i)
}
Looks fine, does nothing. That is, the scrollbar does not do anything, but the list itself can be scrolled by dragging the mouse above or below the list widget.

That is inconvenient when the list gets longer, so here goes:

bar.command(proc { |args|
  list.yview(*args)
})
list.yscrollcommand(proc { |first, last|
  bar.set(first, last)
})
This is a very elegant way to pass action from the two widgets to each other. If you're adventurous, print args, it is nice to see what the scrollbar actually does.

But it can be even shorter; instead of the above two commands, give:

list.yscrollbar(bar)

Text

The above can be repeated for a TkText widget. Upon vertical scrolling, a text widget can also perform horizontal scrolling when wrapping is disabled:
root = TkRoot.new() { title "(Sc)rolling, (sc)rolling), (sc)rolling..." }
bar = TkScrollbar.new(root, 'orient'=>'hor').pack('side'=>'bottom', 'fill'=>'x')
text = TkText.new(root, 'wrap'=>'none', 'width'=>20).pack('fill'=>'both', 'expand'=>true)
text.insert('end', "A string that is longer than fits on one line...")
bar.command(proc { |args|
  text.xview(*args)
})
text.xscrollcommand(proc { |first, last|
  bar.set(first, last)
})
Differences are the orient going horizontal and the text view/scroll commands using x instead of y.

Canvas

Slightly trickier, the TkCanvas:
root = TkRoot.new() { title "(Sc)rolling, (sc)rolling), (sc)rolling..." }
bar = TkScrollbar.new(root, 'orient'=>'hor').pack('side'=>'bottom', 'fill'=>'x')
canvas = TkCanvas.new(root, 'width'=>320, 'height'=>200).pack('fill'=>'both', 'expand'=>true)
TkcLine.new(canvas, 0, 0, 400, 400)
TkcLine.new(canvas, 0, 400, 400, 0)
bar.command(proc { |args|
  canvas.xview(*args)
})
canvas.xscrollcommand(proc { |first, last|
  bar.set(first, last)
})
Which shows what we expect, a window of size 320x200, displaying parts of the 400x400 cross we drew on it. Though the scrollbar looks like it won't work, it does partially. Just press the small triangles. No, dragging the canvas like you could drag a TkText is impossible.
canvas.configure('scrollregion'=>'0 0 400 400')
does the trick.

The second scrollbar

To get the second scrollbar where we want, we need to leave a small piece of space in the total window open. This is impossible with packing, so we use a grid:
root = TkRoot.new { title "Canvas, Grid, and Scrollbars" }
hbar = TkScrollbar.new(root) { orient 'horiz' }
vbar = TkScrollbar.new(root) { orient 'vert' }
canvas = TkCanvas.new(root) {
        width   320
        height  200
        scrollregion '0 0 400 400'
}
canvas.xscrollbar(hbar)
canvas.yscrollbar(vbar)

TkcLine.new(canvas, 0, 0, 400, 400)
TkcLine.new(canvas, 0, 400, 400, 0)

TkGrid.grid(canvas, vbar, 'sticky'=>'ns')
TkGrid.grid(hbar,         'sticky'=>'ew')

TkGrid.columnconfigure(root, 0, 'weight'=>1)
TkGrid.rowconfigure(   root, 0, 'weight'=>1)
(thanks to Mike Hall)

What we see here is:
Hello, World! Simple Widgets Binding Events More Widgets Scrollbars Menus Canvas Make things look Beautiful More Information

Kero