目前各个帖子都没有完美解决QT下模态窗口的键盘无响应问题,此帖已解决此问题。
问题原因:原因主要是模态窗口卡住了虚拟键盘的事件响应,导致两者冲突,出现界面假死现象
目前主要解决方案是设置Dialog为非模态窗口,此法属于绕过虚拟键盘问题,模态窗口的作用就没有了,也就没有这个帖子的意义了。
那要怎么解决这个事件无响应,并且不能修改模态窗口的属性呢?
我思索了很久,偶然想起来模态窗口的子控件是完全可以响应事件的,那我们可以在创建虚拟键盘时将模态窗口设置为虚拟键盘的父对象,不就可以了吗?
//如果当前焦点控件的父控件存在模态窗口就将键盘窗口设置为模态窗口的子类
if(!m_keyboard){
if(b){
m_keyboard = new KeyBoard(testParent);
}else{
m_keyboard = new KeyBoard();
}
}
那么现在又存在两个问题了
一、怎么知道当前控件的上层父控件是模态窗口呢?
二、一个控件的父对象可以一直向上有多个,怎么一直查找呢?
第一个解决方案很简单,通过 QWidget中的windowModality()方法获取窗口模式,判断是否为模态窗口。
第二个我们可以通过递归查找方式来判断,代码如下。
bool isDialogParent(QWidget* _widget)
{
if(_widget == nullptr){
return false;
}
if(_widget->windowModality() & Qt::ApplicationModal){
testParent = _widget;
return true;
}
if(_widget->parent() != nullptr){
auto wid = qobject_cast<QWidget*>(_widget->parent());
if(wid){
return isDialogParent(wid);
}
}
return false;
}
经过测试,目前这个没有任何问题。
详细代码如下:
键盘布局文件:
KeyBoard.h
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include <QWidget>
#include <QPushButton>
class KeyBoard : public QWidget
{
Q_OBJECT
public:
explicit KeyBoard(QWidget *parent = nullptr);
~KeyBoard();
signals:
void sendKeyToFocusItem(const QString &keytext);
void _move(int x,int y);
int _show(bool b);
void _setInputType(int type);
private:
QPushButton * btn1 = nullptr;
QPushButton * btn2 = nullptr;
QPushButton * btn3 = nullptr;
QPushButton * btn4 = nullptr;
QPushButton * btn5 = nullptr;
QPushButton * btn6 = nullptr;
QPushButton * btn7 = nullptr;
QPushButton * btn8 = nullptr;
QPushButton * btn9 = nullptr;
QPushButton * btnA = nullptr;
QPushButton * btnB = nullptr;
QPushButton * btnC = nullptr;
QPushButton * btnD = nullptr;
QPushButton * btnE = nullptr;
QPushButton * btnF = nullptr;
QPushButton * btn0 = nullptr;
QPushButton * btnDel = nullptr;
QPushButton * btnPoint = nullptr;
};
#endif // KEYBOARD_H
KeyBoard.cpp
#include "KeyBoard.h"
#include <QtDebug>
#include <QGridLayout>
#define BTN_SIZE 60
KeyBoard::KeyBoard(QWidget *parent) :
QWidget(parent)
{
//设置主窗体样式
//this->setAttribute(Qt::WA_TranslucentBackground);
this->setWindowFlags(Qt::Tool | \
Qt::FramelessWindowHint | \
Qt::WindowStaysOnTopHint | \
Qt::WindowDoesNotAcceptFocus);
//this->setFixedSize(150,200);
this->setStyleSheet("QWidget{"
"background-color:rgb(25,25,25);"
"}"
"QPushButton{"
" font:25px;"
" background-color:rgb(49,49,49);"
" color:white;"
" border:2px solid rgb(25,25,25);"
" border-radius:5px;"
" }"
"QPushButton:hover{"
" background-color:rgb(36,177,213);"
" color:white;"
"}"
"QPushButton:pressed{"
" color:blue;"
"}");
btn1 = new QPushButton("1",this);btn1->setFixedSize(BTN_SIZE,BTN_SIZE);
btn2 = new QPushButton("2",this);btn2->setFixedSize(BTN_SIZE,BTN_SIZE);
btn3 = new QPushButton("3",this);btn3->setFixedSize(BTN_SIZE,BTN_SIZE);
btn4 = new QPushButton("4",this);btn4->setFixedSize(BTN_SIZE,BTN_SIZE);
btn5 = new QPushButton("5",this);btn5->setFixedSize(BTN_SIZE,BTN_SIZE);
btn6 = new QPushButton("6",this);btn6->setFixedSize(BTN_SIZE,BTN_SIZE);
btn7 = new QPushButton("7",this);btn7->setFixedSize(BTN_SIZE,BTN_SIZE);
btn8 = new QPushButton("8",this);btn8->setFixedSize(BTN_SIZE,BTN_SIZE);
btn9 = new QPushButton("9",this);btn9->setFixedSize(BTN_SIZE,BTN_SIZE);
btnA = new QPushButton("A",this);btn7->setFixedSize(BTN_SIZE,BTN_SIZE);
btnB = new QPushButton("B",this);btn8->setFixedSize(BTN_SIZE,BTN_SIZE);
btnC = new QPushButton("C",this);btn9->setFixedSize(BTN_SIZE,BTN_SIZE);
btnD = new QPushButton("D",this);btn7->setFixedSize(BTN_SIZE,BTN_SIZE);
btnE = new QPushButton("E",this);btn8->setFixedSize(BTN_SIZE,BTN_SIZE);
btnF = new QPushButton("F",this);btn9->setFixedSize(BTN_SIZE,BTN_SIZE);
btn0 = new QPushButton("0",this);btn0->setFixedSize(BTN_SIZE,BTN_SIZE);
btnDel = new QPushButton(u8"←",this);btnDel->setFixedSize(BTN_SIZE,BTN_SIZE);
btnPoint = new QPushButton(".",this);btnPoint->setFixedSize(BTN_SIZE,BTN_SIZE);
auto layout = new QGridLayout(this);
layout->setSpacing(3);
layout->setMargin(3);
layout->addWidget(btn1,0,1);
layout->addWidget(btn2,0,2);
layout->addWidget(btn3,0,3);
layout->addWidget(btn4,1,1);
layout->addWidget(btn5,1,2);
layout->addWidget(btn6,1,3);
layout->addWidget(btn7,2,1);
layout->addWidget(btn8,2,2);
layout->addWidget(btn9,2,3);
layout->addWidget(btnA,3,1);
layout->addWidget(btnB,3,2);
layout->addWidget(btnC,3,3);
layout->addWidget(btnD,4,1);
layout->addWidget(btnE,4,2);
layout->addWidget(btnF,4,3);
layout->addWidget(btnPoint,5,1);
layout->addWidget(btn0,5,2);
layout->addWidget(btnDel,5,3);
connect(btn1,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("1");});
connect(btn2,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("2");});
connect(btn3,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("3");});
connect(btn4,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("4");});
connect(btn5,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("5");});
connect(btn6,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("6");});
connect(btn7,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("7");});
connect(btn8,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("8");});
connect(btn9,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("9");});
connect(btnA,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("A");});
connect(btnB,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("B");});
connect(btnC,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("C");});
connect(btnD,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("D");});
connect(btnE,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("E");});
connect(btnF,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("F");});
connect(btn0,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("0");});
connect(btnPoint,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem(".");});
connect(btnDel,&QPushButton::clicked,this,[&](){emit sendKeyToFocusItem("\x7F");});
connect(this,&KeyBoard::_move,this,[&](int x,int y){
this->move(x,y);
});
connect(this,&KeyBoard::_show,this,[&](bool b){
if(b){
this->show();
}else{
this->hide();
}
});
//在这里扩展用户输入类型
connect(this,&KeyBoard::_setInputType,this,[&](int type){
if(type == 0){
btnA->setVisible(false);
btnB->setVisible(false);
btnC->setVisible(false);
btnD->setVisible(false);
btnE->setVisible(false);
btnF->setVisible(false);
}else{
btnA->setVisible(true);
btnB->setVisible(true);
btnC->setVisible(true);
btnD->setVisible(true);
btnE->setVisible(true);
btnF->setVisible(true);
}
});
}
KeyBoard::~KeyBoard()
{
}
虚拟键盘实现接口文件:
GZH_VirtualKeyBoard.h
#ifndef GZH_VIRTUALKEYBOARD_H
#define GZH_VIRTUALKEYBOARD_H
#include <qpa/qplatforminputcontext.h>
#include "KeyBoard.h"
#include <QThread>
class GZH_VirtualKeyBoard : public QPlatformInputContext
{
Q_OBJECT
public:
GZH_VirtualKeyBoard();
~GZH_VirtualKeyBoard();
bool isValid() const Q_DECL_OVERRIDE;
void setFocusObject(QObject *object) Q_DECL_OVERRIDE;
void showInputPanel() Q_DECL_OVERRIDE;
void hideInputPanel() Q_DECL_OVERRIDE;
bool isInputPanelVisible() const Q_DECL_OVERRIDE;
private:
void sendKeyToFocusItem(const QString &keytext);
KeyBoard * m_keyboard = nullptr;
QObject * m_focusitem = nullptr;
QWidget * testParent = nullptr;
bool isDialogParent(QWidget*);
};
#endif // GZH_VIRTUALKEYBOARD_H
GZH_VirtualKeyBoard.cpp
#include "GZH_VirtualKeyBoard.h"
#include <QCoreApplication>
#include <QKeyEvent>
#include <QApplication>
#include <QDesktopWidget>
#include "KeyBoard.h"
#include <QtDebug>
GZH_VirtualKeyBoard::GZH_VirtualKeyBoard()
{
}
GZH_VirtualKeyBoard::~GZH_VirtualKeyBoard()
{
disconnect(m_keyboard, &KeyBoard::sendKeyToFocusItem, this, &GZH_VirtualKeyBoard::sendKeyToFocusItem);
if(m_keyboard) delete m_keyboard;
}
void GZH_VirtualKeyBoard::sendKeyToFocusItem(const QString &keytext)
{
if(!m_focusitem)return;
if(keytext == QString("\x7F"))
{
QCoreApplication::sendEvent(m_focusitem, new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier));
QCoreApplication::sendEvent(m_focusitem, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier));
}else
{
QCoreApplication::sendEvent(m_focusitem, new QKeyEvent(QEvent::KeyPress, 0, Qt::NoModifier, keytext));
QCoreApplication::sendEvent(m_focusitem, new QKeyEvent(QEvent::KeyRelease, 0, Qt::NoModifier, keytext));
}
}
bool GZH_VirtualKeyBoard::isValid() const
{
return true;
}
void GZH_VirtualKeyBoard::setFocusObject(QObject *object)
{
m_focusitem = object;
}
void GZH_VirtualKeyBoard::showInputPanel()
{
//如果当前焦点控件的父控件存在模态窗口就将键盘窗口设置为模态窗口的子类
bool b = isDialogParent(qobject_cast<QWidget*>(m_focusitem));
if(!m_keyboard){
if(b){
m_keyboard = new KeyBoard(testParent);
}else{
m_keyboard = new KeyBoard();
}
connect(m_keyboard, &KeyBoard::sendKeyToFocusItem, this, &GZH_VirtualKeyBoard::sendKeyToFocusItem);
}
if(m_keyboard->isHidden())emit m_keyboard->_show(true);
QWidget *widgetTmp = qobject_cast<QWidget*>(m_focusitem);
if(widgetTmp){
QPoint widgetGlobalPos = widgetTmp->mapToGlobal(QPoint(0, 0));
if(widgetGlobalPos.x() < 0){
widgetGlobalPos.setX(0);
}
if(widgetGlobalPos.y() < 0){
widgetGlobalPos.setY(0);
}
if(qApp->desktop()->width() - widgetGlobalPos.x() < m_keyboard->width()){
widgetGlobalPos.setX(qApp->desktop()->width() - m_keyboard->width());
}
if(qApp->desktop()->height() - widgetGlobalPos.y() - 30 < m_keyboard->height()){
widgetGlobalPos.setY(widgetGlobalPos.y() - m_keyboard->height() - 10);
}
else{
widgetGlobalPos = widgetGlobalPos + QPoint(0,30);
}
emit m_keyboard->_setInputType(widgetTmp->property("bdtype").toInt());
emit m_keyboard->_move(widgetGlobalPos.x(),widgetGlobalPos.y());
}
}
void GZH_VirtualKeyBoard::hideInputPanel()
{
if(!m_keyboard){
return;
}
delete m_keyboard;
m_keyboard = nullptr;
}
bool GZH_VirtualKeyBoard::isInputPanelVisible() const
{
return m_keyboard->isVisible();
}
//核心方法,查找当前焦点所在窗口是否为dialog窗口
bool GZH_VirtualKeyBoard::isDialogParent(QWidget* _widget)
{
if(_widget == nullptr){
return false;
}
if(_widget->windowModality() & Qt::ApplicationModal){
testParent = _widget;
return true;
}
if(_widget->parent() != nullptr){
auto wid = qobject_cast<QWidget*>(_widget->parent());
if(wid){
return isDialogParent(wid);
}
}
return false;
}
新手使用指导帖子:QT 虚拟键盘使用问题_悟情道长的博客-CSDN博客
完整项目地址:
https://download.csdn.net/download/qq_32854345/87173147?spm=1001.2014.3001.5501文章来源:https://www.toymoban.com/news/detail-485136.html
如需要积分,可以联系球球654320149发送文章来源地址https://www.toymoban.com/news/detail-485136.html
到了这里,关于QT 虚拟键盘问题解决,dialog,模态窗口,无感知的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!