关于QLineEdit自定义范围
Qt中有很多种情况,比如输入用户名,输入名称等功能,要用到QLineEdit,如果想设置指定的范围,比如说关于名称,常用的可输入配置为,支持中文、英文、数字、特殊符号 - ,长度不超过64字符。在我目前的Qt5.9.6版本中,无法通过简单的正则和方法直接完成。因为关于特殊符号我无论怎么设置都可以输入@ , 。 、 【 】等这些英文和中文的符号,于是我考虑到另一个方法,自定义QLineEdit,重新实现它的KeyPressEvent事件。代码如下
/***************.h文件****************/ #include <QLineEdit> #include <QKeyEvent> class MyLineEdit : public QLineEdit { Q_OBJECT public: explicit MyLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) {} protected: // 重写键盘按下事件 void keyPressEvent(QKeyEvent *event) override; }; /***************.cpp文件****************/ #include "your_header.h" // 包含你的头文件 void MyLineEdit::keyPressEvent(QKeyEvent *event) { // 1. 先放行所有的控制键(比如:退格键删除、Ctrl+C/V、方向键移动光标等) // 如果不放行这些,你的输入框将无法删除内容,也无法使用快捷键 if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete || event->key() == Qt::Key_Left || event->key() == Qt::Key_Right || (event->modifiers() & Qt::ControlModifier)) { QLineEdit::keyPressEvent(event); return; } // 2. 获取当前按下的文本 QString text = event->text(); // 如果文本为空(比如按下了 Shift、Alt 等不产生字符的键),直接放行 if (text.isEmpty()) { QLineEdit::keyPressEvent(event); return; } // 3. 提取第一个字符进行白名单判断 QChar ch = text.at(0); // 白名单规则: // ch.isDigit() -> 数字 (0-9) // ch.isLetter() -> 英文字母 (a-z, A-Z) // (ch >= 0x4e00 && ch <= 0x9fa5) -> 常用中文字符 Unicode 范围 // ch == '-' -> 特殊符号连字符 bool isAllowed = ch.isDigit() || ch.isLetter() || (ch >= 0x4e00 && ch <= 0x9fa5) || ch == '-'; // 4. 如果是允许的字符,就交给 QLineEdit 正常处理;否则直接拦截(不调用父类方法) if (isAllowed) { QLineEdit::keyPressEvent(event); } // 如果不允许(比如输入了 @),这里什么都不做,就相当于把这次按键吞掉了 }代码完成后,我发现确实英文键盘的情况已经满足我的需求了,特殊符号也仅能输入-了,但是切到中文输入法后,仍然有问题,中文的任意符号是可以输入的,通过打断点发现,在有输入法的时候,qt处理不会进入该事件。
查阅资料后得知,当用输入法打字时,按下键盘,这个事件并没有直接变成字符塞进QLineEdit,而是先被操作系统和Qt的输入法框架(Input Method Framework)给“劫持”了。
完整流程如下
1. 按下键盘-> 产生QKeyEvent(此时进入KeyPressEvent)
2. 输入法拦截了这个事件,把它转换成拼音或候选词(进入了输入法编辑状态)
3. 在输入法里选好了字或符号 (比如选中了一个中文逗号,)
4. 输入法框架会生成一个专门的QInputMethodEvent(输入法事件),直接把最终的字符(,)塞进你的输入框里。
所以,中文符号和汉字是没有经过KeyPressEvent白名单安检,而是走了InputMethodEvent这条通道。
所以我们需要再重写一个InputMethodEvent函数,用和白名单完全一样的逻辑处理输入法提交的字符。
因此在原有类中,加入以下代码
#include <QInputMethodEvent> // 在你的 .h 文件中声明: protected: void inputMethodEvent(QInputMethodEvent *event) override* // 在你的 .cpp 文件中实现: void MyLineEdit::inputMethodEvent(QInputMethodEvent *event) { // 获取输入法最终要提交上屏的文本(比如你选的中文逗号) QString commitText = event->commitString(); // 如果输入法提交了文本,我们就进行拦截检查 if (!commitText.isEmpty()) { // 遍历提交的每一个字符(防止一次性粘贴或输入多个符号) for (QChar ch : commitText) { bool isDigitOrLetter = ch.isDigit() || ch.isLetter(); bool isChineseChar = (ch >= 0x4e00 && ch <= 0x9fa5); bool isHyphen = (ch == '-'); // 拦截全角符号(中文符号) bool isFullWidthSymbol = (ch >= 0xFF00 && ch <= 0xFFEF); // 只要发现有一个字符不符合白名单,或者是全角符号,就直接把整个事件忽略掉 if (!((isDigitOrLetter || isChineseChar || isHyphen) && !isFullWidthSymbol)) { event->ignore(); // 拒绝这次输入法提交 return; } } } // 如果检查通过,或者输入法只是在打出拼音(commitString为空),就正常放行 QLineEdit::inputMethodEvent(event); }这样,就完成了一个专属于名称输入的控件。
