2010-06-24 64 views
3

下面的代碼創建了一個由三個標籤組成的列。我想採用中間標籤,並在初始創建UI後,使用標籤中的文本替換爲其他小部件。PyGTK小部件的就地替換

我的實際使用案例是採用GTKBuilder填充的UI,並在運行時用dynamically wrapped label替換任何特定的名稱標籤。 (我在這裏使用了一個按鈕,因爲它很簡單但是截然不同)。然後,我仍然可以使用Glade設置UI,包括標籤,並且如果我稍後想要製作標籤包裝,請不要在錯誤的標籤和字符串中粘貼我的Python代碼。

代碼不起作用 - 新按鈕被添加到列的末尾,我希望它保持在中間,其中label2開始。我能做些什麼,最好在wrap_in_button,以確保它在正確的地方結束?我寧願保持一般,因爲父母可能是BoxTable或任何一般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() 
+0

如果您需要的僅僅是替換標籤中的TEXT(而不是替換標籤本身),則可以使用標籤實例的label.set_text()方法。 – heltonbiker 2011-05-13 14:10:47

+0

@heltonbiker - 不,我會用動態包裝標籤小部件替換它(請參閱鏈接)。 – detly 2011-05-13 14:37:42

回答

3

不是將標籤直接放入主容器中,而是將每個標籤放入它自己的盒子中。

更改此:

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) 

的代碼的其餘部分可以保持不變。 您只需確保一次只在這些框中有1個子部件。

+1

我最終做了類似的事情 - 使用'gtk.Alignment's而不是'HBox's。 – detly 2010-06-29 16:00:01

0

的pygtk的文檔對add功能一些有用的信息:

此方法通常用於 簡單的容器,如gtk.Window, gtk.Frame,或gtk.Button那持有一個 單個子部件。對於處理多個 孩子的佈局 容器,如gtk.Box或gtk.Table, 此功能將選取默認 裝箱參數,該參數可能不是 正確。

對於具有多個子項目的容器,它接着說它們具有用於添加項目的專門功能。在你的情況下,gtk.Box有三個選項:pack_start,pack_endreorder_child

我不知道它將如何處理使用pack_start(或pack_end)後,項目已被刪除。否則,reorder_child聽起來可能會有所幫助。

如果這些都不起作用,您可以隨時使用pack_start以正確的順序刪除並重新添加所有小部件。

+0

雖然我不能在'Table'上使用'pack_start'和朋友。刪除和重新添加所有小部件都假定沒有特殊的設置可以在Glade中調整包裝,填充等。 – detly 2010-06-24 06:38:18

+0

表具有「附加」功能。這會有幫助嗎?無論如何,你想在什麼情況下動態改變控制?用戶不會被這個困惑嗎? – Jon 2010-06-24 06:48:53

+0

該標籤可能位於任何**'gtk.Container'內。它不會動態變化,它在界面第一次構建時會發生變化。我只想將我的標籤和文本保存在gtkbuilder文件中,並將代碼保存在Python文件中。 – detly 2010-06-24 07:14:07

5

我在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()from here,它大部分時間都在工作。但是,這不是一個完美的解決方案,因爲我無法正確對齊自動包裝的文本。

0

到Matthias'es答案相似,我寫了下面的代碼,一旦:

它不會把所有的性質,儘管,所以只能用一些容器,那些關心我當時的測試工作。

用於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)