我正在用python创建一个应用程序.一切正常.到目前为止,一切都在一个源文件中.你从小开始,然后一切都在增长.我到了一个代码很难理解的地方.所以我决定我需要在模块和类中拆分代码.
我终于把一些东西放在一起,让它全部运转起来.但是,我对使用python制作复杂的GUI没有太多帮助.因此使用类来创建小部件等.
我做了一个小示例应用程序,演示了以下内容:
这篇文章的目的是双重的.
我的例子有四个源文件.
start.py.该模块仅启动应用程序,创建Gui类的对象.
import main
if __name__ == '__main__':
title = "Test"
gui = main.Gui(title)
Run Code Online (Sandbox Code Playgroud)main.py. 该模块包含Gui类,并保存GUI的根元素.
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)
Run Code Online (Sandbox Code Playgroud)widget.py.该模块包含两个自定义小部件,用于GUI.
import Tkinter
class Input(Tkinter.LabelFrame):
def __init__(self, master):
Tkinter.LabelFrame.__init__(self, master, text = "Input")
self.inputText = Tkinter.StringVar()
#create entry box
self.entInput = Tkinter.Entry(self, textvariable = self.inputText, width = 20,)
self.entInput.grid(row = 0, column = 0, padx = 5, pady = 2, sticky = Tkinter.N)
#create submite button
self.btnSubmit = Tkinter.Button(self, text = "Add", width = 10,
command = self.__handlerSubmitButton)
self.btnSubmit.grid(row = 1, column = 0, padx = 5, pady = 2, sticky = Tkinter.N)
def getValue(self):
value = self.inputText.get()
if value.isdigit():
return int(value)
else:
None
def __handlerSubmitButton(self, event = None):
self.btnSubmit.event_generate("<<input_submit>>")
class Output(Tkinter.LabelFrame):
def __init__(self, master):
Tkinter.LabelFrame.__init__(self, master, text = "Output")
self.outputText = Tkinter.StringVar()
#create out put label box
self.lblOutput = Tkinter.Label(self, textvariable = self.outputText, width = 20,
anchor = Tkinter.E)
self.lblOutput.grid(row = 0, column = 0, padx = 5, pady = 2, sticky = Tkinter.N)
def setValue(self, value):
self.outputText.set(value)
Run Code Online (Sandbox Code Playgroud)action.py.此模块包含将执行应用程序的实际任务的代码.
class Adder():
def __init__(self):
self.count = 0
def addValue(self, value):
if value:
self.count += value
return self.count
Run Code Online (Sandbox Code Playgroud)任何改进都非常受欢迎.
通常,实现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()
Run Code Online (Sandbox Code Playgroud)
这种技术的优点有两个方面:
作为后一点的一个例子:
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)
Run Code Online (Sandbox Code Playgroud)
此方法将责任链模式引入您的应用程序,因为您现在可以控制链中任何点的消息流(即执行某些操作或将其向上游传递回下游,但通过不同的路径).但要注意,良好的应用程序设计会尝试将模型视图控制器模式合并到他们的代码中,如果您在"视图"代码链中的某个位置引入"控制"代码,这可能会让人头疼.
在Tkinter层次结构中使用责任链的最佳方法是将代码限制为仅涉及接口问题,并将其他所有内容(即修改数据的代码)传递给某些适当的控制器,例如您引用的操作类.
那你为什么要使用上面这样的模式呢?当您的界面以复杂的方式与自身交互时.一个示例可能是某些子菜单中的控件更改了某些其他帧中可见的内容.该行为并不真正关注或依赖于模型,因此如上所述实现它将起作用.
我曾经为Python编写了一个代码编辑器,它在你输入的时候自动编译并在另一个窗口中运行代码(实际上很烦人),显示代码输出或发生了哪些异常.我使用一系列职责从编辑器小部件中收集代码,并将程序输出发送到输出窗口.我还使用它同时对两个窗口应用语法高亮更改.