在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。
一、QT的事件发送类QCoreApplication
QT使用QCoreApplication类为Qt程序提供了事件循环机制。该类继承QObject。QCoreApplication包含主事件循环,来自操作系统的事件(例如计时器和网络事件)和其他事件都将在主事件循环中被处理和调度。
在QT的程序中,主函数一般都是这样的
int main(int argc, char *argv[])
{QApplication a(argc, argv);mainWindow w;w.show();return a.exec();
}
在QT的main函数中,第一句必须定义一个QApplication的对象。QApplication间接继承了QCoreApplication,其对象a调用的是父类QCoreApplication中的exec(),然后进入了主事件循环。
static int QCoreApplication::exec()
主事件循环的生命周期和函数exec的生命周期是相等的,如果主事件循环不退出,那么exec将永远执行,不结束
QCoreApplication中的quit()函数和exit()函数可以使主事件循环退出
static void QCoreApplication::quit()
static void QCoreApplication::exit(int returnCode = 0)
当调用上述两个函数中的任何一个后,QT应用程序的主事件循环退出,并且QT应用程序返回到调用exec的地方,同时exec函数退出并返回对应的退出码,退出码正常值是0,表示正常退出,非0值表示有错误,此外,如果没有主事件循环,那么,调用该函数将不会执行任何动作
QCoreApplication除了提供exec()、quit()和exit()外,还提供了sendEvent()立刻发送事件;postEvent()将事件发布到事件队列中,等待处理;removePostedEvents()将删除事件队列中的所有事件;也可以使用sendPostedEvents()分发事件队列中的所有事件。
1.sendEvent
static bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
sendEvent()通过notify函数立刻将事件event发送给接受者receiver。返回值由对象的实际事件处理程序决定是true or false,所以,当sendEvent()返回时,事件过滤器或对象本身的事件处理程序已经处理完该事件。sendEvent发送完事件后,并不会删除该事件。
示例
int main(int argc, char *argv[])
{QApplication a(argc, argv);mainWindow w;QPointF pos;pos.setX(100);pos.setY(100);QMouseEvent event(QEvent::MouseButtonPress, pos, Qt::NoButton, 0, 0);QApplication::sendEvent(w.gettextEdit(), &event);w.show();return a.exec();
}
可见,当运行主函数后,事件马上发送,并通过事件过滤其打印出一条log
2.postEvent
static void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
postEvent并不会立刻发送事件,而是将事件event添加到事件队列中并立即返回
当QT程序回到主事件循环时,将使用notify()函数将队列中存储的所有事件一起发送。
事件event的对象必须分配在堆上,因为事件的发送队列要在发送后把事件删除,而不能让事件的生命周期自动结束,分配在堆上可以保证事件的生命周期。
事件按优先级从高到低的顺序排序,即优先级高的事件在优先级较低的事件之前排队。优先级介于INT_MAX和INT_MIN之间;有具有相同优先级的事件将按照发布(添加)的顺序进行处理。
事件的优先级在枚举Qt::EventPriority中定义
enum EventPriority {HighEventPriority = 1,//具有此优先级的事件将在具有NormalEventPriority或LowEventPriority的事件之前发送。NormalEventPriority = 0,//具有此优先级的事件在具有HighEventPriority的事件之后但在具有LowEventPriority的事件之前发送。LowEventPriority = -1//具有高优先级的事件在具有HighEventPriority或NormalEventPriority的事件之后发送。
};
优先级示例
enum CustomEventPriority{ImportantEventPriority = Qt::HighEventPriority, // An important eventMoreImportantEventPriority = ImportantEventPriority + 1,// A more important eventCriticalEventPriority = 100 * MoreImportantEventPriority, // A critical eventStatusEventPriority = Qt::LowEventPriority,// Not that importantIdleProcessingDoneEventPriority = StatusEventPriority - 1// These are less important than Status events};
3.notify
virtual bool QCoreApplication::notify(QObject *receiver, QEvent *event)
该函数是将事件event发给接受者receiver的实际执行者,返回值由具体的事件处理程序决定,所有事件的发送最终都会调用该函数。
当某些事件发送给接受者后,如果接受者对该事件不感兴趣(比如返回值为false),那么该事件会发给接受者对象的父对象(不是基类或者父类)处理,以此类推,直至发送给位于对象树模型上的最顶层对象,也就是说,无论任何事件,一定有接收者和接收者的事件处理程序来接收,事件处理程序有可能是父类的事件处理程序或者是父对象的事件处理程序或者是本类中的重写的事件处理程序
4.removePostedEvents
static void QCoreApplication::removePostedEvents(QObject *receiver, int eventType = 0)
删除事件队列中的所有事件,不要调用这个函数!!!
5.sendPostedEvents
static void QCoreApplication::sendPostedEvents(QObject *receiver = Q_NULLPTR, int event_type = 0)
立即分派事件排队中的所有事件,如果receiver为空,则event_type事件将被发送给所有对象。如果event_type为0,则将所有事件发送给接收者。这两个参数都由默认实参,也就是说,默认情况下,调用该函数后会将事件队列中的所有事件发送给QT程序中的所有对象
注意:窗口相关的事件不是由此函数分发,而是由函数processEvents()分发
6.processEvents
static void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents)
static void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime)
这个函数有两种重载形式,第一种形式是根据ProcessEventsFlags处理调用线程中所有还没处理的事件,第二种形式是根据ProcessEventsFlags在maxtime毫秒内处理调用线程中还没处理的事件
这个函数通常可以在长时间繁忙运行的QT程序中被调用,以保持QT程序对事件的响应速度
二、QT的t事件队列接口类QAbstractEventDispatcher
QAbstractEventDispatcher类提供了管理Qt事件队列的接口,事件分配器接收事件后,将它们发送到QCoreApplication或QApplication实例进行处理。QAbstractEventDispatcher是一个纯虚基类,具体的接口实现根据操作系统而在不同的子类中实现
其中的processEvents函数形式如下
virtual bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) = 0;
该函数处理与标志匹配的未处理事件,直到没有更多事件可处理为止。 如果事件被处理,则返回true;否则,返回false。
如果在标志中设置了QEventLoop :: WaitForMoreEvents标志,则此函数的行为如下:
如果有未处理事件,则此函数在处理完事件后返回。
如果没有可用的事件,则此函数将会等待,直到有更多未处理事件为止,然后处理完新的事件后返回。
如果没有在标志中设置QEventLoop :: WaitForMoreEvents标志,并且没有未处理事件,则此函数将立即返回。
此函数不会连续处理事件; 在处理所有可获得的事件后,根据标志位看看是否需要等待新的事件或者直接返回
三、QT的事件循环类QEventLoop
QEventLoop类提供一种进入和退出事件循环的方法。
创建一个QEventLoop对象并对其调用exec()以启动事件循环。 从事件循环中,调用exit()将强制exec()返回,事件循环退出。
int QEventLoop::exec(ProcessEventsFlags flags = AllEvents)
void QEventLoop::exit(int returnCode = 0)
和QCoreApplication中的exec和exit的作用相同,因为QCoreApplication中的exec最终会创建QEventLoop对象并调用QEventLoop的exec
所以,QT的事件循环机制相关的主要类除了QObject外,还有三个,QCoreApplication负责事件的发送,QAbstractEventDispatcher负责事件队列的管理和事件队列的分发,QEventLoop负责创建事件循环
参考
https://doc.qt.io/Qt-5/qabstracteventdispatcher.html
https://doc.qt.io/Qt-5/eventsandfilters.html
https://doc.qt.io/Qt-5/qcoreapplication.html
https://doc.qt.io/Qt-5/qeventloop.html
欢迎大家评论交流,作者水平有限,如有错误,欢迎指出