Qt event system: keyboard events

1. Introduction

The QKeyEvent class is used to describe a keyboard event. When a keyboard key is pressed or released, keyboard events are sent to the widget that has the keyboard input focus.

The key() function of QKeyEvent can get the specific key. For all the given keys in Qt, you can check the Qt: :Key keyword in the help. It should be noted that the Enter key here is Qt::Key_Return; some modifier keys on the keyboard, such as Ctrl and Shift, etc., need to be obtained by using the modifiers() function of QKeyEvent, and you can use Qt:: in the help KeyboardModifier keyword to see all modifier keys.

QKeyEvent has two keyboard event member functions, which are declared in the header file.h:

#include <QKeyEvent>

protected:
    void keyPressEvent(QKeyEvent *event); //键盘按下事件
    void keyReleaseEvent(QKeyEvent *event); //键盘松开事件

2. Common operations

Here are some common operations:

// 键盘按下事件
void Widget::keyPressEvent(QKeyEvent * event)
{
    // 普通键
    switch (event->key())
    {
        // ESC键
        case Qt::Key_Escape:
            qDebug() <<"ESC";
        break;
        // 回车键
        case Qt::Key_Return:
            qDebug() <<"Enter";
        break;
        // F1键
        case Qt::Key_F1:
            qDebug() <<"F1";
        break;
    }

    // 两键组合
    if(event->modifiers() == Qt::ControlModifier) { // 如果按下了CTRL键
        if(event->key() == Qt::Key_M){
           qDebug()<<"CTRL + M";
        }
    }

    if(event->modifiers() == Qt::AltModifier) { // 如果按下了ALT键
       if(event->key() == Qt::Key_M)
           qDebug()<<"ALT + M";
    }

    if(event->modifiers() == Qt::ShiftModifier){ // 如果按下了Shift键
           if(event->key() == Qt::Key_M)
               qDebug()<<"Shift + M";
    }

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

// 键盘释放事件
void Widget::keyReleaseEvent(QKeyEvent *event)
{
    // 方向UP键
    if(event->key() == Qt::Key_Up)
    {
        qDebug() << "release: "<< "up";
    }
}

Press ESC, Enter, CTRL + M, ALT + M and other keys respectively, and the output of the "Application Output" window is as follows:

ESC
Enter
CTRL + M
ALT + M
release:  up

The following figure lists all modifier keys:

 

3. Button and auto-repeat

Auto-repeat means that when a key on the keyboard (except the modifier key) is pressed and held, the key press event will be sent repeatedly. Qt defaults to enabling auto-repeat. To implement shortcut keys such as keys A+D , you need to turn off auto-repeat. Auto-repeat can be turned off using the following methods:

// 若自动重复则什么也不做
if(QKeyEvent::isAutoRepeat()) 
    return;

The overall performance of Qt's keyboard events is that when a key is pressed:
1. KeyPressEvent() is triggered for the first time, and isAutoRepeat() returns false

2. KeyReleaseEvent() is not triggered, pause for a while

3. Trigger keyPressEvent() again, and isAutoRepeat() returns true

4. Trigger keyReleaseEvent()

5. If the button is not released, isAutoRepeat() returns true and returns to step 3; if the button is released, isAutoRepeat() returns false

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓

4. Keyboard Capture

You can specify only a certain control in the window to capture keyboard events, so that other controls cannot obtain keyboard events, as shown below.

MyButton.h:

#ifndef MYBUTTON_H
#define MYBUTTON_H

#include <QWidget>
#include <QPushButton>
#include <QKeyEvent>
#include <QDebug>

class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);

protected:
    void keyPressEvent(QKeyEvent *event);
};

#endif // MYBUTTON_H

MyButton.cpp

#include "MyButton.h"

MyButton::MyButton(QWidget *parent) : QPushButton(parent)
{

}

void MyButton::keyPressEvent(QKeyEvent *event)
{
    qDebug() << "button键盘按键事件:" << this->objectName();
    QWidget *ww = keyboardGrabber(); // 返回正在捕获键盘输入的部件,若没有则返回 0
    qDebug() << "正在捕获的控件:" << ww;

    if(event->key() == Qt::Key_Q) {
        qDebug() << "按下了Q键";
        this->releaseKeyboard();   // 释放捕获的键盘输入
     }
}

Widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QKeyEvent>
#include "MyButton.h"

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);

protected:
    void keyPressEvent(QKeyEvent *event);

private:
    MyButton* m_pBtn1;
    MyButton* m_pBtn2;
};
#endif // WIDGET_H

