如何在多层Tkinter GUI中组织数据/信息

时间:2019-05-19 16:15:18

标签: python tkinter tkinter-layout

我正在使用Python / tkinter构建具有多个框架层的GUI,并且需要一种结构来简化内部层之间的数据传输。

到目前为止,我已经尝试了几种方法,但是发现使用集中式controller类以最好的方式管理所有重要属性。但我想知道是否可能有针对这种问题的更好实践。

基本上,该想法是在根级别启动controller实例并将其传递给所有内部层。 controller的相关方法/属性将在相应的层中调用/更新。

下面是该问题的简化版本的代码:

  • 需要通过单击topEntry中的Ok按钮来显示Display and Ask中用户的输入(并按下mid frame按钮。)
  • 单击Display and Ask中的mid frame按钮可打开listBox,要求用户进行选择。此选择需要由showLabel中的dummy value(最初为bottom frame)显示。
import tkinter as tk
from tkinter import messagebox


class controllerClass(object):
    """class to control data across many layers"""

    def __init__(self):
        # updated by top frame of main app
        self.topVal = None
        # update by askOneSelection window; use stringVar to automatically link to bottom label
        self.midVal = tk.StringVar(value="Inital dummy val")

    def getMidVal(self):
        return self.midVal

    def setMidVal(self, val):
        self.midVal.set(val)

    def getTopVal(self):
        return self.topVal

    def setTopVal(self, val):
        self.topVal = val


class MainApp(tk.Frame):
    """Main app"""

    def __init__(self, master):
        super(MainApp, self).__init__(master)
        self.master = master
        # init controller instance at MainApp; to be passed to all inner layers
        self.controller = controllerClass()
        # 3 frames
        # top frame for user input
        self.top = topEntry(self)
        # mid frame to display input in top frame and open new window, asking to choose Val1 or Val2
        self.mid = midButton(self)
        # label in bottom frame to display selection resulted from mid frame
        self.bottom = showLabel(self)
        # position 3 frames
        self.top.grid(row=0)
        self.mid.grid(row=1)
        self.bottom.grid(row=2)


class topEntry(tk.Frame):
    """class for top frame in Main App"""

    def __init__(self, master):
        super(topEntry, self).__init__(master, bg='green', padx=5, pady=5)
        self.master = master
        self.controller = master.controller  # controller from Main App
        self.Input = tk.Entry(self)
        self.updateButton = tk.Button(
            self, text="Ok", command=self.updateTopVal)
        self.Input.grid(row=0, column=0)
        self.updateButton.grid(row=0, column=1)

    def updateTopVal(self):
        currentInput = self.Input.get()
        # controoler is used
        self.controller.setTopVal(currentInput)


class midButton(tk.Frame):
    """class for mid frame in Main App"""

    def __init__(self, master):
        super(midButton, self).__init__(master, bg='blue', padx=5, pady=5)
        self.master = master
        self.controller = master.controller  # controller from Main App
        self.button = tk.Button(
            self, text="Display and Ask", command=self.promptAskSelection)
        self.button.grid()

    def promptAskSelection(self):
        # controoler is used
        topVal = self.controller.getTopVal()
        messagebox.showinfo(
            message="User input '{}'' in top frame".format(topVal))
        askOneSelection(self)


class askOneSelection(tk.Toplevel):
    """called by button in mid frame"""

    def __init__(self, master):
        super(askOneSelection, self).__init__(master)
        self.master = master
        # controller from mid frame, whose controller is from Main App
        self.controller = master.controller
        self.choicesBox = tk.Listbox(self)
        for each in ['Val1', 'Val2']:
            self.choicesBox.insert(tk.END, each)
        self.Ok = tk.Button(self, text="OK", command=self.getChoice)
        self.choicesBox.grid()
        self.Ok.grid()

    def getChoice(self):
        selection = self.choicesBox.get(self.choicesBox.curselection())
        # controoler is used
        self.controller.setMidVal(selection)
        self.destroy()


class showLabel(tk.Frame):
    """class for bottom frame in Main App"""

    def __init__(self, master):
        super(showLabel, self).__init__(master, bg='yellow', padx=5, pady=5)
        self.master = master
        self.controller = master.controller  # controller from Main App
        self.showMidSelection = tk.Label(
            self, textvariable=self.controller.getMidVal())  # controoler is used
        self.showMidSelection.grid()


if __name__ == "__main__":
    root = tk.Tk()
    MainApp(root).grid()
    root.mainloop()

0 个答案:

没有答案