• QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    Chapter1 QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样

    原文链接:https://blog.csdn.net/qq_41632571/article/details/125808787

    一、本自制虚拟键盘特点

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

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

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

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

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

    6.支持win7、win10、Linux等各个系统。

    7.界面好看。

    总之跟真的虚拟键盘一样,不会有不爽的地方

    二、windows打开系统自带软键盘

    QDesktopServices::openUrl(QUrl("osk.exe", QUrl::TolerantMode));
    
    • 1

    传统打开系统自带虚拟键盘的方法如上,一行代码即可,但是系统自带的虚拟键盘不一定好用,有的按键太小,有的电脑上可能没有自带的软键盘,干脆直接写一个。

    三、让键盘界面保持在最上方、不改变底层界面焦点

    很多自制键盘时不知道怎么使键盘保持在最顶层,发现点击键盘界面后系统焦点在键盘界面上了,光标不在底层的行输入框里,就通过输入完成后点击确定的方式将键盘内容传到底层界面,显得不nice,其实这两个问题都很简单能够解决,代码如下

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

    Qt::WindowStaysOnTopHint 设置窗口置顶

    Qt::WindowDoesNotAcceptFocus 设置无焦点窗口

    四、长按按键重复输入键盘内容

    特别是我们点击退格删除键时,文本比较多是我们使用真实键盘就会长按退格键把十多个文本挨个删除,而使用虚拟键盘时要按十多次退格键,显得不nice。那么我们使用QPushButton的setAutoRepeat为true,就可以实现按键长按功能了,设置重复操作延时为500ms差不多了,按下的时长超过500ms后马上再次执行按键槽函数。

    pbtn->setAutoRepeat(true);    //允许自动重复
    pbtn->setAutoRepeatDelay(500);//设置重复操作的时延
    
    • 1
    • 2

    五、模拟键盘点击事件完成虚拟键盘输入

    一些自制虚拟键盘完成键盘输入的方式是同传递文本到输入框的方式,话不多说,就是不nice。点击虚拟按键直接发送对应的按键点击事件就很nice,这样其实就不会太死,甚至中文输入也可以,我们写的是键盘,不是写中文输入法,那些下载网上含有中文输入法的库的大可不必,输入法你系统用的什么就是什么。如果你想中文输入,系统下载的有搜狗输入法,你的键盘只需按下ctrl+shift切换输入法即可,而不是在键盘里实现中文输入法的功能。那样不nice,模拟发送按键点击事件代码如下。

    	QPushButton* pbtn = (QPushButton*)sender();
    	if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {
    		QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
    		QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通过QApplication::sendEvent发送一个按键按下和按键松开的事件就相当于模拟一个按键按下事件

    QKeyEvent说明:

    QKeyEvent::QKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text = QString(), bool autorep = false, ushort count = 1)
    
    • 1

    类型参数必须为QEvent::KeyPress、QEvent::KeyRelease或QEvent::ShortcutOverride。

    Int key是事件循环应该监听的Qt:: key的代码。 如果key为0,则事件不是已知键的结果; 例如,它可能是组合序列或键盘宏的结果。 修饰符包含键盘修饰符,给定的文本是键生成的Unicode文本。 如果autorep为真,isAutoRepeat()将为真。 Count是事件中涉及的键的数量。

    QKeyEvent在我们这里用4个参数就行了,第二个参数Qt:: key对应的按键,第四个参数是需要发送的文本,没有这个参数是无法输入任何内容的。

    QApplication::sendEvent的第一个参数非常重要,是接收键盘输入的控件,比如是底层界面的lineEdit。

    六、键盘符号输入

    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);
     
        QKeyEvent keyPress(QEvent::KeyPress, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
    	QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
    	QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    	QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    键盘输入特定的符号重要是找到QKeyEvent第二个参数对应的按键值即可。按键中的值被都在qnamespace.h的头文件中的enum Key枚举类型内。

    七、界面

    在这里插入图片描述

    八、头文件代码

    #pragma once
    #pragma execution_character_set("utf-8")
    #include 
    #include "ui_frmKeyBoard.h"
    #include "moveWidget.h"
    #include 
    #include 
    #include 
    #include 
     
    class frmKeyBoard : public QDialog
    {
    	Q_OBJECT
     
    public:
    	frmKeyBoard(QWidget *parent = nullptr);
    	~frmKeyBoard();
     
    	void initFocusWidget(QWidget*);
     
    private slots:
    	void slotKeyButtonClicked();
    	void slotKeyLetterButtonClicked();
    	void slotKeyNumberButtonClicked();
     
    private:
    	Ui::frmKeyBoardClass ui;
    	void initFrm();
    	void initStyleSheet();
     
    	QWidget* m_focusWidget;	//键盘输入主窗口
     
    	QVector<QPushButton*> m_letterKeys;
    	QVector<QPushButton*> m_NumberKeys;
     
    	QMap<QString, Qt::Key> m_mapSymbolKeys;
     
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    九、源文件代码

    #include "frmKeyBoard.h"
     
    frmKeyBoard::frmKeyBoard(QWidget *parent)
    	: QDialog(parent)
    {
    	ui.setupUi(this);
     
    	this->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
    	this->setWindowTitle("屏幕键盘");
    	this->setWindowModality(Qt::WindowModal); 
    	this->setAttribute(Qt::WA_DeleteOnClose);
     
    	MoveWidget* moveWidget = new MoveWidget();
    	moveWidget->setWidget(this);
     
    	this->initFrm();
    	this->initStyleSheet();
    }
     
    frmKeyBoard::~frmKeyBoard()
    {
    }
     
    void frmKeyBoard::initFocusWidget(QWidget* widget)
    {
    	m_focusWidget = widget;
    }
     
    void frmKeyBoard::initFrm()
    {
        ui.pushButton_closeKeyboard->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
    	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);
    		}
    	}
     
    	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 += "QPushButton{ color:white; background-color:rgb(51,51,51); height:60px; 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::slotKeyButtonClicked()
    {
    	QPushButton* pbtn = (QPushButton*)sender();
    	QString objectName = pbtn->objectName();
    	if (objectName == "pushButton_closeKeyboard") {
    		this->close();
    		return;
    	}
    	if (pbtn->text().contains("Backspace")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->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") {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Space, Qt::NoModifier, " ");
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Space, Qt::NoModifier, " ");
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Tab")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Tab, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Enter")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Shift")) {
    		if (pbtn->isChecked()) {
    			for (auto pbtnKey : m_letterKeys) {
    				pbtnKey->setText(pbtnKey->text().toUpper());
    			}
    		}
    		else {
    			for (auto pbtnKey : m_letterKeys) {
    				pbtnKey->setText(pbtnKey->text().toLower());
    			}
    		}
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Shift, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Ctrl")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Control, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Win")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("Alt")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Alt, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("↑")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Up, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("↓")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Down, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("←")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text().contains("→")) {
    		QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
    		QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->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), Qt::NoModifier, symbol);
    		QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	//取消组合键按下
    	if (!pbtn->text().contains("Shift") && !pbtn->text().contains("Ctrl") && !pbtn->text().contains("Win") && !pbtn->text().contains("Alt")) {
    		if (ui.pushButton_shift->isChecked()) {
    			ui.pushButton_shift->setChecked(false);
    			for (auto pbtnKey : m_letterKeys) {
    				pbtnKey->setText(pbtnKey->text().toLower());
    			}
    		}
    		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);
    	}
    }
     
     
    void frmKeyBoard::slotKeyLetterButtonClicked()
    {
    	QPushButton* pbtn = (QPushButton*)sender();
    	if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {
    		QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
    		QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	else if (pbtn->text() >= 'A' && pbtn->text() <= 'Z') {
    		QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()), Qt::NoModifier, pbtn->text());
    		QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()), Qt::NoModifier, pbtn->text());
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    		QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	}
    	//取消组合键按下
    	if (ui.pushButton_shift->isChecked()) {
    		ui.pushButton_shift->setChecked(false);
    		for (auto pbtnKey : m_letterKeys) {
    			pbtnKey->setText(pbtnKey->text().toLower());
    		}
    	}
    	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);
    }
     
    void frmKeyBoard::slotKeyNumberButtonClicked()
    {
    	QPushButton* pbtn = (QPushButton*)sender();
    	QKeyEvent keyPress(QEvent::KeyPress, pbtn->text().toInt() + 48, Qt::NoModifier, pbtn->text());
    	QKeyEvent keyRelease(QEvent::KeyRelease, pbtn->text().toInt() + 48, Qt::NoModifier, pbtn->text());
    	QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
    	QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
    	//取消组合键按下
    	if (ui.pushButton_shift->isChecked()) {
    		ui.pushButton_shift->setChecked(false);
    		for (auto pbtnKey : m_letterKeys) {
    			pbtnKey->setText(pbtnKey->text().toLower());
    		}
    	}
    	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);
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277

    十、使用示例

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
     
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
     
        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->initFocusWidget(this);
        keyBoard->show();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    十一、效果

    在这里插入图片描述

    Chapter2 [QDialog]qt虚拟键盘的实现以及qdateedit实现打开虚拟键盘

    原文链接:https://blog.csdn.net/x1010121/article/details/126534744

    一、虚拟键盘的拖动

    首先,实现虚拟键盘的拖动功能就需要对QDialog的鼠标事件进行重写,所以就需要自己写一个继承于QDialog的子类。
    在这里插入图片描述
    这里代码参考qt实现窗口拖动的两种思路_肩上风骋的博客-CSDN博客_qt 拖动窗口

    二、创建QDialog类继承于自己写的dialog类并布局键盘界面

    在这里插入图片描述
    这里除了构造函数以外,还需要初始化、读取字符、添加字符、删除字符四个函数以及一个按钮按下的槽函数,然后对按钮界面进行布局,我的布局如下:。
    在这里插入图片描述
    一个lineedit以及一些按钮,我这里是写了一个自定义的按钮类,将按钮都提升为我自定义的类型,可以使得按钮更美观。

    三、具体函数的实现

    3.1初始化

    在这里插入图片描述
    初始化中是对所有的自定义按钮连接信号与槽,其中findChildren<>函数是搜寻所有能转换为指定类型的控件,这个用于批量处理非常方便,所以这里就批量将按钮的clicked信号与自定义的clicked槽函数绑定。

    3.2读取字符

    在这里插入图片描述
    打开键盘时,要将目标的lineEdit的内容读取到键盘中的lineEdit中,并将私有成员变量value也进行初始化,该函数在构造函数中调用。

    3.3增加字符

    在这里插入图片描述
    实现点击按钮增加对应的字符,并更新lineEdit显示的内容。

    3.4删除字符

    在这里插入图片描述

    实现点击删除按钮时,删除一个字符。

    3.5槽函数

    在这里插入图片描述
    第一步是获取发送信号的按钮的指针,根据指针来判断当前的按钮是哪种类型。第二步针对不同类型做出不同处理,当类型是关闭按钮时就触发qdialog自带的reject信号实现关闭对话框;是接收按钮时就触发qdialog自带的accept信号,这个是用于要写入数据的QLineEdit的信号,后面会用到;是删除按钮就调用删除字符的函数;剩下的就只有添加字符的按钮也就是键盘上的各个数字,实现增加字符。

    4、自定义QLineEdit实现点击打开自定义键盘

    这里只需要重写lineEdit的mousePressEvent事件,在事件中添加以下代码。
    在这里插入图片描述

    这里意思是当QLineEdit检测到鼠标按下事件时,打开键盘,并用exec()循环检测是否有Accepted信号触发,这个accepted信号就是前面那个槽函数点击确定时触发的信号,收到这个信号就读取键盘中当前的value的值并写入到控件中。

    5、qdateedit和qtimeedit控件实现点击打开自定义键盘

    首先也是需要重写这两个类,但与QlineEdit不同的是,这两个控件本身是组合型控件,所以不能简单的重写mousePressEvent事件,而是需要用到事件过滤器。

    5.1安装事件过滤器

    在这里插入图片描述
    这里的lineEdit()就是返回一个QLineEdit对象,这个是这个控件本身获取lineedit子控件的一个方法。

    5.2写事件过滤

    在这里插入图片描述
    这里的主要逻辑是,判断是否是lineedit子控件的鼠标按压事件,如果是就打开键盘,之后根据点击位置的不同来对时、分、秒的数据进行修改,修改完后同样是用exec()循环检测信号来实现输入。

    虚拟键盘参考Qt 实现虚拟键盘_lie to me的博客-CSDN博客_qt 虚拟键盘

    Chapter3 Qt 实现虚拟键盘

    https://blog.csdn.net/weixin_42193704/article/details/108255663?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2defaultOPENSEARCHRate-1-108255663-blog-126534744.pc_relevant_multi_platform_featuressortv2dupreplace&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2defaultOPENSEARCHRate-1-108255663-blog-126534744.pc_relevant_multi_platform_featuressortv2dupreplace&utm_relevant_index=1

    利用重写LineEdit 然后监听鼠标点击事件,根据LineEdit 的选择控制是数字键盘还是英文数字混合键盘。
    在这里插入图片描述
    在这里插入图片描述
    实现方式非常的简单

    只需要遍历所有的按键然后绑定槽函数

    void keyboardNumDialog::init()
    {
     
    //    this->setWindowFlags(Qt::FramelessWindowHint);
    //    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
         setWindowModality(Qt::WindowModal);//半阻塞模式
        QList<QPushButton *> btn = this->findChildren<QPushButton *>();
        foreach (QPushButton * b, btn) {
            connect(b, SIGNAL(clicked()), this, SLOT(btn_clicked()));
        }
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    特殊按键单独处理,如果是数值直接将显示的内容添加到编辑框上就行了

    void keyboardNumDialog::btn_clicked()
    {
        QPushButton *btn = (QPushButton *)sender();
     
        if(btn == ui->pb_close){
            this->reject();
            return ;
        }
        if(btn == ui->pb_enter)
        {
            this->accept();
            return ;
        }
        if(btn == ui->pb_delete)
        {
            delOneValue();
            return ;
        }
        if(btn == ui->pb_clear)
           {
               this->value = "";
               ui->lineEdit->clear();
               return ;
           }
        QString objectName = btn->text();
        addChar(objectName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    LineEdit部分

    继承这个控件然后重写鼠标松开事件

    然后再界面上提升控件 就可以了

    直接监听鼠标单击事件(这样把自己坑了,监听鼠标事件不能监听按下事件要监听松开事件,因为按下以后需要和松开同步使用的,这样操作会导致第一次点击输入法无效)

    因为数字输入操作比较频繁,这里改成单例

    void LineEditInput::mouseReleaseEvent(QMouseEvent * )
    {
         qDebug()<<this->inputMethodHints()<<" ";
        if(this->inputMethodHints() == Qt::ImhPreferNumbers)
        {
            keyboardNumDialog *input = keyboardNumDialog::GetInstance();
            input->setInputType(QLineEdit::Normal);
            input->initValue(this->text());
    //        keyboardNumDialog *input = bn(this->text());
     
            if(input->exec() == QDialog::Accepted)
            {
                this->setText(input->getValue());
            }
            else
            {
     
            }
            input->close();
     
        }
        else if(this->inputMethodHints() == Qt::ImhHiddenText)
            {
                keyboardEnDialog input;
                input.initValue(this->text());
                        if(input.exec() == QDialog::Accepted)
                        {
                            this->setText(input.getValue());
                        }
                        else
                        {
    
                        }
    
            }
        else if(this->echoMode() == QLineEdit::Password)
        {
            keyboardNumDialog *input = keyboardNumDialog::GetInstance();
            input->initValue(this->text());
            input->setInputType(QLineEdit::Password);
    //        keyboardNumDialog *input = bn(this->text());
     
            if(input->exec() == QDialog::Accepted)
            {
                this->setText(input->getValue());
            }
            else
            {
     
            }
            input->close();
        }
        else
        {
    //        ErrorMessage(tr("Error"),tr("未设置输入类型"));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    然后就可以通过Qt Creator UI编辑器中的
    在这里插入图片描述
    通过选择这两个的其中一个就可以切换数字键盘或者是英文键盘了

    在这里插入图片描述

    2023.11.15添加大小写处理部分

    头文件里面添加:

    private:
        Ui::keyboardEnDialog *ui;
        QString value;
        bool flagCapslock; //大小写按键标志位
    
    • 1
    • 2
    • 3
    • 4

    CPP文件里面添加:

    void keyboardEnDialog::btn_clicked()
    {
    //    static bool flagCapslock = false; //大小写按键标志位
        QPushButton *btn = (QPushButton *)sender();
    
        if(btn == ui->pb_close){
            this->reject();
            return ;
        }
        if(btn == ui->pb_enter)
        {
            this->accept();
            return ;
        }
        if(btn == ui->pb_delete)
        {
            delOneValue();
            return ;
        }
        if(btn == ui->pb_clear)
        {
            this->value = "";
            ui->lineEdit->clear();
            return ;
        }
        if(btn == ui->pb_capslk) //按下CAPSLOCK按键
        {
            if(flagCapslock == false)
            {
                ui->pb_a->setText(tr("A"));
                ui->pb_b->setText(tr("B"));
                ui->pb_c->setText(tr("C"));
                ui->pb_d->setText(tr("D"));
                ui->pb_e->setText(tr("E"));
                ui->pb_f->setText(tr("F"));
                ui->pb_g->setText(tr("G"));
                ui->pb_h->setText(tr("H"));
                ui->pb_i->setText(tr("I"));
                ui->pb_j->setText(tr("J"));
                ui->pb_k->setText(tr("K"));
                ui->pb_l->setText(tr("L"));
                ui->pb_m->setText(tr("M"));
                ui->pb_n->setText(tr("N"));
                ui->pb_o->setText(tr("O"));
                ui->pb_p->setText(tr("P"));
                ui->pb_q->setText(tr("Q"));
                ui->pb_r->setText(tr("R"));
                ui->pb_s->setText(tr("S"));
                ui->pb_t->setText(tr("T"));
                ui->pb_u->setText(tr("U"));
                ui->pb_v->setText(tr("V"));
                ui->pb_w->setText(tr("W"));
                ui->pb_x->setText(tr("X"));
                ui->pb_y->setText(tr("Y"));
                ui->pb_z->setText(tr("Z"));
    
                flagCapslock = true;
                return ;
            }
            else
            {
                ui->pb_a->setText(tr("a"));
                ui->pb_b->setText(tr("b"));
                ui->pb_c->setText(tr("c"));
                ui->pb_d->setText(tr("c"));
                ui->pb_e->setText(tr("e"));
                ui->pb_f->setText(tr("f"));
                ui->pb_g->setText(tr("g"));
                ui->pb_h->setText(tr("h"));
                ui->pb_i->setText(tr("i"));
                ui->pb_j->setText(tr("j"));
                ui->pb_k->setText(tr("k"));
                ui->pb_l->setText(tr("l"));
                ui->pb_m->setText(tr("m"));
                ui->pb_n->setText(tr("n"));
                ui->pb_o->setText(tr("o"));
                ui->pb_p->setText(tr("p"));
                ui->pb_q->setText(tr("q"));
                ui->pb_r->setText(tr("r"));
                ui->pb_s->setText(tr("s"));
                ui->pb_t->setText(tr("t"));
                ui->pb_u->setText(tr("u"));
                ui->pb_v->setText(tr("v"));
                ui->pb_w->setText(tr("w"));
                ui->pb_x->setText(tr("x"));
                ui->pb_y->setText(tr("y"));
                ui->pb_z->setText(tr("z"));
    
                flagCapslock = false;
                return ;
            }
        }
        QString objectName = btn->text();
        addChar(objectName);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    或者引用第三方处理思路:
    在这里插入图片描述

    修改效果

    在这里插入图片描述

    2023-11-27修改bug

    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); //要去掉

    keyboardEnDialog::keyboardEnDialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::keyboardEnDialog)
    {
        ui->setupUi(this);
    //    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); //要去掉
    
        this->value = "";
        flagCapslock = false;
        this->init();
        //    this->setStyleSheet("{ background-color: blue; }"); //设置背景颜色
    }
    
    
    void keyboardEnDialog::init()
    {
        //            this->setWindowFlags(Qt::FramelessWindowHint);
        //            this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
        //    this->setWindowTitle(tr("数字键盘"));
    //    setWindowModality(Qt::WindowModal);//半阻塞模式
        setWindowModality(Qt::ApplicationModal);//阻塞模式
        QList<QPushButton *> btn = this->findChildren<QPushButton *>();
        foreach (QPushButton * b, btn) {
            connect(b, SIGNAL(clicked()), this, SLOT(btn_clicked()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); //要去掉

    keyboardNumDialog::keyboardNumDialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::keyboardNumDialog)
    {
        ui->setupUi(this);
    //    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); //要去掉
    
        this->value = "";
        this->init();
        //    this->setStyleSheet("{ background-color: blue; }"); //设置背景颜色
    }
    
    void keyboardNumDialog::init()
    {
        //        this->setWindowFlags(Qt::FramelessWindowHint);
        //        this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
        //    this->setWindowTitle(tr("数字键盘"));
    //    setWindowModality(Qt::WindowModal);//半阻塞模式
        setWindowModality(Qt::ApplicationModal);//阻塞模式
        QList<QPushButton *> btn = this->findChildren<QPushButton *>();
        foreach (QPushButton * b, btn) {
            connect(b, SIGNAL(clicked()), this, SLOT(btn_clicked()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    本周技术概要20231016-20231022与生活点滴
    Meilisearch客户端完美改造
    django setting.py中的SECRET_KEY
    为什么 0.1 + 0.1 !== 0.2
    哪里有写毕业论文需要的外文文献?
    图的遍历—图的DFS—反向建边;
    【设计模式】概述
    【图像分类】【深度学习】【Pytorch版本】Inception-ResNet模型算法详解
    html网页如何获取后台数据库的数据(html + ajax + php + mysql)
    【store商城项目02】登录功能的开发
  • 原文地址:https://blog.csdn.net/m0_46577050/article/details/133701956