使用Signals在类之间进行通信

时间:2012-03-03 23:13:40

标签: python model-view-controller pyqt signals

我想使用signals在我的视图和应用程序控制器之间进行通信。我有以下方法,但由于我是PyQt的初学者,我不知道这是否是正确的。谁能告诉我如果我走在正确的道路上还是有更好的解决方案?

编辑:我已将示例更改为完整的示例。

import sys
from PyQt4 import QtGui, QtCore

class View(QtGui.QMainWindow):

    sigFooChanged = QtCore.pyqtSignal()  
    sigBarChanged = QtCore.pyqtSignal()  

    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        central_widget = QtGui.QWidget()
        central_layout = QtGui.QHBoxLayout()

        self.__cbFoo = QtGui.QComboBox()
        self.__cbBar = QtGui.QComboBox()
        self.__cbFoo.currentIndexChanged[str].connect(lambda x: self.sigFooChanged.emit())
        self.__cbBar.currentIndexChanged[str].connect(lambda x: self.sigBarChanged.emit())

        central_layout.addWidget(QtGui.QLabel("Foo:"))
        central_layout.addWidget(self.__cbFoo)
        central_layout.addWidget(QtGui.QLabel("Bar:"))
        central_layout.addWidget(self.__cbBar)

        central_widget.setLayout(central_layout)
        self.setCentralWidget(central_widget)

    def setFooModel(self, model):
        self.__cbFoo.setModel(model)

    def setBarModel(self, model):
        self.__cbBar.setModel(model)

class Controller:
    def __init__(self, view):
        self.__view = view
        # Connect all signals from view with according handlers
        self.__view.sigFooChanged.connect(self.handleFooChanged)
        self.__view.sigBarChanged.connect(self.handleBarChanged)

        self.__fooModel = QtGui.QStringListModel(["Foo1", "Foo2", "Foo3"])
        self.__barModel = QtGui.QStringListModel(["Bar1", "Bar2", "Bar3"])

        self.__view.setFooModel(self.__fooModel)
        self.__view.setBarModel(self.__barModel)

    def handleFooChanged(self):
        print("Foo Changed")

    def handleBarChanged(self):
        print("Bar Changed")

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    view = View()
    controller = Controller(view)
    view.show()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:2)

就个人而言,我没有像这样创建一个单独的通用控制器类。这可能是我自己的偏好,但我倾向于将实际的QWidget类视为我的控制器,并且视图通常是我从QtDesigner(例如Ui_Dialog)生成的仅GUI定义,或者手动创建。我在相关的QWidget中建立了所有的连接。

现在你的代码,我不知道你是否只是在考虑这个代码片段是你正在采取的方向的一般伪代码示例......但它有错误...我会通常建议发布工作代码,这样人们就不会因为它是否有错误而感到困惑,或者只是询问它是否通常是一个正确的布局代码的方向。

您忘记在QMainWindow超类上调用__init__()

我不确定controller.show()会做什么(现在失败),因为我没有看到你打算如何将show()命令转发到主窗口对象的例子?我再也不明白为什么甚至有必要拥有那个单独的课程。

以下是我将如何看待一个更现实的例子,再次将QWidget类本身视为控制器:

查看

## mainUI.py ##

from PyQt4 import QtCore, QtGui

class Ui_MyWidget(object):

    def setupUi(self, obj):
        obj.layout = QtGui.QVBoxLayout(obj)

        obj.cbFoo = QtGui.QComboBox()
        obj.cbBar = QtGui.QComboBox()

        obj.layout.addWidget(self.cbFoo)
        obj.layout.addWidget(self.cbBar)

非Gui图书馆模块(控制器)

## nonGuiModule.py ##

class LibModule(object):

    def handleBarChanged(self, *args):
        print("Bar Changed: %s" % args)

控制器(任何入口点)

## main.py ##

import sys
from PyQt4 import QtCore, QtGui

from mainUI import Ui_MyWidget
from nonGuiModule import LibModule


class Main(QtGui.QMainWindow):

    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        self.resize(640,480)

        self._lib = LibModule()

        self.myWidget = MyWidget(self)
        self.setCentralWidget(self.myWidget)

        self.myWidget.sigFooChanged.connect(self.handleFooChanged)
        self.myWidget.sigBarChanged.connect(self._lib.handleBarChanged)


    def handleFooChanged(self, *args):
        print("Foo Changed: %s" % args)


class MyWidget(QtGui.QFrame, Ui_MyWidget):

    sigFooChanged = QtCore.pyqtSignal(str)  
    sigBarChanged = QtCore.pyqtSignal(str) 

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        # this is where you set up from the view
        self.setupUi(self)

        self.cbFoo.addItems(['Foo1', 'Foo2'])
        self.cbBar.addItems(['Bar1', 'Bar2'])

        self.layout.addWidget(self.cbFoo)
        self.layout.addWidget(self.cbBar)

        # going to forward private signals to public signals
        self.cbFoo.currentIndexChanged[str].connect(self.sigFooChanged)
        self.cbBar.currentIndexChanged[str].connect(self.sigBarChanged)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv[1:])
    view = Main()
    view.show()
    sys.exit(app.exec_())