Widget.cpp:

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->resize(300,400);

    // 初始化按钮1
    m_pBtn1=new MyButton();
    m_pBtn1->setParent(this);
    m_pBtn1->setText("AAA");
    m_pBtn1->move(10,10);
    m_pBtn1->resize(100,100);
    m_pBtn1->setObjectName("aaa");
    // 初始化按钮2
    m_pBtn2=new MyButton();
    m_pBtn2->setParent(this);
    m_pBtn2->setText("BBB");
    m_pBtn2->move(150,10);
    m_pBtn2->resize(100,100);
    m_pBtn2->setObjectName("bbb");

    // 指定控件捕获键盘
    m_pBtn1->grabKeyboard();
    /*使按钮 AAA 捕获键盘,此时产生的键盘事件都只会发送给按钮 AAA,也就是说
        其他部件无法获得键盘事件。
        只有可见的部件才能捕获键盘输入,若 isVisible()返回 false,则该部件不能调用grabKeyboard()函数
    */
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    Q_UNUSED(event);

    qDebug()<<"Widget发生键盘事件";
}

Press any key and find that only button AAA can get keyboard events, and button BBB cannot get keyboard events.

5. Keyboard button click, double click

First of all, QTimer is used for single-click and double-click implementation of keyboard buttons. When it comes to this, most people probably know what's going on, but there is also a misunderstanding here, that is, how to distinguish between single-click and double-click. The time interval between two key presses is used here to distinguish . It is possible to implement it in the press or release. Here I finally choose to implement it in the release, and I will talk about the reason later.

Several related variables are defined in the header file:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QKeyEvent>
#include <QTimer>
#include <QDebug>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);

protected:
    void keyReleaseEvent(QKeyEvent *event);

private:
    QTimer* m_pTimer; // Ctrl双击定时器
    int m_nClickCnt = 0; // 点击次数
    bool m_bLongPress = false; // 是否为长按    
};
#endif // WIDGET_H

Look at the keyboard button click, double-click implementation:

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 定时器
    m_pTimer = new QTimer(this);
    connect(m_pTimer, &QTimer::timeout, [=]{
        m_nClickCnt = 0; // 计数清零
        m_pTimer->stop(); // 停止计时
        qDebug() << "键盘单击";
    });
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    Q_UNUSED(event);

    if(event->key() == Qt::Key_A) {
        // 计数期间,如果QTimer已开始,则不重新开始
        if(!m_pTimer->isActive())
            m_pTimer->start(500); // 500ms是判断双击的时间间隔,不唯一,可根据实际情况改变

        m_nClickCnt++; // 点击计数,在500ms内如果点击两次认为是双击
        if(m_nClickCnt >= 2) {
            m_nClickCnt = 0; // 计数清零
            m_pTimer->stop(); // 停止计时
            qDebug() << "键盘双击";
        }
    }
}

Click , and the number of double-clicks is not reached within 500ms, that is, timer_->stop() is not executed; when the time is exhausted, the timeout signal is triggered, and the click action is executed. Let me mention the stop() function here. After QTimer executes start(n), if it does not stop(), it will execute in a loop.

6. Long press the keyboard button

So far, the keyboard click and double-click reuse has been realized, so let's take a look at how to deal with the long press?

In order to distinguish whether it is a long press, QKeyEvent provides an isAutoRepeat() function to automatically detect whether the key is long pressed

  • Long press to return true
  • Non-long press returns false

As mentioned earlier, the distinction between single-click and double-click can be used in void keyPressEvent(QKeyEvent *event) and void keyReleaseEvent(QKeyEvent *event) functions. Anyway, there is a difference between the recording time and press-press or release-release. Why choose to implement it in the button release function?

The problem is that the long press function has to be implemented at the same time. I just analyzed that whether you press long press or not long press, the first press action is a non-long press. If it is in void keyPressEvent(QKeyEvent *event) Realized, the long press will inevitably add an additional click, which is of course not what we want;

Now that the analysis is over, I think it's time for us to start writing code.

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 定时器
    m_pTimer = new QTimer(this);
    connect(m_pTimer, &QTimer::timeout, [=]{
        m_nClickCnt = 0; // 计数清零
        m_pTimer->stop(); // 停止计时
        qDebug() << "键盘单击";
    });
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    Q_UNUSED(event);

    if(event->key() == Qt::Key_A) { // Qt::Key_Control经实测,长按永远不会使isAutoRepeat()为true
        // 是否是长按可以从release中直接判断
        if (!event->isAutoRepeat()) {
            // LongPress_初始值为false,如果非长按执行单击或双击动作判断
            // 如果长按会在长按里将其置true,在最后的Relese(非长按)里就不会执行单击、双击判断的动作
            if (!m_bLongPress) {
                if (!m_pTimer->isActive()) {
                    m_pTimer->start(500);
                }
                m_nClickCnt++;
                if (m_nClickCnt == 2){
                    m_nClickCnt = 0; // 计数清零
                    m_pTimer->stop(); // 停止计时
                    qDebug() << "键盘双击";
                }
            }
            m_bLongPress = false; // 置false
        }
        else{
            if (!m_bLongPress) {
                qDebug() << "键盘长按";
                // 限定长按只执行一次,最后会在Relese(非长按)里将LongPress_重新置false
                m_bLongPress = true;
            }
        }
    }
}

The benefits of this article, free to receive Qt development learning materials package, technical video, including (C++ language foundation, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project combat, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click on the bottom of the article to receive the fee↓↓ 

 

Guess you like

Origin blog.csdn.net/QtCompany/article/details/131743524