在Python中使用Tkinter进行子类化
我正在用python制作一个应用程序。一切正常。到目前为止,所有内容都在一个源文件中。你从小处做起,然后一切都在成长。 我已经到了代码很难理解的地步。所以我决定我需要把代码分成模块和类 我终于弄到了一些东西来让它发挥作用。然而,我找不到太多关于用python制作复杂GUI的信息。因此,使用类来创建小部件等等 我制作了一个小示例应用程序,演示了以下内容:在Python中使用Tkinter进行子类化,python,tkinter,Python,Tkinter,我正在用python制作一个应用程序。一切正常。到目前为止,所有内容都在一个源文件中。你从小处做起,然后一切都在成长。 我已经到了代码很难理解的地步。所以我决定我需要把代码分成模块和类 我终于弄到了一些东西来让它发挥作用。然而,我找不到太多关于用python制作复杂GUI的信息。因此,使用类来创建小部件等等 我制作了一个小示例应用程序,演示了以下内容: 拆分GUI代码和操作代码。在我的示例中,操作代码由一个单独的类处理,这也可能只是一个单独的模块 在我的示例Tkinter.LabelFrame中
import main
if __name__ == '__main__':
title = "Test"
gui = main.Gui(title)
import Tkinter
import action
import widget
class Gui():
def __init__(self, title):
self.root = Tkinter.Tk()
self.root.protocol("WM_DELETE_WINDOW", self.applicationExit)
self.root.title(title)
#create the action object
self.process = action.Adder()
#create the input frame
self.frameIn = widget.Input(self.root)
self.frameIn.grid(row=0, column=0, padx = 5, pady =5, ipadx = 5, ipady = 5, sticky = Tkinter.N)
#create the output frame
self.frameOut = widget.Output(self.root)
self.frameOut.grid(row=1, column=0, padx = 5, pady =5, ipadx = 5, ipady = 5, sticky = Tkinter.N)
#bind events
self.root.bind("<<input_submit>>", self.__submit)
self.root.mainloop()
def applicationExit(self):
self.root.destroy()
def __submit(self, event = None):
value = self.frameIn.getValue()
result = self.process.addValue(value)
self.frameOut.outputText.set(result)
任何改进都是非常受欢迎的。通常,实现Tkinter应用程序的标准模式是使用名为
application
的根对象或扩展Tkinter.Frame
的对象,然后创建定义界面的所有小部件:
import Tkinter as tk
class Application(tk.Frame):
def __init__(self, root, *args, **kwargs):
tk.Frame.__init__(self, root, *args, **kwargs)
... #do other initialisation
self.grid() #or pack()
...
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
root.mainloop()
这种技术的优点有两个方面:
- 现在,您拥有了一个可以触发Tkinter事件和行为的对象(因为Tkinter有自己的小部件层次结构),并且还可以使用普通的类习惯用法(例如方法)拦截这些行为
- 您的根类可以传递您自己的消息处理方案(用于处理需求4),该方案可以与您构建接口时将形成的自然层次结构保持一致和协调
class Message(object):
def __init__(self, kind, data):
self.kind = kind
self.data = data
class Application(tk.Frame):
def __init__(self, root, *args, **kwargs):
self.widgets = []
... #do widget declarations
def message_downstream(self, message):
for widget in self.widgets:
widget.receive_message(message)
def message_upstream(self, message):
#do some logic based on the message
...
class Widget(tk.Button):
def __init__(self, master, name, *args, **kwargs):
tk.Button.__init__(self, master, *args, **kwargs)
self.master = master
#perhaps set command event to send a message
self['command'] = lambda: self.message_upstream(Message(self.name, "I Got Clicked"))
def message_downstream(self, message):
#similar to above
pass
def message_upstream(self, message):
self.master.message_upstream(self, message)
这种方法将责任链模式引入到你的应用程序中,因为你现在可以在链中的任何一点控制消息流(即,做某事或将其上传下传,但通过不同的路径)小心但是,好的应用程序设计会尝试将模型-视图-控制器模式合并到其代码中,如果在“视图”代码链的某个位置引入“控制”代码,这可能会造成混乱,导致头痛
在Tkinter层次结构中使用责任链的最佳方法是将代码仅限于接口关注点,并将所有其他内容(即修改数据的代码)传递给某个适当的控制器,如您提到的操作类
那么,为什么要使用上面这样的模式呢?当界面以复杂的方式与自身交互时。例如,某些子菜单中的控件可能会更改某些其他帧中可见的内容。该行为并不真正关心或依赖于模型,因此按照上面的方式实现它是可行的
我曾经为Python编写了一个代码编辑器,当您键入代码时,它会自动编译并在另一个窗口中运行代码(这实际上很烦人),显示代码输出或发生的异常。我使用责任链从编辑器小部件收集代码,并将程序输出发送到输出窗口。我还使用它将语法突出显示更改同时应用于两个窗口。如果您唯一的问题是“也许其他人可以进一步改进示例”,这将更适合于
import Tkinter as tk
class Application(tk.Frame):
def __init__(self, root, *args, **kwargs):
tk.Frame.__init__(self, root, *args, **kwargs)
... #do other initialisation
self.grid() #or pack()
...
if __name__ == '__main__':
root = tk.Tk()
app = Application(root)
root.mainloop()
class Message(object):
def __init__(self, kind, data):
self.kind = kind
self.data = data
class Application(tk.Frame):
def __init__(self, root, *args, **kwargs):
self.widgets = []
... #do widget declarations
def message_downstream(self, message):
for widget in self.widgets:
widget.receive_message(message)
def message_upstream(self, message):
#do some logic based on the message
...
class Widget(tk.Button):
def __init__(self, master, name, *args, **kwargs):
tk.Button.__init__(self, master, *args, **kwargs)
self.master = master
#perhaps set command event to send a message
self['command'] = lambda: self.message_upstream(Message(self.name, "I Got Clicked"))
def message_downstream(self, message):
#similar to above
pass
def message_upstream(self, message):
self.master.message_upstream(self, message)