gpt4 book ai didi

c++ - QAbstractTableModel 并为单行发出 dataChanged

转载 作者:行者123 更新时间:2023-11-30 02:17:50 27 4
gpt4 key购买 nike

我从 QAbstractTableModel 派生了一个模型,现在我想通知一整行的数据已被更改。例如,如果更改了索引为 5 的行的数据(4 列),则使用以下代码将按预期工作。

emit dataChanged(index(5,0), index(5, 0));
emit dataChanged(index(5,1), index(5, 1));
emit dataChanged(index(5,2), index(5, 2));
emit dataChanged(index(5,3), index(5, 3));

但如果我尝试只用一次发射实现相同,则 View 中所有行的所有列都会更新。

emit dataChanged(index(5, 0), index(5, 3));

我做错了什么?

最小示例(C++11、QTCreator 4.7.1、Windows 10 (1803)、64 位)

演示.h

#pragma once
#include <QAbstractTableModel>
#include <QTime>
#include <QTimer>

class Demo : public QAbstractTableModel
{
Q_OBJECT
QTimer * t;
public:
Demo()
{
t = new QTimer(this);
t->setInterval(1000);
connect(t, SIGNAL(timeout()) , this, SLOT(timerHit()));
t->start();
}

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
int c = index.column();
if (role == Qt::DisplayRole)
{
QString strTime = QTime::currentTime().toString();
if (c == 0) return "A" + strTime;
if (c == 1) return "B" + strTime;
if (c == 2) return "C" + strTime;
if (c == 3) return "D" + strTime;
}
return QVariant();
}

int rowCount(const QModelIndex &) const override { return 10; }
int columnCount(const QModelIndex &) const override { return 4; }
private slots:
void timerHit()
{
//Works
emit dataChanged(index(5,0), index(5, 0));
emit dataChanged(index(5,1), index(5, 1));
emit dataChanged(index(5,2), index(5, 2));
emit dataChanged(index(5,3), index(5, 3));

//emit dataChanged(index(5,0), index(5, 3)); // <-- Doesn't work
}
};

main.cpp

#include "demo.h"
#include <QApplication>
#include <QTreeView>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTreeView dataView;
Demo dataModel{};
dataView.setModel( &dataModel );
dataView.show();
return a.exec();
}

最佳答案

我认为问题在于当 QAbstractItemModel::dataChanged 时您对 QTreeView 的行为所做的某些假设发出信号。

具体来说,您假设 View 只会调用 QAbstractItemModel::data在信号中指定的那些索引上。不一定是这样。

查看 QAbstractItemView::dataChanged 的源代码(Qt 5.11.2)您会看到...

void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
Q_UNUSED(roles);
// Single item changed
Q_D(QAbstractItemView);
if (topLeft == bottomRight && topLeft.isValid()) {
const QEditorInfo &editorInfo = d->editorForIndex(topLeft);
//we don't update the edit data if it is static
if (!editorInfo.isStatic && editorInfo.widget) {
QAbstractItemDelegate *delegate = d->delegateForIndex(topLeft);
if (delegate) {
delegate->setEditorData(editorInfo.widget.data(), topLeft);
}
}
if (isVisible() && !d->delayedPendingLayout) {
// otherwise the items will be update later anyway
update(topLeft);
}
} else {
d->updateEditorData(topLeft, bottomRight);
if (isVisible() && !d->delayedPendingLayout)
d->viewport->update();
}

#ifndef QT_NO_ACCESSIBILITY
if (QAccessible::isActive()) {
QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::DataChanged);
accessibleEvent.setFirstRow(topLeft.row());
accessibleEvent.setFirstColumn(topLeft.column());
accessibleEvent.setLastRow(bottomRight.row());
accessibleEvent.setLastColumn(bottomRight.column());
QAccessible::updateAccessibility(&accessibleEvent);
}
#endif
d->updateGeometry();
}

重要的一点是这段代码的行为不同取决于信号是否指定了一个QModelIndex——例如topLeftbottomRight 相同。如果它们 相同,则 View 会尝试确保仅更新该模型索引。但是,如果指定了多个模型索引,那么它将调用...

d->viewport->update();

这大概会导致查询所有可见模型索引的数据。

由于您实现的 Demo::data 总是根据当前时间返回新数据,您将看到 View 更新的整个可见部分,给人的印象是 dataChanged 所有行和列都发出了信号。

因此,解决方法实际上是让您的数据模型更加“有状态”——它需要跟踪值而不是简单地按需生成它们。

关于c++ - QAbstractTableModel 并为单行发出 dataChanged,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53139727/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com