Scrollbar tutorial

Tutorial

Andreas Leitgeb 2004-03-31 - This is kind of an interactive tutorial. Start wish, arrange it such that all three, the wish window, the wish-console (or the xterm you started wish from) and this article are all (ideally) completely visible at the same time.

Imagine you have those two widgets:

 text .t
 scrollbar .sby -orient vert
 pack .sby .t -expand yes -fill both -side right

At this point you have a text widget and a scrollbar which are completely disconnected. The scrollbar shows a very small slider at the very top, and wherever you click on the scrollbar, nothing happens.

Now we make a dummy-procedure, that will just show the arguments it is called with:

 proc showargs {args} {puts $args}

and we set up the text-widget to send it's scroll-stuff to this dummy:

 .t conf -yscrollcommand {showargs .sby set}

If you do this in an interactive session (which I recommend), you'll quite instantly see ".sby set 0 1" be printed. This is what would be directly executed if we left out the "showargs", in order to set its slider to start at top (0) and extend to the bottom (1)

Now, we execute this manually:

 .sby set 0 1

and see the slider update as expected.

Lars H: It disappeared! No, wait, it only got disabled. Hmm... I suppose this is what one should expect, but nonetheless a bit startling.

Type a few times the <Return> key into the text-widget, until you hit the bottom. (Also, if you resize the window, you'll notice that the text-widget attempts to update the scrollbar) Once you've got more lines than fit, you'll see that the "0 1" changes to some decimal numbers, the first of which is larger than zero. (because now the scrollbar's slider is not supposed to start at top anymore). You also notice, that the slider is actually updated quite often - seemingly whenever you type or click anywhere into the text-widget.

Lars H: This isn't quite how I would put it. I see updates (i) when the text widget scrolls (makes sense, no need to update the scrollbar if just moving the cursor around in the window, as long as the view remains the same) and (ii) when switching to or from the . toplevel. There is a lot of the latter when working through this tutorial.

Then, we also set up this dummy for the scrollbar:

 .sby conf -command {showargs .t yview}

Now, manipulate (click various parts of) the scrollbar, and watch the commands printed.

Next, we change the procedure to print and then execute the arguments:

 proc showargs {args} {puts $args; eval $args}

After this, you'll see that scrollbar and text-widget successfully talk to each other, and you can also watch their communication.

Things, you should notice while playing:

  • clicking on the scrollbar causes one command to be sent, and the text-widget answer with a command to update the shape of the slider.
  • moving around in the text-widget (or typing characters) will update the scrollbar, but the scrollbar will *not* send back anything.
  • You could easily write another procedure (in place of showargs) that would let one text-widget control (and be controlled by) two (or arbitrary many) scrollbars. :-)
  • Controlling two text-widgets with one scrollbar is possible, too, but not that trivial. -> <multi scrolling>

Appendix:

For real use (one widget - one scrollbar per direction), you omit the "showargs":

 .t conf -yscrollcommand {.sby set}
 .sby conf -command {.t yview}

and let them talk directly...

I hope this was enlightening, and welcome anyone who thinks it was, to put it to appropriate places on the wiki. (I won't) - RS did.


Ro: Introspection is a wonderful way to learn what is happening internally in Tk. Great page!

Lars H: A very nice tutorial! It really demonstrates the basic structure of what does what and when. I see two problems, though (probably more with Tk itself than with the tutorial):

  1. When there is just a small amount of text in the text widget, then moving the scrollbar just a little isn't enough to make the text widget scroll, and as a result it doesn't update the scrollbar. This makes the scrollbar seem unresponsive.
  2. A cross-platform problem. In MacOS (X or not), the lower right corner of a window is the resize box (the one you grab when resizing a window). Just packing the scrollbar as shown above will cause the "down" arrow to be hidden under this resize box. Hints on how to handle this are appreciated (especially handling it in a cross-platform manner).

Ro: Does this still happen in 2011?

UKo: I always pack all my widgets inside a frame that is inside the toplevel. By making the appropriate padding around it the widgets stay away from all gadgets the windows manager paints inside the window boundaries. Another plus: you can embed the widgets all together into another window by just redefining one variable (assuming that all widgets are named like $f.widget)

LV Is working with scrollbars and the grid command identical to the pack? Or does one have to do something differently? Or can scrollbars even be used with grid? Nearly every example I see is with pack. Ro: You can definitely use grid to pack scrollbars and a text or a canvas widget together in a frame. See Dissecting a scrollbar or A little XML browser for an example.