Qt键盘事件

这篇具有很好参考价值的文章主要介绍了Qt键盘事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

QKeyEvent 类用来描述一个键盘事件。当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件。
QKeyEvent 的 key() 函数可以获取具体的按键,对于 Qt 中给定的所有按键,可以在帮助中查看 Qt: :Key 关键字。需要特别说明的是,回车键在这里是 Qt::Key_Return;键盘上的一些修饰键,比如 Ctrl 和 Shift 等, 这里需要使用 QKeyEvent 的 modifiers() 函数来获取,可以在帮助中使用 Qt:: KeyboardModifier 关键字来査看所有的修饰键。
QKeyEvent 有两个键盘事件成员函数,在头文件.h中进行声明:

#include <QKeyEvent>

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

二、常用操作

下面是些常用操作:

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

分别按下 ESC、Enter、CTRL + M、ALT + M 等键,“应用程序输出”窗口输出如下:

ESC
Enter
CTRL + M
ALT + M
release:  up

三、按键与自动重复

自动重复是指按下键盘上的键(修饰键除外)不放时,会不断重复的发送键按下事件,Qt 默认是启用自动重复的,若要实现类似按键 A+D 之类的快捷键,就需要关闭自动重复。可使用如下方法来关闭自动重复:

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

Qt 的键盘事件整体表现为,按住一个键时:

1、第一次触发 keyPressEvent(),isAutoRepeat() 返回 false
2、没有触发 keyReleaseEvent(),停顿一会
3、再一次触发 keyPressEvent(),isAutoRepeat() 返回true
4、触发 keyReleaseEvent()
5、若没松开按键,isAutoRepeat() 返回 true,返回第 3 步;若松开按键,isAutoRepeat() 返回 false

四、键盘捕获

可以只指定窗口中的某个控件捕获键盘事件,使其他控件无法获得键盘事件,示例如下。
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发生键盘事件";
}

按下任何键,发现只有按钮 AAA 才能获得键盘事件,按钮 BBB 无法获得键盘事件。

五、键盘按键单击、双击

首先键盘按键的单击、双击实现用的 QTimer,一说到这估计大部分人都知道怎么回事了,但这里也有个误区,那就是如何区分单击和双击的问题。这里使用两次按键的时间间隔来区分,这里在按下、或释放里实现都是可以的,这里我最后选择在释放里实现,后面再说原因。

头文件里定义几个相关变量:

#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

再看键盘按键单击、双击实现:

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

单击,在 500ms 内未达到双击次数,也就是未执行 timer_->stop(); 时间耗尽触发 timeout 信号,执行单击动作。这里提一下 stop() 函数,QTimer 执行 start(n) 后,如果不 stop(),那它会循环执行。

六、键盘按键长按

此实现键盘单击和双击复用,那么我们再来看一下长按怎么处理呢?

为了区分是否是长按,QKeyEvent 提供了一个 isAutoRepeat() 函数自动检测按键是否长按

长按返回 true
非长按返回 false
前面提到单击和双击的区分,其实在void keyPressEvent(QKeyEvent *event)、void keyReleaseEvent(QKeyEvent *event)函数里都可以,反正都是记录时间差,press-press 或 release-release 没分别,那最后为什么选择在按键释放函数里实现呢?

问题就在还得同时实现长按功能,刚刚分析得出无论你长按还是非长按,第一次的 press 动作他都是按下非长按的,如果在void keyPressEvent(QKeyEvent *event)里实现,那长按必然会附加一次单击,这当然不是我们想要的;

至此分析完毕,我想我们该开始写代码了。文章来源地址https://www.toymoban.com/news/detail-491886.html

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

到了这里,关于Qt键盘事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包