tkinter:使用相同的框架但具有不同的命令按钮?

tkinter: Using same frame but having different command button?

请原谅我糟糕的语法或解释,因为我不知道如何正确解释。

我尝试构建一些可以在框架之间切换的图形用户界面,以此为基础使用脚本 Switch between two frames in tkinter

在这种情况下,我将有几个设计相似但按下按钮时功能不同的框架。例如,我有 2 个帧,它们具有相似的 2 个条目和 1 个按钮,但按钮执行不同的命令(在 sub01 帧它将相乘,在 sub02 帧将相除)

这是我的代码:

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self)
        container.grid(row=1,columnspan=4,sticky='nsew')
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (sub01, sub02):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=1,sticky="nsew")
        
        self.choices = {'sub01','sub02'}
        self.tkvar = tk.StringVar()
        self.tkvar.set('sub01')
        self.popMenu = tk.OptionMenu(self,self.tkvar,*self.choices)
        self.popMenu.grid(row=0)
        self.show_frame()

        self.button1 = tk.Button(self, text="Go to Layer",command=lambda: self.show_frame())
        self.button1.grid(row=0, column=1)

    def show_frame(self):
        '''Show a frame for the given page name'''
        page_name = self.tkvar.get()
        frame = self.frames[page_name]
        frame.tkraise()

class sub01(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This SubLayer 1")
        label.grid(row=0)
        self.entries=[]
        i = 0
        while i < 2:
            self.entries.append(tk.Entry(self,width=10))
            self.entries[i].grid(row=i+1,columnspan=2,sticky='we')
            i += 1
        self.btn = tk.Button(self,text="multiply", command=lambda : self.multiply())
        self.btn.grid(row=i+1, columnspan=2,sticky='we')

    def multiply(self):
        pass

class sub02(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This SubLayer 2")
        label.grid(row=0)
        self.entries=[]
        i = 0
        while i < 2:
            self.entries.append(tk.Entry(self,width=10))
            self.entries[i].grid(row=i+1,columnspan=2,sticky='w')
            i += 1
        self.btn = tk.Button(self,text="divide",command=lambda : self.divide())
        self.btn.grid(row=i+1, columnspan=2,sticky='we')

    def divide(self):
        pass

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

这段代码本身可以工作,但是当我需要创建更多这样的框架时,它就变得不方便了。我怎样才能使这段代码更简单?就像具有与 class 相似的框架,以及与其他 class 不同的按钮一样,它们的行为取决于显示的层。

提前致谢

做这类事情的规范方法是为您的页面 classes 创建一个 class 层次结构,并将通用功能放在基础 classes 中并派生子classes 指定了它们之间不同的行为。以下是您如何使用问题中的示例代码执行此操作。

因为它们之间的不同点是:

  1. Label上显示的文字。
  2. Button上显示的文字。
  3. 单击 Button 时执行的代码。

这意味着派生的 classes 只需要知道在一般命名的 btn_func() 方法中要 运行 的代码以及要在两个小部件上显示的文本。下面的代码说明了如何做到这一点。

请注意,我已经更改了您的 class 名称的拼写,以符合 PEP 8 - Style Guide for Python Code 中描述的命名约定。

import Tkinter as tk


class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        container = tk.Frame(self)
        container.grid(row=1,columnspan=4,sticky='nsew')
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (Sub01, Sub02):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=1,sticky="nsew")

        self.choices = {'Sub01','Sub02'}
        self.tkvar = tk.StringVar()
        self.tkvar.set('Sub01')
        self.popMenu = tk.OptionMenu(self,self.tkvar,*self.choices)
        self.popMenu.grid(row=0)
        self.show_frame()

        self.button1 = tk.Button(self, text="Go to Layer",command=lambda: self.show_frame())
        self.button1.grid(row=0, column=1)

    def show_frame(self):
        '''Show a frame for the given page name'''
        page_name = self.tkvar.get()
        frame = self.frames[page_name]
        frame.tkraise()


class BaseSubLayer(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text=self.lbl_text)
        label.grid(row=0)
        self.entries=[]
        i = 0
        while i < 2:
            self.entries.append(tk.Entry(self,width=10))
            self.entries[i].grid(row=i+1,columnspan=2,sticky='we')
            i += 1
        self.btn = tk.Button(self,text=self.btn_func_name, command=self.btn_func)
        self.btn.grid(row=i+1, columnspan=2,sticky='we')

    def btn_func(self):
        raise NotImplementedError


class Sub01(BaseSubLayer):
    lbl_text = 'This SubLayer 1'
    btn_func_name = 'multiply'

    def btn_func(self):
        print('Running multiply() method.')


class Sub02(BaseSubLayer):
    lbl_text = 'This SubLayer 2'
    btn_func_name = 'divide'

    def btn_func(self):
        print('Running divide() method.')


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()