QMLでQAbstractListModel派生モデルを使用したいと思います。モデルをビューにバインドすることは、すでにうまく機能しています。
次に達成したいのは、特定のアイテムにアクセスする機能と、QMLListModelで可能なようにそれらの役割です。
grid.model.get(index).DisplayRole
しかし、QAbstractListModel派生モデルにこのgetメソッドを実装する方法がわかりません。
ヒントはありますか?
次のように、Q_INVOKABLE関数をQAbstractItemModel派生クラスに追加できます。
_...
Q_INVOKABLE QVariantMap get(int row);
...
QVariantMap get(int row) {
QHash<int,QByteArray> names = roleNames();
QHashIterator<int, QByteArray> i(names);
QVariantMap res;
while (i.hasNext()) {
i.next();
QModelIndex idx = index(row, 0);
QVariant data = idx.data(i.key());
res[i.value()] = data;
//cout << i.key() << ": " << i.value() << endl;
}
return res;
}
_
これにより、{ "bookTitle" : QVariant("Bible"), "year" : QVariant(-2000) }
のようなものが返されるため、.bookTitleを使用できます。
リストモデルのロールに従来のアプローチを使用する場合は、C++側で特別なことを行う必要はありません。いつものようにモデルがあり、データメソッドを実装する必要があります。
QVariant QAbstractItemModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const
qMLからさまざまなロールにアクセスするには、ListViewデリゲートでmodel
添付プロパティを使用できます。
model.display // model.data(index, Qt::DisplayRole) in c++
model.decoration // Qt::DecorationRole
model.edit // Qt::EditRole
model.toolTip // Qt::ToolTipRole
// ... same for the other roles
それは(まだ)Qtドキュメントに記載されているとは思いませんが、QMLからアクセスできるプロパティを見つけるには、アプリをデバッグモードで起動し、デリゲートにブレークポイントを設定するか、すべてのプロパティをコンソールに出力します。ところで、デリゲート内のmodel
プロパティはタイプQQmlDMAbstractItemModelDataであるため、バックグラウンドで「Qtマジック」が発生し、リストモデルデータのラッパーのように見えますが、Qtで公式なものは見つかりませんでしたそれに関するドキュメント(私はQMLデバッガーなどを使って自分でそれを理解しました)。
デリゲートの外部からモデルデータにアクセスする必要がある場合、そのための組み込み機能はないと思います。そのため、自分で行う必要があります。
デフォルトのQMLListModelと同様のcount
プロパティとget
-関数を公開するカスタムQAbstractListModelクラスの例を作成しました。
mylistmodel.h
class MyListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
explicit MyListModel(QObject *parent = 0);
int rowCount(const QModelIndex & = QModelIndex()) const override { return m_data.count(); }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE int get(int index) const { return m_data.at(index); }
signals:
void countChanged(int c);
private:
QList<int> m_data;
};
mylistmodel.cpp
MyListModel::MyListModel(QObject *parent) :
QAbstractListModel(parent)
{
m_data << 1 << 2 << 3 << 4 << 5; // test data
emit countChanged(rowCount());
}
QVariant MyListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount())
return QVariant();
int val = m_data.at(index.row());
switch (role) {
case Qt::DisplayRole:
return QString("data = %1").arg(val);
break;
case Qt::DecorationRole:
return QColor(val & 0x1 ? Qt::red : Qt::green);
break;
case Qt::EditRole:
return QString::number(val);
break;
default:
return QVariant();
}
}
プロパティと関数をQMLに公開するのは非常に簡単なので、これは知っておくとよい方法だと思います。
完全を期すために、カスタムモデルを使用したListViewの例を次に示します。
ListView {
anchors.fill: parent
model: MyListModel { id: myModel }
delegate: Text {
text: model.display
}
Component.onCompleted: {
console.log(myModel.count) // 5
console.log(myModel.get(0)) // 1
}
}
Stackoverflowには多くの誤った解決策があるため、これを見つけるのに非常に長い時間がかかりました。
私はここに返信を投稿しました:
qmlからListViewの現在のアイテムにアクセスする方法
これは、QAbstractItemModelから派生したものであれ、QMLで直接構築されたものであれ、すべてのモデルで機能し、ツリー型モデルへのアクセスも可能にします。
これを行う別のアプローチは、QAbstractItemModel
の組み込み関数を直接使用することです。経由
_grid.model.data(grid.model.index(index, 0), 0 /*== Qt::DisplayRole*/)
_
これは技術的には機能しますが、ユーザーは文字列を指定する代わりに、役割の数値コードを知っている必要があります。ここでの主な問題は、roleNames()
を決定するための組み込み関数しか存在しないことです。名前文字列を対応する数値に適切にマッピングするには、反転関数を実装して_Q_INVOKABLE
_を使用して公開するか、roleNames()
の結果であるQHash
を処理する必要があります。手動でQML。
私のアプローチは、オブジェクトのプロパティをQMLに直接公開することです。これがその実装です- https://stackoverflow.com/a/14424517/1059494