[pygtk] synchronizing HPaned widgets
John Finlay
finlay at moeraki.com
Fri Feb 6 05:15:57 WST 2009
Stephen Langer wrote:
> Hi --
>
> I'm hoping that someone can tell me if this is a bug or if I'm doing
> something wrong.
>
> I have two HPaned widgets whose separators I'd like to keep
> synchronized. Both Paneds are in the same VBox, so they have the same
> width.
>
> As described at http://faq.pygtk.org/index.py?req=show&file=faq19.013.htp
> , I connect to the 'notify' signal for each pane to find out when the
> separator has been moved. The callback function blocks the signal for
> the other pane, changes its position to match the first pane, and
> then unblocks the signal.
>
> The problem is that the signal doesn't seem to be blocked sometimes,
> so the program goes into an infinite loop. There are easy workarounds
> for this, but they're ugly and unsatisfying. In particular, the
> program loops when the panes are first shown if the contents of two
> diagonally opposite subpanes are larger than the contents of the other
> two.
>
> I've appended short program that illustrates the problem. Just
> starting the program will put it into an infinite loop. If you
> replace paneMoved by paneMoved_workaround, the problem goes away.
>
> Why doesn't blocking the signal work? Am I doing something wrong?
>
> I've run this test on OS X with python 2.5, gtk 2.14.7, and pygtk
> 2.12.1, and on Linux with python 2.4, gtk 2.8.20, and pygtk 2.8.6.
>
> Thanks,
> Steve
>
>
>
> import gtk
>
> def setPos(pane, signal, pos):
> "Set a Paned position without propagating signals"
> pane.handler_block(signal)
> pane.set_position(pos)
> pane.handler_unblock(signal)
>
> def paneMoved(pane, gparamspec):
> "Callback for synchronizing Paned position changes"
> if gparamspec.name == 'position':
> pos = pane.get_position()
> if pane is topPane:
> print "top"
> setPos(botPane, botSignal, pos)
> else:
> print "bottom"
> setPos(topPane, topSignal, pos)
>
> count = 0
> def paneMoved_workaround(pane, gparamspec):
> "Callback for synchronizing Paned position changes"
> global count
> if gparamspec.name == 'position':
> count += 1
> pos = pane.get_position()
> if count == 1:
> if pane is topPane:
> print "top"
> setPos(botPane, botSignal, pos)
> else:
> print "bottom"
> setPos(topPane, topSignal, pos)
> elif count > 1:
> count = 0
>
> window = gtk.Window()
> box = gtk.VBox()
> window.add(box)
> window.connect("delete-event", gtk.main_quit)
>
> # Create two panes, one on top of the other
> topPane = gtk.HPaned()
> box.pack_start(topPane, expand=1, fill=1)
> botPane = gtk.HPaned()
> box.pack_start(botPane, expand=1, fill=1)
>
> # Synchronize the pane positions
> topSignal = topPane.connect('notify', paneMoved)
> botSignal = botPane.connect('notify', paneMoved)
>
> # If the displayed sizes of shortstring and longstring are different,
> # the program will enter an infinite loop after show_all(). If the
> # strings are identical, the program behaves correctly (no infinite
> # loop, the panes can be resized and stay synchronized).
> shortstring = "string"
> longstring = "long string" # Try "String" too.
>
> # Put each string into two diagonally opposite labels in the panes.
> topPane.pack1(gtk.Label(longstring), resize=1, shrink=0)
> topPane.pack2(gtk.Label(shortstring), resize=1, shrink=0)
>
> botPane.pack1(gtk.Label(shortstring), resize=1, shrink=0)
> botPane.pack2(gtk.Label(longstring), resize=1, shrink=0)
>
> window.show_all()
>
> gtk.main()
>
>
You have to allow the widgets to shrink - remove the "shrink=0" args
from the pack1() and pack2() calls.
John
More information about the pygtk
mailing list