Qt / Qml 中捕获(中文)输入法事件(按下 提交)

news2024/11/28 16:53:00

【写在前面】

        最近工作中遇到一个奇怪的问题:

        本来想在 TextEdit ( QTextEdit ) 中捕获一下键盘按键按下的事件。

        然而,当输入法为英文时( 正常输入字符 ),可以捕获到按键事件,但当我切换到中文时,弹出输入法选框后,却无法再像英文那样捕获到事件。

        经过查阅资料,发现在使用输入法时,不会发出按键事件,而是另外一种不太常见的事件类型:QEvent::InputMethod ,与之关联的事件为:QInputMethodEvent

        为了正确处理这类事件,我简单封装了一个辅助类,效果相当不错。


 【正文开始】

        首先,因为要处理特殊事件,必须重新实现 bool QObject::event(QEvent *e),不过我们并不需要重写 TextEdit ( QTextEdit ) 这些类,只需借助事件过滤器即可:

        使用 void QObject::installEventFilter(QObject *filterObj) 函数为指定对象安装事件过滤器。

        这里的过滤器称为 InputMethodEventCatch 

class InputMethodEventCatch : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged)

public:
    explicit InputMethodEventCatch(QObject *parent = nullptr);
    ~InputMethodEventCatch();

    QObject *target();
    void setTarget(QObject *target);

    bool eventFilter(QObject *obj, QEvent *event);

signals:
    void targetChanged();
    void inputMethodEventPressed(int code, const QString &key);
    void inputMethodEventCommitted(const QString &commitString);

private:
    QObject *m_target = nullptr;
};

        它提供主要两个信号:

        void inputMethodEventPressed(int code, const QString &key) 输入法按键按下时发出,code为 Qt::Key Qt 按键枚举,key 则为按键字符(串)。

        void inputMethodEventCommitted(const QString &commitString) 输入法编辑完成时发出,代表文本从输入法提交到编辑器,其中 commitString 为提交的文本。

        接下来是实现部分:

InputMethodEventCatch::InputMethodEventCatch(QObject *parent)
    : QObject{parent}
{

}

InputMethodEventCatch::~InputMethodEventCatch()
{
    if (m_target) m_target->removeEventFilter(this);
}

QObject *InputMethodEventCatch::target()
{
    return m_target;
}

void InputMethodEventCatch::setTarget(QObject *target)
{
    if (!target) return;

    if (m_target != target) {
        if (m_target) m_target->removeEventFilter(this);
        target->installEventFilter(this);
        m_target = target;
        emit targetChanged();
    }
}

bool InputMethodEventCatch::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::InputMethod) {
        QInputMethodEvent *input = static_cast<QInputMethodEvent *>(event);
        if (input->preeditString().isEmpty()) {
            emit inputMethodEventCommitted(input->commitString());
        } else {
            QString key;
            for (const auto &attr: input->attributes()) {
                if (attr.type == QInputMethodEvent::AttributeType::Cursor && attr.start > 0) {
                    key = input->preeditString().mid(attr.start - 1, attr.length);
                    break;
                }
            }
            if (key.size() == 1)
                emit inputMethodEventPressed(key2code(*key.begin()), key);
        }
    }
    return QObject::eventFilter(obj, event);
}

        关键代码在 eventFilter() 中:

        1、如果预编辑字符串为空,则认为编辑完成。

        2、如果不为空,那么我们取出光标处的字符,然后使用 key2code() 转换为 Qt::Key

        其中 key2code() 实现如下:

static int key2code(const QChar &key)
{
    switch (key.toLatin1())
    {
    case 'q': case 'Q': return Qt::Key_Q;
    case 'w': case 'W': return Qt::Key_W;
    case 'e': case 'E': return Qt::Key_E;
    case 'r': case 'R': return Qt::Key_R;
    case 't': case 'T': return Qt::Key_T;
    case 'y': case 'Y': return Qt::Key_Y;
    case 'u': case 'U': return Qt::Key_U;
    case 'i': case 'I': return Qt::Key_I;
    case 'o': case 'O': return Qt::Key_O;
    case 'p': case 'P': return Qt::Key_P;
    case 'a': case 'A': return Qt::Key_A;
    case 's': case 'S': return Qt::Key_S;
    case 'd': case 'D': return Qt::Key_D;
    case 'f': case 'F': return Qt::Key_F;
    case 'g': case 'G': return Qt::Key_G;
    case 'h': case 'H': return Qt::Key_H;
    case 'j': case 'J': return Qt::Key_J;
    case 'k': case 'K': return Qt::Key_K;
    case 'l': case 'L': return Qt::Key_L;
    case 'z': case 'Z': return Qt::Key_Z;
    case 'x': case 'X': return Qt::Key_X;
    case 'c': case 'C': return Qt::Key_C;
    case 'v': case 'V': return Qt::Key_V;
    case 'b': case 'B': return Qt::Key_B;
    case 'n': case 'N': return Qt::Key_N;
    case 'm': case 'M': return Qt::Key_M;
    }

    return Qt::Key_unknown;
}

        注意:该实现只转换了 26 个字母,其他的根据需要自己加上即可。


 【如何使用】

        使用起来相当简单:

