情况描述
今天我创建了一个QT多线程的工程,框架如下。我希望通过指针的方式,让子线程去直接修改主线程的ui组件,但事与愿违。
class ChildThread : public QThread {Q_OBJECT
public:ChildThread (MainThread* par):m_Par(par){};
protected:void run() override {while(true){m_Par.ui->label.setValue()//子线程修改主线程的ui组件}}
public:MainThread* m_Par
};class MainThread : public QWidget {Q_OBJECT
public:MainThread (QWidget *parent = nullptr) : QWidget (parent) {QLabel *label = new QLabel("Current Time: ", this);setCentralWidget(label);// 创建子线程m_ChildThread= new ChildThread (this);// 启动子线程m_ChildThread->start();}
private:ChildThread *m_ChildThread;
};
存在的问题:子线程修改主线程ui是不安全操作
在Qt中,GUI相关的操作(例如更新UI元素)通常应该在主线程中执行。直接在子线程中更新UI是不安全的,可能会导致未定义的行为或崩溃。
正确的做法是:利用QT的信号与槽函数机制。在子线程处理完业务后,发出信号并携带上结果给主线程,交给主线程渲染。
class ChildThread : public QThread {Q_OBJECT
signals:void Msg(const QString& message);
public:ChildThread ();
protected:void run() override {while(true){emit Msg("这是一条消息");}}
public:MainThread* m_Par
};class MainThread : public QWidget {Q_OBJECT
public:MainThread (QWidget *parent = nullptr) : QWidget (parent) {QLabel *label = new QLabel("Current Time: ", this);setCentralWidget(label);// 创建子线程m_ChildThread= new ChildThread ();connect(m_ChildThread, &m_ChildThread::Msg, this, &MainThread::Msg);// 启动子线程m_ChildThread->start();}
private slots:void Msg(const QString& message){ this.label.setText(message); }
private:ChildThread *m_ChildThread;
};
这里要注意两点:
1、信号携带的数据要和槽函数接受的数据保持一致,变量名可以不一样。
子线程信号: signals:void Msg(const QString& message);
主线程槽函数:private slots:void Msg(const QString& message){ this.label.setText(message); }
2、信号与槽函数链接,如果官方的链接方式无效果,就换成直接引用。
方式一 connect(m_ChildThread, SINGAL(m_ChildThread::Msg), this, SLOT(&MainThread::Msg));
方式二 connect(m_ChildThread, &m_ChildThread::Msg, this, &MainThread::Msg);