You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter中访问非严格父类的变量与方法

问题解答

1. 关于Table与Application的关系理解

你的理解完全正确:Table和Application并非严格意义上的父子类(继承关系),而是组合关系——Application类实例化了Table对象并使用它。具体来说:

  • Table继承自tk.Frame,是一个自定义UI组件;
  • Application继承自tk.Tk,是整个应用的主窗口;
  • Application内部创建Table实例时将自身作为master传递,二者是使用者与被使用者的关系,不存在继承关联。

2. 实现行增删时更新total并调用show_total

方案1:直接通过master引用操作(简单直接)

利用Table的master属性就是Application实例的特性,直接在Table的增删方法中操作Application的变量和方法:

修改后的Table类代码:

class Table(tk.Frame):
    def __init__(self, master, header_labels:tuple, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        
        self.lbl_cfg = {
            'master'     : self,
            'foreground' : 'blue',
            'relief'     : 'raised',
            'font'       : 'Arial 16 bold',
            'padx'       : 0,
            'pady'       : 0,
            'borderwidth': 1,
            'width'      : 11,
        }
        
        self.headers = []
        self.rows    = []
        
        for col, lbl in enumerate(header_labels):
            self.grid_columnconfigure(col, weight=1)
            (header := tk.Label(text=lbl, **self.lbl_cfg)).grid(row=0, column=col, sticky='nswe')
            self.headers.append(header)
            
    def add_row(self, desc:str, quantity:int, rate:float, amt:float, pending:bool) -> None:
        # 更新total并调用show_total
        self.master.total += amt
        self.master.show_total()
        
        self.rows.append([])
        for col, lbl in enumerate((desc, quantity, rate, amt, pending), 1):
            (entry := tk.Label(text=lbl, **self.lbl_cfg)).grid(row=len(self.rows), column=col, sticky='nswe')
            self.rows[-1].append(entry)
            
    def del_row(self, i:int) -> None:
        # 获取要删除行的金额并更新total
        amt = float(self.rows[i][3]['text'])
        self.master.total -= amt
        self.master.show_total()
        
        for ent in self.rows[i]:
            ent.destroy()
            
        del self.rows[i]
        
        for r, row in enumerate(self.rows, 1):
            for c, ent in enumerate(row, 1):
                ent.grid_forget()
                ent.grid(row=r, column=c, sticky='nswe')

方案2:使用回调函数(低耦合,更灵活)

如果希望降低类之间的耦合度,可以在初始化Table时传入回调函数,由Table触发回调更新总额:

修改后的Application类:

class Application(tk.Tk):
    def __init__(self, title:str="Sample Application", x:int=0, y:int=0, **kwargs):
        tk.Tk.__init__(self)

        self.title(title)
        self.config(**kwargs)
        
        header_labels = ('', 'Description', 'Quantity', 'Rate', 'Amt', 'pending')
        self.total=0
        # 传入更新总额的回调函数
        self.table = Table(self, header_labels, update_callback=self.update_total)
        self.table.grid(row=0, column=0, sticky='nswe')
        
        self.update_idletasks()
        self.geometry(f'{self.winfo_width()}x{self["height"] or self.winfo_screenheight()}+{x}+{y}')
        
        # test
        self.table.add_row("A", 2, 12.5, 25, True)
        self.table.add_row("B", 4, 12.5, 50, False)
        self.table.del_row(0)
        self.table.add_row("A", 2, 12.5, 25, True)

    def update_total(self, amt, is_add=True):
        if is_add:
            self.total += amt
        else:
            self.total -= amt
        self.show_total()

    def show_total(self):
        print(self.total)
        print("Total has been updated")
        return

修改后的Table类:

class Table(tk.Frame):
    def __init__(self, master, header_labels:tuple, update_callback=None, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.update_callback = update_callback
        
        self.lbl_cfg = {
            'master'     : self,
            'foreground' : 'blue',
            'relief'     : 'raised',
            'font'       : 'Arial 16 bold',
            'padx'       : 0,
            'pady'       : 0,
            'borderwidth': 1,
            'width'      : 11,
        }
        
        self.headers = []
        self.rows    = []
        
        for col, lbl in enumerate(header_labels):
            self.grid_columnconfigure(col, weight=1)
            (header := tk.Label(text=lbl, **self.lbl_cfg)).grid(row=0, column=col, sticky='nswe')
            self.headers.append(header)
            
    def add_row(self, desc:str, quantity:int, rate:float, amt:float, pending:bool) -> None:
        # 触发回调更新总额
        if self.update_callback:
            self.update_callback(amt, is_add=True)
            
        self.rows.append([])
        for col, lbl in enumerate((desc, quantity, rate, amt, pending), 1):
            (entry := tk.Label(text=lbl, **self.lbl_cfg)).grid(row=len(self.rows), column=col, sticky='nswe')
            self.rows[-1].append(entry)
            
    def del_row(self, i:int) -> None:
        # 获取要删除行的金额并触发回调
        amt = float(self.rows[i][3]['text'])
        if self.update_callback:
            self.update_callback(amt, is_add=False)
            
        for ent in self.rows[i]:
            ent.destroy()
            
        del self.rows[i]
        
        for r, row in enumerate(self.rows, 1):
            for c, ent in enumerate(row, 1):
                ent.grid_forget()
                ent.grid(row=r, column=c, sticky='nswe')

两种方案均可实现需求:方案1简单直接,适合小型项目;方案2耦合度低,更利于代码维护和扩展。

内容的提问来源于stack exchange,提问作者user1371666

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:00:15