web-dev-qa-db-ja.com

PyQtとMVCパターン

PyQtでMVCパターンを設計しようとしています。すべてのプログラムを3つの部分に分割したいと思います。

  1. すべてのQtクラスから抽象化されたクラス(モデル)
  2. モデルからQtアプリ(コントローラー)にデータを提供するクラス
  3. 信号をコントローラーに接続する定義済みのメソッドSignalsToSlotsを使用したQtアプリ自体。

これは最適ですか? PyQt開発での使用にはどのスキームが推奨されますか?

30
aluuu

最初にすべきことの1つは、Qt4デザイナーを使用してGUIを設計し、pyuic4を使用してpython GUIを生成することです。これがビューになります。これらを編集しないでくださいpythonファイルは手動で作成します。常にデザイナーを使用して変更を加えます。これにより、ビューがモデルやコントロールから分離されます。

制御要素には、QMainWindowなどの基本GUIウィジェットから継承する中央クラスを作成します。このオブジェクトは、生成したビューオブジェクトであるメンバーUIをcontainします。

これが チュートリアル の例です

UPDATE 2013:これはPyQtとMVCモデルに関する最近のチュートリアルです PyQt MVCチュートリアルシリーズ

import sys
from PyQt4 import QtCore, QtGui
from edytor import Ui_notepad

class StartQT4(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_notepad()
        self.ui.setupUi(self)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = StartQT4()
    myapp.show()
    sys.exit(app.exec_())

上記の例の重要なポイントは、コントローラーにuiが含まれており、それを直接継承しないことです。コントローラは、GUIの信号スロット接続を管理し、データモデルへのインターフェイスを提供する役割を果たします。

モデル部分を説明するために例が必要です。プロジェクトが映画コレクションデータベースを作成することであると仮定しましょう。モデルには、映画のリストを表すオブジェクトとともに、個々の映画を表す内部オブジェクトが含まれます。コントロールは、ビューから入力されたデータを取得して信号をキャッチし、モデルに更新を依頼する前にそれらを検証します。その部分は非常に重要です。コントローラーは、可能な限りモデルに直接アクセスするべきではなく、モデルに自分自身にアクセスするように要求する必要があります。

この相互作用の小さな例を次に示します(テストされていない、いくつかのタイプミスがある可能性があります)。

class Movie():
    def __init__(self,title=None,year=None,genre=None):
        self.title=title
        self.year=year
        self.genre=genre
    def update(self,title=None,year=None,genre=None):
        self.title=title
        self.year=year
        self.genre=genre
    def to_xml(self,title=None,date=None,genre=None):
        pass #not implementing this for an example!

#when the controller tries to update it should use update function
movie1.update("Manos Hands Of Fate",1966,"Awesome")
#don't set by direct access, your controller shouldn't get that deep
movie1.title="Bad Idea" #do not want!

MVCでは、アクセスを一元化することも重要です。たとえば、ユーザーは画面上でタイトルをダブルクリックするか、タイトルフィールドの横にある[編集]をクリックしてタイトルを変更できますbothこれらのインターフェイスのうち、変更には同じ方法を使用する必要があります。そしてこれは、それぞれがmovie.update_title(title)を呼び出すという意味ではありません。つまり、両方の信号がコントローラーで同じ方法を使用する必要があります。

ビューとコントローラーの間のすべての関係をできるだけ多く1にするようにしてください。つまり、GUIで何かを変更する方法は5つあり、コントローラーにはこれを処理するメソッドが1つあります。スロットにすべての互換性がない場合は、メソッドごとにメソッドを作成してから、1つのメソッドを呼び出します。 5つのビュースタイルで問題を5回解決した場合、ビューをコントロールから分離する理由は実際にはありません。また、コントローラーで何かを行う方法が1つしかないため、コントロールとモデルの間に1対1の優れた関係があります。

モデルをQtから完全に分離する限り、それは実際には必要ではなく、実際にあなたの生活を困難にする可能性があります。モデルでQStringsのようなものを使用すると便利です。別のアプリケーションで、Guiのオーバーヘッドを必要とせず、モデルにQtCoreのみをインポートしたい場合。うまくいけば、これが役立ちます!

42
cmaynard

はい、PyQtはモデル/ビューの概念を使用しています(公式には「コントローラー」部分はありません)が、PyQtでの意味が多少歪んでいる可能性があります。

2つの部分があります:

  1. 適切なPyQtベース抽象モデルクラス(QAbstractItemModelQAbstractTableModelQAbstractListModelなど)からサブクラス化されたモデル。これらのモデルは、データソース(ファイル、データベース)と直接通信することも、以前に作成された独自のPyQtに依存しないモデルをプロキシすることもできます。
  2. ビュー。Qtライブラリに実装されており、多くの場合、変更は必要ありません(例:QTreeViewQTableViewなど)。 QComboBoxのようないくつかのより単純なコントロールでさえ、PyQtモデルのビューとして機能することができます。

シグナルなどに反応するアプリケーションの他のすべての部分は、「コントローラー」と見なされる場合があります。

PyQtは、QStringListModelQStandardItemModelなど、モデルの単純な機能のみが必要な場合にサブクラス化または直接使用できる、事前定義された「ユニバーサル」モデルのセットも提供します。モデルもあります。 QSqlTableModelのようにデータベースと直接通信できます。

6
abbot

QtアーキテクチャがModel-Viewデザインをアプリケーションに提供する方法に関する公式の詳細なガイドへのリンクは次のとおりです。

http://doc.qt.io/qt-5/model-view-programming.html

Qtでは、ビューとコントローラーが組み合わされているため、Model-Viewフレームワークを使用してアプリを設計できます。

モデルはデータソースと通信し、アーキテクチャ内の他のコンポーネントにインターフェイスを提供します。通信の性質は、データソースのタイプとモデルの実装方法によって異なります。ビューはモデルからモデルインデックスを取得します。これらはデータ項目への参照です。モデルインデックスをモデルに提供することにより、ビューはデータソースからデータのアイテムを取得できます。標準ビューでは、デリゲートはデータのアイテムをレンダリングします。アイテムが編集されると、デリゲートはモデルインデックスを使用してモデルと直接通信します。

.。

モデル、ビュー、およびデリゲートは、シグナルとスロットを使用して相互に通信します

4
Jayesh