web-dev-qa-db-ja.com

QAbstractListModel派生モデルのgetメソッドのようなQMLListModelを実装する方法

QMLでQAbstractListModel派生モデルを使用したいと思います。モデルをビューにバインドすることは、すでにうまく機能しています。

次に達成したいのは、特定のアイテムにアクセスする機能と、QMLListModelで可能なようにそれらの役割です。

grid.model.get(index).DisplayRole

しかし、QAbstractListModel派生モデルにこのgetメソッドを実装する方法がわかりません。

ヒントはありますか?

11
avb

次のように、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を使用できます。

20
labsin

リストモデルのロールに従来のアプローチを使用する場合は、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
    }
}
13
Xander

Stackoverflowには多くの誤った解決策があるため、これを見つけるのに非常に長い時間がかかりました。

私はここに返信を投稿しました:

qmlからListViewの現在のアイテムにアクセスする方法

これは、QAbstractItemModelから派生したものであれ、QMLで直接構築されたものであれ、すべてのモデルで機能し、ツリー型モデルへのアクセスも可能にします。

1
Richard1403832

これを行う別のアプローチは、QAbstractItemModelの組み込み関数を直接使用することです。経由

_grid.model.data(grid.model.index(index, 0), 0 /*== Qt::DisplayRole*/)
_

これは技術的には機能しますが、ユーザーは文字列を指定する代わりに、役割の数値コードを知っている必要があります。ここでの主な問題は、roleNames()を決定するための組み込み関数しか存在しないことです。名前文字列を対応する数値に適切にマッピングするには、反転関数を実装して_Q_INVOKABLE_を使用して公開するか、roleNames()の結果であるQHashを処理する必要があります。手動でQML。

1
Sty

私のアプローチは、オブジェクトのプロパティをQMLに直接公開することです。これがその実装です- https://stackoverflow.com/a/14424517/1059494

0
Pavel Osipov