2012-03-03 2 views
3

私のビューとアプリケーションコントローラ間の通信にsignalsを使用します。私は次のアプローチを持っていますが、私はPyQtの初心者ですから、それが正しいかどうかわかりません。誰かが私に正しい道にいるのか、もっと良い解決策があるのか​​教えてもらえますか?クラス間の通信に信号を使用する

EDIT:例を完全に動作する例に変更しました。

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__()を呼び出すことを忘れています。

メインウィンドウオブジェクトにそのshow()コマンドをどのように転送するかの例が表示されないため、controller.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

+0

あなたはgui依存関係から分離しておきたい非guiモジュールを持っていて、シグナルをそのメソッドに接続したい場合、その1つです。しかし、誰かがQtのジェネリックコントローラクラスにすべてのイベントとシグナルを転送しているところで、まだコードを見たことはありません。複雑なUIクラスをビュー(レイアウトとロジックなし)として使用している場合は、ロジックを分離しているので、コントローラとしてサブクラス化するQWidgetを検討してください。それまでの私はそれをどのように見てきたのですか?たくさんのコード例を見てください。 – jdi

+0

私は、ビューをどこに、次にコントローラと見なすべきかを示すコード例を更新しました。私の見解は、レイアウトだけを定義し、ビジネスロジックを定義しない別々のUiモジュールです。それからあなたはそれから継承するクラスを持っていて、すべてのロジックを加えて、それをすべて結びつけます。 – jdi