Python Tkinter : App hangs when changing window title via callback event

标签 python callback tkinter python-2.7

我正在通过 Tkinter 创建一个简单的 Python UI,我想使用 self.title 在生成回调事件时更改窗口标题。

如果我将事件绑定(bind)到按钮,或直接在 Tk 线程中调用事件处理程序,窗口标题会按预期更改。但是,我打算由单独的线程调用此事件,并且我发现在回调事件处理程序中使用 title 会导致应用程序挂起。

我在事件处理程序中执行的其他任务(例如更新标签)工作正常,因此我必须假设事件被正确调用。我已经尝试使用 wm_title 而不是 title,但没有发现任何区别。我仔细研究了一下,发现 title 的用法没有什么奇怪的,只需用一个字符串调用它来设置标题。

这是一个复制问题的精简示例(我在 WinXP 上运行 v2.7.1,仅供引用);应用程序运行正常 10 秒(可以移动窗口、调整大小等),之后 Timer 生成事件,然后应用程序卡住。

import Tkinter
import threading

class Gui(Tkinter.Tk):

    def __init__(self, parent=None):
        Tkinter.Tk.__init__(self, parent)
        self.title('Original Title')
        self.label = Tkinter.Label(self, text='Just a Label.',
            width=30, anchor='center')
        self.label.grid()

        self.bind('<<change_title>>', self.change_title)

        timer = threading.Timer(10, self.event_generate, ['<<change_title>>'])
        timer.start()

    def change_title(self, event=None):
        self.title('New Title')

G = Gui(None)
G.mainloop()

最佳答案

我遇到了同样的问题,当从主线程以外的线程调用 self.title() 时,UI 挂起。 Tkinter 期望所有 UI 内容都在同一个线程(主线程)中完成。

我的解决方案是让单独的线程将函数放入队列中。主线程使用 Tkinter 提供的 after(ms) 函数定期为队列提供服务。这是您的代码示例:

import Tkinter
import threading
from Queue import Queue, Empty

class Gui(Tkinter.Tk):

    def __init__(self, parent=None):
        Tkinter.Tk.__init__(self, parent)
        self.ui_queue = Queue()
        self._handle_ui_request()
        self.title('Original Title')
        self.label = Tkinter.Label(self, text='Just a Label.',
            width=30, anchor='center')
        self.label.grid()

        self.bind('<<change_title>>', self.change_title)

        timer = threading.Timer(1, self.event_generate, ['<<change_title>>'])
        timer.start()

    def change_title(self, event=None):
        # Separate the function name, it's args and keyword args, 
        # and put it in the queue as a tuple.
        ui_function = (self.title, ('New Title',), {})
        self.ui_queue.put(ui_function)

    def _handle_ui_request(self):
        '''
        Periodically services the UI queue to handles UI requests in the main thread.
        '''
        try:
            while True:
                f, a, k = self.ui_queue.get_nowait()
                f(*a, **k)
        except Empty:
            pass

        self.after(200, self._handle_ui_request)


G = Gui(None)
G.mainloop()

关于Python Tkinter : App hangs when changing window title via callback event,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7157868/

相关文章:

python - 如何优化代码以从列表列表中删除所有列表中的 n 个位置

java - 让 "Calling method"等待数据 "Return"

c++ - dll到主程序通信

python - 如何清除 ttk.Combobox 的文本字段部分?

Tkinter 中的 python 语音识别

python - 将图像添加到 Tkinter

Python:如何以编程方式清除 FreeCAD 中的查看器?

python - python 中的简单蒙特卡罗模拟

python - Django 中的第二个静态文件目录

javascript - 实现 Chrome 扩展开/关切换按钮