21 Jul

There comes a time in every man's life where a single goocanvas.Canvas widget just won't cut it. Imagine you need two separate canvases for your interface, but you want them to scroll together with a single scroll bar. How would you solve this problem?

First, to enable a goocanvas.Canvas object to scroll is very easy (or so it would seem). Simply drop it into a gtk.ScrolledWindow widget, and you're done. As long as the boundary of your canvas exceeds the size, the scroll bars will work.

The Problem...

However, don't get too excited. A scrolledWindow widget that has a goocanvas.Canvas object as a child will not bubble up any scroll signals / events. So, if you have another canvas on the window, you will have no luck trying to synchronize up the scrollbars. Or if you want only part of the canvas to scroll, and part to remain fixed, this will not work.

The Solution...
Place two canvas objects next to each other. Place a vertical and horizontal scroll bar where you want them to appear. Create a signal handler for the scroll events, and use the Canvas.scroll_to(x, y) method to manually scroll both canvases.

Example Code:
Here are the signal handler functions for the 2 scroll bars to synchronize the scrolling of 2 goocanvas.Canvas objects:

#----------------------------------------------------------------------
def on_vscrollbar1_value_changed(self, widget):
isinstance(widget, gtk.VScrollbar)
vertical_value = widget.get_value()

# Get horizontal value
horizontal_scrollbar = self.frmMain.get_widget("hscrollbar1")
horizontal_value = horizontal_scrollbar.get_value()

# scroll the canvases
self.MyCanvas.scroll_to(horizontal_value, vertical_value)
self.MyCanvas_Left.scroll_to(horizontal_value, vertical_value)

#----------------------------------------------------------------------
def on_hscrollbar1_value_changed(self, widget):
isinstance(widget, gtk.HScrollbar)
horizontal_value = widget.get_value()

# Get vertical value
vertical_scrollbar = self.frmMain.get_widget("vscrollbar1")
vertical_value = vertical_scrollbar.get_value()

# scroll the canvases
self.MyCanvas.scroll_to(horizontal_value, vertical_value)

A picture is worth a thousand words:
Here are 2 similar screens using a goocanvas.Canvas object. Notice the horizontal scroll bar placement on them (at the bottom of the screen). The 2nd screen has an offset scroll bar, which will only scroll that half of the Canvas. Pretty cool!

Screen 1 - Using a single goocanvas.Canvas and a gtk.ScrolledWindow widget:

Screen 2 - Using two goocanvas.Canvas objects and individual scroll bar widgets: