Qt响应多个按键同时按下

3 篇文章 0 订阅
该博客介绍了如何利用Qt的键盘事件处理、定时器和容器来实现在WASD四键同时按下时,QLabel控件的平滑移动。通过监听按键按下和释放事件,将按键值存入容器,并用定时器遍历容器,根据不同的按键执行相应的移动操作。这种方法避免了长按时不必要的事件触发,提高了效率。
摘要由CSDN通过智能技术生成

1.Qt的键盘事件:

void keyReleaseEvent(QKeyEvent *); //按键释放事件
void keyPressEvent(QKeyEvent *);   //按键按下事件

2.Qt可以响应的按键事件:

单个按键、组合键(例如:crtl+c)
注意:

  1. 当单个按键按下释放后,按键事件还会停顿一下,所以我们不能在按键事件里面直接处理逻辑。--------借助定时器。
  2. 如果我们想响应多个按键同时按下的效果,单凭这键盘事件是没办法实现的。-------借助容器

3.借助定时器和容器,实现多个按键按下的同时响应

  1. 以WASD四按键为例,实现QLabel控件的丝滑移动。首先准备一个容器用于存放按下按键的key

    QList<int> keys;	//头文件中添加成员
    
  2. 定义一个定时器用于遍历容器

    QTimer* keyRespondTimer;	//头文件中添加成员
    
    keyRespondTimer = new QTimer(this);	//构造函数中创建定时器对象,并连接信号槽
    connect(keyRespondTimer, &QTimer::timeout, this, &Widget::slotTimeOut);
    
    
  3. 处理按键按下事件

    void Widget::keyPressEvent(QKeyEvent *event){
        if(!event->isAutoRepeat())  //判断如果不是长按时自动触发的按下,就将key值加入容器
            keys.append(event->key());
        if(!keyRespondTimer->isActive()) //如果定时器不在运行,就启动一下
            keyRespondTimer->start(4);
    }
    
  4. 处理按键释放事件

    void Widget::keyReleaseEvent(QKeyEvent *event){
        if(!event->isAutoRepeat())  //判断如果不是长按时自动触发的释放,就将key值从容器中删除
            keys.removeAll(event->key());
        if(keys.isEmpty()) //容器空了,关闭定时器
            keyRespondTimer->stop();
    }
    

注意点if(!event->isAutoRepeat()),增加这一判断是为了避免在按键长按期间一直触发按键事件,对同一键值一直做容器追加和删除操作。这显然是没必要的耗时操作,我们只需要保证在长按期间,那个按键的键值key一直在容器里就好了。

  1. 遍历key值容器,实现多个按键的同时响应

    void Widget::slotTimeOut(){
        foreach (int key, keys) {
            switch (key) {
            case Qt::Key_W:
                ui->label->move(ui->label->x(), ui->label->y() - 1);
                break;
            case Qt::Key_A:
                ui->label->move(ui->label->x() - 1, ui->label->y());
                break;
            case Qt::Key_S:
                ui->label->move(ui->label->x(), ui->label->y() + 1);
                break;
            case Qt::Key_D:
                ui->label->move(ui->label->x() + 1, ui->label->y());
                break;
            default:
                break;
            }
        }
    }
    

4.效果图

在这里插入图片描述

5.源码

#ifndef WIDGET_H
#define WIDGET_H

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

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    void keyPressEvent(QKeyEvent *event) override;
    void keyReleaseEvent(QKeyEvent *event) override;

private:
    Ui::Widget *ui;
    QList<int> keys;
    QTimer* keyRespondTimer;
    void slotTimeOut();
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget){
    ui->setupUi(this);
    keyRespondTimer = new QTimer(this);
    connect(keyRespondTimer, &QTimer::timeout, this, &Widget::slotTimeOut);

}

Widget::~Widget(){
    delete keyRespondTimer;
    delete ui;
}

void Widget::keyPressEvent(QKeyEvent *event){
    if(!event->isAutoRepeat())  //判断如果不是长按时自动触发的按下,就将key值加入容器
        keys.append(event->key());
    if(!keyRespondTimer->isActive()) //如果定时器不在运行,就启动一下
        keyRespondTimer->start(4);
}

void Widget::keyReleaseEvent(QKeyEvent *event){
    if(!event->isAutoRepeat())  //判断如果不是长按时自动触发的释放,就将key值从容器中删除
        keys.removeAll(event->key());
    if(keys.isEmpty()) //容器空了,关闭定时器
        keyRespondTimer->stop();
}

void Widget::slotTimeOut(){
    foreach (int key, keys) {
        switch (key) {
        case Qt::Key_W:
            ui->label->move(ui->label->x(), ui->label->y() - 1);
            break;
        case Qt::Key_A:
            ui->label->move(ui->label->x() - 1, ui->label->y());
            break;
        case Qt::Key_S:
            ui->label->move(ui->label->x(), ui->label->y() + 1);
            break;
        case Qt::Key_D:
            ui->label->move(ui->label->x() + 1, ui->label->y());
            break;
        default:
            break;
        }
    }
}
  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值