最近,项目需要统一界面风格样式,自定义UI界面,或多或少会用到Qt事件系统,进一步了解以后你会发现跟MFC、wxWidgets这些前端界面框架的事件机制有些相似,甚至Qt同样可以完全使用Qt事件系统(实际上还不够完善,还有很多控件事件没有定义,需要为人为自定义)。说到事件,必然要说到Qt的信号与槽,信号与槽是Qt的核心机制,本质是回调技术的替代方案。
Qt的主事件循环(QCoreApplication::exec())从事件队列中获取平台窗口系统事件,将它们转换为qevent,并将转换后的事件发送给qobject。一般来说,事件来自底层窗口系统(),但是也可以使用QCoreApplication::sendEvent()和QCoreApplication::postEvent() 手动发送事件。针对事件发生起源可以分为来自应用程序内部和来自底层窗口系统的 由spontaneous()表示,由主函数main中的主事件循环捕获的则返回true,否则返回false。QObjects(大家都知道Qt大部分类都继承了QObject类)通过调用其QObject::event()函数来接收事件,该函数可以在子类中重新实现,以自定义事件处理并添加其他事件类型;QWidget::event()就是一个典型的例子。默认情况下,事件被分派到事件处理程序,如QObject::timerEvent()和QWidget::mouseMoveEvent(),当在子类重载QObject::event()函数,这类已经实现的事件处理都失效了,需要在QObject::event()中重新定义。QObject::installEventFilter()允许一个对象拦截指向另一个对象的事件。
(1) 事件发送 - 接收 类型,屏蔽所有已实现的事件 bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)使用notify()函数将事件直接发送到receiver。返回从事件处理程序返回的值。事件发送后,该事件不会被删除。一般直接在堆栈上创建事件 (同步方式)
//事件发送
QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);
//事件接收
重载QObject::event(QEvent *e);在此函数中定义事件处理
void QCoreApplication::postEvent(QObject*receiver, QEvent *event, int priority = Qt::NormalEventPriority)该事件为异步方式,事件必须在堆上分配,因为post事件队列将获得事件的所有权,并在发布事件后删除它。在发布事件之后访问该事件是不安全的。当控制返回到主事件循环QCoreApplication::exec()时,存储在队列中的所有事件将使用notify()函数发送。以下为Qt提供的可拓展事件类型的id值 查找已有的事件类型可通过QEvent::Type::MouseButtonDblClick 枚举类型查找
Constant | Value | Description |
---|---|---|
QEvent::User | 1000 | User-defined event. |
QEvent::MaxUser | 65535 | Last user event ID. |
自定义事件 可利用int QEvent::registerEventType(int hint = -1)来为应用程序注册事件。个人不太建议用此方法,因为这将屏蔽掉已实现的事件,比如双击事件,单击事件等。
(2) 事件筛选器 eventFilter
事件过滤器是接收发送给自己的所有事件的对象,属于接收者。筛选器可以过滤(停止)事件继续传递(子窗口)或将其转发给自己。事件过滤器通过其eventFilter()函数接收事件。如果事件应该被过滤,(即停止),eventFilter()函数必须返回true,;否则它必须返回false。注意,过滤对象必须与此对象在同一个线程中。如果事件过滤对象在不同的线程中,这个函数什么也不做。如果filterObj或此对象在调用此函数后移动到不同的线程,则不会调用事件筛选器,直到这两个对象再次具有相同的线程相关性(它不会被删除)。关于事件筛选器的理解: 某个界面需要重定义某一事件的功能,则一般由父窗口为其安装事件筛选器,即该界面作为事件筛选对象,最后利用eventFilter()函数处理事件。具体用法如下:
class MainWindow : public QMainWindow
{
public:
MainWindow();
protected:
bool eventFilter(QObject *obj, QEvent *ev) override;
private:
QTextEdit *textEdit;
};
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget(textEdit);
textEdit->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == textEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
qDebug() << "Ate key press" << keyEvent->key();
return true;
} else {
return false;
}
} else {
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
}
}
警告:如果删除了eventFilter()函数中的receiver对象,请确保返回true。如果你返回false, Qt发送事件给被删除的对象,程序将崩溃。