【问题标题】:tkinter: Using same frame but having different command button?tkinter:使用相同的框架但有不同的命令按钮?
【发布时间】:2021-04-25 22:57:31
【问题描述】:

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

我尝试构建一些可以在框架之间切换的 gui,使用此脚本作为基础 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()

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

提前谢谢你

【问题讨论】:

    标签: python tkinter frame python-2.x


    【解决方案1】:

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

    由于它们之间的不同之处在于:

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

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

    请注意,我已更改您的类名的拼写以符合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()
    
    

    【讨论】:

    • 感谢您的回答。但我不能用 python 2.7 运行它,它说 super() 至少需要 1 个参数(给定 0)。我试图寻找这方面的线索并找到了这个,stackoverflow.com/questions/38963018/…。尝试了 super(self).__init__(parent) 或 super(parent).__init__() 仍然无法正常工作
    • 当我像这样更改 BaseSub 类时,脚本可以工作:BaseSub(tk.Frame,object) 然后像这样更改 super():super(BaseSub,self).__init__(),但老实说,我知道将 BaseSub 类的“对象”添加到另一个类会有什么影响
    • 如果您使用的是 Python 2,则需要使用“python-2.x”标记您的问题。 super() 函数在该版本中不适用于 tkinter(它在 Python 3 中有效)。我已经相应地修改了我的答案。
    • 请原谅我,谢谢你的回答,它工作得很好
    猜你喜欢
    • 2015-08-21
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2018-05-31
    • 2020-09-22
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多