QT自制软键盘 最完美、最简单、支持中文输入(二)

源客V 2024-07-17 11:35:03 阅读 86

目录

一、前言

二、本自制虚拟键盘特点

三、中文输入原理

四、组合键输入

五、键盘事件模拟

六、界面

 七、代码

7.1 frmKeyBoard 头文件代码

7.2 frmKeyBoard 源文件代码

八、使用示例

九、效果

十、结语


一、前言

        由于系统自带虚拟键盘不一定好用,也不一定好看,有的按键太小,有的电脑上可能没有自带的软键盘,干脆直接自己设计一个。        

        在现代的用户界面设计中,屏幕键盘是一种重要的辅助工具,特别是在触摸屏设备上。本文将深入解析一个使用Qt框架自制的屏幕键盘,具有丰富的功能和用户友好的界面,支持中文输入、组合键操作等多种特性。

        之前写过一篇不带中文的屏幕键盘,本文在该基础上升级部分功能:QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样(一)

二、本自制虚拟键盘特点

1.支持中文输入。

2.支持组合键,例如“Ctrl+C”复制粘贴操作。

3.键盘界面保持在所有界面最上方。

4.点击键盘按钮不会改变底层文本输入框焦点。

5.通过模拟键盘点击事件完成键盘输入文本信息。

6.包含各种键盘自带符号输入。

7.长按按键可以持续重复输入键盘内容。

三、中文输入原理

        资源中包含了“PinYin_Chinese.txt”文本文件,文件内容为七千多个汉字以及对应的拼音,通过加载中文拼音数据,实现了基于拼音的中文输入。在用户输入拼音时,屏幕键盘匹配对应的汉字词组,并显示在候选列表中。

加载中文汉字代码:

<code>void frmKeyBoard::loadChineseFontData()

{

QFile pinyin(":/PinYin_Chinese.txt");

if (!pinyin.open(QIODevice::ReadOnly)) {

qDebug() << "Open pinyin file failed!";

return;

}

while (!pinyin.atEnd()) {

QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();

if (buf.isEmpty())

continue;

/* 去除#号后的注释内容 */

if (buf.left(1) == "#")

continue;

buf=buf.replace("\t"," ");

QString pinyin = buf.mid(1,buf.size() - 1);

QString word = buf.mid(0,1);

QString abb;

QStringList pinyinList = pinyin.split(" ");

for (int i = 0; i < pinyinList.count(); i++) {

/* 获得拼音词组的首字母(用于缩写匹配) */

abb += pinyinList.at(i).left(1);

}

QList<QPair<QString, QString>> &tmp = m_data[pinyin.left(1)];

/* 将'拼音(缩写)'和'词组'写入匹配容器 */

tmp.append(qMakePair(abb, word));

/* 将'拼音(全拼)'和'词组'写入匹配容器 */

tmp.append(qMakePair(pinyin.remove(" "), word));

}

qDebug() << m_data.size();

pinyin.close();

}

点击列表选择汉字输入:

void frmKeyBoard::on_listWidget_itemClicked(QListWidgetItem *item)

{

QKeyEvent keyPress(QEvent::KeyPress, 0, m_curModifier, item->;text().right(1));

QKeyEvent keyRelease(QEvent::KeyRelease, 0, m_curModifier, item->text().right(1));

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

}

 另外,点击汉字对应的数字、点击空格都可以输入汉字,点击回车输入对应的英文字母,部分关键代码:

void frmKeyBoard::slotKeyButtonClicked()

