Help us understand the problem. What is going on with this article?

ツリー構造のモデルの内容をQMLのListViewで表示する

はじめに

この記事は Qt Advent Calendar 2019 の16日目の記事です。
タイトルどおりの内容で捻りも何も無いですが、QML側でDelegateModelを使うとListViewのdelegateプロパティが機能しなくなる辺りでちょっと残念な気持ちになったりしたので自分のメモ書き程度に。Qt5.6を使用しています。

実装

早速実装いきます。

モデル

main.cppでモデルを構築してQML側へcontextPropertyとして登録しておきます。今回はモデルの中身にはこだわらないのでQStandardItemModelでささっと作っておきます。
モデルの中身をQML側から見るとこんなカンジです。

  • {display: "item_1"}
    • {display: "item_1_1", decoration: Qt.red}
    • {display: "item_1_2", decoration: Qt.green}
    • (中略)
    • {display: "item_1_1000", decoration: Qt.darkCyan}
  • {display: "item_2"}
    • {display: "item_2_1", decoration: Qt.red}
    • {display: "item_3_2", decoration: Qt.green}
    • (中略)
    • {display: "item_3_1000", decoration: Qt.darkCyan}
  • (中略)
  • {display: "item_100"}
    • {display: "item_100_1", decoration: Qt.red}
    • (後略)
main.cpp
    // [1] サンプル用のツリー構造のモデルを作る
    QStandardItemModel model;
    for (int i = 0; i < 100; ++i) {
        auto row = new QStandardItem(QString("item_%1").arg(i+1));
        QList<QStandardItem*> children;
        for (int j = 0; j < 1000; ++j) {
            auto child = new QStandardItem(QString("item_%1_%2").arg(i+1).arg(j+1));
            child->setData(QColor(static_cast<Qt::GlobalColor>((j % 10) + Qt::red)), Qt::DecorationRole);
            children.append(child);
        }
        row->appendRows(children);
        model.appendRow(row);
    }
    view.rootContext()->setContextProperty("dataModel", &model);
    // [1] ここまで

QML

ツリー構造の親子を見せるためにListViewを横並びに2つ並べました。
左の ListView で全親アイテムを表示し、左の ListView で選択されたアイテムの子アイテムを右の ListView に表示します。
ポイントは右の ListView の model プロパティに DelegateModel を使っているところで、 rootIndex プロパティによって元のモデルのどこを見せるのかを制御できます。 QAbstractItemView::setRootIndexはどこに行ったんだよ
DelegateModel を使うと右の ListView の デリゲートは DelegateModel の delegate プロパティで指定することになります。 ListView の delegate プロパティにセットしたコンポーネントは使われないことに注意が必要です。

main.qml
// 右側のリスト
ListView {
    id: rightList
    Layout.fillHeight: true
    Layout.preferredWidth: 400
    // [2] modelにDelegateModelを使う
    model: DelegateModel {
        rootIndex: leftList.model.index(leftList.currentIndex, 0) // [2] rootIndex指定
        model: leftList.model
        delegate: rightDelegate // [2] DelegateModel.delegate でデリゲート指定
        onRootIndexChanged: rightList.positionViewAtBeginning()
    }
    // delegate: rightDelegate // [3] 効かない
    highlight: highlight
    highlightMoveDuration: 200
    Keys.onUpPressed: decrementCurrentIndex()
    Keys.onDownPressed: incrementCurrentIndex()
    Keys.onLeftPressed: leftList.focus = true
    keyNavigationWraps: true
}

実行結果

こうなります。100×1000で100000アイテム程度なら、中身も単純なのでストレスなく動きます。
image.png

ソースコード

ソースコードは github に公開しています。

おわりに

QMLのListViewにDelegateModelを使用してrootIndexを指定すればツリー構造のデータを表示できます。 DelegateModel.modelIndex と DelegateModel.parentModelIndex を使うとファイルマネージャーのフォルダ移動のようなことも実装できるんじゃないかな、かな。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした