每一个ui框架都需要一个事件监听体系,下面代码演示怎么用python实现事件监听系统,我们定义一个Event
类,一般需要确定定义事件的类型,和event传递的数据:如在js中事件类型有click,mouseover,keypress... 事件的数据就是触发此事件的时候产生的数据如:产生事件的位置,...
class Event( object ): """ Generic event to use with EventDispatcher. 用于事件分发 """ def __init__(self, event_type, data=None): """ The constructor accepts an event type as string and a custom data 定义event的类型和数据 """ self._type = event_type self._data = data @property def type(self): """ Returns the event type 返回event类型 """ return self._type @property def data(self): """ Returns the data associated to the event 返回event传递的数据 """ return self._data
这个就是一个简单的event
类,如果你写过ui程序,或者js程序的对event
对象应该都不陌生,如jquery中的click方法中传递给bind的函数的参数就是一个event实例pyside或者pyqt中也是这样
现在我们写事件分发类,如下:
class EventDispatcher( object ): """ Generic event dispatcher which listen and dispatch events event分发类 监听和分发event事件 """ def __init__(self): """ 初始化类 """ self._events = dict() def __del__(self): """ 清空所有event """ self._events = None def has_listener(self, event_type, listener): """ Return true if listener is register to event_type 返回注册到event_type的listener """ # Check for event type and for the listener if event_type in self._events.keys(): return listener in self._events[ event_type ] else: return False def dispatch_event(self, event): """ Dispatch an instance of Event class """ # 分发event到所有关联的listener if event.type in self._events.keys(): listeners = self._events[ event.type ] for listener in listeners: listener( event ) def add_event_listener(self, event_type, listener): """ Add an event listener for an event type 给某种事件类型添加listener """ # Add listener to the event type if not self.has_listener( event_type, listener ): listeners = self._events.get( event_type, [] ) listeners.append( listener ) self._events[ event_type ] = listeners def remove_event_listener(self, event_type, listener): """ 移出某种事件类型的所以listener """ # Remove the listener from the event type if self.has_listener( event_type, listener ): listeners = self._events[ event_type ] if len( listeners ) == 1: # Only this listener remains so remove the key del self._events[ event_type ] else: # Update listeners chain listeners.remove( listener ) self._events[ event_type ] = listeners
The constructor of the EventDispatcher class simply create an empty “protected” dictionary of event->listeners and set to None it when del() method is called. Because del() method is called when the class is about to be destroyed we are sure no reference to listeners are left in memory.The exampleIn this example we create a simple event, MyEvent, and two classes: a class who send events. WhoAsk, and a class who listen for events and send a response back to the sender through another event, WhoRespond.下面我们自定义一个event类,并且写两个类一个触发事件一个应答事件
class MyEvent( Event ): """ When subclassing Event class the only thing you must do is to define a list of class level constants which defines the event types and the string associated to them """ ASK = "askMyEvent" RESPOND = "respondMyEvent"
The method is very simple, only two events are implemented, ASK and RESPOND.
class WhoAsk( object ): """ First class which ask who is listening to it """ def __init__(self, event_dispatcher): # Save a reference to the event dispatch self.event_dispatcher = event_dispatcher # Listen for the RESPOND event type self.event_dispatcher.add_event_listener( MyEvent.RESPOND, self.on_answer_event ) def ask(self): """ Dispatch the ask event """ print ">>> I'm instance {0}. Who are listening to me ?".format( self ) self.event_dispatcher.dispatch_event( MyEvent( MyEvent.ASK, self ) ) def on_answer_event(self, event): """ Event handler for the RESPOND event type """ print "<<< Thank you instance {0}".format( event.data )
The WhoAsk class adds an event listener for the MyEvent.RESPOND event and implement and ask() method which dispatch and MyEvent.ASK.
class WhoRespond( object ): """ Second class who respond to ASK events """ def __init__(self, event_dispatcher): # Save event dispatcher reference self.event_dispatcher = event_dispatcher # Listen for ASK event type self.event_dispatcher.add_event_listener( MyEvent.ASK, self.on_ask_event ) def on_ask_event(self, event): """ Event handler for ASK event type """ self.event_dispatcher.dispatch_event( MyEvent ( MyEvent.RESPOND, self ) )
WhoResponde class is similar to WhoAsk class except it has only the listener for the MyEvent.ASK event.Both WhoAsk and WhoRepsond classes accepts the instance of EventDispatcher class as a parameter for their constructors.Finally we test our example:
dispatcher = EventDispatcher()
who_ask = WhoAsk( dispatcher )who_responde1 = WhoRespond( dispatcher )who_responde2 = WhoRespond( dispatcher )# WhoAsk ask who_ask.ask()
We create an instance of EventDispatcher class, and instance of WhoAsk class and two instance of WhoRespond class, then we call the ask() method of WhoAsk class.
$ python eventdispatcher.py>>> I'm instance <__main__.WhoAsk object at 0x100491ad0>. Who are listening to me ?<<< Thank you instance <__main__.WhoRespond object at 0x100491b10><<< Thank you instance <__main__.WhoRespond object at 0x100491b50>
As you can see we get two MyEvent.RESPOND events for the MyEvent.ASK event because we have two classes which listen to it.Conclusion
Develop a simple event dispatcher mini-framework is really straight forward, and is some situations is more simple to use a custom event dispatcher system than try to adapt a third-party one.
If you want to learn more about event driven system, take a look at PubSub, Qt Signals and Slots and wxPython. The documentation for Qt Signals and Slots reports examples in C++ but if you use
PyQt or PySide the classes, methods and logic is the same.Here you can download the source code for the Event and EventDisatcher classes with also the example code.
联系客服