Python 直到封闭方法完成,gtk消息对话框才关闭

Python 直到封闭方法完成,gtk消息对话框才关闭,python,dialog,gtk,pygtk,messagedialog,Python,Dialog,Gtk,Pygtk,Messagedialog,下面是我在GUI中尝试执行的模拟版本。我有一个MessageDialog,它是在回调方法执行期间创建的。我的问题是,在回调方法完成其执行之前,MessageDialog不会关闭 我有一个“dialog.destroy()”,我希望它能破坏这个对话框。我点击“是/否”并按下按钮,但对话框直到“_go”结束才会消失 其中的“time.sleep(4)”用于模拟MessageDialog交互结束后在我的“\u go”方法中发生的其他事情 from gi.repository import Gtk, G

下面是我在GUI中尝试执行的模拟版本。我有一个MessageDialog,它是在回调方法执行期间创建的。我的问题是,在回调方法完成其执行之前,MessageDialog不会关闭

我有一个“dialog.destroy()”,我希望它能破坏这个对话框。我点击“是/否”并按下按钮,但对话框直到“_go”结束才会消失

其中的“time.sleep(4)”用于模拟MessageDialog交互结束后在我的“\u 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()

这是正确的行为。只有当控制权返回到Gtk的主循环时,该窗口才会消失,而主循环仅发生在您的_go回调结束时。

这是正确的行为。只有当控制权返回到Gtk的主循环时,该窗口才会消失,而主循环仅发生在您的_go回调结束时。

此问题并非特定于对话框。任何GUI更改都是不可见的,直到您返回到主循环,并让系统有机会处理通过修改小部件累积的事件

如果您真的想在回调中立即更新GUI,可以在调用
dialog.destroy()
之后,使用如下循环手动旋转累积事件:


但是,请注意,这不仅会更新屏幕,还会运行其他累积事件,包括空闲和超时处理程序以及按钮单击回调(如果有挂起的话)。这可能会产生意想不到的后果。

此问题不是对话框特有的。任何GUI更改都是不可见的,直到您返回到主循环,并让系统有机会处理通过修改小部件累积的事件

如果您真的想在回调中立即更新GUI,可以在调用
dialog.destroy()
之后,使用如下循环手动旋转累积事件:

但是,请注意,这不仅会更新屏幕,还会运行其他累积事件,包括空闲和超时处理程序以及按钮单击回调(如果有挂起的话)。这可能会产生意想不到的后果。

根据对的评论,我提出了一个使用嵌套主循环的解决方案。这个类接受一个对话框并提供一个run方法

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"
根据上面的评论,我提出了一个使用嵌套主循环的解决方案。这个类接受一个对话框并提供一个run方法

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"

我应该补充说,如果有人想尝试运行它,你需要‘pythongi’(apt get install pythongi)我应该补充说,如果有人想尝试运行它,你需要‘pythongi’(apt get install pythongi)是的,手动旋转主循环通常是一件坏事,除非你真的知道自己在做什么。更好的方法是在空闲函数中花费很长时间来完成任何事情。在“main”mainloop中嵌套另一个mainloop怎么样?启动它只是为了启动对话框并处理它们的删除事件,并在对话框关闭时退出(退出事件由对话框删除事件触发)。这会让我有“立即关闭”的行为吗?(我在读了一点Gtk对话框之后,实际上还以为这就是Gtk对话框的工作方式。)@rikityplikity模态对话框确实是这样工作的,但是在退出内部循环后调用
destroy
。我发布的
while
循环是一个小型主循环,它只运行足够长的时间来拾取挂起的事件(在您的例子中,只有那些将显示对话框关闭的事件)。好吧,这是有意义的,我认为嵌套循环的概念刚刚从您的答案中单击(对于GUI编程来说是非常新的)。我添加了一个解决方案,它使用嵌套循环来实现我所追求的行为。是的,手动旋转主循环通常是一件坏事,除非你真的知道自己在做什么。更好的方法是在空闲函数中花费很长时间来完成任何事情。在“main”mainloop中嵌套另一个mainloop怎么样?启动它只是为了启动对话框并处理它们的删除事件,并在对话框关闭时退出(退出事件由对话框删除事件触发)。这会让我有“立即关闭”的行为吗?(我在读了一点Gtk对话框之后,实际上还以为这就是Gtk对话框的工作方式。)@rikityplikity模态对话框确实是这样工作的,但是在退出内部循环后调用
destroy
。我发布的
while
循环是一个小型主循环,它只运行足够长的时间来拾取挂起的事件(在您的例子中,只有那些将显示对话框关闭的事件)。好吧,这是有意义的,我认为嵌套循环的概念刚刚从您的答案中单击(对于GUI编程来说是非常新的)。我添加了一个解决方案,它使用嵌套循环来实现我所追求的行为。嵌套的主循环是不好的。它们使得创建小部件的上下文与处理小部件产生的事件的上下文非常容易耦合。当你真的不应该的时候,他们让你很容易成为再进入者。它们可以阻止其他系统自己的循环。最终,它们颠覆了GLib、GTK+和所有其他此类框架的事件驱动哲学。您应该使用“showwidget,sethandler,return,waitforcallback”模式。这不仅仅是一个无聊的哲学建议:
gtk\u dialog\u run()
是不推荐使用的,例如嵌套的主循环是坏的。它们使得创建小部件的上下文与处理小部件产生的事件的上下文非常容易耦合。当你真的不应该的时候,他们让你很容易成为再进入者。它们可以阻止其他系统自己的循环。最终,它们颠覆了GLib、GTK+和所有其他此类框架的事件驱动哲学。你知道吗