这是我创建自定义虚拟事件的示例代码。我创建了这段代码来模拟需要很长时间才能响应数据的调用服务器:
#Custom Virtual Event
try:
from Tkinter import *
import tkMessageBox
except ImportError:
try:
from tkinter import *
from tkinter import messagebox
except Exception:
pass
import time
from threading import Thread
VirtualEvents=["<<APP_DATA>>","<<POO_Event>>"]
def TS_decorator(func):
def stub(*args, **kwargs):
func(*args, **kwargs)
def hook(*args,**kwargs):
Thread(target=stub, args=args).start()
return hook
class myApp:
def __init__(self):
self.root = Tk()
self.makeWidgets(self.root)
self.makeVirtualEvents()
self.state=False
self.root.mainloop()
def makeWidgets(self,parent):
self.lbl=Label(parent)
self.lbl.pack()
Button(parent,text="Get Data",command=self.getData).pack()
def onVirtualEvent(self,event):
print("Virtual Event Data: {}".format(event.VirtualEventData))
self.lbl.config(text=event.VirtualEventData)
def makeVirtualEvents(self):
for e in VirtualEvents:
self.root.event_add(e,'None') #Can add a trigger sequence here in place of 'None' if desired
self.root.bind(e, self.onVirtualEvent,"%d")
def FireVirtualEvent(self,vEvent,data):
Event.VirtualEventData=data
self.root.event_generate(vEvent)
def getData(self):
if not self.state:
VirtualServer(self)
else:
pooPooServer(self)
self.state = not self.state
@TS_decorator
def VirtualServer(m):
time.sleep(3)
m.FireVirtualEvent(VirtualEvents[0],"Hello From Virtual Server")
@TS_decorator
def pooPooServer(m):
time.sleep(3)
m.FireVirtualEvent(VirtualEvents[1],"Hello From Poo Poo Server")
if __name__=="__main__":
app=myApp()
在此代码示例中,我正在创建自定义虚拟事件,一旦模拟服务器完成检索数据就会调用这些事件。事件处理程序 onVirtualEvent 绑定到根级别的自定义虚拟事件。
单击按钮时,模拟服务器将在单独的执行线程中运行。我正在使用自定义装饰器 TS_decorator 来创建调用模拟服务器的执行线程。
我的方法真正有趣的部分是,我可以通过调用 FireVirtualEvent 方法将从模拟服务器检索到的数据提供给事件处理程序。在此方法中,我向 Event 类添加了一个自定义属性,该属性将保存要传输的数据。然后,我的事件处理程序将使用此自定义属性从服务器中提取数据。
虽然概念简单,但此示例代码也缓解了在处理需要很长时间执行的代码时 GUI 元素不更新的问题。由于所有工作代码都在单独的执行线程中执行,因此对函数的调用会很快返回,这允许 GUI 元素更新。请注意,我还将对 myApp 类的引用传递给模拟服务器,以便它们可以在数据可用时调用其 FireVirtualEvent 方法。