QAbstractListModel数据更改信号未更新ListView(QML) 我有一个QuestActListMod连接到QML中的ListVIEW,但是我有一个问题,从C++更新视图。这与Qt 5.6 mingw、QtQuick 2.6和QtQuick.Controls 1.5一起使用
设置: ListView使用带有属性的自定义复选框委托来存储模型中的值。当用户单击代理时,代理将更新模型。在我的QML中,我还有一个切换按钮,它调用模型中的一个插槽,该插槽切换模型中的数据,并为所有行发出dataChanged()信号(将所有复选框设置为not checked或checked) 问题: 切换按钮工作正常,直到用户与任何复选框代理交互为止。用户执行此操作后,dataChanged()信号不再更新该特定委托。我还验证了我的模型的data()函数在用户交互之前被所有行调用,然后它只在用户交互之后没有单击的行上被调用。这让我相信,在幕后的某个地方,视图选择不更新某些行,但我不知道为什么 可能的解决办法: 在模型中发出layoutChanged()会更新“我的切换”按钮的视图,而不考虑用户交互,但这会导致重新绘制整个视图,并且速度相对较慢 此问题是使用复选框创建的,但它适用于任何类型的用户交互。下面是重新创建我的问题所需的所有代码 main.qmlQAbstractListModel数据更改信号未更新ListView(QML) 我有一个QuestActListMod连接到QML中的ListVIEW,但是我有一个问题,从C++更新视图。这与Qt 5.6 mingw、QtQuick 2.6和QtQuick.Controls 1.5一起使用,c++,qt,listview,qml,qtquick2,C++,Qt,Listview,Qml,Qtquick2,设置: ListView使用带有属性的自定义复选框委托来存储模型中的值。当用户单击代理时,代理将更新模型。在我的QML中,我还有一个切换按钮,它调用模型中的一个插槽,该插槽切换模型中的数据,并为所有行发出dataChanged()信号(将所有复选框设置为not checked或checked) 问题: 切换按钮工作正常,直到用户与任何复选框代理交互为止。用户执行此操作后,dataChanged()信号不再更新该特定委托。我还验证了我的模型的data()函数在用户交互之前被所有行调用,然后它只在用
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
ColumnLayout {
anchors.fill: parent
spacing: 10
Button {
Layout.preferredHeight: 100
Layout.preferredWidth: 100
text: "Test!"
onClicked: {
console.log("attempting to refresh qml")
testModel.refresh()
testModel.print()
}
}
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
ListView {
id: view
anchors.fill: parent
spacing: 5
model: testModel
delegate: Rectangle {
height: 50
width: 100
color: "lightgray"
CheckBox {
id: checkBox
anchors.fill: parent
checked: valueRole
onClicked: {
valueRole = checked
}
}
}
}
}
}
}
TestModel.cpp
#include "testmodel.h"
TestModel::TestModel(QObject *parent) : QAbstractListModel(parent) {
roleVector << TaskRoles::valueRole;
testValue = false;
}
TestModel::~TestModel() {}
void TestModel::setup(const QList<bool> &inputList) {
// Clear view
removeRows(0, valueList.length());
// Update value list
valueList = inputList;
// Add rows
insertRows(0, valueList.length());
}
// Emits data changed for entire model
void TestModel::refresh() {
qDebug() << "attempting to refresh c++";
// Toggle all values in model
for (int i=0; i < valueList.length(); i++) {
valueList[i] = testValue;
}
// Toggle test value
testValue = !testValue;
// Update view
// this works but is slow
// layoutAboutToBeChanged();
// layoutChanged();
// this doesn't work if the user clicked the checkbox already
dataChanged(createIndex(0, 0), createIndex(rowCount()-1, 0), roleVector);
}
void TestModel::print() {
qDebug() << "Model:" << valueList;
}
QHash<int, QByteArray> TestModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[valueRole] = "valueRole";
return roles;
}
int TestModel::rowCount(const QModelIndex & /*parent*/) const {
return valueList.length();
}
QVariant TestModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const {
return QVariant();
}
Qt::ItemFlags TestModel::flags(const QModelIndex & /*index*/) const {
return static_cast<Qt::ItemFlags>(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable);
}
QVariant TestModel::data(const QModelIndex &index, int role) const {
// qDebug() << QString("Get Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
int row = index.row();
if (row >= 0 && row < valueList.length()) {
switch(role) {
case valueRole:
qDebug() << QString("Get Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
return valueList.at(row);
default:
return QVariant();
}
}
return QVariant();
}
bool TestModel::setData(const QModelIndex &index, const QVariant &value, int role) {
qDebug() << QString("Set Data - Row: %1, Col: %2, Role: %3").arg(index.row()).arg(index.column()).arg(role);
int row = index.row();
if (row >= 0 && row < valueList.length()) {
switch(role) {
case valueRole:
valueList[row] = value.toBool();
break;
default:
break;
}
dataChanged(index, index, QVector<int>() << role);
print();
}
return true;
}
bool TestModel::insertRows(int row, int count, const QModelIndex & /*parent*/) {
// Check bounds
if (row < 0 || count < 0) {
return false;
}
if (count == 0) {
return true;
}
if (row > rowCount()) {
row = rowCount();
}
beginInsertRows(QModelIndex(), row, row+count-1);
endInsertRows();
return true;
}
bool TestModel::removeRows(int row, int count, const QModelIndex & /*parent*/) {
// Check bounds
if (row < 0 || count < 0 || rowCount() <= 0) {
return false;
}
if (count == 0) {
return true;
}
if (row >= rowCount()) {
row = rowCount() - 1;
}
beginRemoveRows(QModelIndex(), row, row+count-1);
endRemoveRows();
return true;
}
将您的委托修改为以下内容:
delegate: Rectangle {
height: 50
width: 100
color: "lightgray"
CheckBox {
id: checkBox
anchors.fill: parent
checked: valueRole
// onClicked: {
// valueRole = checked
// }
}
MouseArea {
anchors.fill: parent
onClicked: {
valueRole = !checkBox.checked
}
}
}
复选框
的值绑定到valueRole
,但单击时,它只是用bool
值覆盖此绑定。如果您以其他方式处理单击,例如用MouseArea
覆盖复选框
,您将忽略破坏绑定,一切都将正常工作。另一个选项是恢复绑定
CheckBox {
onClicked: {
valueRole = checked;
checked = Qt.binding(function() { return valueRole; });
}
}
这种方法的优点是,如果用户交互不是简单的点击,也就是说,如果用户交互不能简单地用鼠标拦截,那么它也可以工作。我刚刚测试了这段代码,它可以工作!谢谢你的回答和解释。这很有见地。
dataChanged()
不是一种方法!这是一个信号
qml: attempting to refresh qml
attempting to refresh c++
"Get Data - Row: 0, Col: 0, Role: 257"
"Get Data - Row: 1, Col: 0, Role: 257"
"Get Data - Row: 2, Col: 0, Role: 257"
"Get Data - Row: 3, Col: 0, Role: 257"
"Get Data - Row: 4, Col: 0, Role: 257"
Model: (false, false, false, false, false)
qml: clicked checkbox
"Set Data - Row: 0, Col: 0, Role: 257"
Model: (true, false, false, false, false)
qml: attempting to refresh qml
attempting to refresh c++
"Get Data - Row: 1, Col: 0, Role: 257"
"Get Data - Row: 2, Col: 0, Role: 257"
"Get Data - Row: 3, Col: 0, Role: 257"
"Get Data - Row: 4, Col: 0, Role: 257"
Model: (true, true, true, true, true)
qml: attempting to refresh qml
attempting to refresh c++
"Get Data - Row: 1, Col: 0, Role: 257"
"Get Data - Row: 2, Col: 0, Role: 257"
"Get Data - Row: 3, Col: 0, Role: 257"
"Get Data - Row: 4, Col: 0, Role: 257"
Model: (false, false, false, false, false)
delegate: Rectangle {
height: 50
width: 100
color: "lightgray"
CheckBox {
id: checkBox
anchors.fill: parent
checked: valueRole
// onClicked: {
// valueRole = checked
// }
}
MouseArea {
anchors.fill: parent
onClicked: {
valueRole = !checkBox.checked
}
}
}
CheckBox {
onClicked: {
valueRole = checked;
checked = Qt.binding(function() { return valueRole; });
}
}