Замена на месте PyGTK-виджетов - PullRequest
3 голосов
/ 24 июня 2010

Код ниже создает столбец из трех меток. Я хотел бы взять среднюю метку и заменить ее другим виджетом, используя текст из метки после первоначального создания пользовательского интерфейса .

Мой реальный вариант использования - взять заполненный пользовательский интерфейс GTKBuilder и заменить любую конкретную именованную метку динамически упакованной меткой во время выполнения. (Я использовал здесь кнопку, потому что она проста, но отличается.) Тогда я все еще могу использовать Glade для настройки пользовательского интерфейса, включая метки, и не засыпать мой код Python ошибочными метками и строками, если позже я захочу сделать перенос меток.

Код в его нынешнем виде не работает - новая кнопка добавляется в конец столбца, и я хочу, чтобы она оставалась посередине, где label2 должен был начинаться. Что я могу сделать, предпочтительно в wrap_in_button, чтобы убедиться, что он оказался в правильном месте? Я бы предпочел придерживаться общего, поскольку родитель может быть Box или Table или любым общим 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()

Ответы [ 4 ]

5 голосов
/ 08 ноября 2010

Я нашел решение в коде дизайнера интерфейса gazpacho .

Вы можете использовать эту функцию:

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)

Ключ, похоже, заключается в переносе дочерних свойств из старого виджета в новый после запуска gtk.Container.add().

Применительно к вашему примеру это будет:

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()

Это работает для меня, используя Python 2.6.6 и PyGTK 2.17.

В качестве решения вашей исходной проблемы я использовал label_set_autowrap() отсюда , и она работала большую часть времени. Однако это не идеальное решение, так как я не смог правильно выровнять автоматически обернутый текст.

3 голосов
/ 29 июня 2010

Вместо того, чтобы помещать этикетки непосредственно в основной контейнер, вы можете поместить каждую в свою собственную коробку.

Изменить это:

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)

На это:

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)

Остальная часть кода может остаться прежней.Вам просто нужно убедиться, что у вас есть только один дочерний виджет в этих полях одновременно.

0 голосов
/ 27 октября 2012

Как и в ответе Матиаса, я однажды написал код ниже:

он не сохраняет все свойства, поэтому работает только с некоторыми контейнерами, которые я хотел протестировать в то время.

Сделано для python 2.4.x и pygtk того же возраста, все еще может работать для вас.

def replace_widget(cur, replace):
  """replace cur widget with another in a container keeping child properties"""
  con = cur.get_parent()
  pos = con.child_get_property(cur, "position")
  pak = con.query_child_packing(cur)
  con.remove(cur)
  if replace.get_parent(): replace.get_parent().remove(replace)
  con.add_with_properties(replace, "position", pos)
  con.set_child_packing(replace, *pak)
0 голосов
/ 24 июня 2010

Документация pygtk содержит полезную информацию о функции add:

Этот метод обычно используется для простые контейнеры, такие как gtk.Window, gtk.Frame или gtk.Button, которые содержат один дочерний виджет. Для макета контейнеры, которые обрабатывают несколько дети, такие как gtk.Box или gtk.Table, эта функция выберет значение по умолчанию параметры упаковки, которые не могут быть правильный.

Для контейнеров с более чем одним дочерним элементом далее говорится, что они имеют специализированные функции для добавления элементов. В вашем случае gtk.Box имеет три варианта: pack_start, pack_end и reorder_child.

Я не уверен, как он справится с использованием pack_start (или pack_end) после удаления элемента. В противном случае reorder_child звучит так, как будто это может помочь.

Если ничего из этого не работает, вы всегда можете удалить и повторно добавить все виджеты в правильном порядке, используя pack_start.

...