首页 > 其他分享 >QML 全局键盘 监控

QML 全局键盘 监控

时间:2023-01-31 22:57:58浏览次数:46  
标签:filterEvent 界面 FilterEvent QObject 键盘 QML 过滤器 全局

开发环境

  • windows
  • QtCreator 4.10.2(Community)
  • C++和QML混合编辑

应用场景

应用程序分为登录界面和主界面2个窗口。要求在主界面有全局键盘监控的功能,比如按ESC时,确认后退回到登录窗口。

QML中的按键事件处理

三要素:

  • focus :true            //组件必须获得焦点,只有在获得焦点时,该组件的Key事件才有效
  • Key.enabled:true  //使能Key功能
  • Key.onPress:{}        //重写Key按下的处理时间

  举个例子:我们假想这个Rect是主界面最外部的包围框(root),即所有的界面元素都在这个Rect中。

 View Code

  按这个方法,假如主界面一开始加载完成时,获得焦点的是这个Rect,那么当然可以实现我们的需求。但是用户一旦在界面上操作一些获取焦点的组件,使得这个Rect失去了焦点。那么这个全局监控键盘得到功能就无法实现了。如果想反复设置Rect的focus属性,显然不是一个好办法。

Qt的事件过滤器

  QML不方便完成的事情,我们自然想到了C++了。原则上讲:QML负责界面逻辑,C++负责数据处理和功能实现。这边博客给了我基本的思路:https://blog.csdn.net/weixin_34354945/article/details/92973701

  思路:实现一个过滤器类。这个类只要是继承自QObject或其子类,它就有一个虚函数eventFilter。我们只要实现它,在其中捕获按钮事件,进行处理。其他事件放行。捕获到按键事件时,C++发出信号,QML处理信号。只要把这个过滤器类安装我们的主窗口就可以实现需求。

 过滤器类

 filterevent.h 

复制代码
#ifndef FILTEREVENT_H
#define FILTEREVENT_H

#include <QObject>
#include <QDebug>

class FilterEvent : public QObject
{
    Q_OBJECT
public:
    explicit FilterEvent(QObject *parent = nullptr);
protected:
protected:
      bool eventFilter(QObject *obj, QEvent *ev) override;

signals:
      void myExited();

public slots:
};

#endif // FILTEREVENT_H
复制代码

 filterevent.cpp 

复制代码
#include "filterevent.h"

#include <qevent.h>

FilterEvent::FilterEvent(QObject *parent) : QObject(parent)
{

}

bool FilterEvent::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        switch (keyEvent->key()) {
        case Qt::Key_Escape:
            qDebug()<<"pressed Key_Escape";
            emit myExited();
            return true;
        case Qt::Key_Enter:
            qDebug()<<"pressed Key_Enter";
            return true;
        }
        qDebug() << "Ate key press" << keyEvent->key();
    }
    return false;
}
复制代码

安装过滤器

  在这里,我遇到了一个问题:这个过滤器的实例对象应该放在哪里?放在 main.cpp 的main函数中,我们是可以通过调用 installEventFilter 安装到主窗口上,但是按键事件处理中的信号该怎么处理呢,信号的处理地点是要放在QML中的。

参照其它博客的写法试了试,最后QML会报错过滤器实例对象can not find(虽然名字是变蓝色了...)。最后结合自己的经历,想了另一个办法。

  • filterEvent实现在QML端,采用on+信号的形式处理按键事件中发出的信号
  • main.cpp 中通过查找objectName的方式,得到主窗口和filterEvent 的指针
  • 主窗口调用installEventFilter 函数安装上filterEvent

  首先要将过滤器类注册到QML的元象树系统中。第一个参数是自己定义的包名,要改成自己的,用到的时候QML端import。

qmlRegisterType<FilterEvent>("an.qt.UserDefine", 1, 0, "FilterEvent");

  然后安装

//安装事件过滤器
    QObject* mainRootItem = engine.rootObjects().at(1);
    QObject* filterEvent = mainRootItem->findChild<QObject*>("filterEvent");
    mainRootItem->installEventFilter(filterEvent);

  QML端

