[转]QT子线程与主线程的信号槽通信-亲测可用!

  近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI。所以,网络通信端采用新开线程的方式。在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦。网上提供了很多同一线程不同类间采用信号槽通信的方式,但是并不完全适合线程间的信号槽通信,这主要体现在自定义消息的传递上。

首先我们看看一般的方式:
利用信号-槽发送Qt内置的元数据类型
testthread.h 文件

#ifndef TESTTHREAD_H
#define TESTTHREAD_H

#include <QThread>

#include "msg.h"

class TestThread : public QThread
{
    Q_OBJECT
public:
    explicit TestThread(QObject *parent = 0);

protected:
    void run();

signals:
    void TestSignal(int);

private:
    Msg msg;
};

#endif // TESTTHREAD_H

testthread.cpp文件

#include "testthread.h"

TestThread::TestThread(QObject *parent) :
    QThread(parent)
{
}

void TestThread::run()
{
    //触发信号
    emit TestSignal(123);
}

自己定义的类继承了QThread类,重写run函数,然后触发TestSignal信号。

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "testthread.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void DisplayMsg(int);

private:
    Ui::MainWindow *ui;
    TestThread *t;
};

#endif // MAINWINDOW_H

mainwindow.cpp

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

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

    //进行connect前必须实例化
    t = new TestThread();   

    connect(t, SIGNAL(TestSignal(int)), this, SLOT(DisplayMsg(int)));

    //执行子线程
    t->start();
}

void MainWindow::DisplayMsg(int a)
{
    ui->textBrowser->append(QString::number(a));
}

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

Mainwindow里面连接信号槽,并且将收到的int参数显示在界面上。

运行效果:

利用信号-槽发送自定义消息

下面我们对程序进行一些简单,修改,使得它传输我们的自定义消息。

testthread.h 文件

#ifndef TESTTHREAD_H
#define TESTTHREAD_H

#include <QThread>

#include "msg.h"

class TestThread : public QThread
{
    Q_OBJECT
public:
    explicit TestThread(QObject *parent = 0);
    Msg msg;

protected:
    void run();

signals:
    void TestSignal(Msg);   //Msg!!!
};

#endif // TESTTHREAD_H

testthread.h 文件

#include "testthread.h"

TestThread::TestThread(QObject *parent) :
    QThread(parent)
{
}

void TestThread::run()
{
    msg.int_info = 999;
    msg.str_info = "Hello Main Thread!";
    //触发信号
    emit TestSignal(msg);
}

mainwindow.h 文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "testthread.h"
#include "msg.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void DisplayMsg(Msg);   //Msg!!!

private:
    Ui::MainWindow *ui;
    TestThread *t;
};

#endif // MAINWINDOW_H

mainwindow.cpp 文件

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

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

    //进行connect前必须实例化
    t = new TestThread();

    //Msg!!!
    connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));

    //执行子线程
    t->start();
}

void MainWindow::DisplayMsg(Msg msg)
{
    ui->textBrowser->append(QString::number(msg.int_info));
    ui->textBrowser->append(msg.str_info);
}

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

此时再进行编译,能够通过,但是Qt Creator会有提示:

QObject::connect: Cannot queue arguments of type ‘Msg‘
(Make sure ‘Msg‘ is registered using qRegisterMetaType().)

并且运行程序,不会有任何反应。需要对mainwindow类的构造方法进行改造。mainwindow.cpp文件改动(蓝色加粗部分)为:

//以上代码省略ui->setupUi(this); 
qRegisterMetaType<Msg>("Msg");
//以下代码省略

此时能够正常运行。以上测试用例,经过本人亲测可用!!!!

结论:

(1)在线程间使用信号槽进行通信时,需要注意必须使用元数据类型,Qt内生的元数据类型,如int double QString 等。

(2)如果要用自己定义的数据类型,需要在connect前将其注册为元数据类型。形式见代码。

参考链接:

1、QT子线程与主线程的信号槽通信-(重点参考)

2、Qt子线程如何更新UI,完整的代码示例,有图有真相-(重点参考)

3、QT其他线程和UI主线程通信方式

4、Qt5中运行后台网络读取线程与主UI线程互交

5、QT小例子GUI(主)线程与子线程之间的通信-子线程和主线程互相发送信号

6、QT线程发送消息通知界面小例

