Qt 自定义事件

自定义事件类型

Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展。在 Qt 中,你需要继承的类是 QEvent。
继承QEvent类,你需要提供一个QEvent::Type类型的参数,作为自定义事件的类型值。QEvent::Type类型是QEvent里面定义的一个enum,
自定义事件类型不能和已经存在的type值重复,否则会有不可预料的错误发生!因为系统会将你的事件当做系统事件进行派发和调用。在Qt中,系统将保留0- 999的值,也就是说,你的事件type要大于999. 具体来说,你的自定义事件的type要在QEvent::User和QEvent::MaxUser的范围之间。其中,QEvent::User值是1000,QEvent::MaxUser的值是65535。
为了保证自定义事件之间不会被覆盖,Qt提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名如下:函数是线程安全的,因此不必另外添加同步

static int QEvent::registerEventType ( int hint = -1 );
事件发送

第一种

static bool QCoreApplication::sendEvent(QObjecy * receiver, QEvent * event)

事件被QCoreApplication的notify()函数直接发送给receiver对象,返回值是事件处理函数的返回值。使用这个函数必须要在栈上创建对象,例如:

QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0); QApplication::sendEvent(mainWindow, &event);

第二种

static bool QCoreApplication::postEvent(QObject * receiver, QEvent * event)

事件被QCoreApplication追加到事件列表的最后,并等待处理,该函数将事件追加后会立即返回,并且注意,该函数是线程安全的。另外一点是,使用这个函数必须要在堆上创建对象,例如:

QApplication::postEvent(object, new MyEvent(QEvent::registerEventType(2048)));

这个对象不需要手动delete,Qt会自动delete掉!因此,如果在post事件之后调用delete,程序可能会崩溃。
二者区别

sendEvent:是同步执行,它一发送,就会通过notify直接执行相关事件,并且它是在栈区创建。
postEvent:是异步执行,它一发送,事件就会通过主线程的QEventLoop把它从输入事件队列queuedSocketEvents加到执行事件队列,然后按照顺序执行,并且它在堆区创建。

事件接收

如果要处理自定义事件,可以重写QObject的customEvent()函数,该函数接收一个QEvent对象作为参数。注意,在Qt3中这个参数是QCustomEvent类型的。

void CustomWidget::customEvent(QEvent *event) { CustomEvent *customEvent = static_cast<CustomEvent *>(event); // .... }

也可以通过重写event()函数来处理自定义事件:

bool CustomWidget::event(QEvent *event) 
{ 
	if (event->type() == MyCustomEventType) 
	{ 
		CustomEvent *myEvent = static_cast<CustomEvent *>(event); // processing... 
		return  true; 
	} 
		return QWidget::event(event);
	 }
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QEvent>
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>
#include <QComboBox>
#include <QLineEdit>
#include <QTextEdit>

class Widget : public QWidget
{
    Q_OBJECT

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

protected:
    void customEvent(QEvent *event);
    bool eventFilter(QObject *obj, QEvent *event);
private slots:
    void slotsystem();
    void slotusr();
private:
    QLabel* m_systemlab;
    QLabel* m_userlab;
    QPushButton* m_systembtn;
    QPushButton* m_userbtn;
    QComboBox* m_systembox;
    QLineEdit* m_useredit;
    QTextEdit* m_textedit;
};

//定义自定义事件ID
const int userId = QEvent::User;
const int MyEventId = userId+6;

//继承QEvent创建自定义事件类,注意初始化向量表时需要初始化事件ID。
class MyEvent :public QEvent
{
public:
    MyEvent(QObject*parent,QString val);
    QString m_val;
    QObject* m_parent;
};

#endif // WIDGET_H

#include "widget.h"
#include <QApplication>
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    m_systemlab = new QLabel("系统事件:",this);
    m_userlab = new QLabel("用户事件:",this);
    m_systembox = new QComboBox(this);
    m_useredit = new QLineEdit("0",this);
    m_systembtn = new QPushButton("发送",this);
    m_userbtn = new QPushButton("发送",this);
    m_textedit = new QTextEdit(this);

    m_systembox->addItems(QStringList()<<"Hide"<<"Show"<<"Close");

    QGridLayout* lay = new QGridLayout(this);
    lay->addWidget(m_systemlab,0,0,1,1);
    lay->addWidget(m_systembox,0,1,1,1);
    lay->addWidget(m_systembtn,0,2,1,1);
    lay->addWidget(m_userlab,1,0,1,1);
    lay->addWidget(m_useredit,1,1,1,1);
    lay->addWidget(m_userbtn,1,2,1,1);
    lay->addWidget(m_textedit,2,0,5,3);
    this->setLayout(lay);

    this->installEventFilter(this);
    connect(m_systembtn,SIGNAL(clicked()),this,SLOT(slotsystem()));
    connect(m_userbtn,SIGNAL(clicked()),this,SLOT(slotusr()));
}

