如何使用类重构Tkinter代码?实现标签页与控件复用
优化Tkinter库存管理程序的代码结构
问题背景
我刚完成第一个Tkinter库存管理程序,为了扩展功能,希望优化代码、消除重复并提升扩展性。原代码中存在大量重复创建ttk.Notebook标签页、Frame、LabelFrame、Treeview的代码。
原重复代码
from tkinter import * from tkinter import ttk #Creating window, calling it root root = Tk() root.title("Ges_Stock") root.geometry("1000x600") #Creating Notebook so I can create tabs on it my_notebook = ttk.Notebook(root) my_notebook.pack(pady=10, fill="both") # Tabs creation, packing, and naming it my_frame1 = Frame(my_notebook, width=1200, height=700) my_frame2 = Frame(my_notebook, width=1200, height=700) my_frame3 = Frame(my_notebook, width=1200, height=700) #my_frame4 = Frame(my_notebook, width=1200, height=700) my_frame1.pack(fill="both", expand=1, pady=20) my_frame2.pack(fill="both", expand=1, pady=20) my_frame3.pack(fill="both", expand=1, pady=20) #my_frame4.pack(fill="both", expand=1) my_notebook.add(my_frame1, text="Barcode") my_notebook.add(my_frame2, text="Manual Code") my_notebook.add(my_frame3, text="Inventory Jumbo") #my_notebook.add(my_frame4, text="Code Generator") # Creating LabelFrames wrapper1 = LabelFrame(my_frame1, text="Items List") wrapper2 = LabelFrame(my_frame1, text="Add and Remove") wrapper4 = LabelFrame(my_frame2, text="Items List") wrapper5 = LabelFrame(my_frame2, text="Add and Remove") wrapper7 = LabelFrame(my_frame3, text="Items List") wrapper8 = LabelFrame(my_frame3, text="Add and Remove") #wrapper10 = LabelFrame(my_frame4, text="Items List") #wrapper11 = LabelFrame(my_frame4, text="Command Bar") #Packing the frames wrapper2.pack(fill="both", expand="yes", padx=20, ipady=20) wrapper1.pack(fill="both", expand="yes", padx=20, ipady=20) wrapper5.pack(fill="both", expand="yes", padx=20, ipady=20) wrapper4.pack(fill="both", expand="yes", padx=20, ipady=20) wrapper8.pack(fill="both", expand="yes", padx=20, ipady=20) wrapper7.pack(fill="both", expand="yes", padx=20, ipady=20) #wrapper11.pack(fill="both", expand="yes", padx=20, ipady=10) #wrapper10.pack(fill="both", expand="yes", padx=20, ipady=10) #endregion # TREEVIEW CREATION #Treeview on frame 1 trv = ttk.Treeview(wrapper1, columns=(1,2,3,4,5,6,7), show="headings", height="15") # trv.pack(fill="both",padx=20, ipady=10) #Treeview on frame 2 trv_est = ttk.Treeview(wrapper4, columns=(1, 2, 3, 4, 5, 6, 7), show="headings", height="15") # trv_est.pack(fill="both", padx=20, ipady=10) #Treeview on frame 3 trv_jmb = ttk.Treeview(wrapper7, columns=(1, 2, 3, 4, 5, 6, 7), show="headings", height="15") # trv_jmb.pack(fill="both", padx=20, ipady=10) root.mainloop()
尝试的简化代码
我尝试用类和函数简化代码,但没理清层级关系,目前的尝试代码如下:
from tkinter import * from tkinter import ttk root = Tk() root.title('Codemy.com - Classes') root.geometry("1000x600") my_notebook = ttk.Notebook(root) my_notebook.pack(pady=10, fill="both") def btn_add(): pass class nt_book: def __init__(self, name_tab, num_frame): self.nome_aba = name_tab self.num_frame = num_frame self.num_frame = Frame(my_notebook, width=1200, height=700) self.num_frame.pack() my_notebook.add(self.num_frame, text=self.nome_aba) def wrap(self, name_wrap): self.name_wrap = name_wrap wrapper = LabelFrame(self.num_frame, text=self.name_wrap) wrapper.pack(fill="both", expand="yes", padx=20, ipady=20) # Trying to call a tab and frames inside iest = nt_book("Inventory", "frame1") est_fr1 = est.wrap("Command Bar") est_fr2 = est.wrap("Item List") add_btn = Button(est_fr1, text="Add", command=btn_add) add_btn.grid(row=1, column=1, padx=10, pady=5) root.mainloop()
需求目标
- 创建用于添加标签页的类;
- 创建用于给标签页添加LabelFrame的类或函数;
- 创建用于给LabelFrame添加Button和Treeview的类或函数;
不想每次新增标签页和功能都复制粘贴重复代码,不清楚是否需要使用内部类、子类或嵌套类。
解决方案
可以通过分层类结构实现代码复用,把标签页、LabelFrame、控件的创建封装成职责单一的类,保持层级清晰:
1. 核心类设计
InventoryApp: 主应用类,负责初始化窗口和Notebook容器TabPage: 标签页类,每个实例对应一个Notebook标签页SectionFrame: 标签页内的分组容器(LabelFrame)WidgetFactory: 工具类,封装Treeview和Button的创建逻辑
2. 完整优化代码
from tkinter import * from tkinter import ttk class WidgetFactory: """工具类:封装常用控件的创建逻辑""" @staticmethod def create_treeview(parent, columns, height=15): tree = ttk.Treeview(parent, columns=columns, show="headings", height=height) tree.pack(fill="both", padx=20, ipady=10) # 统一设置表头和列宽 for idx, col in enumerate(columns, 1): tree.heading(col, text=f"列 {idx}") tree.column(col, width=100) return tree @staticmethod def create_button(parent, text, command, row=0, col=0, padx=10, pady=5): btn = Button(parent, text=text, command=command) btn.grid(row=row, column=col, padx=padx, pady=pady) return btn class SectionFrame: """标签页内的分组容器(LabelFrame)""" def __init__(self, parent, title): self.frame = ttk.LabelFrame(parent, text=title) self.frame.pack(fill="both", expand=True, padx=20, ipady=20) def get_frame(self): return self.frame class TabPage: """Notebook标签页类""" def __init__(self, notebook, tab_title): self.notebook = notebook self.tab_frame = Frame(notebook, width=1200, height=700) self.tab_frame.pack(fill="both", expand=True, pady=20) notebook.add(self.tab_frame, text=tab_title) # 存储当前标签页的分组容器 self.sections = {} def add_section(self, section_title): """给当前标签页添加一个分组容器""" section = SectionFrame(self.tab_frame, section_title) self.sections[section_title] = section return section.get_frame() def get_section(self, section_title): """获取指定标题的分组容器""" return self.sections.get(section_title, None) class InventoryApp: """主应用类""" def __init__(self, root): self.root = root self.root.title("Ges_Stock") self.root.geometry("1000x600") # 初始化Notebook self.notebook = ttk.Notebook(root) self.notebook.pack(pady=10, fill="both") # 存储所有标签页 self.tabs = {} def add_tab(self, tab_title): """添加一个新的标签页""" tab = TabPage(self.notebook, tab_title) self.tabs[tab_title] = tab return tab def get_tab(self, tab_title): """获取指定标题的标签页""" return self.tabs.get(tab_title, None) # 示例用法 def btn_add_handler(): print("添加按钮被点击") if __name__ == "__main__": root = Tk() app = InventoryApp(root) # 创建标签页1:Barcode barcode_tab = app.add_tab("Barcode") barcode_items_frame = barcode_tab.add_section("Items List") barcode_ops_frame = barcode_tab.add_section("Add and Remove") WidgetFactory.create_treeview(barcode_items_frame, columns=(1,2,3,4,5,6,7)) WidgetFactory.create_button(barcode_ops_frame, "Add", btn_add_handler, row=0, col=0) WidgetFactory.create_button(barcode_ops_frame, "Remove", lambda: print("移除"), row=0, col=1) # 创建标签页2:Manual Code manual_tab = app.add_tab("Manual Code") manual_items_frame = manual_tab.add_section("Items List") manual_ops_frame = manual_tab.add_section("Add and Remove") WidgetFactory.create_treeview(manual_items_frame, columns=(1,2,3,4,5,6,7)) WidgetFactory.create_button(manual_ops_frame, "Add", btn_add_handler) # 创建标签页3:Inventory Jumbo jumbo_tab = app.add_tab("Inventory Jumbo") jumbo_items_frame = jumbo_tab.add_section("Items List") jumbo_ops_frame = jumbo_tab.add_section("Add and Remove") WidgetFactory.create_treeview(jumbo_items_frame, columns=(1,2,3,4,5,6,7)) root.mainloop()
3. 代码优势
- 零重复代码:新增标签页、分组容器、控件只需调用对应方法,无需复制粘贴
- 层级清晰:主应用→标签页→分组容器→控件,每个类只负责单一职责
- 扩展性强:新增控件类型只需在
WidgetFactory中添加静态方法;修改容器样式只需调整SectionFrame实现 - 易于维护:模块职责明确,修改某部分功能不会影响其他模块
内容的提问来源于stack exchange,提问作者Leandro Bertarelli
相关产品推荐
相关产品推荐

