PyQtにおけるクラス設計 -MVCパターン-
MVCパターン
MVCパターンとはUIをもつアプリケーションにおけるデザインパターンである。クラスをModel、View、Controllerの3つに分ける。'単一責任原則'を考えるとそれぞれのクラスは以下の責務をもつ。
Model: データの格納とそのデータを用いた処理。
View: Modelのデータを描画。
Controller: Model、Viewに司令を出す。
MVCパターンは上の図のようになる。記事によってはModelとViewを繋いでいないものがある。どちらも不正解ではなく、その状況によって繋ぐか繋がないかの選択をする。ここに関しては以下の記事の後半が参考になった。
qiita.com
まずはMVCパターンのベースを構築
ContollerとViewはそれぞれ他2つにアクセスできるが、Modelは他クラスの情報にアクセスできない。この状態をコードに落としてみたのが以下。
# -*- coding: utf-8 -*- class View(object): # 何も継承しないときは'object'を継承することが推奨されている def __init__(self,model): self.model = model def register(self,controller): self.controller = controller class Model(object): def __init__(self): pass class Controller(object): def __init__(self,view,model): self.view = view self.model = model self.view.register(self) if __name__ == '__main__': model = Model() view = View(model) controller = Controller(view,model)
ベースに簡単なGUIを載せてみる
PyQtについては以下のページなどを参照してほしい。
qiita.com
myenigma.hatenablog.com
d.hatena.ne.jp
実際に処理をそれぞれのクラスに乗せるときに、各クラスの役割の規範を超えたことをしないように注意して以下のプログラムを作成した。
# -*- coding: utf-8 -*- from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLabel import sys class View(QWidget): def __init__(self, model): super().__init__() self.model = model def register(self,controller): self.controller = controller # controller生成後にinitUIしないとcontrollerのメソッドにバインドできない # これであってるかは不明... self.initUI() def initUI(self): self.setGeometry(200,200,150,100) button = QPushButton('sayHello!!',self) button.clicked.connect(self.controller.pushButton) self.label = QLabel("none",self) self.label.setGeometry(20,50,50,20) def updateUI(self): self.label.setText(model.word) class Model(object): # 何も継承しないときは'object'を継承することが推奨されている def __init__(self): self.word = 'none' def sayHello(self): # Modelは自身のデータを処理するだけ self.word = 'Hello' class Controller(object): def __init__(self, view, model): self.view = view self.model = model self.view.register(self) def pushButton(self): # 複数の処理を行いたい際などに直接Modelに渡すのでなくControllerを挟むということが活きてくる self.model.sayHello() self.view.updateUI() if __name__ == '__main__': app = QApplication(sys.argv) model = Model() view = View(model) controller = Controller(view,model) view.show() sys.exit(app.exec_())