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

最近在重新学习Qt的时候,因为要涉及到子线程与主线程传递消息,所以便琢磨了一下,顺便把实用的记录下来,方便自己以后查询及各位同仁的参考!

特此声明,本篇博文主要讲述实用的,也就是直接说明怎么实现,就不打算陈述一大堆理论啦,不过,还是建议大家去查查相应的理论比较好,这样能对Qt的消息传送机制的理解更加深入!

根据网上大多数人的资料,要实现自定义消息,需要从QEvent 派生一个自定义的事件;其实也可以不需要,只要使用QEvent::Type自定义一个事件就行了。在这里,本人把两种实现方法都在这里讲述一下!

一、这里先讲述使用 QEvent::Type 定义一个自定义事件

1、新建一个新的工程 “myEvent” ,在 ui 界面添加一个按钮,并未按钮添加 onclick() 响应函数。

2、在 widget.h 头文件使用 QEvent::Type 定义两个自定义事件。

3、重新实现 event() 虚函数

bool event(QEvent* e);

4、添加 #include<QEvent>

整个头文件如下:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QEvent>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

    bool event(QEvent* e);

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;

    QEvent::Type myEvent1;
    QEvent::Type myEvent2;

};

#endif // WIDGET_H

5、使用QEvent::registerEventType() 静态函数为刚才两个自定义事件注册值。

6、重新实现 event()  函数 。

7、在 按钮响应函数里面发送时间消息。

widget.cpp 文件如下:

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QCoreApplication>
#include <QDebug>

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

    myEvent1 = static_cast<QEvent::Type>(QEvent::registerEventType(-1));
    myEvent2 = static_cast<QEvent::Type>(QEvent::registerEventType(-1));
}

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

bool Widget::event(QEvent* e)
{
    if(e->type() == myEvent1){
        QMessageBox::warning(this, tr("event"), tr("myEvent1"), QMessageBox::Yes); return true;

    }else if(e->type() == myEvent2){
        QMessageBox::warning(this, tr("event"), tr("myEvent2"), QMessageBox::Yes); return true;

    }

    return QWidget::event(e);
}

void Widget::on_pushButton_clicked()
{
    QCoreApplication::sendEvent(this, &QEvent(myEvent1));
    QCoreApplication::sendEvent(this, &QEvent(myEvent2));

}

编译运行后界面如下:

二、从 QEvent 派生一个自定义事件类,类名取为 myEvent 。

1、myevent.h 头文件如下,里面自定义了三个自定义事件,分别为
m_event1, m_event2,
m_event3:

#ifndef MYEVENT_H
#define MYEVENT_H

#include <QEvent>

class myEvent : public QEvent
{
public:
    myEvent(Type e);

public:
    static Type m_event1;
    static Type m_event2;
    static Type m_event3;
};

#endif // MYEVENT_H

2 、在myevent.cpp 文件里面使用QEvent::registerEventType()
为自定义的事件注册。

myevent.cpp 文件如下:

#include "myevent.h"
#include <QEvent>

QEvent::Type myEvent::m_event1 = static_cast<QEvent::Type>(QEvent::registerEventType());
QEvent::Type myEvent::m_event2 = static_cast<QEvent::Type>(QEvent::registerEventType());
QEvent::Type myEvent::m_event3 = static_cast<QEvent::Type>(QEvent::registerEventType());

myEvent::myEvent(Type e):QEvent(e)
{
}

3、在 widget.cpp 文件 添加   myevent.h 头文件 。

4、修改 widget.cpp 文件里面的按钮响应函数如下:

void Widget::on_pushButton_clicked()
{
    myEvent e(myEvent::m_event1);
    QCoreApplication::sendEvent(this, &e);
}

5、修改 widget.cpp 文件里面的 event() 函数如下:

bool Widget::event(QEvent* e)
{
    if(e->type() == myEvent1){
        QMessageBox::warning(this, tr("event"), tr("myEvent1"), QMessageBox::Yes); <pre name="code" class="cpp">        return true;

    }else if(e->type() == myEvent2){
        QMessageBox::warning(this, tr("event"), tr("myEvent2"), QMessageBox::Yes);
<pre name="code" class="cpp"><pre name="code" class="cpp">        return true;

}else if(e->type() == myEvent::m_event1){ QMessageBox::warning(this, tr("myEvent"), tr("m_event1"), QMessageBox::Yes); return true; } else if(e->type() == myEvent::m_event2){ QMessageBox::warning(this, tr("myEvent"), tr("m_event2"), QMessageBox::Yes); return
true; } return QWidget::event(e);}



