2013-02-14 80 views
0

下面是我在GUI中試圖做的一個模擬版本。我有一個MessageDialog在執行回調方法的過程中創建的。我的問題是MessageDialog在回調方法結束執行之前不會關閉。gtk MessageDialog直到封閉方法完成後纔會關閉

我有一個「dialog.destroy()」這是我所期望的破壞對話。我點擊「是/否」並按下按鈕,但直到「_go」結束,對話框纔會消失。

的「time.sleep(4)」是在有模擬其他的東西我MessageDialog相互作用後發生的事情在我的「_go」的方法結束。

from gi.repository import Gtk, GObject 
import time 

class Gui(Gtk.Window): 
    def __init__(self): 
     Gtk.Window.__init__(self) 
     self.connect("delete_event", Gtk.main_quit) 
     self.set_size_request(700, 600) 
     notebook = Gtk.Notebook() 
     notebook.set_tab_pos(Gtk.PositionType.TOP) 
     notebook.append_page(MyTab(), Gtk.Label("A tab")) 
     self.add(notebook) 
     notebook.show_all() 
     self.show() 

class MyTab(Gtk.VBox): 
    def __init__(self): 
     super(MyTab, self).__init__() 
     self.go_button = Gtk.Button() 
     self.go_button.add(Gtk.Image().new_from_stock(Gtk.STOCK_APPLY, 
               Gtk.IconSize.BUTTON)) 
     top_box = Gtk.HBox() 
     top_box.pack_start(self.go_button, False, True, 5) 
     self.pack_start(top_box, False, True, 5) 

     # setup callbacks 
     self.go_button.connect("clicked", self._go) 

    def _go(self, _): 
     dialog = Gtk.MessageDialog(Gtk.Window(), 
            Gtk.DialogFlags.MODAL, 
            Gtk.MessageType.QUESTION, 
            Gtk.ButtonsType.YES_NO, 
            "RESPONSE REQUIRED") 
     dialog.format_secondary_text("are you having fun?") 
     response = dialog.run() 
     dialog.destroy() 
     print "your response is: " + str(response) 
     time.sleep(4) 
     print "left _go" 

def main(): 
    """ 
    Main entry point. 
    """ 
    Gui() 
    Gtk.main() 

if __name__ == "__main__": 
    main() 
+0

我要補充的,如果有人想嘗試運行此,你需要 '中的python-GI'(apt-get的安裝python-GI) – rikityplikity 2013-02-15 00:01:36

回答

1

按上user4815162342's answer的意見,我想出了一個使用嵌套的主循環的解決方案。這個類需要一個對話框並提供一個運行方法。

class NestedDialog(object): 
    def __init__(self, dialog): 
     self.dialog = dialog 
     self.response_var = None 

    def run(self): 
     self._run() 
     return self.response_var 

    def _run(self): 
     self.dialog.show() 
     self.dialog.connect("response", self._response) 
     Gtk.main() 

    def _response(self, dialog, response): 
     self.response_var = response 
     self.dialog.destroy() 
     Gtk.main_quit() 

對話框然後作爲運行如下:

def _go(self, _): 
    dialog = Gtk.MessageDialog(Gtk.Window(), 
       Gtk.DialogFlags.MODAL, 
       Gtk.MessageType.QUESTION, 
       Gtk.ButtonsType.YES_NO, 
       "RESPONSE REQUIRED") 
    dialog.format_secondary_text("are you having fun?") 
    nested_dialog = NestedDialog(dialog) 
    response = nested_dialog.run() 
    print "your response is: " + str(response) 
    time.sleep(4) 
    print "left _go" 
+0

嵌套主循環不好。他們很容易將創建窗口小部件的上下文與處理事件的上下文大量耦合在一起。當你真的不應該這樣做時,它們很容易變得重入。他們可以阻止其他系統自己的循環。最終,他們顛覆了GLib,GTK +和所有其他此類框架的事件驅動理念。你應該使用'show widget,set handler,return,等待回調'的模式。這不僅僅是一個閒置的哲學建議:例如,'gtk_dialog_run()'就會被棄用,例如 – 2017-06-03 19:49:15

1

這是正確的行爲。當控制返回到Gtk的主循環時,窗口只會消失,這個循環只發生在_go回調結束時。

3

此問題不是特定於對話框。 任何直到您返回到主循環並讓系統有機會處理通過修改小部件所累積的事件之後,GUI更改纔可見。

如果你真的想立即更新GUI回調,您可以手動旋轉與呼叫後,像這樣的循環累積事件dialog.destroy()

while Gtk.events_pending(): 
    Gtk.main_iteration() 

但是,要知道,這不會只更新屏幕,但也運行其他累積事件,包括空閒和超時處理程序和按鈕點擊回調(如果有任何未決)。這會產生意想不到的後果。

+1

是的,除非你真的知道你在做什麼,否則手動旋轉主循環通常是一件壞事。一個更好的方法是做一些閒置功能需要很長時間的事情。 – iain 2013-02-17 13:34:55

+0

如何在'主'主循環中嵌套另一個主循環?它只會啓動對話框並處理它們的刪除事件,並在對話框關閉時退出(退出事件由對話框刪除事件觸發)。這是否會爲我提供「我馬上就要接近」的行爲? (其實我認爲這是基於GTK對話框做對他們一點閱讀後如何工作的。) – rikityplikity 2013-02-18 22:30:00

+0

@rikityplikity模式對話框做的工作那樣,但是你叫'destroy' * *後退出內部循環。我發佈的'while'循環是一個小型的主循環,只運行足夠長的時間來拾取未決事件(在你的情況下只有那些會顯示對話框關閉的循環)。 – user4815162342 2013-02-18 22:42:33