![](/img/trans.png)
[英]Why does ttk.Button appears in the main window instead of tk.Toplevel?
[英]Why does holding down the 'X' button in a toplevel stop execution of main window in tkinter?
我有一個程序需要打開頂層Toplevel
除了 tkinter 中的主要Tk()
window 之外。 在主要的 window 中,我有一個Scale
小部件,它每 100 毫秒after
調用后更新一次。 然而,在 state 中,頂層 window 處於打開狀態,當我按下頂層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()
即使按住“X”按鈕,如何保持滑塊/刻度正常流動?
還有為什么會這樣?
提前致謝!
這個問題會發生在 Windows 上。 您的代碼在 Linux 上運行良好。(我已經測試過了)
一個可能的原因在這里:
這里發生的事情(簡化了很多)是,一旦 Windows 在非客戶區檢測到按下按鈕事件,它就會停止發送更新消息,獲取 window 的快照並准備開始繪制所有這些漂亮的效果窗口移動、調整大小等。然后 window 將保持凍結狀態,直到相應的鼠標向上結束僵局。
這篇文章還提到了另一個解決方案:使用線程。
由於 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()
綁定一些事件或使用一些漂亮的顏色會讓你的 UI 更漂亮。
我有一個程序需要打開頂層Toplevel
除了 tkinter 中的主要Tk()
window 之外。 在主要的 window 中,我有一個Scale
小部件,它每 100 毫秒after
調用后更新一次。 然而,在 state 中,頂層 window 處於打開狀態,當我按下頂層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()
win.mainloop()
root.bind('<space>', lambda x: [main(), toplevel()])
root.mainloop()
即使按住“X”按鈕,如何保持滑塊/刻度正常流動?
還有為什么會這樣?
提前致謝!
簡而言之,那是一個“功能”,至少在windows上,菜單按鈕預計不會支持按住它的動作。 發生這種情況是因為mainloop
只是要求從同一個地方更新自己的實例,即全局_default_root
,解決方法是在分離的進程上創建一個新的Tk
。 請注意,並非每個 gui 庫都會發生這種情況,例如 wxWidgets 可以正常工作。
正如您在此示例中看到的,常規按鈕不受影響。
import tkinter as tk
class Top_Window(tk.Toplevel):
@staticmethod
def button_release(_):
print('Button released')
def __init__(self, name, **kwargs):
tk.Toplevel.__init__(self, **kwargs)
self.protocol('WM_DELETE_WINDOW', self.quit_button)
self.geometry('300x200+300+300')
self.title = name
self.button = tk.Button(self, text='Button')
self.button.bind('<ButtonRelease>', self.button_release)
self.button.pack()
def quit_button(self):
print('Top window destroyed')
self.destroy()
class Main_Window(tk.Tk):
num = 0
def after_loop(self):
self.num += 1
self.slider.set(self.num)
self.after(500, self.after_loop)
def __init__(self):
tk.Tk.__init__(self)
self.geometry('300x200+100+100')
self.slider = tk.Scale(self, orient='horizontal')
self.slider.pack()
self.bind('<space>', self.spawn_top_level)
self.after(500, self.after_loop)
def spawn_top_level(self, _):
Top_Window('Top', master=self)
if __name__ == '__main__':
app = Main_Window()
app.mainloop()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.