Qt 事件系统 #

事件系统概述 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Qt 事件处理流程                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   事件源                                                    │
│   ├── 用户输入(鼠标、键盘)                                 │
│   ├── 系统事件(定时器、窗口)                               │
│   └── 自定义事件                                            │
│         │                                                   │
│         ▼                                                   │
│   ┌─────────────┐                                          │
│   │  事件循环    │  QCoreApplication::exec()                │
│   │ (Event Loop)│                                          │
│   └──────┬──────┘                                          │
│          │                                                  │
│          ▼                                                  │
│   ┌─────────────┐                                          │
│   │  事件分发    │  QCoreApplication::notify()              │
│   └──────┬──────┘                                          │
│          │                                                  │
│          ▼                                                  │
│   ┌─────────────┐                                          │
│   │  事件处理    │  QWidget::event()                       │
│   └─────────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

事件类型 #

常见事件类型 #

cpp
// 常见事件类型
QEvent::MouseButtonPress    // 鼠标按下
QEvent::MouseButtonRelease  // 鼠标释放
QEvent::MouseMove           // 鼠标移动
QEvent::MouseButtonDblClick // 鼠标双击
QEvent::Wheel               // 鼠标滚轮

QEvent::KeyPress            // 键盘按下
QEvent::KeyRelease          // 键盘释放
QEvent::Shortcut            // 快捷键

QEvent::Resize              // 大小改变
QEvent::Move                // 位置移动
QEvent::Show                // 显示
QEvent::Hide                // 隐藏
QEvent::Close               // 关闭
QEvent::Paint               // 绘制

QEvent::FocusIn             // 获得焦点
QEvent::FocusOut            // 失去焦点

QEvent::Enter               // 鼠标进入
QEvent::Leave               // 鼠标离开

QEvent::Timer               // 定时器
QEvent::User                // 用户自定义事件

事件处理 #

重写事件处理函数 #

cpp
class MyWidget : public QWidget
{
    Q_OBJECT
protected:
    // 重写 event 函数
    bool event(QEvent *event) override
    {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            if (keyEvent->key() == Qt::Key_Escape) {
                // 处理 Escape 键
                return true;  // 事件已处理
            }
        }
        return QWidget::event(event);  // 调用父类处理
    }

    // 重写具体事件处理函数
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            qDebug() << "Left button pressed at" << event->pos();
        }
        QWidget::mousePressEvent(event);
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        qDebug() << "Mouse released";
        QWidget::mouseReleaseEvent(event);
    }

    void mouseMoveEvent(QMouseEvent *event) override
    {
        qDebug() << "Mouse moved to" << event->pos();
        QWidget::mouseMoveEvent(event);
    }

    void keyPressEvent(QKeyEvent *event) override
    {
        switch (event->key()) {
        case Qt::Key_Up:
            qDebug() << "Up arrow pressed";
            break;
        case Qt::Key_Down:
            qDebug() << "Down arrow pressed";
            break;
        default:
            QWidget::keyPressEvent(event);
        }
    }

    void keyReleaseEvent(QKeyEvent *event) override
    {
        qDebug() << "Key released:" << event->key();
        QWidget::keyReleaseEvent(event);
    }

    void paintEvent(QPaintEvent *event) override
    {
        QPainter painter(this);
        painter.fillRect(rect(), Qt::white);
        painter.drawText(rect(), Qt::AlignCenter, "Hello Qt");
    }

    void resizeEvent(QResizeEvent *event) override
    {
        qDebug() << "New size:" << event->size();
        QWidget::resizeEvent(event);
    }

    void closeEvent(QCloseEvent *event) override
    {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::question(this, "Confirm",
            "Are you sure you want to quit?",
            QMessageBox::Yes | QMessageBox::No);
        
        if (reply == QMessageBox::Yes) {
            event->accept();
        } else {
            event->ignore();
        }
    }

    void enterEvent(QEnterEvent *event) override
    {
        qDebug() << "Mouse entered";
        QWidget::enterEvent(event);
    }

    void leaveEvent(QEvent *event) override
    {
        qDebug() << "Mouse left";
        QWidget::leaveEvent(event);
    }

    void focusInEvent(QFocusEvent *event) override
    {
        qDebug() << "Got focus";
        QWidget::focusInEvent(event);
    }

    void focusOutEvent(QFocusEvent *event) override
    {
        qDebug() << "Lost focus";
        QWidget::focusOutEvent(event);
    }

    void wheelEvent(QWheelEvent *event) override
    {
        qDebug() << "Wheel delta:" << event->angleDelta();
        QWidget::wheelEvent(event);
    }
};

鼠标事件详解 #

cpp
void MyWidget::mousePressEvent(QMouseEvent *event)
{
    // 获取按钮
    Qt::MouseButton button = event->button();
    if (button == Qt::LeftButton) {
        qDebug() << "Left button";
    } else if (button == Qt::RightButton) {
        qDebug() << "Right button";
    } else if (button == Qt::MiddleButton) {
        qDebug() << "Middle button";
    }

    // 获取同时按下的按钮
    Qt::MouseButtons buttons = event->buttons();
    if (buttons & Qt::LeftButton && buttons & Qt::RightButton) {
        qDebug() << "Both left and right buttons";
    }

    // 获取位置
    QPoint pos = event->pos();        // 相对于控件的坐标
    QPoint globalPos = event->globalPosition().toPoint();  // 全局坐标

    // 获取修饰键
    Qt::KeyboardModifiers modifiers = event->modifiers();
    if (modifiers & Qt::ControlModifier) {
        qDebug() << "Ctrl is pressed";
    }
    if (modifiers & Qt::ShiftModifier) {
        qDebug() << "Shift is pressed";
    }
}

