The code below creates a column of three labels. I would like to take the middle label, and replace it with another widget using the text from the label after the initial creation of the UI.
My actual use case is to take a GTKBuilder populated UI, and replace any particular named label with a dynamically wrapped label at run time. (I used a button here because it's simple but distinct.) Then I can still use Glade to set up the UI, including the labels, and not pepper my Python code with errant labels and strings if I later want to make a label wrap.
The code as it stands does not work - the new button gets added to the end of the column, and I want it to remain in the middle, where label2
was to begin with. What can I do, preferably in wrap_in_button
, to make sure it ends up in the correct place? I'd rather keep it general, since the parent may be a Box
or a Table
or any general Container
.
import pygtk
import gtk
def destroy(widget, data=None):
gtk.main_quit()
def wrap_in_button(label):
text = label.get_text()
button = gtk.Button(text)
parent = label.get_parent()
if parent:
parent.remove(label)
parent.add(button)
def Main():
# Pretend that this chunk is actually replaced by GTKBuilder work
# From here...
window = gtk.Window()
window.connect('destroy', destroy)
box = gtk.VBox()
window.add(box)
label1 = gtk.Label("Label 1")
label2 = gtk.Label("Label 2")
label3 = gtk.Label("Label 3")
box.pack_start(label1)
box.pack_start(label2)
box.pack_start(label3)
# ...up to here
# Comment this to see the original layout
wrap_in_button(label2)
window.show_all()
gtk.main()
if __name__ == "__main__":
Main()
I found the solution in the code of the gazpacho interface designer.
You can use this function:
def replace_widget(current, new):
"""
Replace one widget with another.
'current' has to be inside a container (e.g. gtk.VBox).
"""
container = current.parent
assert container # is "current" inside a container widget?
# stolen from gazpacho code (widgets/base/base.py):
props = {}
for pspec in gtk.container_class_list_child_properties(container):
props[pspec.name] = container.child_get_property(current, pspec.name)
gtk.Container.remove(container, current)
container.add(new)
for name, value in props.items():
container.child_set_property(new, name, value)
The key seems to be to transfer the child properties from the old widget to the new one after running gtk.Container.add()
.
Applied to your example, this would be:
import pygtk
import gtk
def replace_widget(current, new):
"""
Replace one widget with another.
'current' has to be inside a container (e.g. gtk.VBox).
"""
container = current.parent
assert container # is "current" inside a container widget?
# stolen from gazpacho code (widgets/base/base.py):
props = {}
for pspec in gtk.container_class_list_child_properties(container):
props[pspec.name] = container.child_get_property(current, pspec.name)
gtk.Container.remove(container, current)
container.add(new)
for name, value in props.items():
container.child_set_property(new, name, value)
def destroy(widget, data=None):
gtk.main_quit()
def wrap_in_button(label):
text = label.get_text()
button = gtk.Button(text)
replace_widget(label, button)
def Main():
# Pretend that this chunk is actually replaced by GTKBuilder work
# From here...
window = gtk.Window()
window.connect('destroy', destroy)
box = gtk.VBox()
window.add(box)
label1 = gtk.Label("Label 1")
label2 = gtk.Label("Label 2")
label3 = gtk.Label("Label 3")
box.pack_start(label1)
box.pack_start(label2)
box.pack_start(label3)
# ...up to here
wrap_in_button(label2)
window.show_all()
gtk.main()
if __name__ == "__main__":
Main()
This works for me using Python 2.6.6 and PyGTK 2.17.
As a solution to your original problem, I used label_set_autowrap()
from here and it worked most of the time. However, it's not a perfect solution as I wasn't able to correctly right-align auto-wrapped text.
Instead of putting the labels directly into the main container you can put each one into it's own box.
Change this:
label1 = gtk.Label("Label 1")
label2 = gtk.Label("Label 2")
label3 = gtk.Label("Label 3")
box.pack_start(label1)
box.pack_start(label2)
box.pack_start(label3)
To this:
box1 = gtk.HBox()
label1 = gtk.Label("Label 1")
box1.pack_start(label1)
box2 = gtk.HBox()
label2 = gtk.Label("Label 2")
box2.pack_start(label2)
box3 = gtk.HBox()
label3 = gtk.Label("Label 3")
box3.pack_start(label3)
box.pack_start(box1)
box.pack_start(box2)
box.pack_start(box3)
The rest of the code can stay the same. You just have to make sure that you only have 1 child widget in those boxes at a time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With