{

QPushButton* pbtn = (QPushButton*)sender();

QString objectName = pbtn->objectName();

if (pbtn->text().contains("Backspace")) {

if(isChinese){

if(recordLitterBuf.size() > 0){

recordLitterBuf.remove(recordLitterBuf.size() - 1, 1);

findChineseFontData(recordLitterBuf);

if(!m_labelShowPinyin->text().isEmpty())

m_labelShowPinyin->setText(recordLitterBuf);

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Backspace, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Backspace, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if(pbtn->text() == "Space") {

if(isChinese){

if(ui.listWidget->count() > 0){

//按下空格输入列表第一汉字

on_listWidget_itemClicked(ui.listWidget->item(0));

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Space, m_curModifier, " ");

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Space, m_curModifier, " ");

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text().contains("Enter")) {

if(isChinese){

if(!m_labelShowPinyin->text().isEmpty()){

//按下回车输入拼音字母

QKeyEvent keyPress(QEvent::KeyPress, 0, m_curModifier, m_labelShowPinyin->text());

QKeyEvent keyRelease(QEvent::KeyRelease, 0,m_curModifier, m_labelShowPinyin->text());

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Enter, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text().contains("Shift")) {

if (pbtn->isChecked()) {

isChinese = true;

m_curModifier = Qt::ShiftModifier;

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toUpper());

}

}

else {

isChinese = false;

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

m_curModifier = Qt::NoModifier;

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toLower());

}

}

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Shift, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Shift, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

//......

else {

QString symbol;

if (ui.pushButton_shift->isChecked())

symbol = pbtn->text().split("\n").at(0);

else

symbol = pbtn->text().split("\n").at(1);

QKeyEvent keyPress(QEvent::KeyPress, m_mapSymbolKeys.value(symbol), m_curModifier, symbol);

QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), m_curModifier, symbol);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

四、组合键输入

       4.1 定义m_curModifier 记录当前键盘模式。

Qt::KeyboardModifier m_curModifier = Qt::NoModifier;

       4.2 特殊按键选中时切换对应的按键模式 

<code>if (pbtn->;text().contains("Ctrl")) {

if(pbtn->isChecked())

m_curModifier = Qt::ControlModifier;

else

m_curModifier = Qt::NoModifier;

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Control, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Control, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

五、键盘事件模拟

        通过模拟键盘事件,实现了对底层文本输入框的模拟输入。这样,用户可以在使用屏幕键盘的同时,保持对其他界面元素的操作。

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Enter, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

        另外,通过qApp->focusWidget()获取当前焦点所在的窗口,可以将键盘模拟输入到各个窗口的输入框中。

六、界面

界面新增了一个QListWidget用于显示候选汉字列表,列表方向从左至右。

 七、代码

7.1 frmKeyBoard 头文件代码

<code>#pragma once

#pragma execution_character_set("utf-8")

#include <QDialog>

#include "ui_frmKeyBoard.h"

#include <QPushButton>

#include <QKeyEvent>

#include <QDebug>

#include <QStyle>

#include <QListWidgetItem>

#include <QLabel>

#include <QVBoxLayout>

#include <QToolTip>

class frmKeyBoard : public QDialog

{

Q_OBJECT

public:

frmKeyBoard(QWidget *parent = nullptr);

~frmKeyBoard();

void initFocusWidget(QWidget*);

private slots:

void slotKeyButtonClicked();

void slotKeyLetterButtonClicked();

void slotKeyNumberButtonClicked();

void on_listWidget_itemClicked(QListWidgetItem *item);

void on_toolButton_lastPage_clicked();

void on_toolButton_nextPage_clicked();

private:

Ui::frmKeyBoardClass ui;

void initFrm();

void initStyleSheet();

void loadChineseFontData();

void findChineseFontData(QString text);

void addOneItem(QString text);

QMap<QString, QList<QPair<QString, QString>>> m_data;

bool isChinese = false;

QString recordLitterBuf;

QVector<QPushButton*> m_letterKeys;

QVector<QPushButton*> m_NumberKeys;

QMap<QString, Qt::Key> m_mapSymbolKeys;

QStringList m_showTextList;

int m_curPage = 0;

QLabel* m_labelShowPinyin;

Qt::KeyboardModifier m_curModifier = Qt::NoModifier;

};

7.2 frmKeyBoard 源文件代码

#include "frmKeyBoard.h"

frmKeyBoard::frmKeyBoard(QWidget *parent)

: QDialog(parent)

{

ui.setupUi(this);

this->;setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);

this->setWindowTitle("屏幕键盘(源客V)");

this->setWindowModality(Qt::WindowModal);

this->setAttribute(Qt::WA_DeleteOnClose);

this->initFrm();

this->initStyleSheet();

this->loadChineseFontData();

}

frmKeyBoard::~frmKeyBoard()

{

}

void frmKeyBoard::initFrm()

{

m_letterKeys.clear();

m_NumberKeys.clear();

QList<QPushButton*> pbtns = this->findChildren<QPushButton*>();

foreach(QPushButton * pbtn, pbtns) {

pbtn->setAutoRepeat(true); //允许自动重复

pbtn->setAutoRepeatDelay(500);//设置重复操作的时延

if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {

connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyLetterButtonClicked);

m_letterKeys.push_back(pbtn);

}

else if (pbtn->text().toInt() > 0 && pbtn->text().toInt() <= 9 || pbtn->text() == "0") {

connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyNumberButtonClicked);

m_NumberKeys.push_back(pbtn);

}

else{

connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyButtonClicked);

}

}

//添加label显示拼音

m_labelShowPinyin = new QLabel();

QVBoxLayout* vLayout = new QVBoxLayout();

vLayout->addWidget(m_labelShowPinyin);

vLayout->addStretch();