键盘事件详解 #

cpp
void MyWidget::keyPressEvent(QKeyEvent *event)
{
    // 获取按键
    int key = event->key();
    
    // 常用按键判断
    switch (key) {
    case Qt::Key_Return:
    case Qt::Key_Enter:
        qDebug() << "Enter pressed";
        break;
    case Qt::Key_Escape:
        qDebug() << "Escape pressed";
        break;
    case Qt::Key_Tab:
        qDebug() << "Tab pressed";
        break;
    case Qt::Key_Backspace:
        qDebug() << "Backspace pressed";
        break;
    case Qt::Key_Delete:
        qDebug() << "Delete pressed";
        break;
    case Qt::Key_Space:
        qDebug() << "Space pressed";
        break;
    default:
        if (key >= Qt::Key_A && key <= Qt::Key_Z) {
            qDebug() << "Letter:" << QChar(key);
        }
    }

    // 获取文本
    QString text = event->text();

    // 获取修饰键
    Qt::KeyboardModifiers modifiers = event->modifiers();
    if (modifiers & Qt::ControlModifier) {
        qDebug() << "Ctrl+" << key;
    }
    if (modifiers & Qt::AltModifier) {
        qDebug() << "Alt+" << key;
    }

    // 判断是否自动重复
    if (event->isAutoRepeat()) {
        qDebug() << "Key auto repeat";
    }
}

事件过滤器 #

安装事件过滤器 #

cpp
class MyWidget : public QWidget
{
    Q_OBJECT
public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        // 为自己安装事件过滤器
        installEventFilter(this);
        
        // 为子控件安装事件过滤器
        QPushButton *button = new QPushButton("Click", this);
        button->installEventFilter(this);
    }

protected:
    bool eventFilter(QObject *watched, QEvent *event) override
    {
        if (watched == this) {
            if (event->type() == QEvent::KeyPress) {
                QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
                qDebug() << "Widget key press:" << keyEvent->key();
                return true;  // 事件已处理
            }
        }
        
        if (watched == button) {
            if (event->type() == QEvent::MouseButtonPress) {
                qDebug() << "Button mouse press intercepted";
                return true;  // 阻止事件传递
            }
        }
        
        return QWidget::eventFilter(watched, event);
    }

private:
    QPushButton *button;
};

应用级事件过滤器 #

cpp
class MyApplication : public QApplication
{
    Q_OBJECT
public:
    MyApplication(int &argc, char **argv) : QApplication(argc, argv) {}

protected:
    bool notify(QObject *receiver, QEvent *event) override
    {
        // 全局事件拦截
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            qDebug() << "Global key press:" << keyEvent->key();
        }
        
        return QApplication::notify(receiver, event);
    }
};

自定义事件 #

定义自定义事件 #

cpp
// 自定义事件类型
const QEvent::Type MyEventType = static_cast<QEvent::Type>(QEvent::User + 1);

class MyEvent : public QEvent
{
public:
    MyEvent(int value) : QEvent(MyEventType), m_value(value) {}
    
    int value() const { return m_value; }

private:
    int m_value;
};

发送自定义事件 #

cpp
// 发送事件(同步)
MyEvent event(42);
QCoreApplication::sendEvent(receiver, &event);

// 发送事件(异步)
MyEvent *event = new MyEvent(42);
QCoreApplication::postEvent(receiver, event);

处理自定义事件 #

cpp
class MyWidget : public QWidget
{
    Q_OBJECT
protected:
    bool event(QEvent *event) override
    {
        if (event->type() == MyEventType) {
            MyEvent *myEvent = static_cast<MyEvent*>(event);
            qDebug() << "Custom event received:" << myEvent->value();
            return true;
        }
        return QWidget::event(event);
    }
};

事件接受与忽略 #

cpp
void MyWidget::mousePressEvent(QMouseEvent *event)
{
    // 接受事件(默认行为)
    event->accept();
    
    // 忽略事件(传递给父控件)
    event->ignore();
}

void MyWidget::closeEvent(QCloseEvent *event)
{
    if (hasUnsavedChanges()) {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::question(this, "Save",
            "Save changes before closing?",
            QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        
        switch (reply) {
        case QMessageBox::Save:
            saveChanges();
            event->accept();
            break;
        case QMessageBox::Discard:
            event->accept();
            break;
        case QMessageBox::Cancel:
            event->ignore();
            break;
        }
    } else {
        event->accept();
    }
}

事件传递链 #

text
┌─────────────────────────────────────────────────────────────┐
│                    事件传递链                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   1. 事件产生                                              │
│      │                                                      │
│      ▼                                                      │
│   2. QCoreApplication::notify()                             │
│      │                                                      │
│      ▼                                                      │
│   3. 应用级事件过滤器                                       │
│      │                                                      │
│      ▼                                                      │
│   4. 窗口级事件过滤器                                       │
│      │                                                      │
│      ▼                                                      │
│   5. 控件的 event() 函数                                    │
│      │                                                      │
│      ├── 返回 true → 事件处理完成                           │
│      │                                                      │
│      └── 返回 false → 继续传递                              │
│           │                                                 │
│           ▼                                                 │
│      6. 父控件的 event() 函数                               │
│           │                                                 │
│           └── 继续向上传递直到顶层                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

现在你已经掌握了事件系统,接下来学习 定时器,了解 Qt 的定时任务处理!

最后更新:2026-03-29