Events and Event Filters in Qt

Events and Event Filters

In Qt, events are objects, derived from the abstract QEvent class, that represent things that have happened either within an application or as a result of outside activity that the application needs to know about. Events can be received and handled by any instance of a QObject subclass, but they are especially relevant to widgets. This document describes how events are delivered and handled in a typical application.

How Events are Delivered

When an event occurs, Qt creates an event object to represent it by constructing an instance of the appropriate QEvent subclass, and delivers it to a particular instance of QObject (or one of its subclasses) by calling its event() function.

This function does not handle the event itself; based on the type of event delivered, it calls an event handler for that specific type of event, and sends a response based on whether the event was accepted or ignored.

Some events, such as QMouseEvent and QKeyEvent, come from the window system; some, such as QTimerEvent, come from other sources; some come from the application itself.

Event Types

Most events types have special classes, notably QResizeEventQPaintEventQMouseEventQKeyEvent, and QCloseEvent. Each class subclasses QEvent and adds event-specific functions. For example,QResizeEvent adds size() and oldSize() to enable widgets to discover how their dimensions have been changed.

Some classes support more than one actual event type. QMouseEvent supports mouse button presses, double-clicks, moves, and other related operations.

Each event has an associated type, defined in QEvent::Type, and this can be used as a convenient source of run-time type information to quickly determine which subclass a given event object was constructed from.

Since programs need to react in varied and complex ways, Qt's event delivery mechanisms are flexible. The documentation for QCoreApplication::notify() concisely tells the whole story; the Qt Quarterlyarticle Another Look at Events rehashes it less concisely. Here we will explain enough for 95% of applications.

Event Handlers

The normal way for an event to be delivered is by calling a virtual function. For example, QPaintEvent is delivered by calling QWidget::paintEvent(). This virtual function is responsible for reacting appropriately, normally by repainting the widget. If you do not perform all the necessary work in your implementation of the virtual function, you may need to call the base class's implementation.

For example, the following code handles left mouse button clicks on a custom checkbox widget while passing all other button clicks to the base QCheckBox class:

 void MyCheckBox::mousePressEvent(QMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton) {
         // handle left mouse button here
     } else {
         // pass on other buttons to base class
         QCheckBox::mousePressEvent(event);
     }
 }

If you want to replace the base class's function, you must implement everything yourself. However, if you only want to extend the base class's functionality, then you implement what you want and call the base class to obtain the default behavior for any cases you do not want to handle.

Occasionally, there isn't such an event-specific function, or the event-specific function isn't sufficient. The most common example involves Tab key presses. Normally, QWidget intercepts these to move the keyboard focus, but a few widgets need the Tab key for themselves.

These objects can reimplement QObject::event(), the general event handler, and either do their event handling before or after the usual handling, or they can replace the function completely. A very unusual widget that both interprets Tab and has an application-specific custom event might contain the following event() function:

 bool MyWidget::event(QEvent *event)
 {
     if (event->type() == QEvent::KeyPress) {
         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
         if (ke->key() == Qt::Key_Tab) {
             // special tab handling here
             return true;
         }
     } else if (event->type() == MyCustomEventType) {
         MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event);
         // custom event handling here
         return true;
     }

     return QWidget::event(event);
 }

Note that QWidget::event() is still called for all of the cases not handled, and that the return value indicates whether an event was dealt with; a true value prevents the event from being sent on to other objects.

Event Filters

Sometimes an object needs to look at, and possibly intercept, the events that are delivered to another object. For example, dialogs commonly want to filter key presses for some widgets; for example, to modify Return-key handling.

The QObject::installEventFilter() function enables this by setting up an event filter, causing a nominated filter object to receive the events for a target object in its QObject::eventFilter() function. An event filter gets to process events before the target object does, allowing it to inspect and discard the events as required. An existing event filter can be removed using the QObject::removeEventFilter() function.

When the filter object's eventFilter() implementation is called, it can accept or reject the event, and allow or deny further processing of the event. If all the event filters allow further processing of an event (by each returning false), the event is sent to the target object itself. If one of them stops processing (by returning true), the target and any later event filters do not get to see the event at all.

 bool FilterObject::eventFilter(QObject *object, QEvent *event)
 {
     if (object == target && event->type() == QEvent::KeyPress) {
         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
         if (keyEvent->key() == Qt::Key_Tab) {
             // Special tab handling
             return true;
         } else
             return false;
     }
     return false;
 }

The above code shows another way to intercept Tab key press events sent to a particular target widget. In this case, the filter handles the relevant events and returns true to stop them from being processed any further. All other events are ignored, and the filter returns false to allow them to be sent on to the target widget, via any other event filters that are installed on it.

