Qt/Qml中捕获(中文)输入法事件(按下提交)
- 其他
- 2025-08-21 04:54:01

【写在前面】
最近工作中遇到一个奇怪的问题:
本来想在 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. github /mengps/QtExamples
CSDN的: download.csdn.net/download/u011283226/87276813 download.csdn.net/download/u011283226/87276813
Qt/Qml中捕获(中文)输入法事件(按下提交)由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Qt/Qml中捕获(中文)输入法事件(按下提交)”
上一篇
App黑白化技术实践
下一篇
JAVA实训第四天