问题
Coming from C++ I dont know how to correctly implement a checkable ListView in QtQuick.
For testing purposes I created a small test application.
The model:
class MyModel : public QAbstractListModel
{
Q_OBJECT
public:
MyModel(QObject *parent = Q_NULLPTR) :
QAbstractListModel(parent)
{
for(int i = 0; i < 10; i++)
m_items.insert(QString("item%0").arg(i), qrand() % 2 == 0 ? Qt::Checked : Qt::Unchecked);
}
int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE
{
return m_items.count();
}
QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE
{
if(index.row() >= m_items.count())
return QVariant();
auto key = m_items.keys().at(index.row());
switch(role)
{
case Qt::DisplayRole:
return key;
case Qt::CheckStateRole:
return m_items[key];
}
return QVariant();
}
bool setData(const QModelIndex& index, const QVariant& value, int role) Q_DECL_OVERRIDE
{
qDebug() << "setData()" << index.row() << value << role;
switch(role)
{
case Qt::CheckStateRole:
{
auto key = m_items.keys().at(index.row());
m_items[key] = value.value<Qt::CheckState>();
emit dataChanged(index, index, QVector<int> { Qt::CheckStateRole });
return true;
}
}
return QAbstractListModel::setData(index, value, role);
}
Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE
{
Qt::ItemFlags f = QAbstractListModel::flags(index);
if(index.isValid())
f |= Qt::ItemIsUserCheckable;
return f;
}
QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE
{
return QHash<int, QByteArray> {
{ Qt::DisplayRole, QByteArrayLiteral("display") },
{ Qt::CheckStateRole, QByteArrayLiteral("checkState") },
};
}
private:
QMap<QString, Qt::CheckState> m_items;
};
On runtime I create a QListView widget and a ListView QtQuick2 item. Both are attached to the same model.
When checking/unchecking in the widget, the qml view gets updated correctly. When checking/unchecking in the qml view, the widget view does not change!
I noticed that my setData is not being called.
What is the correct way to implement a checkable ListView in QtQuick2?
ListView {
anchors.fill: parent
model: __myModel
delegate: CheckDelegate {
text: model.display
checked: model.checkState
}
}
回答1:
The problem is indeed that the CheckDelegate
doesn't call setData
automatically.
You have to tell it to do that. For this you can use the toggled signal :
delegate: CheckDelegate {
text: model.display
checked: model.checkState
onToggled: model.checkState = checked // this will call setData for CheckStateRole
}
来源:https://stackoverflow.com/questions/45194359/how-to-correctly-implement-a-checkable-listview-in-qtquick2