复制代码
//事件过滤器
    FilterEvent{
        objectName: "filterEvent"  //objectName用以元象树查找元素
        onMyExited: {
            console.log("filterEvent trigged");
            //todo
        }
    }
复制代码

补充说明

  这里要补充说明的是:QML的对象是以树的形式进行管理的。可以这样理解:最外围的最大的组件可以看成是根节点,它包含的组件呢,是根节点的分支。子节点再包含一些组件,就再分支。(个人对元象树的理解,错误请指出)。然后我们可以通过 findChild<QObject*>("objectName") 的方式得到我们想要找的对象。比如可以进行一些信号与槽函数绑定。

  安装过滤器中的 mainRootItem 也是这样获得的。之所以是 at(1) 是因为我第一步加载的是登录界面(0)。

  信号与槽函数绑定举例

复制代码
    QObject* logInRootItem = engine.rootObjects().at(0);
    QObject* logInButton = logInRootItem->findChild<QObject*>("logInButton");//根据qml中的objectName找到这个对象,获取到它的指针
    if(logInButton)
    {
        //连接QML元素中的信号到C++的槽函数
        QObject::connect(logInButton,SIGNAL(logIn(QString)),&control,SLOT(showWindow(QString)));
    }
    https://www.cnblogs.com/yinxiuzhe/p/13278189.html  

标签:filterEvent,界面,FilterEvent,QObject,键盘,QML,过滤器,全局
From: https://www.cnblogs.com/im18620660608/p/17081091.html

相关文章

  • QML 自定义窗口简易实现:使用过滤 WINDOW 事件的方式
      1.前言QML自定义窗口目前看到的主要有两种方式,一种是纯QML实现,使用MouseArea来处理鼠标相关事件;另一种是事件过滤,用系统本地API进行操作。前两天看了涛哥......
  • QML全局按键监视、拦截
    最近尝试使用Qt做android应用,一路不顺,满地都是坑,不过开发的应用不复杂,坑不算深,都一步步走过来了,唯独一个问题解决不了——Back按钮返回功能,不过今天总算解决了......  ......
  • QML实现换肤(主题样式切换)
    QtQuick没有像QtWidgets那样的QSS样式表机制,只能通过自定义组件或者设置Controls主题来实现样式定制。目前网上搜到的换肤功能,大多是定义一个全局的样式文件,在自定......
  • 使用 java.time.LocalDateTime(续):全局返回时间戳给前端
    Java8PostgreSQL14spring-boot-starter-parent2.7.3mybatis-plus-boot-starter3.4.3.4--ben发布于博客园前文:使用java.time.LocalDateTimehttps://www.cnblogs......
  • 使用vant、promise封装回调、全局状态共享、分包
    应用的生命周期onLaunch:启动应用时调用onShow:显示时调用,可能调用多次onHide:隐藏时调用(进入到后台),可能调用多次onError:整个应用如果某个部分有报错就调用页面的......
  • Qml类型:State 状态
    Qml类型:State状态1、定义一个状态2、状态名称3、绑定目标4、触发状态改变我们来写一个状态转换器。1、定义一个状态一个状态的定义可以声明为states:State{...},也......
  • Qml中使用动画Animation
    Animation是Qml中所有动画类的基类。Qml中动画的分类PropertyAnimation:改变控件的属性来产生动画。NumberAnimation:专门改变数字类型的动画,效率优于PropertyAnimation......
  • 全局负采样-minbatch负采样
    参考:https://developer.aliyun.com/article/873405defsoftmax_loss_with_negative_mining(user_emb,item_emb,......
  • 局部变量与全局变量
    不同的函数之间传递数据:(1)参数:通过形参或实参(2)返回值:用return语句返回计算结果(3)全局变量:外部变量注:如果全局变量与局部变量重名,那么将采取就近原则,即实际获取和修改的值......
  • MIT最新工作:使用三维线、面的激光雷达闭环检测的全局数据关联方法
    以下内容来自从零开始机器人SLAM知识星球每日更新内容点击领取学习资料→机器人SLAM学习资料大礼包论文#GlobalDataAssociationforSLAMwith3DGrassmannianMa......