It is also possible to filter all events for the entire application, by installing an event filter on the QApplication or QCoreApplication object. Such global event filters are called before the object-specific filters. This is very powerful, but it also slows down event delivery of every single event in the entire application; the other techniques discussed should generally be used instead.

Sending Events

Many applications want to create and send their own events. You can send events in exactly the same ways as Qt's own event loop by constructing suitable event objects and sending them withQCoreApplication::sendEvent() and QCoreApplication::postEvent().

sendEvent() processes the event immediately. When it returns, the event filters and/or the object itself have already processed the event. For many event classes there is a function called isAccepted() that tells you whether the event was accepted or rejected by the last handler that was called.

postEvent() posts the event on a queue for later dispatch. The next time Qt's main event loop runs, it dispatches all posted events, with some optimization. For example, if there are several resize events, they are are compressed into one. The same applies to paint events: QWidget::update() calls postEvent(), which eliminates flickering and increases speed by avoiding multiple repaints.

postEvent() is also used during object initialization, since the posted event will typically be dispatched very soon after the initialization of the object is complete. When implementing a widget, it is important to realise that events can be delivered very early in its lifetime so, in its constructor, be sure to initialize member variables early on, before there's any chance that it might receive an event.

To create events of a custom type, you need to define an event number, which must be greater than QEvent::User, and you may need to subclass QEvent in order to pass specific information about your custom event. See the QEvent documentation for further details.

### Laya.events.Event 枚举的定义和用法 Laya.events.Event 是 LayaAir 引擎中用于事件处理的一个核心枚举类。它主要用于定义常见的事件类型,这些事件类型可以在对象之间进行通信和交互。以下是关于 Laya.events.Event 枚举的详细信息和用法。 #### 1. 常见的事件类型 Laya.events.Event 枚举定义了一系列标准事件类型,以下是一些常用的事件名称及其含义: - **Event.MOUSE_DOWN**[^3]:鼠标按下事件。 - **Event.MOUSE_UP**[^3]:鼠标释放事件。 - **Event.CLICK**[^3]:鼠标点击事件(通常由 MOUSE_DOWN 和 MOUSE_UP 触发)。 - **Event.RIGHT_CLICK**[^3]:鼠标右键点击事件。 - **Event.MOUSE_OVER**[^3]:鼠标移入事件。 - **Event.MOUSE_OUT**[^3]:鼠标移出事件。 - **Event.CHANGE**[^3]:当对象的状态发生改变时触发的事件,例如下拉框选择值发生变化。 - **Event.ADD**[^3]:当对象被添加到显示列表时触发。 - **Event.REMOVE**[^3]:当对象从显示列表中移除时触发。 - **Event.COMPLETE**[^3]:某个操作完成时触发的事件,例如加载资源完成。 #### 2. 使用方法 在 LayaAir 中,可以通过 `on` 或 `once` 方法为对象绑定事件监听器,通过 `off` 方法解除绑定。以下是具体的使用示例: ```javascript // 创建一个 Sprite 对象 var sprite = new laya.display.Sprite(); // 绑定鼠标点击事件 sprite.on(laya.events.Event.CLICK, this, function () { console.log("Sprite 被点击了!"); }); // 模拟触发事件 sprite.event(laya.events.Event.CLICK); // 解除绑定 sprite.off(laya.events.Event.CLICK, this, null); ``` #### 3. 自定义事件 除了内置的事件类型外,还可以通过 `dispatchEvent` 方法自定义事件并触发它们。例如: ```javascript // 定义自定义事件类型 var CUSTOM_EVENT = "customEvent"; // 绑定自定义事件监听器 sprite.on(CUSTOM_EVENT, this, function (data) { console.log("自定义事件被触发,数据为:", data); }); // 触发自定义事件 sprite.dispatchEvent(new laya.events.Event(CUSTOM_EVENT, { data: "测试数据" })); ``` #### 4. 注意事项 - 在绑定事件时,确保事件类型字符串与枚举中的定义一致,否则可能无法正确触发事件。 - 如果需要传递额外的数据,可以通过 `dispatchEvent` 方法的参数实现。 - 当不再需要事件监听器时,及时调用 `off` 方法解除绑定,以避免内存泄漏。 #### 5. 示例代码 以下是一个完整的示例,展示如何使用 Laya.events.Event 枚举处理鼠标事件: ```javascript // 创建一个矩形 var rect = new laya.display.Sprite(); rect.graphics.drawRect(0, 0, 100, 100, "#FF0000"); rect.pos(100, 100); // 添加到舞台 laya.stage.addChild(rect); // 绑定鼠标事件 rect.on(laya.events.Event.MOUSE_DOWN, this, function () { console.log("鼠标按下"); }); rect.on(laya.events.Event.MOUSE_UP, this, function () { console.log("鼠标释放"); }); rect.on(laya.events.Event.CLICK, this, function () { console.log("点击矩形"); }); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值