#include "inputmethodeventcatch.h"

#include <QApplication>
#include <QDebug>
#include <QTextEdit>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QTextEdit edit;
    InputMethodEventCatch editCatch;
    QObject::connect(&editCatch, &InputMethodEventCatch::inputMethodEventPressed, &editCatch, [](int code, const QString &key){
        qDebug() << "inputMethodEventPressed" << Qt::Key(code) << key;
    });
    QObject::connect(&editCatch, &InputMethodEventCatch::inputMethodEventCommitted, &editCatch, [](const QString &commitString){
        qDebug() << "inputMethodEventCommitted" << commitString;
    });
    editCatch.setTarget(&edit);
    edit.show();

    return app.exec();
}

        绑定相关信号并 setTarget() 即可。

        效果如下所示:


 【结语】

        最后,实际上 Qml 中也一样可以使用,只需要将 InputMethodEventCatch 注册进 Qml 中即可,然后类似这样:

TextEdit {
    id: textEdit
}

InputMethodEventCatch {
    target: textEdit
    onInputMethodEventPressed: { }
    onInputMethodEventCommitted: { }
}

        源码地址,Github的:GitHub - mengps/QtExamples: 分享各种 Qt 示例,,说不定用得上呢~分享各种 Qt 示例,,说不定用得上呢~. Contribute to mengps/QtExamples development by creating an account on GitHub.https://github.com/mengps/QtExamples

        CSDN的:https://download.csdn.net/download/u011283226/87276813https://download.csdn.net/download/u011283226/87276813

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/88158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web前端网页设计期末课程大作业:企业网页主题网站设计——舞蹈培训11页HTML+CSS+JavaScript

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

从零开始,教你写一个串口调试助手

摘要&#xff1a;相信很多小伙伴都没接触过QT&#xff0c;如果想用QT写一个调试助手&#xff0c;首先是要会一点C语法。只要能看得懂C的代码&#xff0c;就能很快的写一个串口调试助手。 下面先推荐两个视频教程&#xff0c;感兴趣的可以看一看&#xff01; 1、B站Jomse工 B站…

项目建议书怎么写?

Why 为什么需要项目建议书? 行政、国企、事业单位间的买卖需要按国家规定的“政府采购法”进行(个体户,私企间的买卖不需要按“政府采购法”进行),不是个人的消费,有一整套流程,《项目建议书》这套流程中的产物之一。 即国家规定,纳税人的钱不能乱花,买之前要想好买…

南卡和Snowkids电容笔哪款更值得入手?口碑最佳的国产电容笔

随着苹果推出了Apple Pencil之后后&#xff0c;平替电容笔的产品也随之出现了不少&#xff0c;其中大部分都是没很高知名度的牌子&#xff0c;价格也是五花八门&#xff0c;有便宜的也有昂贵的&#xff0c;让消费者有了更多的选择&#xff0c;对于第一次购买电容笔的小白来说但…

【Python】【期末复习题】

文章目录一、单选题&#xff08;20分&#xff09;二、判断题&#xff08;10分&#xff09;三、填空题&#xff08;10分&#xff09;四、问答题&#xff08;共30分&#xff0c;6题&#xff0c;每题5分&#xff09;五、程序题&#xff08;3题&#xff0c;每题10分&#xff0c;共3…

WIFI智能电子标牌的优势

一、与市面产品对比有什么优化升级? 使用环境标准wifi通信&#xff0c;避免单独安装基站&#xff0c;减少部署的麻烦。 二、刷新一次消耗多少电量&#xff0c;平均每秒消耗多少? 0.09879mAh&#xff0c;每秒平均电流105uA。 三、充满电需要多久&#xff0c;充一次电可以用…

【JS020】原生JS实现AJAX

日期&#xff1a;2022年12月14日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#x…

TFT显示模组是什么?tft显示模组有什么功能?

TFT显示模组的出现&#xff0c;让手机屏幕成为一种刚需。但随着技术的发展&#xff0c;越来越多的厂商开始推出折叠屏手机&#xff0c;这也意味着手机屏幕的形态正在发生变化。在此背景下&#xff0c;折叠屏手机市场迎来爆发期。根据中国信通院数据&#xff0c;2020年上半年&am…

