我正在使用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()