Widget::~Widget()
{
}

//发送系统事件
void Widget::slotsystem()
{
#if 1
    //1
    if (m_systembox->currentText() == "Hide")
    {
    QEvent *e = new QEvent(QEvent::Hide);
    QApplication::postEvent(this,e);
    }
    else if(m_systembox->currentText() == "Show")
    {
        QEvent *e = new QEvent(QEvent::Show);
        QApplication::postEvent(this,e);
    }
    else if(m_systembox->currentText() == "Close")
    {
        QEvent *e = new QEvent(QEvent::Close);
        QApplication::postEvent(this,e);
    }
#else
    //2
    if (m_systembox->currentText() == "Hide")
    {
        QEvent e(QEvent::Hide);
        QApplication::sendEvent(this,&e);
    }
    else if (m_systembox->currentText() == "Show")
    {
        QEvent e(QEvent::Show);
        QApplication::sendEvent(this,&e);
    }
    else if (m_systembox->currentText() == "Close")
    {
        QEvent e(QEvent::Close);
        QApplication::sendEvent(this,&e);
    }
#endif
}

//发送自定义事件
void Widget::slotusr()
{
#if 0
    //1
    MyEvent* myevent = new MyEvent(this,m_useredit->text());
    QApplication::postEvent(this,myevent);
#else
    //2
    MyEvent myevent(this,m_useredit->text());
    QApplication::sendEvent(this,&myevent);
#endif
}

//只能接收自定义事件
void Widget::customEvent(QEvent *event)
{
    if (event->type() == MyEventId)
    {
        MyEvent* e = dynamic_cast<MyEvent*>(event);
        if (e)
        {
            m_textedit->append("customEvent接收事件:自定义事件:参数:"+e->m_val);
        }
    }
    return QWidget::customEvent(event);
}

//接收自定义事件和系统事件
bool Widget::eventFilter(QObject* obj,QEvent* event)
{
    if (event->type() == QEvent::Hide)
    {
        m_textedit->append("eventFilter接收事件:系统事件:参数:Hide");
    }
    else if (event->type() == QEvent::Show)
    {
        m_textedit->append("eventFilter接收事件:系统事件:参数:Show");
    }
    else if (event->type() == QEvent::Close)
    {
        m_textedit->append("eventFilter接收事件:系统事件:参数:Close");
    }
    if (event->type() == MyEventId)
    {
        MyEvent* e = dynamic_cast<MyEvent*>(event);
        if (e)
        {
            m_textedit->append("eventFilter接收事件:自定义事件:参数:"+e->m_val);
        }
    }
}

//--------------------------MyEvent-----注意初始化向量表时需要初始化事件ID。
MyEvent::MyEvent(QObject *parent, QString val)
    :QEvent(QEvent::Type(MyEventId)),m_parent(parent),m_val(val)
{

}

文章出处

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值