QTableView 和 QStandardItemModel 的问题

Posted

技术标签:

【中文标题】QTableView 和 QStandardItemModel 的问题【英文标题】:Issue with QTableView and QStandardItemModel 【发布时间】:2020-03-21 20:11:05 【问题描述】:

我在向我的 QStandardItemModel 动态添加项目并使用 QTableView 显示它们时遇到了奇怪的事情。如果事件之间的时间足够长(比如 50 毫秒),那么视图是可滚动的,但在更快的事件(10 毫秒)的情况下,视图总是向下滚动并且不允许我做任何事情。

所以这里是简单的代码sn-p:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();

主窗口.h

#include <QMainWindow>
#include <QTimer>
#include <QTableView>
#include <QStandardItemModel>


QT_BEGIN_NAMESPACE
namespace Ui  class MainWindow; 
QT_END_NAMESPACE

class MainWindow : public QMainWindow

    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QTimer dataTimer;

    QStandardItemModel *model;
    QTableView *view;

public slots:
    void insertData();
;

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);

    view = new QTableView(this);
    this->setCentralWidget(view);

    model = new QStandardItemModel(this);
    model->setColumnCount(1);
    view->setModel(model);

    QObject::connect(&dataTimer, &QTimer::timeout, this, &MainWindow::insertData);
    dataTimer.start(10); // 50 here gives correct behaviour while 10 does not


MainWindow::~MainWindow()

    delete ui;


void MainWindow::insertData()

    QList<QStandardItem *> items;
    items.append(new QStandardItem(QTime::currentTime().toString("hh:mm:ss.zzz")));

    model->insertRow(0, items);
    if (model->rowCount() > 20)
        model->removeRow(model->rowCount()-1);
    

dataTimer.start(50) 工作正常,而 dataTimer.start(10) 制动行为。它适用于我的笔记本电脑,也许对于其他人来说,数字会有所不同,但我认为逻辑很清楚。

我在想它有点太快了,像 beginInsertRows() 这样的一些方法不能很好地工作。但这通常适用于定制模型,这里只是一个标准模型。

谁能告诉我为什么会这样? 谢谢

【问题讨论】:

【参考方案1】:

GUI 线程中影响 GUI 元素的 10 毫秒计时器本身就是一个坏主意。例如,在 Windows 10 毫秒超时是无法通过标准方式实现的。您的用户是否真的需要每秒超过 1 次查看某些表数据的更新?他真正需要的是什么?在此基础上,您应该确定优化方法。

那么你可以选择:

    减少计时器的超时并影响每个事件的几行。 看来您无论如何都必须减少 GUI 计时器的超时时间。 提前定期保留所需的行数,例如通过model-&gt;setRowCount(n)

    通过setUpdatesEnabled()方法暂时禁用表刷新:

    setUpdatesEnabled(false); bigVisualChanges(); setUpdatesEnabled(true);

    子类化 Qt 模型类之一并重新实现 insertRows() 或更多。

阅读Fetch More Example.Qt Model/View Programming.

【讨论】:

谢谢,我会尝试使用定时器进行批量更新。如果它有效,我会将答案标记为解决方案【参考方案2】:

你好。好的,所以当计时器设置为 10 毫秒时,它会在每次屏幕刷新时添加和删除一行。

Qtimer 与屏幕刷新率相关联。这意味着如果计时器在 16 毫秒内关闭,它会在每次屏幕刷新时关闭。

当您将项目添加到列表时,Qt 会在列表上运行其他 UI 事件以用于布局和视图边界。因为您在每个屏幕刷新时都在添加和删除,所以您的列表陷入了运行这些事件的不断循环中。更不用说您的列表基本上每 20 帧就被完全替换一次。

我不确定您为什么需要如此频繁地将项目添加到列表中,但也许您应该将添加和删除批量添加到列表中,然后每 100 毫秒进行一次批量添加和删除?那将解决问题。

【讨论】:

以上是关于QTableView 和 QStandardItemModel 的问题的主要内容,如果未能解决你的问题,请参考以下文章

QTableView() 仅在选择时更新更改

从 QTableView 读取和写入文件

QTreeView 和 QTableView 的 Qt 模型

QTableView:如何设置搜索栏

QTableView 和 QStandardItemModel 的问题

QTableView和QTableWidget翻页功能实现