【发布时间】:2014-03-07 00:09:31
【问题描述】:
对于必须在屏幕上显示大量数据且更新率很高的应用程序,我很难理解最佳方法。我正在用 Qt for windows 编写这个应用程序。我不会详细介绍实际应用程序,但我在下面编写了一个示例应用程序来演示该问题。
在此我有一个正在计算值的线程。在这种情况下,它是一个简单的计数器值。在实际应用中,它有很多价值。这是每毫秒更新一次。该速率是数据所需的计算速率,而不是 GUI 所需的更新速率。如前所述,这是在它自己的线程中完成的。这个线程的想法是它只关心数据的计算,而不关心它的显示。
现在要更新此示例中的数据显示,我使用 QLabels 网格多次显示值(模拟许多不同值的显示)。我从 Qt 文档中了解到,Widget 的更新必须在主 GUI 线程中完成。所以我在这里所做的是让线程计算值以在每次重新计算时(1ms)发出一个带有计算值的信号。然后将其连接到主 GUI 线程,然后依次更新每个小部件以显示值。
这样做的结论是:
- GUI 线程被数据线程的 1ms 更新所淹没,因此显示更新变得非常缓慢。在我的机器上,更新了 100 个小部件,我估计更新速度约为 4fps。
- GUI 的所有其他方面(例如移动、调整大小和按下按钮)都在努力争取处理器时间。
- 似乎只用文本更新一个简单的 QLabel 似乎很慢。这正常吗?
- 我也为此添加了计时代码,GUI 线程中的 1 毫秒更新平均运行时间约为 1.8 毫秒,最大增量时间为 40-75 毫秒。因此,即使落后,它的运行速度也非常快。但大概在幕后,其他事件正在 GUI 线程事件队列上进行,以实际将更新绘制到屏幕上,这些都非常困难。
- 我真的不明白是什么决定了实际的屏幕更新率? Qt 如何决定何时更新屏幕?
最重要的是,我不确定更新要显示的数据的正确方法是什么。显然,屏幕不需要在 1 毫秒内更新,即使它可以,显示器也不会刷新得那么快。另一方面,我不希望我的数据线程与屏幕更新率有关。有没有更好的方法可以在不占用 GUI 事件队列的情况下将数据从数据线程获取到 GUI 线程?
任何对 Qt 方法解决此问题的见解将不胜感激。
这是在自己的线程中运行的数据生成器:
class Generator : public QObject
{
Q_OBJECT
public:
explicit Generator(QObject *parent = 0);
signals:
void dataAvailable(int val);
public slots:
void run(bool run);
void update(void);
private:
QTimer *timer;
int value;
};
void Generator::run(bool run)
{
if(run)
{
value = 0;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1);
} else
{
timer->stop();
delete timer;
}
}
void Generator::update()
{
value++;
emit dataAvailable(value);
}
这是更新显示的主要 GUI 类:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QLabel *labels[ROW_MAX][COL_MAX];
Generator *dataGenerator;
public slots:
void dataAvailable(int val);
signals:
void runGenerator(bool run);
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QGridLayout *layout = new QGridLayout;
for(int iCol=0; iCol<COL_MAX; iCol++)
{
for(int iRow=0; iRow<ROW_MAX; iRow++)
{
QLabel *label = new QLabel("Hello");
labels[iRow][iCol] = label;
layout->addWidget(labels[iRow][iCol], iRow, iCol);
}
}
centralWidget->setLayout(layout);
dataGenerator = new Generator;
QThread *dgThread = new QThread;
dataGenerator->moveToThread(dgThread);
dgThread->start(QThread::HighestPriority);
connect(this, SIGNAL(runGenerator(bool)), dataGenerator, SLOT(run(bool)));
connect(dataGenerator, SIGNAL(dataAvailable(int)), this, SLOT(dataAvailable(int)));
emit runGenerator(true);
}
void MainWindow::dataAvailable(int val)
{
for(int iCol=0; iCol< COL_MAX; iCol++)
{
for(int iRow=0; iRow<ROW_MAX; iRow++)
{
labels[iRow][iCol]->setText(QString::number(val));
}
}
}
【问题讨论】:
标签: multithreading performance qt user-interface