自定义事件类型
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)
{
}