Sistema de eventos Qt: eventos de teclado

1. Introdução

A classe QKeyEvent é usada para descrever um evento de teclado. Quando uma tecla do teclado é pressionada ou liberada, os eventos do teclado são enviados para o widget que tem o foco de entrada do teclado.

A função key() de QKeyEvent pode obter a chave específica. Para todas as chaves fornecidas no Qt, você pode verificar a palavra-chave Qt: :Key na ajuda. Deve-se notar que a tecla Enter aqui é Qt::Key_Return; algumas teclas modificadoras no teclado, como Ctrl e Shift, etc., precisam ser obtidas usando a função modifiers() de QKeyEvent, e você pode usar Qt :: na palavra-chave KeyboardModifier da ajuda para ver todas as teclas modificadoras.

QKeyEvent tem duas funções de membro de evento de teclado, que são declaradas no arquivo de cabeçalho.h:

#include <QKeyEvent>

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

2. Operações comuns

Aqui estão algumas operações comuns:

// 键盘按下事件
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";
    }
}

Pressione ESC, Enter, CTRL + M, ALT + M e outras teclas, respectivamente, e a saída da janela "Saída do aplicativo" é a seguinte:

ESC
Enter
CTRL + M
ALT + M
release:  up

A figura a seguir lista todas as teclas modificadoras:

 

3. Botão e repetição automática

Repetição automática significa que quando uma tecla no teclado (exceto a tecla modificadora) é pressionada e mantida, o evento de pressionamento de tecla será enviado repetidamente. O padrão do Qt é ativar a repetição automática. Para implementar teclas de atalho como as teclas A+D , você precisa desativar a repetição automática. A repetição automática pode ser desativada usando os seguintes métodos:

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

O desempenho geral dos eventos de teclado do Qt é quando uma tecla é pressionada:
1. KeyPressEvent() é acionado pela primeira vez e isAutoRepeat() retorna false

2. KeyReleaseEvent() não é acionado, pare um pouco

3. Acione keyPressEvent() novamente e isAutoRepeat() retornará verdadeiro

4. Acionar keyReleaseEvent()

5. Se o botão não for liberado, isAutoRepeat() retornará verdadeiro e retornará à etapa 3; se o botão for liberado, isAutoRepeat() retornará falso

Os benefícios deste artigo, grátis para receber o pacote de materiais de aprendizado de desenvolvimento Qt, vídeo técnico, incluindo (base da linguagem C++, introdução à programação Qt, sinal QT e mecanismo de slot, desenho de imagem de desenvolvimento de interface QT, rede QT, programação de banco de dados QT, QT combate do projeto, QSS, OpenCV, módulo rápido, perguntas da entrevista, etc.) ↓↓↓↓↓↓Veja abaixo↓↓Clique na parte inferior do artigo para receber a taxa↓↓

4. Captura de teclado

Você pode especificar apenas um determinado controle na janela para capturar eventos de teclado, para que outros controles não possam obter eventos de teclado, conforme mostrado abaixo.

MeuBotão.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

MeuBotão.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发生键盘事件";
}

Pressione qualquer tecla e descubra que apenas o botão AAA pode obter eventos de teclado e o botão BBB não pode obter eventos de teclado.

5. Clique no botão do teclado, clique duas vezes

Em primeiro lugar, o QTimer é usado para implementação de clique único e clique duplo dos botões do teclado. Quando se trata disso, a maioria das pessoas provavelmente sabe o que está acontecendo, mas também há um mal-entendido aqui, ou seja, como distinguir entre -clique e clique duas vezes. O intervalo de tempo entre dois pressionamentos de tecla é usado aqui para distinguir . É possível implementá-lo no press ou release. Aqui, finalmente, escolho implementá-lo no release e falarei sobre o motivo mais tarde.

Várias variáveis ​​relacionadas são definidas no arquivo de cabeçalho:

#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

Observe o clique do botão do teclado, a implementação de clique duplo:

#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() << "键盘双击";
        }
    }
}

Clique , e o número de cliques duplos não é atingido em 500ms, ou seja, timer_->stop() não é executado; quando o tempo se esgota, o sinal de timeout é acionado e a ação de clique é executada. Deixe-me mencionar a função stop() aqui.Depois que o QTimer executar start(n), se não stop(), ele executará em um loop.

6. Pressione e segure o botão do teclado

Até agora, a reutilização do clique do teclado e do clique duplo foi realizada, então vamos dar uma olhada em como lidar com o pressionamento longo?

Para distinguir se é um pressionamento longo, QKeyEvent fornece uma função isAutoRepeat() para detectar automaticamente se a tecla é pressionada por muito tempo

  • Pressione e segure para retornar verdadeiro
  • Pressão não longa retorna falso

Conforme mencionado anteriormente, a distinção entre clique único e clique duplo pode ser usada nas funções void keyPressEvent(QKeyEvent *event) e void keyReleaseEvent(QKeyEvent *event). release-release Por que optar por implementá-lo na função de liberação do botão?

O problema é que a função de pressionamento longo deve ser implementada ao mesmo tempo. Acabei de analisar que, independentemente de você pressionar pressionamento longo ou não, a primeira ação de pressionamento não é pressionada longamente. Se estiver em void keyPressEvent(QKeyEvent *evento) Realizado, o pressionamento longo inevitavelmente adicionará um clique adicional, o que obviamente não é o que queremos;

Agora que a análise acabou, acho que é hora de começarmos a escrever o código.

#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;
            }
        }
    }
}

Os benefícios deste artigo, grátis para receber o pacote de materiais de aprendizado de desenvolvimento Qt, vídeo técnico, incluindo (base da linguagem C++, introdução à programação Qt, sinal QT e mecanismo de slot, desenho de imagem de desenvolvimento de interface QT, rede QT, programação de banco de dados QT, QT combate do projeto, QSS, OpenCV, módulo rápido, perguntas da entrevista, etc.) ↓↓↓↓↓↓Veja abaixo↓↓Clique na parte inferior do artigo para receber a taxa↓↓ 

 

Acho que você gosta

Origin blog.csdn.net/QtCompany/article/details/131743524
Recomendado
Clasificación