1

次の質問は、QAbstractItemModelおよびQModelIndexクラスの設計とそれらの間の相互作用に関するもので、以下のコード サンプルで強調されています。

class Data:
    def __init__(self):
        self.value = 42

class Model( QAbstractItemModel ):
    def __init__( self ):
        QAbstractItemModel.__init__(self)
        data = Data()

        modelIndex = self.createIndex( 1 , 2 , data ) ### 1
        self.index( 1 , 2 , QModelIndex() ) ### 2
        self.setData( modelIndex , data.value ) ### 3
        self.dataChanged.emit( modelIndex , modelIndex )

        modelIndex.data() ###4
        self.data( modelIndex ) ### 5
  1. の作成方法QModelIndex。ドキュメントを読んだところ、答えはQAbstractItemModel::createIndex()ですが、この関数は ModelIndex の親からのオフセットに関する情報を提供しないため、不完全なようです。むしろ、これはQAbstractItemModel::index()によって行われます。両方の機能を一緒に再生する方法はありますか?
  2. データはモデル インデックスにどのように保存する必要がありますか? また、モデル インデックスと内部ポインター(用語は不明) によって、またはモデル インデックスに保存されるデータの違いは何ですか? また、 setData 関数がない場合、モデル インデックスは返すデータをどこで取得するのでしょうか。内部ポインタはデータですか? それはデータになることができますか?
  3. ModelIndex とモデルによって返されるデータの違いは何ですか? つまりQModelIndex::data()QAbstractItemModel::data( QModelIndex , int ) ? そして、セッターQAbstractItemModel::setData( QModelIndex , ... )は単に仮想であるのに、ゲッターQAbstractItemModel::data( QModelIndex , ... ) は純粋な仮想であるのはなぜですか。確かに、API は保存したデータを返すことができるはずです。

私の質問はC++ APIにリンクしていますが、スニペットはPySideにあります。この質問は両方の API にまたがっているため、そうしました。

4

2 に答える 2

3

実装やその他の設計の問題を含む QAbstractItemModel と QModelIndex に関連する多くの質問があることを考慮して、時間をかけて 1 つずつ回答するので、この回答を編集して詳細を説明します。

1.

QModelIndex には、その親が誰であるかの情報も、示すオフセットの情報もありません。行、列、データへのポインター、およびそれが属するモデルの情報のみを保持します (こちらを参照)。したがって、親が誰であるか、つまり自分のタスクがわかっているので、モデルのparent()メソッドをオーバーライドしてそれを返す必要があります。

def parent(self, index):
    if not index.isValid():
        return QtCore.QModelIndex()
    childItem = index.internalPointer()
    parentItem = childItem.parentItem()
    if parentItem == self.rootItem:
        return QtCore.QModelIndex()
    return self.createIndex(..., ..., parentItem)

したがって、QModelIndexのparent()メソッドでは、これはモデルを介して親を取得します (こちらを参照): def parent(self) : return self.model.parent(self)

index( ) メソッドとcreateIndex()メソッドの関係については、2 番目のメソッドが最初のメソッドによって呼び出されますが、データ構造との関係も必要です。一般的な実装は次のとおりです。

def index(self, row, column, parent):
    if not self.hasIndex(row, column, parent):
        return QtCore.QModelIndex()
    parentItem = None
    if not parent.isValid():
        parentItem = self.rootItem 
    else:
        parentItem = parent.internalPointer()
    childItem = parentItem.child(...)
    if childItem is not None:
        return self.createIndex(row, column, childItem)
    return QtCore.QModelIndex()

createIndex() の場合、行、列、モデル、および childItem へのポインターの情報を持つ QModelIndex のみを作成します。そのコンストラクターはプライベート コンストラクターであるため、ドキュメントにはありません (こちらを参照)。

2.

internalPointer はデータのメモリ位置を格納する変数です。つまり、QModelIndex にはデータはありませんが、どこにあるかはわかっているため、データを個別に格納する必要があるため、メソッドdata()を使用してデータを取得する場合は、モデルの情報が格納されているアイテムを返す internalPointer() を取得する必要があり、それに従ってロールがデータを取得します。

def data(self, index, role=QtCore.Qt.DisplayRole):
    if not index.isValid():
        return
    item = index.internalPointer()
    value = item.data(..., role) # like item.value
    return value

3.

QModelIndex のdata ( )メソッドは、モデルの data() メソッドを使用するため (こちらを参照)、概念的には次のように同じですdef data(self, role): return self.model.data(self, role)

すべてのモデルが編集可能であるとは限りません。たとえば、QStringListModel は編集可能ではないため、setData()メソッドを上書きする必要はありません。そのため、Qt はデフォルトでモデルを編集不可にします。つまり、モデルは何もせずに false を返します (こちらを参照)。つまり、このメソッドはオーバーライドされていない場合にのみ変更され、オーバーライドされない場合は親のメソッドと呼ばれます。つまり、何もしません。data()メソッドとは異なり、すべてのモデルが情報を返す必要があるため、開発者は QAbstractItemModel から継承するときにそのクラスを上書きする必要があるため、pure virtualと宣言されます。違いをより詳細に知るために、以下をお読みになることをお勧めします。 C++ 仮想/純粋仮想の説明

于 2019-07-21T00:11:02.873 に答える