QTableView dataChanged 不响应或耗费很多大量CPU资源的一种情况及解决思路

之前有人提到不响应有可能是信号发送方和QTableView不在同一个线程,出现跨线程问题,解决方法就是通过另一个信号中转一下,反正最后在同一个线程(差不多就是gui线程)发射dataChanged信号即可。

这里说QTableView dataChanged 耗费很多大量CPU资源的另一种情况。

This signal is emitted whenever the data in an existing item changes.
If the items are of the same parent, the affected ones are those between topLeft and bottomRight inclusive. If the items do not have the same parent, the behavior is undefined.
此段引用跟本文无关。。。

看源代码(Qt5.9.9)就知道有多坑,粗暴。 其中官方吐槽,最为致命(我知道但我就是不改)。函数文档很丰满,实际实现很骨感。


void QAbstractItemView::update(const QModelIndex &index)
{
    Q_D(QAbstractItemView);
    if (index.isValid()) {
        const QRect rect = visualRect(index);
        //this test is important for peformance reason
        //For example in dataChanged we simply update all the cells without checking
        //it can be a major bottleneck to update rects that aren't even part of the viewport
        if (d->viewport->rect().intersects(rect))
            d->viewport->update(rect);
    }
}

void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &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();
}

似乎只能一个格子一个格子emit dataChanged(实属无奈),此方法确实可以降CPU资源占用,有空继承重写下吧(纯粹空想)。或许Qt高版本就修好了(实际并没有)?

void TableModel::UpdateView(int top, int bottom, int Left, int Right)
{
    //emit dataChanged(index(top, Left), index(bottom, Right), roles);两个index不相等会导致全屏刷新
    int row, column;
    for (row = top; row <= bottom; row++) {
        for (column = Left; column <= Right; column++) {
            auto it = index(row, column);
            emit dataChanged(it, it);//roles官方忽略,坑
        }
    }
}

如果有帮助请点赞,有更好方法欢迎留言。

你可能感兴趣的:(Qt)