binding QStandardItemModel from C++ with QML
-
Hi all,
I was wondering why can't I show check boxes in qml's listview when I use QStandardItemModel. Let me give you an example:
c++ side... QStandardItemModel model; model.setColumnCount(1); const int N = 25; model.setRowCount(N); for (int r = 0; r < N; ++r) { QStandardItem* item = new QStandardItem(QString("item %1").arg(r)); item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); if (r % 2 == 0) item->setData(Qt::Unchecked, Qt::CheckStateRole); else item->setData(Qt::Checked, Qt::CheckStateRole model.setItem(r, 0, item); } QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("myModel", &model); ...
while on the qml's side:
ListView { ... model: myModel delegate: RowLayout { width: parent.width CheckBox { checked: /*what goes in here?*/ } Text { width: 100; height: 32 text: model.display Layout.fillWidth: true } } }
I'm perfectly aware that checkboxes can be set via custom roles, that is:
QStandardItemModel model; model.setColumnCount(1); const int N = 25; model.setRowCount(N); // new roles enum { checkedRole = Qt::UserRole, nameRole }; QHash<int, QByteArray> names; names[checkedRole] = "checked"; names[nameRole] = "name"; model.setItemRoleNames(names); for (int r = 0; r < N; ++r) { QStandardItem* item = new QStandardItem(QString("item %1").arg(r)); item->setData(QString("item %1").arg(r), nameRole); // item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); don't need that anymore if (r % 2 == 0) item->setData(Qt::Unchecked, checkedRole); // instead of Qt::CheckStateRole else item->setData(Qt::Checked, checkedRole); // instead of Qt::CheckStateRole model.setItem(r, 0, item); } ...
and on the qml's side, i can write this:
ListView { ... model: myModel delegate: RowLayout { width: parent.width CheckBox { checked: model.checked } Text { width: 100; height: 32 text: model.name Layout.fillWidth: true } } }
where the name is my custom role instead of Qt::DisplayRole (qml property is display, if I'm not mistaken), and since I can't find qml property for Qt::CheckStateRole, I need to put my custom role, checked.
Finally, the questions.
Is it safe to conclude that the Qt::DisplayRole is exposed to QML via display property, while the Qt::CheckStateRole isn't? Why is it? Is there any rational explanation behind this behaviour?
On the downside, I can't use the same QStandardItemModel code for both QWidgets and QML, since I need to create custom roles for the QML side. Which means, I need to have two different models, one for QWidgets, and one for QML. Yes, I'm aware that I really don't need two instances, but nevertheless, this seems like waste of time and resources. And what's more, the big chunk of the code is practically the same.
Ideally, I'd like to be able to write model code (now it's the QStandardItemModel, developed on the c++ side, nothing fancy), and use it in the QML, or in QWidgets.
Maybe I'm missing something, but I couldn't find anything in the docs about that. -
QML Views expose data do the delegate based on the role names of the model.
The default role names for a
QStandardItemModel
are:{ Qt::DisplayRole: "display", Qt::DecorationRole: "decoration", Qt::EditRole: "edit", Qt::ToolTipRole: "toolTip", Qt::StatusTipRole, "statusTip" Qt::WhatsThisRole, "whatsThis" }
As you can see there's no mention of
Qt::CheckStateRole
.
What you could do is just add it like that :QHash<int, QByteArray> roleNames = model.roleNames(); roleNames[Qt::CheckStateRole] = "checkState"; model.setRoleNames(roleNames);
Then you access it in your QML delegate like this:
checked: model.checkState
, and continue using it normally in QWidgets since you still use the same roles.