1

所以我有一个模型类,我想不知道它在 pyqt 应用程序中运行。但同时,当模型发生变化时,我希望 ui 更新。

我宁愿在模型的代码中没有 pyqt 信号。观察者模式感觉就像一件事的代码太多,要听它。

这个问题的干净解决方案是什么?

4

1 回答 1

4

观察者模式感觉就像一件事的代码太多,要听它。

实际上,观察者模式正是您所需要的,您根本不必使用 PyQt 信号/插槽。构建代码的“正确”方法是编写业务逻辑,不知道 GUI 的存在,但 GUI 应该对业务逻辑有(弱)引用。

程序结构

我通常大致这样启动我的 PyQt 应用程序:

import sys
import weakref
import PyQt4.QtGui as QtGui
from businesslogic import MyBusinessLogicClass
from guimodule import MyGuiClass    

app = QtGui.QApplication(sys.argv)
business_object = MyBusinessLogicClass()
gui = MyGuiClass(weakref.proxy(business_object))
sys.exit(app.exec_())

请注意,gui 接收对业务逻辑对象的引用(通过弱引用)。因此,当人类与 gui 交互时,gui 可以将数据发送到业务逻辑。

从业务逻辑获取信息到 gui

您的问题是关于业务逻辑如何在没有明确引用其代码中的 gui 的情况下将数据获取到 gui。我通过制作一个装饰器解决了这个问题,我可以把它放在我希望 gui 能够知道的函数和方法上。假设业务逻辑如下所示

# businesslogic.py
from observed import event  # Bear with me for a minute.

class MyBusinessLogicClass(object):
    @event
    def do_something_interesting(self, arg):
        print("logic back-end did something interesting with arg=%s"%(arg,))

那个小装饰器@event使它可以让其他东西可以注册以在do_something_interesting被调用时得到通知。gui这样做

# guimodule.py

class MyGuiClass(QtGui.QMainWindow):
    def __init__(self, business):
        QtGui.QMainWindow.__init__(self)
        self.business = business
        business.do_something_interesting.addObserver(self.notify)
    
    def notify(self, arg):
        <present notification to the user>

请注意,MyBusinessLogicClass对 gui 一无所知。对代码的唯一入侵是@event装饰器,它完全不了解 GUI,实际上完全不了解 PyQt。另请注意,arg传入MyBusinessLogicClass的内容将传递给 GUI 中的观察方法notify

观察者模式的实现

好的,这一切都很好,但它依赖于实现观察者模式的东西的存在来获得那个@event装饰器。你可以得到我的实现,在 GitHub 上被称为观察 ,或者你可以做

$ pip install observed

如果您在 Windows 上,只需从 github 下载源代码分发,然后在根目录中执行

> python setup.py install

我真的希望这会有所帮助。我专门为这个用例开发了观察。它非常简单,但解决了我在 python 中看到的其他观察者模式实现的几个缺点。

注意:观察到的库正在开发中,因此自写这篇文章以来语法可能会发生一些变化。


编辑:您说您希望在不更改自定义类的情况下让这一切正常工作。虽然这是可能的,但你必须(我认为)在运行时弄乱你的方法的性质,这通常是不受欢迎的,因为它比直接在代码中做事情更令人困惑和脆弱。如果将@event装饰器添加到某些方法过于侵入,您可以将自定义类子类化并在子类中添加装饰器。您甚至可以使用自定义元类自动应用装饰器。

于 2014-05-27T00:12:37.780 回答