然后重新编译运行,效果如下:

三 、 前面讲的都是在主线程里面传递事件消息,接下来讲述如何 在子线程里面 往主线程 传递事件消息。

1、从 QThread 派生一个自定义事件类,类名取为 myThread , 并重新实现 run() 虚函数。mythread.h 头文件如下:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

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

signals:

public slots:

protected:
    void run();
};

#endif // MYTHREAD_H
 

2、在mythread.cpp 里面重新实现 run() 函数,在里面实现向主线程发送事件消息,mythread.cpp 文件如下:

#include "mythread.h"
#include "myevent.h"
#include <QCoreApplication>

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

void myThread::run()
{
    myEvent e(myEvent::m_event2);
    QCoreApplication::postEvent(this->parent(), new myEvent(myEvent::m_event2));

    //this->exec();
}

3、在 widget.h        里面添加 mythread.h 头文件, 然后定义一个子线程对象, 如下:

#include"mythread.h"

myThread*m_pThread;

4、在堆内存里面为m_pThread开辟一个内存空间,如下:

<span style="color:#000000;">Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    m_pThread = new myThread(this);

   。。。。。。
}</span>

5、在 ui  界面 添加另一个按钮,并为它添加 onclick() 事件响应,然后在里面运行子线程,如下:

void Widget::on_pushButton_2_clicked()
{
    m_pThread->start();
}

编译运行程序,效果如下:

四、QCoreApplication::postEvent(); 和
QCoreApplication::sendEvent();     的区别。

在前面的程序中发送 事件消息 的时候用到了
QCoreApplication::postEvent(); 和
QCoreApplication::sendEvent(); 两个函数,这里可不是随便使用的,这两个函数时又区别的!

1、QCoreApplication::sendEvent();   根据Qt Asistant 里面的讲述,这个函数直接将事件消息直接发送给接受者进行处理,等到事件处理完毕后才返回;并且使用它所传递的消息事件是在
栈(stack) 上创建的,也就是说它的内存空间是有编译器来自动管理的。

2、QCoreApplication::postEvent();    根据Qt
Asistant 里面的讲述,使用这个函数来传递时间消息时,它将事件消息发送到接受者的的消息队列里面,然后立即返回,不需要等到事件处理完毕才返回;并且使用它所传递的消息事件是在 堆(heep) 上创建的,也就是说它的内存空间是又程序员自己管理的,如用 new 创建的变量!

这两个函数对事件的处理方式就像使用 repaint()  和 paint() 这两个函数对界面进行重画一样,前者直接对界面进行重画操作;后者先将重画事件放到消息队列里面,等到适当的时候在对界面进行重画操作。

在上面的子线程给主线程传递消息的时候使用的就是QCoreApplication::postEvent();  函数,因为这里必须保证在子线程退出之前,若子线程所传递的事件消息还未被主线程处理的话,子线程所传递的消息仍然是可用的。

好了,主线程内事件的传递与子线程向主线程传递事件消息的方法就介绍到这里了。至于Qt 的事件传送机制,这里就没有怎么讲了,不过还是建议读者好好去了解一下的好。

时间: 2024-10-10 06:16:38

Qt自定义事件实现及子线程向主线程传送事件消息的相关文章

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

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

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

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

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

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

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

子线程和 主线程 互换

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() {

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

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

Delphi7从子线程中发送消息到主线程触发事件执行

[转载]Delphi7从子线程中发送消息到主线程触发事件执行 在对数据库的操作时,有时要用一个子线程来进行后台的数据操作.比如说数据备份,转档什么的.在主窗口还能同是进行其它操作.而有时后台每处理一个数据文件,要向主窗口发送消息,让主窗口实时显示处理进度在窗口上(可视),同时进行日志处理等.我用的是下面的方法: [1]用到的API函数: RegisterWindowsMessage ---------------------- 函数功能:该函数定义一个新的窗口消息,该消息确保在系统中是唯一的.返