2012-03-03 32 views
3

我想使用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_()) 

回答

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) 

控制器(任何RY点)

## 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_()) 
+0

那么,这种做法也许是更容易的代码,但我认为GUI编程的一个目标应该是分开''gui'and业务logic'?这是如何正常完成的? – Razer 2012-03-04 09:53:19

+0

它的一个方面是,如果你有一个非gui模块,你想保持与gui依赖分离,并将信号连接到它的方法。但是我从来没有见过代码,即有人将所有事件和信号转发给Qt中的通用控制器类。当你有一个严格的UI类作为一个视图(只是布局和没有逻辑)时,你仍然在分离逻辑,然后考虑将它划分为控制器的QWidget。这就是我迄今为止所看到的。看看大量的代码示例。 – jdi 2012-03-04 16:42:04

+0

我刚刚更新了我的代码示例以显示我认为视图的位置,然后是控制器。对我来说,这个视图是单独的Ui模块,它只定义了布局而没有定义业务逻辑。然后你有一个继承它的类,并添加所有的逻辑,将它们联系在一起。 – jdi 2012-03-04 16:57:53

相关问题