您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Qt 及 QML 处理多个按键同时按下

龚建波 发布时间:2020-07-30 00:07:00 ,浏览量:3

1.思路

想写个判断哪些方向键同时按下的逻辑,结果发现 Qt 的按键事件只能取到单个键值,而 QKeyEvent::modifiers() 又只能获取 Ctrl 或者 Shift 这种辅助按键。一番百度之后,发现可以使用容器保存按键值,在 keyPressEvent 添加按键值,在 keyReleaseEvent 移除按键值。

不过单单处理按键的按下和弹起还不够,还需要注意一些事项:

A.弹起其中一个按键时,按键事件的触发会停顿一下。所以,不能在按键事件里直接处理逻辑,需要加个定时器来遍历我们的键值容器;

B.按键长按时会重复触发按下和弹起两个事件,这可能导致我们的键值容器在遍历时值不对(比如长按触发按键事件,导致定时器触发时我们的容器正好弹出键值就为空了)。所以,我们要单独判断下 QKeyEvent 的 isAutoRepeat,如果是自动重复触发就不处理。

实现效果,以移动方块为例(两个方向键同时按下就是斜着移动):

分别展示 QWidget 和 QML 的示例。

2.QWidget 代码
#ifndef UNIT4MOVE_H
#define UNIT4MOVE_H

#include 
#include 
#include 
#include 
#include 

//按键移动物体
class Unit4Move : public QOpenGLWidget, protected QOpenGLFunctions_4_0_Compatibility
{
    Q_OBJECT
public:
    explicit Unit4Move(QWidget *parent = nullptr);

protected:
    //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    void initializeGL() override;
    //渲染OpenGL场景,每当需要更新小部件时使用
    void paintGL() override;
    //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    void resizeGL(int width, int height) override;

    //按键按下
    void keyPressEvent(QKeyEvent *event) override;
    //按键释放
    void keyReleaseEvent(QKeyEvent *event) override;
    //设置切换显示的时候获取焦点
    void showEvent(QShowEvent *event) override;

private:
    //顶点列表
    QList vertexList;
    //移动
    float xOffset=0;
    float yOffset=0;
    //当前按键按下的列表
    //因为Qt按键事件只能判断出一个键值和辅助键值的组合,
    //所以自己保存按下的按键
    QSet pressedKeys;
    //刷新定时器
    QTimer *updateTimer;
};

#endif // UNIT4MOVE_H

 

#include "Unit4Move.h"

#include 
#include 
#include 
#include 
#include 

Unit4Move::Unit4Move(QWidget *parent)
    : QOpenGLWidget(parent)
{
    //默认没得焦点,没法接收按键
    setFocusPolicy(Qt::StrongFocus);

    //多个按键按下还有一个问题,就是最后那个按键弹起后就不会重复触发了
    //所以刷新我们可以用定时器来判断容器列表,release时判断为空就关,press就开
    updateTimer=new QTimer(this);
    connect(updateTimer,&QTimer::timeout,[this]{
        //qDebug()isActive())
        updateTimer->start(100);
}

void Unit4Move::keyReleaseEvent(QKeyEvent *event)
{
    QOpenGLWidget::keyReleaseEvent(event);
    //按键释放,从容器中移除,如果是长按触发的repeat就不判断
    if(!event->isAutoRepeat())
        pressedKeys.remove(event->key());
    if(pressedKeys.isEmpty()){
        updateTimer->stop();
    }
}

void Unit4Move::showEvent(QShowEvent *event)
{
    QOpenGLWidget::showEvent(event);
    setFocus();
}
3.QML 代码
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("GongJianBo")

    //存储当前按下的键值,使用ES6的集合类型
    property variant pressedKeys:new Set()

    Rectangle{
        id: item
        //anchors.centerIn: parent
        x:100
        y:100
        width: 100
        height: 100
        color: "green"

        focus: true
        //按键按下
        Keys.onPressed: {
            //键值放入set
            if(!event.isAutoRepeat){
                pressedKeys.add(event.key)
            }
            if(!timer.running){
                timer.start()
            }
        }
        //按键释放
        Keys.onReleased: {
            //键值弹出set
            if(!event.isAutoRepeat){
                pressedKeys.delete(event.key)
            }
            if(pressedKeys.size            
关注
打赏
1655829268
查看更多评论
0.0770s