我正在构建一个基于Tkinter“笔记本”对象的UI,该对象有几个选项卡。每当用户单击选项卡时,我都希望根据基础对象的当前状态更新框架上的信息,然后再将其显示给用户。
这似乎不起作用:
下面的演示构建了一个三页的笔记本。例程load_page绑定到NotebookTabChanged事件,每次单击选项卡时都应该调用该事件。此例程应打开一个消息窗口,标识触发该选项卡的选项卡,并更新页面上的信息(使用当前时间):
import tkinter as tk
import tkinter.messagebox as msg
from tkinter import ttk
import time
class DemoPage(tk.Frame): # A notebook page
def __init__(self, container, name: str = ""):
# call the superclass init to build the page
tk.Frame.__init__(self, container, highlightbackground="blue", highlightthickness=1)
self._name = name # The name of the page (appears on the page tab)
container.add(self, text=name) # add the notebook tab & associate w. page
# event binding
container.bind("<<NotebookTabChanged>>", func=self.load_page) # load current table
# insert texts
self.const_label = tk.Label(self, text="This is " + self._name)
self.const_label.pack(side='top', fill='x')
self.var_label = tk.Label(self, text="Updated " + time.ctime())
self.var_label.pack(side='top', fill='x')
def load_page(self, event):
self.var_label["text"] = "Updated " + time.ctime()
msg.showinfo(self._name, "Tab clicked")
if __name__ == "__main__":
tk_win = tk.Tk() # establish the root tkinter window
tk_win.title("Master Sequence")
tk_win.geometry("600x400")
# initiate UI
nb = ttk.Notebook(tk_win) # establish notebook
nb.pack(expand=True, fill='both') # widget geometry: Notebook will fill the root window
page1 = DemoPage(nb,"Page 1") # initiate tab object in the notebook
page2 = DemoPage(nb,"Page 2") # initiate tab object in the notebook
page3 = DemoPage(nb,"Page 3") # initiate tab object in the notebook
# wait for user input
tk_win.mainloop()
请注意,当应用程序第一次运行时(不单击其选项卡),该事件将自动触发到第3页。此后,每次单击任何选项卡时,都会为选项卡3触发该事件的,而帧中的信息仅在第3页的中被更新。
我做错了什么?
发布于 2022-04-17 12:05:15
NotebookTabChanged
不仅仅是click
事件--它也可以使用代码生成--当您创建新的选项卡时,它也会生成这个事件。您应该首先创建所有选项卡,然后创建绑定事件。它可能需要使用tk_win.update()
。
但是这个事件的工作方式与您预期的不同--它被分配给Notebook
,而不是选项卡--所以您用新的bind
替换了previus bind
,最后它运行了最后一个被访问的函数,该函数更改了最后一个选项卡中的时间。
您应该使用一个函数来检查哪个选项卡是活动的,并在此选项卡中更改时间。但是,如果您在列表中保留选项卡,则会更简单--因此您可以获取活动选项卡的索引,并使用它访问列表上的选项卡。
def on_tab_change(event):
index = nb.index(nb.select())
print('index:', index)
pages[index].load_page()
pages = [
DemoPage(nb, "Page 1"),
DemoPage(nb, "Page 2"),
DemoPage(nb, "Page 3"),
]
nb.bind("<<NotebookTabChanged>>", on_tab_change)
完整的工作代码。
import tkinter as tk
import tkinter.messagebox as msg
from tkinter import ttk
import time
class DemoPage(tk.Frame): # A notebook page
def __init__(self, container, name: str = ""):
# call the superclass init to build the page
tk.Frame.__init__(self, container, highlightbackground="blue", highlightthickness=1)
self._name = name # The name of the page (appears on the page tab)
container.add(self, text=name) # add the notebook tab & associate w. page
# insert texts
self.const_label = tk.Label(self, text="This is " + self._name)
self.const_label.pack(side='top', fill='x')
self.var_label = tk.Label(self, text="Updated " + time.ctime())
self.var_label.pack(side='top', fill='x')
def load_page(self):
self.var_label["text"] = "Updated " + time.ctime()
msg.showinfo(self._name, "Tab clicked")
def on_tab_change(event):
index = nb.index(nb.select())
print('index:', index)
pages[index].load_page()
if __name__ == "__main__":
tk_win = tk.Tk() # establish the root tkinter window
tk_win.title("Master Sequence")
tk_win.geometry("600x400")
# initiate UI
nb = ttk.Notebook(tk_win) # establish notebook
nb.pack(expand=True, fill='both') # widget geometry: Notebook will fill the root window
pages = [
DemoPage(nb, "Page 1"),
DemoPage(nb, "Page 2"),
DemoPage(nb, "Page 3"),
]
tk_win.update() # update all tabs before assigning `event`
# assign only one function
nb.bind("<<NotebookTabChanged>>", on_tab_change)
tk_win.mainloop()
发布于 2022-04-18 12:22:26
谢谢弗拉斯。
事实上,NotebookTabChanged似乎并不像我所需要的那样运作。要提供同样的功能,一个简单得多的解决方案是更改行:
container.bind("<<NotebookTabChanged>>", func=self.load_page)
至:
self.bind("<Expose>", func=self.load_page)
当用户单击相关选项卡时,将公开"DemoPage“框架并触发事件。
https://stackoverflow.com/questions/71901422
复制相似问题