本节讲解两个事件:

  • 键盘按下事件(QEvent::KeyPress)
  • 键盘释放事件(QEvent::KeyRelease)

当键盘按下和释放时,会被触发。该事件对应的子类是QKeyEvent

本节通过两个案例来讲解这 2 个事件:

  • 键盘按下、释放事件的基本使用
  • 通过键盘的上下左右键,控制标签控件的移动

本节实现的效果,如下:
122.gif

1. 基本使用

只需重写keyPressEvent()keyPressEvent()两个函数即可

首先,在 key_widget.h 中添加两个函数的声明

class KeyWidget : public QWidget {
protected:
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
};

然后,来到key_widget.cpp实现这2个函数:

void KeyWidget::keyPressEvent(QKeyEvent* event)
{  // 单键
    switch (event->key()) {
        case Qt::Key_Return: qDebug() << "Enter"; break;
        case Qt::Key_Escape: qDebug() << "Esc"; break;
        case Qt::Key_Control: qDebug() << "Ctrl"; break;
        case Qt::Key_Shift: qDebug() << "Shift"; break;
        case Qt::Key_Alt: qDebug() << "Alt"; break;
        case Qt::Key_Up: qDebug() << "Up"; break;
        case Qt::Key_Down: qDebug() << "Down"; break;
        case Qt::Key_Left: qDebug() << "Left"; break;
        case Qt::Key_Right: qDebug() << "Right"; break;
        case Qt::Key_A: qDebug() << "A"; break;
        case Qt::Key_B: qDebug() << "B"; break;
        case Qt::Key_C: qDebug() << "C"; break;
        case Qt::Key_D: qDebug() << "D"; break;
        default: break;
    }

    // 两键组合
    //    qDebug() << event->modifiers(); // QFlags<Qt::KeyboardModifier>(ShiftModifier|ControlModifier)
    if ((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_A)) {
        qDebug() << "Ctrl + A";
    }

    if ((event->modifiers() == Qt::ShiftModifier) && (event->key() == Qt::Key_C)) {
        qDebug() << "Shift + B";
    }

    if ((event->modifiers() == Qt::AltModifier) && (event->key() == Qt::Key_B)) {
        qDebug() << "ALT + C";
    }

    // 三键组合Shift + Ctrl + D 的实现
    if ((event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) && (event->key() == Qt::Key_D)) {
        qDebug() << "CTRL + Shift + D";
    }
}

void KeyWidget::keyReleaseEvent(QKeyEvent* event)
{
    switch (event->key()) {
        case Qt::Key_Return: qDebug() << "keyReleaseEvent: Enter"; break;
        case Qt::Key_Escape: qDebug() << "keyReleaseEvent: Esc"; break;
        case Qt::Key_Up: qDebug() << "keyReleaseEvent: Up"; break;
        case Qt::Key_Down: qDebug() << "keyReleaseEvent: Down"; break;
        case Qt::Key_Left: qDebug() << "keyReleaseEvent: Left"; break;
        case Qt::Key_Right: qDebug() << "keyReleaseEvent: Right"; break;
        case Qt::Key_A: qDebug() << "keyReleaseEvent: A"; break;
        case Qt::Key_B: qDebug() << "keyReleaseEvent: B"; break;
        case Qt::Key_C: qDebug() << "keyReleaseEvent: C"; break;
        case Qt::Key_D: qDebug() << "keyReleaseEvent: D"; break;
        case Qt::Key_Control: qDebug() << "keyReleaseEvent: Ctrl"; break;
        case Qt::Key_Shift: qDebug() << "keyReleaseEvent: Shift"; break;
        case Qt::Key_Alt: qDebug() << "keyReleaseEvent: Alt"; break;
    }
}

说明:

  • 每个按键对应一个枚举值,比如Qt::Key_A代表按键AQt::Key_Control 代表Crtl键,等等
  • QKeyEvent类的key()方法,可以获取当前按下的哪个按键
  • 判断Ctrl/Shift/Alt等控制按键,需要使用QKeyEvent类的modifiers()方法

最后,还需要在构造中添加如下语句:

KeyWidget::KeyWidget(QWidget* parent) : QWidget{parent}
{
    setFocusPolicy(Qt::StrongFocus);
}

此时,运行程序,可以看到打印如下:
image-20260820102856368

2. 案例:键盘移动标签

接下来,实现一个小案例:通过上下左右按键,来移动标签的位置

2.1 界面上添加标签

首先,在key_widget.h中添加成员变量:

#include <QLabel>

class KeyWidget : public QWidget {
private:
    QLabel *lbl;
};

然后,在key_widget.cpp的构造中添加一个标签:

KeyWidget::KeyWidget(QWidget* parent) : QWidget{parent}
{
    setFocusPolicy(Qt::StrongFocus);

    // 添加一个 QLabel
    lbl = new QLabel(this);
    lbl->setFrameShape(QFrame::Box);
    lbl->setFixedSize(100, 100);
    lbl->setStyleSheet("background-color: red;");
}

此时,运行效果:
image-20260820102938316

2.2 移动标签

只需修改上下左右按键的逻辑即可(当移动到尽头,则从另一端重新出现开始移动):

void KeyWidget::keyPressEvent(QKeyEvent* event)
{
    QPoint p = lbl->pos();
    int width = lbl->width();
    int height = lbl->height();

    switch (event->key()) {
        case Qt::Key_Up:
            p.setY(p.y() - 20);
            if (p.y() + height <= 0) {
                p.setY(this->height());
            }
            break;
        case Qt::Key_Down:
            p.setY(p.y() + 20);
            if (p.y() > this->height()) {
                p.setY(-height);
            }
            break;
        case Qt::Key_Left:
            p.setX(p.x() - 20);
            if (p.x() + width <= 0) {
                p.setX(this->width());
            }
            break;
        case Qt::Key_Right:
            p.setX(p.x() + 20);
            if (p.x() > this->width()) {
                p.setX(-width);
            }
            break;
    }
    lbl->move(p);
}

此时,按键盘上的上下左右箭头,效果如下:
122.gif