如何将模型中的更改传播到视图? (使用pyqt信号和插槽)

时间:2012-10-02 01:45:39

标签: python pyqt4 signals-slots

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

我宁愿在模型的代码中没有pyqt信号。并且观察者模式对于只有一个会听它的东西感觉太多代码。

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

1 个答案:

答案 0 :(得分:3)

  

并且观察者模式对于只有一个会听它的东西感觉太多代码。

实际上,观察者模式正好你需要什么,而你根本不必使用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的{​​{1}}会传递给GUI中的观察方法MyBusinessLogicClass

观察者模式的实现

好的,这一切都很棒,但它依赖于实现观察者模式的东西的存在来获得notify装饰器。你可以得到我的实现,名为观察 on GitHub,或者你可以做到

@event

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

$ pip install observed

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

注意:我的观察到的库正在开发中,因此自撰写这篇文章以来语法可能有所改变。


编辑:您说过想要在不更改自定义类的情况下完成所有工作。虽然这是可能的,但你必须(我认为)在运行时混淆你的方法的性质,这通常是不赞成的,因为它比直接在代码中做事更令人困惑和脆弱。如果将> python setup.py install装饰器添加到某些方法是太侵入性的,您可以继承自定义类并在子类中添加装饰器。您甚至可以使用自定义元类自动应用装饰器。