ui.listWidget->setLayout(vLayout);

m_mapSymbolKeys.insert("~", Qt::Key_AsciiTilde);

m_mapSymbolKeys.insert("`", Qt::Key_nobreakspace);

m_mapSymbolKeys.insert("-", Qt::Key_Minus);

m_mapSymbolKeys.insert("_", Qt::Key_Underscore);

m_mapSymbolKeys.insert("+", Qt::Key_Plus);

m_mapSymbolKeys.insert("=", Qt::Key_Equal);

m_mapSymbolKeys.insert(",", Qt::Key_Comma);

m_mapSymbolKeys.insert(".", Qt::Key_Period);

m_mapSymbolKeys.insert("/", Qt::Key_Slash);

m_mapSymbolKeys.insert("<", Qt::Key_Less);

m_mapSymbolKeys.insert(">", Qt::Key_Greater);

m_mapSymbolKeys.insert("?", Qt::Key_Question);

m_mapSymbolKeys.insert("[", Qt::Key_BracketLeft);

m_mapSymbolKeys.insert("]", Qt::Key_BracketRight);

m_mapSymbolKeys.insert("{", Qt::Key_BraceLeft);

m_mapSymbolKeys.insert("}", Qt::Key_BraceRight);

m_mapSymbolKeys.insert("|", Qt::Key_Bar);

m_mapSymbolKeys.insert("\\", Qt::Key_Backslash);

m_mapSymbolKeys.insert(":", Qt::Key_Colon);

m_mapSymbolKeys.insert(";", Qt::Key_Semicolon);

m_mapSymbolKeys.insert("\"", Qt::Key_QuoteLeft);

m_mapSymbolKeys.insert("'", Qt::Key_Apostrophe);

}

void frmKeyBoard::initStyleSheet()

{

QString qss;

qss += "QWidget{ background-color:rgb(26,26,26)}";

qss += "QToolButton{ color:white; font:bold 11pt;}";

qss += "QLabel{ color:white; font:13pt;}";

qss += "QListWidget{ color:white; border:none; padding-bottom:10px; }";

qss += "QListWidget::item:hover,QListWidget::item:selected{font:bold; color:yellow; background-color:rgba(0,0,0,0)}";

qss += "QPushButton{ color:white; background-color:rgb(51,51,51); height:50px; font-size:bold 15pt; border:1px solid rgb(26,26,26); border-radius: 0px; min-width:50px;}";

qss += "QPushButton:hover{background-color:rgb(229,229,229); color:black;}";

qss += "QPushButton:pressed,QPushButton:checked{background-color:rgb(0,118,215);}";

qss += "#pushButton_closeKeyboard{background-color:rgba(0,0,0,0); border:0px}";

qss += "#pushButton_closeKeyboard:hover{background-color:#b30220;}";

qss += "#pushButton_space{min-width:500px;}";

qss += "#pushButton_backspace,#pushButton_shift{min-width:100px;}";

qss += "#pushButton_enter{min-width:120px;}";

qss += "#pushButton_tab,#pushButton_ctrl{min-width:70px;}";

qss += "#pushButton_capsLock{min-width:80px;}";

qss += "#pushButton_up{min-width:150px;}";

this->setStyleSheet(qss);

}

void frmKeyBoard::loadChineseFontData()

{

QFile pinyin(":/PinYin_Chinese.txt");

if (!pinyin.open(QIODevice::ReadOnly)) {

qDebug() << "Open pinyin file failed!";

return;

}

while (!pinyin.atEnd()) {

QString buf = QString::fromUtf8(pinyin.readLine()).trimmed();

if (buf.isEmpty())

continue;

/* 去除#号后的注释内容 */

if (buf.left(1) == "#")

continue;

buf=buf.replace("\t"," ");

QString pinyin = buf.mid(1,buf.size() - 1);

QString word = buf.mid(0,1);

QString abb;

QStringList pinyinList = pinyin.split(" ");

for (int i = 0; i < pinyinList.count(); i++) {

/* 获得拼音词组的首字母(用于缩写匹配) */

abb += pinyinList.at(i).left(1);

}

QList<QPair<QString, QString>> &tmp = m_data[pinyin.left(1)];

/* 将'拼音(缩写)'和'词组'写入匹配容器 */

tmp.append(qMakePair(abb, word));

/* 将'拼音(全拼)'和'词组'写入匹配容器 */

tmp.append(qMakePair(pinyin.remove(" "), word));

}

qDebug() << m_data.size();

pinyin.close();

}

void frmKeyBoard::findChineseFontData(QString text)

