Tkinter自定义Notebook事件参数传递与选中组件异常问题
问题分析与解决方案
问题1:无法访问event.data参数
- 原因:Tkinter的
event_generate方法不支持直接通过data参数传递自定义数据到事件对象中,事件对象本身没有data属性,导致你无法直接获取该值。 - 解决方法:在
CustomNotebook类中新增一个临时属性存储被关闭标签的信息,触发事件后在处理函数中通过event.widget读取该属性。
问题2:关闭标签后选中的组件不是被关闭的标签
- 原因:调用
forget(index)移除标签后,ttk.Notebook会自动选中剩余标签中的一个(默认是前一个),被关闭的标签已经被移除,无法保持选中状态。如果需要明确知道哪个标签被关闭,通过存储的标签信息即可;如果需要在关闭前确保该标签处于选中状态,可以在移除操作前先执行选中。
修改后的完整代码
CustomNotebook类(修正笔误+新增数据存储)
import tkinter as tk from tkinter import ttk class CustomNotebook(ttk.Notebook): """A ttk Notebook with close buttons on each tab""" __initialized = False def __init__(self, *args, **kwargs): if not self.__initialized: self.__initialize_custom_style() self.__initialized = True # 修正笔误:原代码多写了一个i kwargs["style"] = "CustomNotebook" ttk.Notebook.__init__(self, *args, **kwargs) self._active = None self._closed_tab_text = "" # 新增:存储被关闭标签的文本 self.bind("<ButtonPress-1>", self.on_close_press, True) self.bind("<ButtonRelease-1>", self.on_close_release) def on_close_press(self, event): """Called when the button is pressed over the close button""" element = self.identify(event.x, event.y) if "close" in element: index = self.index("@%d,%d" % (event.x, event.y)) self.state(['pressed']) self._active = index return "break" def on_close_release(self, event): """Called when the button is released""" if not self.instate(['pressed']): return element = self.identify(event.x, event.y) if "close" not in element: # user moved the mouse off of the close button return index = self.index("@%d,%d" % (event.x, event.y)) if self._active == index: closed_tab_text = self.tab(index, 'text') self._closed_tab_text = closed_tab_text # 存储被关闭标签的文本 self.select(index) # 可选:关闭前先选中该标签 self.forget(index) self.event_generate("<<NotebookTabClosed>>") self.state(["!pressed"]) self._active = None def __initialize_custom_style(self): style = ttk.Style() self.images = ( tk.PhotoImage("img_close", data=''' R0lGODlhCAAIAMIBAAAAADs7O4+Pj9nZ2Ts7Ozs7Ozs7Ozs7OyH+EUNyZWF0ZWQg d2l0aCBHSU1QACH5BAEKAAQALAAAAAAIAAgAAAMVGDBEA0qNJyGw7AmxmuaZhWEU 5kEJADs= '''), tk.PhotoImage("img_closeactive", data=''' R0lGODlhCAAIAMIEAAAAAP/SAP/bNNnZ2cbGxsbGxsbGxsbGxiH5BAEKAAQALAAA AAAIAAgAAAMVGDBEA0qNJyGw7AmxmuaZhWEU5kEJADs= '''), tk.PhotoImage("img_closepressed", data=''' R0lGODlhCAAIAMIEAAAAAOUqKv9mZtnZ2Ts7Ozs7Ozs7Ozs7OyH+EUNyZWF0ZWQg d2l0aCBHSU1QACH5BAEKAAQALAAAAAAIAAgAAAMVGDBEA0qNJyGw7AmxmuaZhWEU 5kEJADs= ''') ) style.element_create("close", "image", "img_close", ("active", "pressed", "!disabled", "img_closepressed"), ("active", "!disabled", "img_closeactive"), border=8, sticky='') style.layout("CustomNotebook", [("CustomNotebook.client", {"sticky": "nswe"})]) style.layout("CustomNotebook.Tab", [ ("CustomNotebook.tab", { "sticky": "nswe", "children": [ ("CustomNotebook.padding", { "side": "top", "sticky": "nswe", "children": [ ("CustomNotebook.focus", { "side": "top", "sticky": "nswe", "children": [ ("CustomNotebook.label", {"side": "left", "sticky": ''}), ("CustomNotebook.close", {"side": "left", "sticky": ''}), ] }) ] }) ] }) ])
OutputNotebook类(修改事件处理逻辑)
class OutputNotebook: def __init__(self, master, **kwargs): self.master = master self.widget = CustomNotebook(master) self.widget.pack(pady=(8,0), anchor='ne', fill='both', expand=True) self.widget.bind("<<NotebookTabClosed>>", self.on_tab_closed) def add_table(self): title = f"Example {len(self.widget.children)}" new_tab = tk.Frame(self.widget) tk.Label(new_tab, text= 'Place Holder Label').pack(fill="both", expand=True) self.widget.add(new_tab, text=title) self.widget.select(new_tab) def on_tab_closed(self, event): # 获取被关闭标签的文本 closed_tab_text = event.widget._closed_tab_text print(f"关闭的标签:{closed_tab_text}") # 可选:查看当前选中的标签 current_selected_idx = self.widget.select() if current_selected_idx: current_selected_text = self.widget.tab(current_selected_idx, 'text') print(f"当前选中的标签:{current_selected_text}")
测试代码(无修改)
root = tk.Tk() notebook = OutputNotebook(root) button = tk.Button( root, text= 'Add new Table', command= notebook.add_table) button.pack(fill='x', expand=True) notebook.widget.pack() root.mainloop()
内容的提问来源于stack exchange,提问作者Ruan Carlo Weiers Britzke
相关产品推荐
相关产品推荐

