Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyGTK: dynamic label wrapping

Tags:

pygtk

It's a known bug/issue that a label in GTK will not dynamically resize when the parent changes. It's one of those really annoying small details, and I want to hack around it if possible.

I followed the approach at 16 software, but as per the disclaimer you cannot then resize it smaller. So I attempted a trick mentioned in one of the comments (the set_size_request call in the signal callback), but this results in some sort of infinite loop (try it and see).

Does anyone have any other ideas?

(You can't block the signal just for the duration of the call, since as the print statements seem to indicate, the problem starts after the function is left.)

The code is below. You can see what I mean if you run it and try to resize the window larger and then smaller. (If you want to see the original problem, comment out the line after "Connect to the size-allocate signal", run it, and resize the window bigger.)

The Glade file ("example.glade"):

<?xml version="1.0"?>
<glade-interface>
  <!-- interface-requires gtk+ 2.16 -->
  <!-- interface-naming-policy project-wide -->
  <widget class="GtkWindow" id="window1">
    <property name="visible">True</property>
    <signal name="destroy" handler="on_destroy"/>
    <child>
      <widget class="GtkLabel" id="label1">
        <property name="visible">True</property>
        <property name="label" translatable="yes">In publishing and graphic design, lorem ipsum[p][1][2] is the name given to commonly used placeholder text (filler text) to demonstrate the graphic elements of a document or visual presentation, such as font, typography, and layout. The lorem ipsum text, which is typically a nonsensical list of semi-Latin words, is a hacked version of a Latin text by Cicero, with words/letters omitted and others inserted, but not proper Latin[1][2] (see below: History and discovery). The closest English translation would be "pain itself" (dolorem = pain, grief, misery, suffering; ipsum = itself).</property>
        <property name="wrap">True</property>
      </widget>
    </child>
  </widget>
</glade-interface>

The Python code:

#!/usr/bin/python

import pygtk
import gobject
import gtk.glade

def wrapped_label_hack(gtklabel, allocation):
    print "In wrapped_label_hack"
    gtklabel.set_size_request(allocation.width, -1)
    # If you uncomment this, we get INFINITE LOOPING!
    # gtklabel.set_size_request(-1, -1)
    print "Leaving wrapped_label_hack"

class ExampleGTK:

    def __init__(self, filename):
        self.tree = gtk.glade.XML(filename, "window1", "Example")
        self.id = "window1"
        self.tree.signal_autoconnect(self)

        # Connect to the size-allocate signal
        self.get_widget("label1").connect("size-allocate", wrapped_label_hack)

    def on_destroy(self, widget):
        self.close()

    def get_widget(self, id):
        return self.tree.get_widget(id)

    def close(self):
        window = self.get_widget(self.id)
        if window is not None:
            window.destroy()
        gtk.main_quit()

if __name__ == "__main__":
    window = ExampleGTK("example.glade")
    gtk.main()
like image 435
detly Avatar asked Dec 12 '09 15:12

detly


3 Answers

Here's a one-line variation on killown's solution:

label.connect('size-allocate', lambda label, size: label.set_size_request(size.width - 1, -1))

The above will make sure that the label takes on the width allocated to it, so that word-wrapping is happy.

Not sure why there's a "-1" for the width, but it seems harmless!

like image 60
Tal Liron Avatar answered Nov 18 '22 20:11

Tal Liron


VMware's libview has a widget called WrapLabel which should do what you want, but it's in C++. A Python translation is available in the Meld repository (separated out from busybox.py).

like image 22
Kai Avatar answered Nov 18 '22 19:11

Kai


example for resize and wrap the label dynamically:

EDIT:

import gtk

class DynamicLabel(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)

        self.set_title("Dynamic Label")
        self.set_size_request(1, 1)
        self.set_default_size(300,300) 
        self.set_position(gtk.WIN_POS_CENTER)

        l = gtk.Label("Dynamic Label" * 10)
        l.set_line_wrap(True)
        l.connect("size-allocate", self.size_request)

        vbox = gtk.VBox(False, 2)
        vbox.pack_start(l, False, False, 0)

        self.add(vbox)
        self.connect("destroy", gtk.main_quit)
        self.show_all()

    def size_request(self, l, s ):
        l.set_size_request(s.width -1, -1)

DynamicLabel()
gtk.main()
like image 3
killown Avatar answered Nov 18 '22 19:11

killown