2012-03-03 4 views
3

Je souhaite utiliser signals pour communiquer entre ma vue et mon contrôleur d'application. J'ai l'approche suivante mais puisque je suis débutant dans PyQt je ne sais pas si c'est la bonne. Quelqu'un peut-il me dire si je suis sur la bonne voie ou y at-il de meilleures solutions?Utilisation de Signaux pour la communication entre classes

EDIT: J'ai changé l'exemple pour un exemple complet.

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_()) 

Répondre

2

Personnellement, je ne crée pas de classe de contrôleur générique séparée comme ça. Cela pourrait être ma préférence, mais j'ai tendance à considérer la classe QWidget réelle de mon contrôleur, et la vue est généralement les définitions GUI uniquement que je génère à partir de QtDesigner (Ui_Dialog par exemple), ou créer manuellement. Et je fais toutes mes connexions dans le QWidget pertinent.

Maintenant sur votre code, je ne sais pas si vous considérez juste cet extrait pseudocode exemple de la direction que vous prenez ... mais il a des erreurs ... Je suggérerais normalement de travailler code de sorte que les gens ne soient pas confus quant à savoir si vous avez des erreurs à cause de cela, ou tout simplement demander si c'est généralement une direction correcte à l'élaboration du code.

Vous oubliez d'appeler __init__() sur la superclasse QMainWindow.

Je ne suis pas sûr de ce que controller.show() ferait (échouer dès maintenant) parce que je ne vois pas un exemple de la façon dont vous avez l'intention de transmettre cette commande show() à votre objet fenêtre principale? Encore une fois je ne vois pas vraiment pourquoi il est même nécessaire d'avoir cette classe séparée.

Voici comment je voyais un exemple plus réaliste, compte tenu de nouveau les classes QWidget eux-mêmes être les contrôleurs:

Voir

## 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) 

Bibliothèque Non-GUI Module (contrôleur)

## nonGuiModule.py ## 

class LibModule(object): 

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

Contrôleur (toute ent point 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

Eh bien, cette approche est peut-être plus facile à coder mais je pensais un but de la programmation devrait être de IUG séparer '' gui'and logic' d'affaires? Comment cela se fait-il normalement? – Razer

+0

Sa seule chose si vous avez un module non-gui que vous voulez garder séparé de la dépendance gui, et connectez les signaux à ses méthodes. Mais je n'ai encore jamais vu de code où quelqu'un transmet tous les événements et signaux à une classe de contrôleur générique dans Qt. Vous séparez toujours la logique lorsque vous avez une classe d'interface utilisateur stricte en tant que vue (juste mise en page et aucune logique), puis considérez le QWidget qui le sous-classe comme contrôleur. C'est comme ça que j'ai vu ça à ce jour. Regardez des tonnes d'exemples de code. – jdi

+0

Je viens de mettre à jour mon exemple de code pour montrer où je considère la vue, puis contrôleur. La vue, pour moi, est le module Ui séparé définissant seulement une mise en page et aucune logique métier. Ensuite, vous avez une classe qui en hérite et ajoute dans toute la logique, l'attachant tous ensemble. – jdi

Questions connexes