原文地址:https://www.cnblogs.com/rainbow70626/p/10332219.html

时间: 2024-11-01 09:23:22

[转]QT子线程与主线程的信号槽通信-亲测可用!的相关文章

QT子线程与主线程的信号槽通信

最近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI.所以,网络通信端采用新开线程的方式.在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦.网上提供了很多同一线程不同类间采用信号槽通信的方式,但是并不完全适合线程间的信号槽通信,这主要体现在自定义消息的传递上. 首先我们看看一般的方式: testthread.h 文件 #ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> #include "ms

Qt自己定义事件实现及子线程向主线程传送事件消息

近期在又一次学习Qt的时候,由于要涉及到子线程与主线程传递消息,所以便琢磨了一下.顺便把有用的记录下来,方便自己以后查询及各位同仁的參考! 特此声明,本篇博文主要讲述有用的,也就是直接说明怎么实现,就不打算陈述一大堆理论啦,只是,还是建议大家去查查对应的理论比較好.这样能对Qt的消息传送机制的理解更加深入. 依据网上大多数人的资料,要实现自己定义消息,须要从QEvent 派生一个自己定义的事件:事实上也能够不须要,仅仅要使用QEvent::Type自己定义一个事件即可了. 在这里,本人把两种实现

Qt自定义事件实现及子线程向主线程传送事件消息

最近在重新学习Qt的时候,因为要涉及到子线程与主线程传递消息,所以便琢磨了一下,顺便把实用的记录下来,方便自己以后查询及各位同仁的参考! 特此声明,本篇博文主要讲述实用的,也就是直接说明怎么实现,就不打算陈述一大堆理论啦,不过,还是建议大家去查查相应的理论比较好,这样能对Qt的消息传送机制的理解更加深入! 根据网上大多数人的资料,要实现自定义消息,需要从QEvent 派生一个自定义的事件:其实也可以不需要,只要使用QEvent::Type自定义一个事件就行了.在这里,本人把两种实现方法都在这里讲

Handler消息传递机制(四)子线程接收主线程发送的消息

package com.example.looper; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widg

子线程和 主线程 互换

package demo; /** * 子线程循环5次,主线程循环10次.依次交替.整个交替循环3次 * */ public class ThreadTest { public static void main(String[] args) { init(); } static void init(){ final Print p = new Print();//封装了 循环的动作 new Thread(new Runnable(){ @Override public void run() {

子线程更新主线程的方法-转

Android的UI更新只能在UI线程中,即主线程.子线程中如果要进行UI更新,都是要通知主线程来进行. 几种实现方式总结如下,欢迎补充. 1.runOnUiThread() 子线程中持有当前Activity引用(假如为Activity mActivity;),即可以调用mActivity的runOnUiThread(Runnable r)方法. 2.post()和postDelay() 子线程如果持有某个View的引用,要对该View进行更新,则可调用该View对象的post(Runnable

Android中,子线程使用主线程中的组件出现问题的解决方法

Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行的功能交由Handler类来处理.这样就解决了线程出现的问题. 下面测试实例功能为单击图片,图片透明度改变为50,300毫秒后恢复不透明,代码如下: public class Demo extends Activity{ private ImageView changeImg = null;//Im

python 多线程中子线程和主线程相互通信

主线程开启多个线程去干活,每个线程需要完成的时间不同,干完活以后都要通知给主线程,下面代码说明该应用: 代码块: import threading import queue import time import random ''' 需求:主线程开启了多个线程去干活,每个线程需要完成的时间 不同,但是在干完活以后都要通知给主线程 多线程和queue配合使用,实现子线程和主线程相互通信的例子 ''' q = queue.Queue() threads=[] class MyThread(threa

Qt 子线程更新Ui

最近做练习,写一个Qt版的飞机大战,需要用子线程更新UI,发现Qt子线程不能更新Ui,否则程序会崩溃.在网上百度了下,说是需要在子线程自定义信号,然后在线程回调的run()函数里发射信号,主线程连接信号和槽,然后在槽函数里面更新UI.虽然最后发现这个办法对我写飞机大战没有啥帮助,但是感觉这个办法还是需要总结下来的.(最后我是用的定时器更新的UI界面) 废话不多说,下面是子线程更新UI的方法: 第一步:写一个线程类,继承自QThread 第二步:自定义信号 class CMyThread : pu