**出发点:由于Qt自带的软键盘是QML的,如果使用QWidget模式去编写调用自带的软键盘的话,在ARM下运行会全屏漆黑,并不是我们想要的效果,所以,在网上搜了很多的资料,自己去做了自制键盘,在项目中使用。 **
新建一个keyboard的Demo
以下是键盘的布局
键盘初始化
准备好26个输入的字符列表,用作大小写、数字切换
QMap<int,QList<QString>> modelMap;
QList<QString> firstList,secordList,thirdList;
firstList<<"Q"<<"W"<<"E"<<"R"<<"T"<<"Y"<<"U"<<"I"<<"O"<<"P"<<"A"<<"S"<<"D"<<"F"<<"G"<<"H"<<"J"<<"K"<<"L"<<"Z"<<"X"<<"C"<<"V"<<"B"<<"N"<<"M";
secordList<<"q"<<"w"<<"e"<<"r"<<"t"<<"y"<<"u"<<"i"<<"o"<<"p"<<"a"<<"s"<<"d"<<"f"<<"g"<<"h"<<"j"<<"k"<<"l"<<"z"<<"x"<<"c"<<"v"<<"b"<<"n"<<"m";
thirdList<<"1"<<"2"<<"3"<<"4"<<"5"<<"6"<<"7"<<"8"<<"9"<<"0"<<"~"<<"!"<<"@"<<"#"<<"%"<<"^"<<"&"<<"*"<<"?"<<"("<<")"<<"-"<<"_"<<":"<<";"<<"/";
modelMap.insert(1,firstList);
modelMap.insert(2,secordList);
modelMap.insert(3,thirdList);
以下是大小写、数字切换的函数接口
/*************************************************
Function:modeExchange// 函数名称
Description: 模式切换// 函数功能、性能等的描述
Input: int modeNum -> 模式值// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::modeExchange(int modeNum)
{
switch (modeNum) {
case 2://小写
for (int i=0;i<modelMap.value(2).length();i++){
btngroup->button(i+1)->setText(modelMap.value(2).at(i));
}
break;
case 1://大写
for (int i=0;i<modelMap.value(2).length();i++){
btngroup->button(i+1)->setText(modelMap.value(1).at(i));
}
break;
case 3://数字
for (int i=0;i<modelMap.value(2).length();i++){
btngroup->button(i+1)->setText(modelMap.value(3).at(i));
}
break;
default:
break;
}
}
26个字符按键输入函数接口
/*************************************************
Function:onClick// 函数名称
Description: 模式切换// 函数功能、性能等的描述
Input: int modeNum -> 模式值// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::onClick(int value)
{
QString buffer;
switch (modeIndex) {
case 0:
buffer=modelMap.value(2).at(value-1);
break;
case 1:
buffer=modelMap.value(1).at(value-1);
break;
case 2:
buffer=modelMap.value(3).at(value-1);
break;
default:
break;
}
if(isChinese){
recordBuf+=buffer;
findFontData(recordBuf);
}else{
recordBuf.clear();
insertValue(buffer);
}
}
除了26个基本字符按键外,还有一些功能按键,如数字切换键,大小写切换键,中英文切换键,删除键等等。。。。。
/*************************************************
Function:otherBtnClick()// 函数名称
Description: 功能按键槽函数// 函数功能、性能等的描述
Input: 无// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::otherBtnClick()
{
QPushButton *b = (QPushButton *)sender();
if(b==ui->spacebtn){//空格
recordBuf+=" ";
findFontData(recordBuf);
}else if(b==ui->keydelbtn){//删除
if(recordBuf.length()!=0){
recordBuf.remove(recordBuf.length()-1,1);
findFontData(recordBuf);
}else{
deleteValue();
}
}else if((b==ui->oneSwitchbtn||b==ui->oneSwitchbtn)&&numFlag==false){//大小写
if(sizeFlag==true){//小写
modeIndex=1;
sizeFlag=false;
modeExchange(1);
}
else{
modeIndex=0;
sizeFlag=true;
modeExchange(2);
}
}else if(b==ui->numbtn){
if(!numFlag){
modeIndex=2;
modeExchange(3);
}
else{
modeIndex=0;
modeExchange(2);
}
numFlag=!numFlag;
} else if(b==ui->ChEnbtn&&numFlag==false){
if(isChinese){
ui->ChEnbtn->setText("英文");
}else{
ui->ChEnbtn->setText("中文");
}
isChinese = !isChinese;
}else if(b==ui->keyexitbtn) {
this->close();
}
}
按键功能接口编写好后,接下来我们需要加载自定义的字库
/*************************************************
Function:loadFontData// 函数名称
Description: 加载字库函数// 函数功能、性能等的描述
Input: 无// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::loadFontData()
{
QFile pinyin(":/pinyin.txt");
if (! pinyin.open(QIODevice::ReadOnly)) {
qDebug() << "Open pinyin file failed!";
return;
}
while (! pinyin.atEnd()) {
QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();
// qDebug()<<buf;
if (buf.isEmpty())
continue;
/* 去除#号后的注释内容 */
if (buf.left(1) == "#")
continue;
buf=buf.replace("\t"," ");
// qDebug()<<buf;
/* 正则匹配词组内容并通过组捕获获取'词组'和'拼音' */
QRegExp regExp("(\\S+) : ([\\S ]+)");
int pos = 0;
while ((pos = regExp.indexIn(buf, pos)) != -1) {
pos += regExp.matchedLength();
QString second = regExp.cap(1); /* 词组 */
QString first = regExp.cap(2); /* 拼音 */
QStringList strList = first.split(" ");
QString abb;
for (int i = 0; i < strList.count(); i++) {
/* 获得拼音词组的首字母(用于缩写匹配) */
abb += strList.at(i).left(1);
}
QList<QPair<QString, QString> > &tmp = m_data[first.left(1)];
/* 将'拼音(缩写)'和'词组'写入匹配容器 */
tmp.append(qMakePair(abb, second));
/* 将'拼音(全拼)'和'词组'写入匹配容器 */
tmp.append(qMakePair(first.remove(" "), second));
}
}
// qDebug()<<m_data["b"];
}
通过用户输入的字符从字库中提取出来
/*************************************************
Function:findFontData()// 函数名称
Description: 从字库中找相对应的中文// 函数功能、性能等的描述
Input: QString text ->输入的字符// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::findFontData(QString text)
{
for (int i = 0; i < ui->listWidget->count(); i++) {
QListWidgetItem *item = ui->listWidget->takeItem(i);
delete item;
item = NULL;
}
ui->listWidget->clear();
addOneItem(text);
/* 通过获取首字母索引词库内容,用于加快匹配词(组)。 */
const QList<QPair<QString, QString> > &tmp = m_data[text.left(1)];
for (int i = 0; i < tmp.count(); i++) {
const QPair<QString, QString> &each = tmp.at(i);
/* 模糊匹配 */
if (each.first.left(text.count()) != text)
continue;
/* 添加到候选栏 */
addOneItem(each.second);
}
}
/*************************************************
Function:addOneItem()// 函数名称
Description: 将词组添加到显示列表// 函数功能、性能等的描述
Input: QString text ->从字库中提取出来的词组// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::addOneItem(QString text)
{
QListWidgetItem *item = new QListWidgetItem(text);
QFont font;
font.setPointSize(18);
font.setBold(true);
font.setWeight(50);
item->setFont(font);
/* 设置文字居中 */
item->setTextAlignment(Qt::AlignCenter);
bool isChineseFlag = QRegExp("^[\u4E00-\u9FA5]+").indexIn(text.left(1)) != -1;
int width = font.pointSize();
if (isChineseFlag)
width += text.count()*font.pointSize()*1.5;
else
width += text.count()*font.pointSize()*2/3;
item->setSizeHint(QSize(width, 50));
ui->listWidget->addItem(item);
}
双击listWidget列表的选项
connect(ui->listWidget,SIGNAL(itemDoubleClicked(QListWidgetItem *)),this,SLOT(listWidgetDoubleClick(QListWidgetItem *)));
void Dialog::listWidgetDoubleClick(QListWidgetItem *item)
{
qDebug()<<item->text();
recordBuf.clear();
findFontData(recordBuf);
}
删除QlineEdit中的字符
void Dialog::deleteValue()
{
if (currentEditType == "QLineEdit"){
currentLineEdit->backspace();
}
}
插入字符到QLineedit上
/*************************************************
Function:insertValue// 函数名称
Description: 插入值到当前焦点控件// 函数功能、性能等的描述
Input: QString value ->插入的字符// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::insertValue(QString value)
{
if (currentEditType == "QLineEdit"){
currentLineEdit->insert(value);
}
}
接口写好后,接下来是触发启动键盘的条件
首先安装事件过滤器
qApp->installEventFilter(this);
绑定全局焦点信号槽
connect(qApp, SIGNAL(focusChanged(QWidget *, QWidget *)),
this, SLOT(focusChanged(QWidget *, QWidget *)));
/*************************************************
Function:focusChanged// 函数名称
Description: 判断焦点改变// 函数功能、性能等的描述
Input: QWidget *oldWidget ->上一个控件
QWidget *nowWidget ->新控件// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
void Dialog::focusChanged(QWidget *oldWidget, QWidget *nowWidget)
{
qDebug() << "oldWidget:" << oldWidget << " nowWidget:" << nowWidget;
if (nowWidget != nullptr && !this->isAncestorOf(nowWidget)){
if (oldWidget == nullptr && !isFirst){
return;
}
isFirst = false;
if (nowWidget->inherits("QLineEdit")){
currentLineEdit = static_cast<QLineEdit *>(nowWidget);
currentEditType = "QLineEdit";
this->setVisible(true);
}
else{
currentWidget = nullptr;
currentLineEdit = nullptr;
currentEditType = "";
this->setVisible(false);
}
}
}
/*************************************************
Function:eventFilter// 函数名称
Description://事件过滤器 QLineEdit弹出小键盘 // 函数功能、性能等的描述
Input: QObject *obj ->对象
QEvent *event ->事件// 输入参数说明,包括每个参数的作用、取值说明及参数间关系。
Return: 无// 函数返回值的说明
*************************************************/
bool Dialog::eventFilter(QObject *obj, QEvent *event)
{
//qDebug()<<__func__<<":"<<obj->objectName();
if (event->type() == QEvent::MouseButtonPress){
//确保每次点击输入栏都弹出虚拟键盘
if (currentEditType == "QLineEdit"){
this->setVisible(true);
}
return false;
}
return QWidget::eventFilter(obj, event);
}
部分效果图如下
由于拍的视频太大,Gif图上传不了,只能截取部分图出来