为什么按住顶层中的“X”按钮会停止执行 tkinter 中的主窗口?

Tha*_*lis 4 python tkinter toplevel tkinter-scale

我有一个程序需要在 tkinter 中打开Toplevel除主Tk()窗口之外的窗口。在主窗口中,我有一个Scale小部件,它每 100 毫秒随着after调用更新一次。但是,在 Toplevel 窗口打开且比例更新的状态下,当我按下Toplevel窗口中的“X”按钮时,Scale停止移动。

在此处输入图片说明

这是我的代码:

from tkinter import Tk, Toplevel, Scale

root = Tk()

slider = Scale(root, orient='horizontal')
slider.pack()
num = 0


def main():
    global num
    slider.set(num)
    num += 1
    slider.after(500, main)


def toplevel():
    win = Toplevel()


root.bind('<space>', lambda x: [main(), toplevel()])

root.mainloop()

Run Code Online (Sandbox Code Playgroud)

当我停止按下“X”按钮时,比例会跳到它应该的位置 在此处输入图片说明

即使按住“X”按钮,如何保持滑块/刻度正常流动?
还有为什么会发生这种情况?

提前致谢!

jiz*_*AMA 5

这个问题会发生在 Windows 上。你的代码在 Linux 上运行良好。(我已经测试过了)

一个可能的原因在这里:

这里发生的事情(简化了很多)是,一旦 Windows 检测到非客户区上的按钮按下事件,它就会停止发送更新消息,获取窗口的快照并准备开始绘制所有这些漂亮的效果窗口移动、调整大小等。然后窗口保持冻结状态,直到相应的鼠标松开结束僵局。

这篇文章还提到了另一个解决方案:使用线程。

由于 tkinter 是单线程的并且这些功能是打包的,因此在 tkinter 中使用线程似乎不起作用。

原因是操作系统如何处理标题栏上的那些“按住”事件。

一个简单的解决方案是隐藏您的标题栏,并自己自定义这些按钮。(避免操作系统处理这些事件。)例如:

from tkinter import Tk, Toplevel, Scale
import tkinter as tk


class CustomToplevel(Toplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.__offset_x = 100
        self.__offset_y = 100
        self.window_width = 100
        self.window_height = 100

        self.overrideredirect(True)
        self.title_bar_frame = tk.Frame(self, bg="grey")
        self.title_bar_frame.pack(fill="x")

        self.title_bar_frame.bind('<Button-1>', self.__click)
        self.title_bar_frame.bind('<B1-Motion>',self.__drag)

        self.close_button = tk.Button(self.title_bar_frame, text="X", bg="red", font=("", 15),
                                      command=self.destroy)
        self.close_button.pack(side="right", fill="y")

        self.geometry(f"{self.window_width}x{self.window_height}+{self.winfo_pointerx() - self.__offset_x}+{self.winfo_pointery() - self.__offset_y}")

    def __click(self, event):
        self.__offset_x = event.x
        self.__offset_y = event.y

    def __drag(self, event):
        self.geometry(f"{self.window_width}x{self.window_height}+{self.winfo_pointerx() - self.__offset_x}+{self.winfo_pointery() - self.__offset_y}")

root = Tk()

slider = Scale(root, orient='horizontal')
slider.pack()
num = 0


def main():
    global num
    slider.set(num)
    num += 1
    slider.after(500, main)


def toplevel():
    win = CustomToplevel()


root.bind('<space>', lambda x: [main(), toplevel()])

root.mainloop()
Run Code Online (Sandbox Code Playgroud)

绑定一些事件或使用一些漂亮的颜色会使您的 UI 更漂亮。