发布
社区首页 >问答首页 >如果用户正在移动主窗口,则当打开对话框时,GTK会冻结。

如果用户正在移动主窗口,则当打开对话框时,GTK会冻结。
EN

Stack Overflow用户
提问于 2022-10-13 14:09:33
回答 1查看 31关注 0票数 0

当用户移动主窗口时,以下代码将冻结,并弹出一个对话框。

https://imgur.com/a/aAh6Xee

以前有人注意到这个问题吗?

我使用idle_add来显示消息对话框,但这并不能解决问题。

代码语言:javascript
代码运行次数:0
复制
from time import sleep
import gtk
import pygtk
pygtk.require("2.0")
from threading import Thread
import gobject

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()
        self.connect("destroy", gtk.main_quit)       
        self.set_size_request(250, 100)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_title("Test")

        btn = gtk.Button("Click Here")
        btn.connect("clicked", self.on_click)
        self.add(btn)

        self.show_all()

    def decorator_threaded(func):
        def wrapper(*args, **kwargs):
            gtk.gdk.threads_enter()
            thread = Thread(target=func, args=args, kwargs=kwargs)
            thread.start()
            return thread
        return wrapper

    @decorator_threaded
    def running_on_another_thread(self):
        sleep(2) # Heavy task
        gobject.idle_add(self.error_message)

    def on_click(self, widget):
        self.running_on_another_thread()

    def error_message(self):
        md = gtk.MessageDialog(self, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, 
            gtk.BUTTONS_CLOSE, "Error")
        md.run()
        md.destroy()

PyApp()
gtk.gdk.threads_init()
gtk.main()

我还尝试使用GTK3.0并注意到了同样的错误。

代码语言:javascript
代码运行次数:0
复制
import threading
import time
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk


def app_main():
    win = Gtk.Window(default_height=100, default_width=250)
    win.connect("destroy", Gtk.main_quit)
    win.set_position(Gtk.WindowPosition.CENTER)

    def error_message():
        md = Gtk.MessageDialog(
            transient_for=win,
            flags=0,
            message_type=Gtk.MessageType.ERROR,
            buttons=Gtk.ButtonsType.CLOSE,
            text="Error",
        )
        md.run()
        md.destroy()

    def example_target():
        time.sleep(2) # Heavy task
        GLib.idle_add(error_message)

    win.show_all()

    thread = threading.Thread(target=example_target)
    thread.daemon = True
    thread.start()


if __name__ == "__main__":
    app_main()
    Gtk.main()
EN

回答 1

Stack Overflow用户

发布于 2022-10-14 15:02:24

解决方案是调用线程上的timeout_add来调度在主GUI线程上运行的MessageDialog

MessageBox类也使用pygtk在Gtk 2中工作。

代码语言:javascript
代码运行次数:0
复制
import threading
import time
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk

class MessageBox(Gtk.MessageDialog):
    def __init__(self, parent, message):
        Gtk.MessageDialog.__init__(self, transient_for=parent,
                                   flags=0,
                                   message_type=Gtk.MessageType.ERROR,
                                   buttons=Gtk.ButtonsType.CLOSE,
                                   text=message)
        self.set_default_response(Gtk.ResponseType.OK)
        self.connect('response', self._handle_clicked)

    def _handle_clicked(self, *args):
        self.destroy()

    def show_dialog(self):
        GLib.timeout_add(0, self._do_show_dialog)

    def _do_show_dialog(self):
        self.show_all()
        return False

def app_main():
    win = Gtk.Window(default_height=100, default_width=250)
    win.connect("destroy", Gtk.main_quit)
    win.set_position(Gtk.WindowPosition.CENTER)

    def error_message():
        dialog = MessageBox(win, "Error")
        dialog.show_dialog()

    def example_target():
        time.sleep(2) # Heavy task
        error_message()

    win.show_all()

    thread = threading.Thread(target=example_target)
    thread.daemon = True
    thread.start()


if __name__ == "__main__":
    app_main()
    Gtk.main()

注意:这个问题不能在Linux上复制。

参考文献:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74057203

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档