如何在 QtQuick2 中正确实现可检查的 ListView?
How to correctly implement a checkable ListView in QtQuick2?
来自 C++ 我不知道如何在 QtQuick 中正确实现可检查的 ListView。
出于测试目的,我创建了一个小型测试应用程序。
型号:
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;
};
在运行时,我创建了一个 QListView 小部件和一个 ListView QtQuick2 项目。两者都附在同一个模型上。
当小部件 checking/unchecking 时,qml 视图会正确更新。
checking/unchecking在qml视图时,widget视图没有变化!
我注意到我的 setData 没有被调用。
在 QtQuick2 中实现可检查的 ListView 的正确方法是什么?
ListView {
anchors.fill: parent
model: __myModel
delegate: CheckDelegate {
text: model.display
checked: model.checkState
}
}
问题确实是 CheckDelegate
没有自动调用 setData
。
你必须告诉它这样做。为此,您可以使用 toggled
signal :
delegate: CheckDelegate {
text: model.display
checked: model.checkState
onToggled: model.checkState = checked // this will call setData for CheckStateRole
}
来自 C++ 我不知道如何在 QtQuick 中正确实现可检查的 ListView。
出于测试目的,我创建了一个小型测试应用程序。
型号:
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;
};
在运行时,我创建了一个 QListView 小部件和一个 ListView QtQuick2 项目。两者都附在同一个模型上。
当小部件 checking/unchecking 时,qml 视图会正确更新。 checking/unchecking在qml视图时,widget视图没有变化!
我注意到我的 setData 没有被调用。
在 QtQuick2 中实现可检查的 ListView 的正确方法是什么?
ListView {
anchors.fill: parent
model: __myModel
delegate: CheckDelegate {
text: model.display
checked: model.checkState
}
}
问题确实是 CheckDelegate
没有自动调用 setData
。
你必须告诉它这样做。为此,您可以使用 toggled
signal :
delegate: CheckDelegate {
text: model.display
checked: model.checkState
onToggled: model.checkState = checked // this will call setData for CheckStateRole
}