一、前言
最近有个朋友找我定制一个输入法,需要高仿一个苹果MAC电脑的输入法,MAC操作系统的审美无疑是相当棒的,于是乎直接拿以前的输入法高仿了一个,由于之前有做过输入法这块的开发,而且改进了四年,各种需求都遇到过,陆陆续续完善了很多年,所以这个高仿起来难度不大,而且要支持滑动选词,直接撸代码。
二、实现的功能
1:采用Qt系统层输入法框架,独创输入切换机制。
2:纯QWidget编写,支持任何目标平台(亲测windows、linux、嵌入式linux等),支持任意Qt版本(亲测Qt4.6.0到Qt5.11.2),支持任意编译器(亲测mingw、gcc、msvc等),支持任意控件输入包括网页中的输入控件。
3:调用极为方便,pri文件调用形式,只要改成文件包含即可,例如pro文件中写 include($PWD/inputnew/inputnew.pri)。
4:界面清晰简洁,UI美观友好,非常适合触摸设备。
5:同时支持实体键盘输入+鼠标单击输入+触摸输入。
6:支持Qt程序嵌入的浏览器中的网页中的文本框等控件的输入。
7:支持迷你模式,界面大小随意设置,采用布局自使用任何分辨率。
8:支持纯数字键盘模式,自由控制弹出完整输入法面板和数字键盘面板,只需要对控件设置属性即可。例如ui->txt->setProperty(“flag”, “number”);
9:自由控制需要显示输入法和不需要显示输入法,当某些控件不需要弹出输入法,只需要对应不需要弹出输入法的控件设置属性noinput为真即可。例如ui->txt->setProperty(“noinput”, true);
10:界面自适应屏幕大小,输入法弹出位置为控件底部时,当超过桌面右边或者底部时,自动调整位置。
11:实现了长按超过500毫秒重复执行按下的键的功能。例如长按退格键,不断删除。
12:shift键切换输入法,esc键隐藏输入法,空格选中第一个汉字,回车选中输入的拼音。和搜狗输入法处理一致。
13:英文、中文、数字字母、大小写、特殊字符自由切换。
14:支持单拼双拼词组输入,网上大部分只支持单个汉字输入。智能分页算法,可任意翻页查看汉字词组。
15:默认自带5种皮肤颜色,可随意切换,用户也可用QSS自定义皮肤。
16:字库文件可大可小,提供迷你版字库大小仅120KB,方便存储空间紧张的硬件,完整版字库25MB。
17:可选谷歌内核的输入法引擎,字库文件1MB,不依赖数据库,资源占用低效率极高。支持模糊拼音,比如nh=你好。
18:可选windows专有版本,支持外部程序输入,比如输入到记事本、QQ聊天窗口等。
19:整个输入法代码行数1000行左右,非常小,不会对程序增加大小造成负担。
20:代码结构极为清晰,注释详细,非常容易阅读和理解,同时也可以自行修改拓展自定义的需求。
三、突出功能
1:界面重新布局,高仿IOS输入法。
2:顶部滑动选词+弹出汉字面板选词,支持滑动。
3:增加记忆功能,优先词库首先显示,支持单个拼音多个汉字,自动调整优先级。
4:增加造词功能,可以直接打开文件文件写入自定义词组,最高级别显示。
四、效果图
五、核心代码
void frmInput2019::btnClicked()
{
QPushButton *btn = (QPushButton *)sender();
QString objectName = btn->objectName();
QString btnText = btn->text();
QString labText = ui->labPY->text();
ui->scrollAreaCn->horizontalScrollBar()->setValue(0);
ui->scrollAreaMore->verticalScrollBar()->setValue(0);
if (objectName == "btnUpper") {
upper = !upper;
setUpper(upper);
clearChinese();
ui->labPY->clear();
} else if (objectName == "btnNumber") {
setInputType("number");
} else if (objectName == "btnNumber2") {
number = !number;
setNumber(number);
} else if (objectName == "btnDelete" || objectName == "btnDelete2") {
//如果当前是中文模式,则删除对应拼音,删除完拼音之后再删除对应文本输入框的内容
int len = labText.length();
if (inputType == "chinese" && len > 0) {
ui->labPY->setText(labText.left(len - 1));
selectChinese();
} else {
deleteValue();
}
ui->scrollAreaCn->horizontalScrollBar()->setValue(0);
ui->scrollAreaMore->verticalScrollBar()->setValue(0);
} else if (objectName == "btnSpace" || objectName == "btnSpace2") {
//如果中文模式而且有待输入字母,判断是否有中文则插入第一个中文否则插入字母
if (inputType == "chinese" && !labText.isEmpty()) {
QString text = labCn.first()->text();
text.isEmpty() ? insertValue(labText) : insertValue(text);
clearChinese();
} else {
insertValue(" ");
}
} else if (objectName == "btnEnter" || objectName == "btnEnter2") {
//如果中文模式而且有待输入字母则立即插入字母
if (inputType == "chinese" && !labText.isEmpty()) {
insertValue(labText);
clearChinese();
}
if (currentWidget != 0 && currentWidget->inherits("QLineEdit") && !onlyControl) {
hidePanel();
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, QString("\n"));
QApplication::sendEvent(currentWidget, &keyPress);
} else {
insertValue("\n");
}
} else {
//如果是&按钮,因为对应&被过滤,所以真实的text为去除前面一个&字符
if (btnText == "&&") {
btnText = "&";
}
//当前不是中文模式,则单击按钮对应text为传递参数,大写优先
if (inputType != "chinese" || upper) {
insertValue(btnText);
} else {
if (btn->property("btnLetter").toBool()) {
ui->labPY->setText(labText + btnText);
selectChinese();
}
}
}
}
void frmInput2019::focusChanged(QWidget *oldWidget, QWidget *nowWidget)
{
//qDebug() << "oldWidget:" << oldWidget << "nowWidget:" << nowWidget;
this->currentWidget = nowWidget;
if (nowWidget != 0 && !this->isAncestorOf(nowWidget)) {
//如果对应属性noinput为真或者只读则不显示
if (nowWidget->property("noinput").toBool() || nowWidget->property("readOnly").toBool()) {
currentWidget = 0;
QTimer::singleShot(0, this, SLOT(hidePanel()));
return;
}
if (nowWidget->inherits("QWidget")) {
//合法的输入控件,可以自行增加
QStringList classNames;
classNames << "QLineEdit" << "QTextEdit" << "QPlainTextEdit" << "QAbstractSpinBox" << "QComboBox";
classNames << "QQuickWidget" << "QWebView" << "QtWebEngineCore::RenderWidgetHostViewQtDelegateWidget";
//查找当前焦点控件是否属于合法输入的控件
bool exist = false;
foreach (QString className, classNames) {
if (nowWidget->inherits(className.toLatin1().constData())) {
//如果当前是下拉框则判断下拉框可编辑属性是否为真
if (className != "QComboBox" || nowWidget->property("editable").toBool()) {
exist = true;
break;
}
}
}
if (exist) {
showPanel();
movePosition();
} else {
currentWidget = 0;
hidePanel();
}
}
}
}
void frmInput2019::movePosition()
{
//根据用户选择的输入法位置设置-居中显示-底部填充-显示在输入框正下方
static int deskWidth = qApp->desktop()->availableGeometry().width();
static int deskHeight = qApp->desktop()->availableGeometry().height();
int width = this->width();
int height = this->height();
if (position == "center") {
QPoint pos = QPoint(deskWidth / 2 - width / 2, deskHeight / 2 - height / 2);
this->setGeometry(pos.x(), pos.y(), width, height);
} else if (position == "bottom") {
this->setGeometry(0, deskHeight - height, deskWidth, height);
} else if (position == "control") {
QRect rect = currentWidget->rect();
QPoint pos = QPoint(rect.left(), rect.bottom() + 2);
pos = currentWidget->mapToGlobal(pos);
int x = pos.x();
if (x + width > deskWidth) {
x = deskWidth - width;
}
int y = pos.y();
if (y + height > deskHeight) {
y = y - height - rect.height() - 2;
}
this->setGeometry(x, y, width, height);
}
}

本文暂时没有评论,来添加一个吧(●'◡'●)