How to add QCheckBox to column and make model appear in QTreeView.
-
I'm using Qt 5.12. I'm trying to create a custom model as opposed to custom views and delegates for reason like keeping my applications data in the model and not having to sync it externally.
My goal is to have a tree like the following where I can add checkboxes to only specific child nodes.
Column 1 Column 2 `- Root |- System1 | |- subsystem1 checkbox | `- subsystem2 checkbox `- System2 |- subsystem3 `- subsystem4
Aside from not knowing how to get the checkbox to appear. the problem I'm having is that the model is not showing up in my QTreeView. The view is empty.
MyTreeModel header:
class MyTreeModel : public QAbstractItemModel { Q_OBJECT private: QObject *root_item; public: explicit MyTreeModel(QObject *, QObject *parent = 0); Qt::ItemFlags flags(const QModelIndex &index) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; };
MyTreeModel source:
MyTreeModel::MyTreeModel(QObject *obj, QObject *parent) : QAbstractItemModel(parent) { root_item = obj; } Qt::ItemFlags MyTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } QVariant MyTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return static_cast<QObject *> (index.internalPointer())->objectName(); case 1: return static_cast<QObject *> (index.internalPointer())->metaObject()->className(); default: break; } } else if (role == Qt::ToolTipRole) { // ... } return QVariant(); } QVariant MyTreeModel::headerData(int section, Qt::Orientation orient, int role) const { if (role != Qt::DisplayRole || orient != Qt::Horizontal) return QVariant(); switch (section) { case 0: return QString("object"); case 1: return QString("class"); default: return QVariant(); } } QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent) const { QObject *parentObject; if (!parent.isValid()) parentObject = root_item; else parentObject = static_cast<QObject *>(parent.internalPointer()); if (row >= 0 && row < parentObject->children().count()) return createIndex(row, column, parentObject->children().at(row)); else return QModelIndex(); } int MyTreeModel::columnCount(const QModelIndex &parent) const { return 2; } int MyTreeModel::rowCount(const QModelIndex &parent) const { QObject *parentObject; if (!parent.isValid()) parentObject = root_item; else parentObject = static_cast<QObject *>(parent.internalPointer()); return parentObject->children().count(); } QModelIndex MyTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); QObject *indexObject = static_cast<QObject*>(index.internalPointer()); QObject *parentObject = indexObject->parent(); if (parentObject == root_item) return QModelIndex(); QObject *grandParentObject = parentObject->parent(); return createIndex(grandParentObject->children().indexOf(parentObject), 0, parentObject); }
And I have this is my MainWindow constructor ...
QObject root; QObject *subsys; root.setObjectName("Root"); QObject *sys1 = new QObject(&root); sys1->setObjectName("System1"); subsys = new QObject(sys1); subsys->setObjectName("subsystem1"); subsys = new QObject(sys1); subsys->setObjectName("subsystem2"); QObject *sys2 = new QObject(&root); bar->setObjectName("System2"); subsys = new QObject(sys2); subsys->setObjectName("subsystem3"); subsys = new QObject(sys2); subsys->setObjectName("subsystem4"); MyTreeModel tree_model(&root); tree_view = new MyTreeView; tree_view->setModel(&tree_model); projectLayout->addWidget(tree_view);
Any help appreciated.
-
Your flags() reimplementation must return Qt::ItemIsUserCheckable and data() must return the desired checkState for Qt::CheckStateRole
-
Still having issues with this. I initiate my tree as such ...
MyTreeItem *root_item = new MyTreeItem; MyTreeModel tree_model(root_item); tree_view = new MyTreeView; tree_view->setModel(&tree_model); // ... projectLayout->addWidget(tree_view);
Then I load a file and build the tree dynamically using ...
{ QString mps = QString::fromStdString("Root Item"); MyTreeItem* mp_item = model->get_root_item(); mp_item->setObjectName(mps); for (auto& i : myList) { QString str = QString::fromStdString(m.get_text()); MyTreeItem *item = new MyTreeItem(mp_item); item->setObjectName(str); } }
My problem is that I can't see anything loading in my view. The following is MyTreeModel.
MyTreeModel::MyTreeModel(MyTreeItem *item, QObject *parent) : QAbstractItemModel(parent) { root_item = item; } MyTreeModel::~MyTreeModel() { delete root_item; } Qt::ItemFlags MyTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable; if (index.column() == 1) flags | Qt::ItemIsUserCheckable; return flags; } QVariant MyTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); MyTreeItem *mti = static_cast<MyTreeItem*> (index.internalPointer()); if (role == Qt::CheckStateRole && index.column() == 1) { return static_cast<int>(mti->isChecked() ? Qt::Checked : Qt::Unchecked); } if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); MyTreeItem *item = getItem(index); return item->data(index.column()); } QVariant MyTreeModel::headerData(int section, Qt::Orientation orient, int role) const { if (role != Qt::DisplayRole || orient != Qt::Horizontal) return QVariant(); switch (section) { case 0: return QString("Object"); case 1: return QString("Class"); default: return QVariant(); } } QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent) const { MyTreeItem *parentObject; if (!parent.isValid()) parentObject = root_item; else parentObject = static_cast<MyTreeItem *>(parent.internalPointer()); if (row >= 0 && row < parentObject->children().count()) return createIndex(row, column, parentObject->children().at(row)); else return QModelIndex(); } int MyTreeModel::columnCount(const QModelIndex &parent) const { return 2; } int MyTreeModel::rowCount(const QModelIndex &parent) const { MyTreeItem *parentObject; if (!parent.isValid()) parentObject = root_item; else parentObject = static_cast<MyTreeItem *>(parent.internalPointer()); return parentObject->children().count(); } QModelIndex MyTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); QObject *indexObject = static_cast<QObject*>(index.internalPointer()); QObject *parentObject = indexObject->parent(); if (parentObject == root_item) return QModelIndex(); QObject *grandParentObject = parentObject->parent(); return createIndex(grandParentObject->children().indexOf(parentObject), 0, parentObject); } MyTreeItem* MyTreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { MyTreeItem *item = static_cast<MyTreeItem*> (index.internalPointer()); if (item) return item; } return root_item; } MyTreeItem* MyTreeModel::get_root_item() { return root_item; }
-
Hi,
@SRaD said in How to add QCheckBox to column and make model appear in QTreeView.:
MyTreeModel tree_model(&root);
tree_view = new MyTreeView;
tree_view->setModel(&tree_model);tree_model
is a local variable, it will be destroyed at the end of the method and thus your tree view won't have any data to show. -
Thanks for catching that, however, I'm still not seeing any items. I am however seeing the headers get filled in now so at least something of it is working.
After loading a file and dynamically creating new MyTreeItems, do I need to do anything to "reload" or refresh the view to get it to appear?
Specifically, here's the piece of code that creates the items, but by this time, I've already called tree_view->setModel, which was called in the main window constructor..
{ QString mps = QString::fromStdString("Root Item"); MyTreeItem* mp_item = model->get_root_item(); mp_item->setObjectName(mps); for (auto& i : myList) { QString str = QString::fromStdString(m.get_text()); MyTreeItem *item = new MyTreeItem(mp_item); item->setObjectName(str); } }
-
I'm sorry but I don't think will compile.
Please provide a minimal, compilable example which shows your problem. E.gint main (int argc, char **argv) { QApplication app(argc, argv); QTreeWidget treeWidget; QTreeWidgetItem *cities = new QTreeWidgetItem(&treeWidget); cities->setText(0, "Cities"); treeWidget.show(); return app.exec(); }