百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Qt编写高仿苹果MAC电脑输入法(支持触摸滑动选词)

liebian365 2024-10-20 09:54 23 浏览 0 评论

一、前言

最近有个朋友找我定制一个输入法,需要高仿一个苹果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);
 }
}

相关推荐

看黑客是如何获取你电脑最高权限的,一定要看

在渗透过程中,通过各种方式获取到一枚cmdshell,但是这个shell的权限比较低,无法让我们做我们想要做的一些操作,比如说获取系统密码,获取数据库信息,又或者比如说拿到服务器中的另一个站点的权限,...

是50个常用的Visual Basic代码示例:

以下是50个常用的VisualBasic代码示例:1.声明变量```vb...

电脑系统型号怎么看版本(如何看电脑系统型号)

有时候我们会需要进行查看电脑上安装的windows系统版本及系统版本号,但对于不懂电脑知识的小白来说要怎么查看电脑系统版本信息呢?别着急,有小编在接下来,就将查看电脑系统版本的教程来分享给你们,希望对...

dos命令systeminfo,查看系统启动时间。电脑卡慢,win10怎么了?

最近一段时间,有几个反应电脑卡慢的,都是windows10的系统。询问得知每天电脑有关机,打开任务管理器,内存使用量达到百分之九十多,而程序只打开微信、wps、360浏览器。cmd窗口运行命令syst...

systeminfo命令:全面解析系统信息!

你是否曾想过,仅凭一条简单的命令,就能深入了解计算机的"内心世界"?是不是有点不可思议?那么,让我们一起探寻这个神奇的命令,揭开它背后的奥秘吧!它能提供的信息超乎你的想象,从操作系统到硬件配置,再到驱...

电脑序列号怎么查询?只需两行命令一键查询

当我们的电脑出问题需要保修的时候,需要查询到电脑的型号和序列号才更便于进行下一步的操作,有包装盒的朋友还可以在包装盒上查询,笔记本用户可以在电脑底部标签上查询,没有包装盒和标签破损的用户就无从下手了。...

快速显示系统信息:Systeminfo命令详解

Systeminfo命令是windows系统中显示系统信息的命令,此命令可以显示出计算机的操作系统的详细配置信息,包括操作系统配置、安全信息、产品ID和硬件属性(如RAM、磁盘空间和网卡)。使用...

dos命令systeminfo图文教程,显示操作系统配置信息msinfo32

大家好,我是老盖,首先感谢观看本文,本篇文章做的有视频,视频讲述的比较详细,也可以看我发布的视频。今天我们学习systeminfo命令,该工具显示本地或远程机器(包括服务包级别)的操作系统配置的信息,...

基于uniapp+vue3跨端仿制chatgpt实例uniapp-chatgpt

#夏日生活打卡季#...

原创新作uniapp+vue3+pinia2高仿微信App聊天

前段时间有给大家分享一个flutter3.x桌面端os系统。今天再分享一款最新原创之作uniapp-vue3-wechat聊天实例。uni-vue3-wechat采用...

UniApp开发的设备适配(uniapp服务器配置)

UniApp是一个跨平台开发框架,支持多端应用(如H5、小程序、iOS、Android等)。由于不同设备的屏幕尺寸、分辨率、操作系统等存在差异,设备适配是开发过程中需要重点关注的问题。以下是Uni...

如何用服务器搭建自己的个人网站(自己服务器怎么做网站)

这篇教程主要是告诉大家如何利用TCP和HTTP协议来完成网站的搭建。首先你需要有C/C++语言基础,且有服务器、客户端概念,如果你了解TCP或者HTTP协议的话,那么将会帮助你更快的学会如何搭建个人网...

大话C语言:字符数组(c语言字符数组教学视频)

1字符数组概述C语言中没有字符串这种数据类型,可以通过char的数组来替代。数字0(和字符'\0'等价)结尾的char数组就是一个字符串,字符串是一种特殊的char的数组。...

源码分享:在pdf上加盖电子签章(pdf怎么加电子签章)

在pdf上加盖电子签章,并不是只是加个印章图片,。而是要使用一对密钥中的私钥对文件进行签字。为啥要用私钥呢?很简单,因为公钥是公开的,其他人才可以用公钥为你证明,这个文件是你签的。这就是我们常说的:私...

C语言wcstombs函数详解:宽字符字符串到多字节的「翻译官」

核心定位wcstombs是C语言中用于将宽字符字符串转换为多字节字符串的「翻译官」,它能将宽字符(wchar_t)转换为多字节字符(如UTF-8编码的中文)。就像一位翻译官,它能将一种语言(宽字符...

取消回复欢迎 发表评论: