为啥gui线程在槽中调用QLabel控件的setText方法响应慢?

Posted

技术标签:

【中文标题】为啥gui线程在槽中调用QLabel控件的setText方法响应慢?【英文标题】:Why does the gui thread respond slowly to calling the setText method of the QLabel control in a slot?为什么gui线程在槽中调用QLabel控件的setText方法响应慢? 【发布时间】:2021-08-13 22:40:49 【问题描述】:

问题

我正在用 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();

主窗口.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

主窗口.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();

主窗口.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 线程对重绘的响应如此缓慢。是否有任何解决方案可以使其快速响应?感谢您的帮助。

【问题讨论】:

使用QLabel 作为QMainWindow 中的中心小部件(在没有ui 文件的情况下)我无法重现。如果将QThread::msleep(500); emit sigTest(); 语句放在while (true) ... 循环中会发生什么?对QLabel::repaint所有 调用是否比预期花费更长的时间,还是只是第一次调用? Qt 是一个信号驱动的框架。在某些情况下,QThread::msleep() 和类似的用法并不是最好的方法。此外,在多线程环境中,您应该在信号和插槽之间使用 Queued Connections @G.M.感谢您的回答。我再次编辑了我的问题并在mainwindow.ui 中添加了代码。我也按照您所说的进行了尝试,并将QThread::msleep(500); emit sigTest(); 语句放入while (true) ... 循环中,然后似乎只有第一个调用比预期的要长(大约四秒),而任何其他调用只需要大约一毫秒。 . @NoobNoob 感谢您的回答。我在这里使用了QThread::msleep(),以替换执行时可能需要很长时间的其他代码。这样我就可以让代码简单易懂,方便读者帮助我分析我的代码。 【参考方案1】:

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

【讨论】:

以上是关于为啥gui线程在槽中调用QLabel控件的setText方法响应慢?的主要内容,如果未能解决你的问题,请参考以下文章

qt自定义信号和槽 在槽中怎么传输字符串

不能在一个槽中两次更改 QLabel 文本

Python Qt GUI设计:QLabel标签类(基础篇—11)

pyqt QLabel 在另一个线程更新其文本时未呈现

qt中如何获得控件所在的布局的指针。。

qt如何让控件在单独线程运行