{

QString lowerText = text.toLower();

m_labelShowPinyin->setText(lowerText);

for (int i = 0; i < ui.listWidget->count(); i++) {

QListWidgetItem *item = ui.listWidget->takeItem(i);

delete item;

item = NULL;

}

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

if(lowerText.count() <= 0)

return;

const QList<QPair<QString, QString> > &tmp = m_data[lowerText.left(1)];

bool fond = false;

for (int i = 0; i < tmp.count(); i++) {

const QPair<QString, QString> &each = tmp.at(i);

if (each.first.left(lowerText.count()) != lowerText)

continue;

fond = true;

addOneItem(each.second);

m_showTextList.push_back(each.second);

}

if(!fond){

if(recordLitterBuf.count() > 1){

recordLitterBuf = recordLitterBuf.right(1);

findChineseFontData(recordLitterBuf);

}

else{

QKeyEvent keyPress(QEvent::KeyPress, int(recordLitterBuf.at(0).toLatin1()), m_curModifier, recordLitterBuf);

QKeyEvent keyRelease(QEvent::KeyRelease, int(recordLitterBuf.at(0).toLatin1()), m_curModifier, recordLitterBuf);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

}

void frmKeyBoard::addOneItem(QString text)

{

if(ui.listWidget->count() >= 9)

return;

QString itemText = QString("%1.%2").arg(ui.listWidget->count() + 1).arg(text);

QListWidgetItem *item = new QListWidgetItem(itemText);

QFont font;

font.setPointSize(15);

font.setBold(true);

font.setWeight(50);

item->setFont(font);

/* 设置文字居中 */

item->setTextAlignment(Qt::AlignBottom | Qt::AlignHCenter);

bool isChineseFlag = QRegExp("^[\u4E00-\u9FA5]+").indexIn(text.left(1)) != -1;

int width = font.pointSize();

if (isChineseFlag)

width += itemText.count()*font.pointSize()*1.5;

else

width += itemText.count()*font.pointSize()*2/3;

item->setSizeHint(QSize(width, 50));

ui.listWidget->addItem(item);

}

void frmKeyBoard::slotKeyButtonClicked()

{

QPushButton* pbtn = (QPushButton*)sender();

QString objectName = pbtn->objectName();

if (pbtn->text().contains("Backspace")) {

if(isChinese){

if(recordLitterBuf.size() > 0){

recordLitterBuf.remove(recordLitterBuf.size() - 1, 1);

findChineseFontData(recordLitterBuf);

if(!m_labelShowPinyin->text().isEmpty())

m_labelShowPinyin->setText(recordLitterBuf);

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Backspace, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Backspace, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text().contains("Caps")) {

if (pbtn->isChecked()) {

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toUpper());

}

}

else {

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toLower());

}

}

}

else if(pbtn->text() == "Space") {

if(isChinese){

if(ui.listWidget->count() > 0){

on_listWidget_itemClicked(ui.listWidget->item(0));

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Space, m_curModifier, " ");

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Space, m_curModifier, " ");

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text().contains("Tab")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Tab, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Tab, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("Enter")) {

if(isChinese){

if(!m_labelShowPinyin->text().isEmpty()){

QKeyEvent keyPress(QEvent::KeyPress, 0, m_curModifier, m_labelShowPinyin->text());

QKeyEvent keyRelease(QEvent::KeyRelease, 0,m_curModifier, m_labelShowPinyin->text());

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

}

}

else{

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Enter, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text().contains("Shift")) {

if (pbtn->isChecked()) {

isChinese = true;

m_curModifier = Qt::ShiftModifier;

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toUpper());

}

}

else {

isChinese = false;

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

m_curModifier = Qt::NoModifier;

for (auto pbtnKey : m_letterKeys) {

pbtnKey->setText(pbtnKey->text().toLower());

}

}

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Shift, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Shift, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("Ctrl")) {

if(pbtn->isChecked())

m_curModifier = Qt::ControlModifier;

else

m_curModifier = Qt::NoModifier;

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Control, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Control, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("Win")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Menu, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Menu, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("Alt")) {

if(pbtn->isChecked())

m_curModifier = Qt::AltModifier;

else

m_curModifier = Qt::NoModifier;

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Alt, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Alt, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("↑")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Up, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Up, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("↓")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Down, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Down, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("←")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Left, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Left, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else if (pbtn->text().contains("→")) {

QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Right, m_curModifier);

QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Right, m_curModifier);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

else {

QString symbol;

if (ui.pushButton_shift->isChecked())

symbol = pbtn->text().split("\n").at(0);

else

symbol = pbtn->text().split("\n").at(1);

QKeyEvent keyPress(QEvent::KeyPress, m_mapSymbolKeys.value(symbol), m_curModifier, symbol);

QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), m_curModifier, symbol);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

