Strumenti Utente

Strumenti Sito


pygtk:resizing

resize tweaks

First: the method gtk.Window.resize() doesnt't work with a single argument (setting the other to -1, as instead does gtk.Widget.set_size_request()). OK, this is documented, though ugly.

Now: if a gtk.Window w has size (100,100) and we run the following code:

w.resize(200,200)
size = w.get_size()
w.resize(*size)

, then the window won't resize to 200,200, but to 100,100. In fact “resize” doesn't really resize, it just queues a resize process, while if we use get_size we get the current size, not the queued one. This means if several functions try to resize (and it makes sense, if each one takes care of a single dimension), we have race conditions.

I solved that (both problems) with the following functions:

def unset_real_size(window, event):
    """Fields 'real width' and 'real height' become obsolete (or at least
    useless) when a resize actually takes place.
    """

    window.set_data('real width', None)
    window.set_data('real height', None)
    
    handler = window.get_data('configure handler')
    if handler:
        # The callback is now useless; remove it.
        window.disconnect(handler)
        window.set_data('configure handler', None)
    
def ensure_configure_handler(window):
    """Ensure that unset_real_size is called.
    """
    if not window.get_data('configure handler'):
        new_handler = window.connect('configure-event', unset_real_size)
        window.set_data('configure handler', new_handler)

def get_width(window):
    width = window.get_data('real width')
    if not width:
        width = window.get_size()[0]
    return width

def get_height(window):
    height = window.get_data('real height')
    if not height:
        height = window.get_size()[1]
    return height

def set_width(window, width):
    ensure_configure_handler(window)

    window.set_data('real width', width)
    height = get_height(window)        
    window.resize(width, height)
  
def set_height(window, height):
    ensure_configure_handler(window)

    window.set_data('real height', height)
    width = get_width(window)        
    window.resize(width, height)

set_size_request

Notice that set_size_request has a similar problem: if a gtk.Widget widget's get_size_request gives (-1,-1) and I run the following code:

widget.set_size_request(100,100)
widget.set_size_request(-1, -1)

, it won't expand at all, nothing will happen. This is an issue if you wanted to use this as a hack to resize the widget but let to the user the possibility to shrink it again; an hackish way to solve this is instead the following code:

widget.set_size_request(100,100)
gobject.idle_add(widget.set_size_request, -1, -1)

gtk.ScrolledWindow

While gtk.Containers usually propagate size requests from child(ren) to parent, gtk.ScrolledWindow doesn't; instead, it sets a predefined (hardcoded, presumably) size. Apparently, this makes sense: if you want the whole widget shown, why a ScrolledWindow?! However, there are 2 situations in which this is hateful:

  • we have a widget that should take all the space available, but without overflowing the screen; if space isn't enough, and only in that case, the Scrollbar should appear. Notice that to reach that behaviour, we should also change gtk.Window behaviour so that its child(ren)'s size_request don't expand it so much that it overflows the screen (if we really want it to be big, we have set_size_request()!).
  • we have a widget that should take all the space needed (even though not known precisely and then not hardcodeable) at startup, but its toplevel gtk.Window shouldn't resize every time it changes size, and in that case only the Scrollbars should appear if needed.

I solved this with the following code (widget is the widget we want to resize so that it is fully shown), thanks to owen in freenode.irc's #gtk+ for the hint:

  
    scrolledwindows = []
    scrolledwindows_policies = []
    scrolledwindows_hscrollbars = []
  
    while widget:
        # The ScrolledWindows stop propagation of queue_redraws, unless they
        # have the scrollbars disabled, so here we disable them...
        if gobject.type_is_a(widget, gtk.ScrolledWindow):
            scrolledwindows.append(widget)
            scrolledwindows_policies.append(widget.get_policy())
            widget.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
            scrolledwindows_hscrollbars.append(widget.get_hscrollbar())
        widget = widget.get_parent()

    toplevel = treeview.get_toplevel()

    # ... then we can take the size...

    new_width = toplevel.size_request()[0]

    # ... add the size of bars...
    bars_width = 0
    for index in range(len(scrolledwindows)):
        # (not needed if the policy hides it)
        if scrolledwindows_policies[index][0] == gtk.POLICY_ALWAYS:
            bars_width += scrolledwindows_hscrollbars[index].size_request()[0]
        scrolledwindows[index].set_policy(*scrolledwindows_policies[index])
#    print "width:", new_width

    # ... and put together the total size.

    new_width += bars_width
pygtk/resizing.txt · Ultima modifica: 2009/01/14 09:20 da pietro