Qt event处理

一 事件来源
  1. 来源有两类:底层窗口系统;使用 QCoreApplication::sendEvent() 和 QCoreApplication::postEvent() 手动发送。

    In general, events come from the underlying window system (spontaneous() returns true), but it is also possible to manually send events using QCoreApplication::sendEvent() and QCoreApplication::postEvent() (spontaneous() returns false).

  2. 来源可以根据 QEvent::spontaneous() 判断。
二 事件基类
  • QEvent
    • QEvent 是Qt 所有事件类的基类。

Qt’s main event loop (QCoreApplication::exec()) fetches native window system events from the event queue, translates them into QEvents, and sends the translated events to QObjects.

三 事件分类
  • QEvent::Type 定义了Qt中所有的有效事件类型。例如:
    • QEvent::Close
    • QEvent::KeyPress
    • QEvent::Enter 等
  • 事件对象中包含了事件的相关参数。例如 QKeyEvent:
    • count() 事件按键数量
    • key() 事件按键码(Qt::Key)等
四 事件一般流程
  1. 首先是QCoreApplication (可能是其子类),相关函数:

    [virtual] bool QCoreApplication::notify(QObject *receiver, QEvent *event)
    
  2. 然后是QObject (receiver,可能是其子类),相关函数:

    [virtual] bool QObject::event(QEvent *e)
    
  3. 具体事件函数:

    [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
    
五 事件过滤器
  • 在一般流程的基础上,要改变事件处理的流程,给对象安装事件过滤器是常见的方法之一。

  • 事件过滤器处理顺序在对象 event() 之前。

  • 相关函数:

    // 安装事件过滤器
    void QObject::installEventFilter(QObject *filterObj)
    // 事件“过滤”
    bool QObject::eventFilter(QObject *watched, QEvent *event)
    
  • 官网例子:

class MainWindow : public QMainWindow
{
public:
    MainWindow();

protected:
    bool eventFilter(QObject *obj, QEvent *ev);

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; // 不希望该事件继续被处理,返回true;
        } else {
            return false; // 希望该事件继续被处理,返回false;
        }
    } else {
        // pass the event on to the parent class
        return QMainWindow::eventFilter(obj, event); // 否则调用基类方法
    }
}
六 事件处理的5种方式

There are five different ways that events can be processed; reimplementing this virtual function is just one of them. All five approaches are listed below:

  1. Reimplementing paintEvent(), mousePressEvent() and so on. This is the most common, easiest, and least powerful way.
  2. Reimplementing this function(QCoreApplication::notify). This is very powerful, providing complete control; but only one subclass can be active at a time.
  3. Installing an event filter on QCoreApplication::instance(). Such an event filter is able to process all events for all widgets, so it’s just as powerful as reimplementing notify(); furthermore, it’s possible to have more than one application-global event filter. Global event filters even see mouse events for disabled widgets. Note that application event filters are only called for objects that live in the main thread.
  4. Reimplementing QObject::event() (as QWidget does). If you do this you get Tab key presses, and you get to see the events before any widget-specific event filters.
  5. Installing an event filter on the object. Such an event filter gets all the events, including Tab and Shift+Tab key press events, as long as they do not change the focus widget.
  • 简述如下:
    1. 通过派生重写具体事件处理函数,例如 paintEvent(), mousePressEvent()等。
    2. 派生QApplication,重写 notify() 方法。
    3. 给进程对象QCoreApplication::instance()安装过滤器。
    4. 通过派生重写 event() 方法。
    5. 给对象安装过滤器。
  • 重写event()例子:
class MyClass : public QWidget
{
    Q_OBJECT

public:
    MyClass(QWidget *parent = 0);
    ~MyClass();

    bool event(QEvent* ev) // 重写
    {
        if (ev->type() == QEvent::PolishRequest) {
            // overwrite handling of PolishRequest if any
            doThings();
            return true;
        } else  if (ev->type() == QEvent::Show) {
            // complement handling of Show if any
            doThings2();
            QWidget::event(ev);
            return true;
        }
        // Make sure the rest of events are handled
        return QWidget::event(ev);
    }
};
七 注意点
  1. 注意 eventfilter() 、event() 等返回值的含义。true代表事件处理到此为止。

    stop it being handled further, return true; otherwise return false.

  2. 同一个对象安装了多个过滤器,最后安装的过滤器最先被触发。

    If multiple event filters are installed on a single object, the filter that was installed last is activated first.

  3. 除了要处理的事件类型,其它情况请确保调用基类相应事件函数。

    Make sure you call the parent event class implementation for all the events you did not handle.

  4. 若事件接收者对事件不感兴趣(不处理或者返回false),事件将沿着父类传播。

    For certain types of events (e.g. mouse and key events), the event will be propagated to the receiver’s parent and so on up to the top-level object if the receiver is not interested in the event (i.e., it returns false).

八 参考
  • Qt Assistant
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值