void frmKeyBoard::slotKeyLetterButtonClicked()

{

QPushButton* pbtn = (QPushButton*)sender();

if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {

if(isChinese){

recordLitterBuf+=pbtn->text().toLower();

findChineseFontData(recordLitterBuf);

}

else{

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()) - 32, m_curModifier, pbtn->text());

QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()) - 32, m_curModifier, pbtn->text());

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

else if (pbtn->text() >= 'A' && pbtn->text() <= 'Z') {

if(isChinese){

recordLitterBuf+=pbtn->text().toLower();

findChineseFontData(recordLitterBuf);

}

else{

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()), m_curModifier, pbtn->text());

QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()), m_curModifier, pbtn->text());

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

}

}

if (ui.pushButton_ctrl->isChecked())

ui.pushButton_ctrl->setChecked(false);

if (ui.pushButton_win->isChecked())

ui.pushButton_win->setChecked(false);

if (ui.pushButton_alt->isChecked())

ui.pushButton_alt->setChecked(false);

m_curModifier = Qt::NoModifier;

}

void frmKeyBoard::slotKeyNumberButtonClicked()

{

QPushButton* pbtn = (QPushButton*)sender();

int num = pbtn->text().toInt();

if(isChinese){

if(num > 0 && num < 9 && ui.listWidget->count() >= num){

on_listWidget_itemClicked(ui.listWidget->item(num - 1));

}

}

else {

QKeyEvent keyPress(QEvent::KeyPress, num + 48, m_curModifier, pbtn->text());

QKeyEvent keyRelease(QEvent::KeyRelease, num + 48, m_curModifier, pbtn->text());

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

if (ui.pushButton_ctrl->isChecked())

ui.pushButton_ctrl->setChecked(false);

if (ui.pushButton_win->isChecked())

ui.pushButton_win->setChecked(false);

if (ui.pushButton_alt->isChecked())

ui.pushButton_alt->setChecked(false);

}

m_curModifier = Qt::NoModifier;

}

void frmKeyBoard::on_listWidget_itemClicked(QListWidgetItem *item)

{

QKeyEvent keyPress(QEvent::KeyPress, 0, m_curModifier, item->text().right(1));

QKeyEvent keyRelease(QEvent::KeyRelease, 0, m_curModifier, item->text().right(1));

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyPress);

QApplication::sendEvent(qApp->focusWidget() == nullptr ? this : qApp->focusWidget(), &keyRelease);

ui.listWidget->clear();

m_showTextList.clear();

m_curPage = 0;

m_labelShowPinyin->clear();

recordLitterBuf.clear();

}

void frmKeyBoard::on_toolButton_lastPage_clicked()

{

if(m_curPage <= 0)

return;

m_curPage--;

ui.listWidget->clear();

for (int i = m_curPage * 9; i < m_curPage * 9 + 9; i++) {

if(i >= m_showTextList.count())

break;

addOneItem(m_showTextList.at(i));

}

}

void frmKeyBoard::on_toolButton_nextPage_clicked()

{

if(m_curPage >= m_showTextList.count() / 9)

return;

m_curPage++;

ui.listWidget->clear();

for (int i = m_curPage * 9; i < m_curPage * 9 + 9; i++) {

if(i >= m_showTextList.count())

break;

addOneItem(m_showTextList.at(i));

}

}

八、使用示例

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent)

, ui(new Ui::MainWindow)

{

ui->setupUi(this);

this->setWindowTitle("屏幕键盘测试(源客V)");

QHBoxLayout* layout = new QHBoxLayout();

layout->setContentsMargins(0, 0, 0, 0);

layout->addWidget(ui->pushButton, 0, Qt::AlignRight);

ui->lineEdit->setLayout(layout);

}

MainWindow::~MainWindow()

{

delete ui;

}

void MainWindow::on_pushButton_clicked()

{

frmKeyBoard* keyBoard = new frmKeyBoard();

keyBoard->show();

}

九、效果

Qt自制虚拟键盘2(支持中文)

十、结语

        通过深度解析,我们更全面地了解了这个使用Qt框架自制的屏幕键盘。其设计理念、功能特点和实现原理展示了在用户界面开发中如何灵活运用Qt框架,为用户提供强大而友好的输入方式。对于需要在触摸屏设备上提供良好用户体验的应用,这个自制的屏幕键盘提供了一种出色的解决方案。

前序文章:QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样(一)

源码资源:Qt自制虚拟键盘(支持中文) 

本方案已经能满足屏幕键盘输入的大部分需求了,还有不足的地方欢迎大家留言补充。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。