2013-02-14 53 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