Kubernetes包管理器Helm的本质

“本质”类的文章&#xff0c;通常很难带流量。而且写起来非常吃力。那我为什么还要写&#xff1f;写作是对自己的锻炼。写作是让自己的思想更有深度的一种有效方式。如果你觉得这篇文章对你有帮助&#xff0c;也你麻烦你转发这篇文章&#xff0c;这是对我的帮助。谢谢。Kubern…

socket.io 使用protobuf 协议发送消息

一、服务端 1、maven引入netty-socketio <dependency><groupId>com.corundumstudio.socketio</groupId><artifactId>netty-socketio</artifactId><version>1.7.22</version></dependency> 2、服务端java代码 Service public…

艾美捷内皮细胞生长添加剂不同研究工具推荐

艾美捷Relia Tech内皮细胞生长添加剂可用于培养没有饲养细胞的杂交瘤细胞&#xff08;Pintus&#xff0c;1983&#xff09;。这些脑提取物中的活性因子已被鉴定为aFGF的变体&#xff08;Burgesse&#xff0c;1985&#xff09;。该ECGF产品补充了生理浓度的人rec.VEGF-A&#xf…

初识 Markdown编辑器

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

真兰仪表通过深交所注册:拟募资17.4亿 上半年净利下降27%

雷递网 雷建平 12月13日上海真兰仪表科技股份有限公司&#xff08;简称&#xff1a;“真兰仪表”&#xff09;日前通过注册&#xff0c;准备在深交所创业板上市。真兰仪表计划募资17.4亿元。其中&#xff0c;7.76亿用于真兰仪表科技有限公司燃气表产能扩建项目&#xff0c;6.12…

NFA的确定化

一、实验目的 &#xff08;1&#xff09;通过本次实验&#xff0c;加深对正则表达式、NFA、DFA及其识别的语言的理解&#xff1b; &#xff08;2&#xff09;掌握从NFA到DFA的转换&#xff0c;以及用子集法把NFA转换成DFA理论&#xff0c;编程实现将NFA&#xff08;不确定有穷…

SAP 事务代码BD20不能处理状态为51的IDoc

SAP 事务代码BD20不能处理状态为51的IDoc 对于SAP IDoc相关的事务代码比如WE02,WE19,BD87等都比较熟悉&#xff0c;因为使用的比较多。但是对于事务代码BD20却很少使用。 笔者在近期的一个项目上&#xff0c;听到客户的global team有使用该事务代码&#xff0c;设置成了一个job…

Oracle RMAN备份相关信息查询

查询 RMAN 备份状态主要是通过视图V$RMAN_STATUS 来进行&#xff0c;这个视图可以查询到 RMAN 执行的操作。 我们主要查看两列&#xff1a;OPERATION 和 STATUS。 OPERATION 的值有&#xff1a;RMAN、BACKUP、DELETE、CROSSCHECK、DELETE OBSOLETE等。 STATUS的值有&#xff1a…

中国电信携手华为建成全球首个支持5G RedCap联合测试能力的5G开放实验室

近日&#xff0c;中国电信物联网开放实验室宣布与华为共同完成了5G RedCap实验室技术验证&#xff0c;并建成了全球首个具备5G R17标准RedCap联合测试能力的开放实验室。 此次技术验证&#xff0c;为RedCap的规模商用奠定了坚实基础&#xff0c;有助于打造RedCap行业终端生态认…

良心总结!Git 各指令的本质,真是通俗易懂啊

1前言 作为当前世界上最强大的代码管理工具Git相信大家都很熟悉&#xff0c;但据我所知有很大一批人停留在clone、commit、pull、push...的阶段&#xff0c;是不是对rebase心里没底只敢用merge&#xff1f;碰见版本回退就抓瞎&#xff1f;别问我怎么知道的&#xff0c;问就是&…

什么是成熟的自动化运维平台?

本文首发于知乎&#xff0c;由嘉为蓝鲸原创。 商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 当企业遇到运维管理对象的急速增长&#xff0c;业务需求频繁变更等传统运维场景问题时&#xff0c;依靠手工运维已经远远满足不了需求&#xff0c;因此我们需要搭建…

2022,itbird的年终总结报告

最近公司要求个人在做年终总结了&#xff0c;趁着这个机会&#xff0c;也想对自己的2022年进行一下回顾总结&#xff0c;最重要的是&#xff0c;对2023的目标&#xff0c;可以有一个指引。 就从工作和生活两方面来讲吧。 1.工作 1.1 行业的状态 本人从事的是android开发工作…