为什么gui线程在slot中调用QLabel控件的setText方法响应慢?

问题描述

问题

我正在用 QT 开发一个程序。最近发现在一个线程中发出信号时,有时在槽函数调用QLabel控件的repaint方法需要两三秒的时间。而有时它只需要大约一毫秒。当我在线程的运行函数中让它休眠不同的秒数时会有所不同。这是我的代码

main.cpp

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

int main(int argc,char *argv[])
{
    QApplication a(argc,argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "testthread.h"
#include <QDateTime>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    TestThread *m_testThread;  //thread
private slots:
    void onTestSlot();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_testThread = new TestThread();
    connect(m_testThread,&TestThread::sigTest,this,&MainWindow::onTestSlot);
    m_testThread->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onTestSlot()
{
    ui->label_resultSimilarity->setText("test");
    qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss:zzz") << ":【MainWindow::onTestSlot】start repaint";
    ui->label_resultSimilarity->repaint();
    qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss:zzz") << ":【MainWindow::onTestSlot】end repaint";
}

testthread.h

#ifndef FACERECOGNIZETHREAD_H
#define FACERECOGNIZETHREAD_H
#include <QThread>
#include <QImage>
#include <QDebug>
#include <QMainWindow>

class TestThread: public QThread
{
    Q_OBJECT
public:
    TestThread();
protected:
    void run();

signals:
    void sigtest();
};

#endif // FACERECOGNIZETHREAD_H

testthread.cpp

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

TestThread::TestThread()
{

}

void TestThread::run()
{
    //QThread::msleep(200);
    QThread::msleep(500);
    emit sigtest();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>817</width>
    <height>478</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QLabel" name="label_preview">
    <property name="geometry">
     <rect>
      <x>93</x>
      <y>9</y>
      <width>571</width>
      <height>401</height>
     </rect>
    </property>
    <property name="sizePolicy">
     <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
      <horstretch>0</horstretch>
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
    <property name="layoutDirection">
     <enum>Qt::LeftToRight</enum>
    </property>
    <property name="frameShape">
     <enum>qframe::Box</enum>
    </property>
    <property name="text">
     <string/>
    </property>
    <property name="scaledContents">
     <bool>false</bool>
    </property>
   </widget>
   <widget class="QWidget" name="widget" native="true">
    <property name="geometry">
     <rect>
      <x>679</x>
      <y>10</y>
      <width>131</width>
      <height>381</height>
     </rect>
    </property>
    <widget class="QLabel" name="label_resultimage">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>20</y>
       <width>111</width>
       <height>151</height>
      </rect>
     </property>
     <property name="frameShape">
      <enum>qframe::Box</enum>
     </property>
     <property name="text">
      <string/>
     </property>
    </widget>
    <widget class="QLabel" name="label_resultSimilarity">
     <property name="geometry">
      <rect>
       <x>20</x>
       <y>210</y>
       <width>91</width>
       <height>20</height>
      </rect>
     </property>
     <property name="text">
      <string/>
     </property>
    </widget>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>817</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="qtoolbar" name="mainToolBar">
   <attribute name="toolBararea">
    <enum>TopToolBararea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

补充说明

在我编辑 testthread.cpp 中的 run 方法并让它休眠 500 毫秒后,我会得到以下结果执行程序:

"2021-05-26 00:15:31:641" :【MainWindow::onTestSlot】start repaint
"2021-05-26 00:15:34:605" :【MainWindow::onTestSlot】end repaint

但是,在我再次编辑 testthread.cpp 中的 run 方法并让它休眠 200 毫秒后,我会得到以下结果执行程序后的结果:

"2021-05-26 00:14:55:954" :【MainWindow::onTestSlot】start repaint
"2021-05-26 00:14:55:970" :【MainWindow::onTestSlot】end repaint

我不知道为什么 gui 线程对重绘的响应如此缓慢。有什么解决方案可以让它快速响应吗?感谢您的帮助。

解决方法

如果您想立即更新 ui,可以将连接模式更改为 'Qt::BlockingQueueConnection'。在 'setData' 方法之后是否需要调用 'repaint()'? 祝你好运~