如何在Python中实现事件?

4

无法弄清楚如何实现事件系统。我正在使用tkinter进行项目开发,并且需要使用事件。如何像Java或C#一样使用事件?

我搜索了很多,但是找不到正确的方法。

以下是我正在尝试实现的事件类。

class Event(object):

    def __init__(self):
        self.handlers = []

    def add(self, handler):
        self.handlers.append(handler)
        return self

    def remove(self, handler):
        self.handlers.remove(handler)
        return self

    def fire(self, sender, earg=None):
        for handler in self.handlers:
            value = handler()
            self.remove(handler)
            return value


    __iadd__ = add
    __isub__ = remove
    __call__ = fire

这里是Car类

class Car:
    _speed = 0
    events = Event()

    def speed_up(self):
        self._speed += 10

    def speed_down(self):
        self._speed -= 10

    def get_speed(self):
        return self._speed

最后,还有一个窗口类(tkinter窗口)。
class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self.car = Car()
        tk.Button(self, text="Speed Up", command=self.increase_speed).grid(sticky="nsew")
        tk.Button(self, text="Speed Down", command=self.decrease_speed).grid(sticky="nsew")
        self.speed_label = tk.Label(self, text="0")
        self.speed_label.grid(sticky="nsew")
        self.mainloop()

    def increase_speed(self):
        self.car

    def decrease_speed(self):
        pass

这里是tkinter窗口: tkinter window

我想要实现以下功能: 1)在“加速”按钮点击时,应将“speed_up”添加到事件中。 2)它应该更改self.speed_label的值。 3)它应该类似于c# / Java事件或c#委托。

尝试学习这个对我来说新的概念。但是实现起来很困难...

更新! 我正在搜索/编辑并提出了一个解决方案。 不知道这个解决方案是否好。 我将问我的老师是否这是实现事件的好方法。 但现在代码看起来像这样:

import tkinter as tk

class Observer():
    _observers = []
    def __init__(self):
        self._observers.append(self)
        self._observed_events = []
    def observe(self, event_name, callback_fn):
        self._observed_events.append({'event_name' : event_name, 'callback_fn' : callback_fn})


class Event():
    def send(self, event_name, *callback_args):
        for observer in Observer._observers:
            for observable in observer._observed_events:
                if observable['event_name'] == event_name:
                    observable['callback_fn'](*callback_args)

    def receive(self, event_name, *callback_args):
        for observer in Observer._observers:
            for observable in observer._observed_events:
                if observable['event_name'] == event_name:
                    response = observable['callback_fn'](*callback_args)
                    return response

class Car(Observer):
    def __init__(self):
        Observer.__init__(self)
        self._current_speed = 0

    def speed(self):
        self._current_speed += 10

    def slow(self):
        self._current_speed -= 10

    def current(self):
        return self._current_speed


class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self._car = Car()
        self.store()
        self.events = Event()
        tk.Button(self, text="Speed Up", command=lambda:self.change_speed("speed")).grid(sticky="nsew")
        tk.Button(self, text="Slow Down", command=lambda:self.change_speed("slow")).grid(sticky="nsew")
        self.label = tk.Label(self, text=0)
        self.label.grid()
        self.settings()


    def store(self):
        self._car.observe("speed", self._car.speed)
        self._car.observe("slow", self._car.slow)
        self._car.observe("current", self._car.current)

    def settings(self):
        self.mainloop()

    def change_speed(self, event):
        self.events.send(event)
        self.label.config(text=self.events.receive("current"))



Window()

你有查阅《Tkinter 事件和绑定》文档吗?除非你想创建自己的事件系统,否则重用tkinter已有的事件系统会更容易些。 - Aaron
我知道这一点,但问题是,这是一个副业项目。我正在构建更大的项目。这个项目是为了让我首先了解事件如何工作。 :) 我必须实现Event类。我认为我不能使用tkinter事件和绑定来实现它。 - LuckyLuke
2个回答

7

没有完全分析问题中的代码,我认为你使用函数回调是正确的方向。这是因为据我所知,Python 没有事件的本地实现。

构建在此基础上的一些有用的库或示例可以在文章中看到,如 观察者 模式、模仿事件 或在相关问题的 答案 中。

这是我能想到的最简单的代码,用于说明回调的概念,不带参数:

   def on_notify():
       print("OK, I'm up-to-date")

   def do_something(update):
       # do whatever I need to do
       print("I've changed\n")
       update()

   do_something(on_notify)

输出为:

我被改变了

好的,我已经是最新的了

我们的“worker”函数接受一个函数参数,用于在事件发生时调用。在这种情况下,只有一个函数参数,但可以使用列表,这样我们就可以拥有多个监视器,这就是其他更完整的示例所做的事情。

还值得注意的是事件对象,这是一种在线程之间通信的机制,这对于用户界面是值得考虑的。我的猜测是,大多数实现“缺失事件”功能的库和框架都基于其中一个或两个核心方法。


2
您可以在这里找到一个很好的解释,介绍如何在默认没有观察者和事件的语言中实现它们。该文章是用c++编写的,但在python中实现方式几乎相同。
我可能会为每个事件使用观察者列表,因此事件不必在观察者列表中搜索其观察者,而只需遍历其个人观察者列表以通知它们。如果事件具有重要的特定参数,例如激活它的实体的ID,则可以将其包含在通知中,每个观察者决定如何处理该信息,如果该信息对他们不相关,则可以简单地不执行任何操作。

2
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接