カスタムリストの作り方
QTではQTreeViewやQListViewなどの1つの部品ではなく複数の部品が組み合わさってできたリストビューに関してはモデル(model)とビューを結びつけて1つのビューにします。
リストビューをカスタムするときもこのモデルを基本にして独自のビューを作っていきます。
ここでは簡単なファイルビューワーにチェックボックスがついたツリービュー(QTreeView)を作ってみます。
ここでは次の手順で作ってみます。
- QFileSystemModelを拡張する
ここで独自のモデルクラスを作ってチェックボックスなどの部品を任意の列に挟むことができます。
- QTreeViewに独自のモデルクラスを設定する
独自のモデルクラスを作る
では例としてQFileSystemModelクラスを拡張して独自のモデルクラスを作ります。以下がそのクラス宣言(MyTreeModel.h)とクラスの定義部分(MyTreeModel.cpp)です。
MyTreeModel.h#ifndef TREEMODEL_H #define TREEMODEL_H #include <QFileSystemModel> #include <QVariant> #include <QSet> class TreeModel : public QFileSystemModel { Q_OBJECT public: explicit TreeModel(QObject* parent = 0); QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); Qt::ItemFlags flags(const QModelIndex &index) const; private slots: void onCheckChanged(const QModelIndex &index); //アイテムがクリックされたときに呼ばれるスロット関数 private: QSet<QPersistentModelIndex> checkList; //1つ1つのアイテムのチェック状況を保存するリスト }; #endif // TREEMODEL_HMyTreeModel.cpp
#include <TreeModel.h> #include <QDebug> TreeModel::TreeModel(QObject* parent) : QFileSystemModel(parent) { } void TreeModel::onCheckChanged(const QModelIndex &index) { //1行目の場合のみチェックは有効 if(index.column() == 0){ //もしcheckListにアイテムが含まれていればチェックされていると判断 if(checkList.contains(index)){ checkList.remove(index); } else{ checkList.insert(index); } } } /**ある場所のデータを取り出す。*/ QVariant TreeModel::data(const QModelIndex &index, int role) const { if(index.isValid() && index.column() == 0 && role == Qt::CheckStateRole){ return (checkList.contains(index)) ? Qt::Checked : Qt::Unchecked; } return QFileSystemModel::data(index, role); } /**あるアイテムのデータを設定する*/ bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { //1列目の場合だけcheckListを更新してチェック状態を更新する if(index.isValid() && index.column() == 0 && role == Qt::CheckStateRole){ if(value == Qt::Checked) checkList.insert(index); else checkList.remove(index); emit dataChanged(index, index); return true; } return QFileSystemModel::setData(index, value, role); }
では何をしているのか簡単に説明します。
このコードでは全ての行の1列目にだけチェックボックスを挿入しています。それが次のコードです。
if(index.isValid() && index.column() == 0 && role == Qt::CheckStateRole){ return (checkList.contains(index)) ? Qt::Checked : Qt::Unchecked; }
もしcheckListのなかにアイテムが含まれていればチェックされていると判断しています。
次のコードで紹介しますが、ツリービューの1つのアイテムがクリックされたらonCheckChanged関数を呼び、この時にcheckListに既にモデルオブジェクトが入っていれば除外し、なければそのオブジェクトを代入することで1つ1つのアイテムのチェック状況を管理しています。
ツリービューにMyTreeModelを設定する
独自に定義したMyTreeModelをQTreeViewに実装します。コードは次の通りです。
#include <QApplication> #include <QTranslator> #include <QtDebug> int main(int argc, char *argv[]) { QApplication app(argc, argv); MyTreeModel model; //カスタムモデルクラス QModelIndex parentIndex = model->setRootPath(""); //親ディレクトリの設定 QTreeView fileViewer; fileViewer.setModel(&model); fileViewer.setRootIndex(parentIndex); fileViewer.show(); return app.exec(); }
ここではQTreeViewにモデルオブジェクトを渡してあげ、トップディレクトリの中身を表示しようとしています。
表示されたビューツリーには次の画像のようにファイル名の左にチェックボックスがつきます。
ツリービューの1行目がクリックされるとそれに合わせてチェックボックスにチェックが入ったり消えたりします。
このようにモデルクラスを拡張すれば自分の好きなようにリストビューをカスタマイズ可能です。