赞
踩
这几天在用QT做项目,遇到键盘问题。项目是用在window 10 平板。手指点击输入框window自带的键盘就会弹出,而且会遮挡界面,window键盘找不到任何接口,不支持定制,透明度不能调,大小不能调。最可气的是点击输入框毕弹出,遮挡自己写的键盘,又不能关闭触屏弹出键盘。
经过多次多次测试,发现把当前窗口设置焦点,让输入框失去焦点,系统键盘就会退出,然后手动设置输入框为焦点。想想是不是很好呀,只是猜测,还要明天去公司验证。
或者在view层对点击事件进行拦截不让点击事件传入输入框内,然后手动设置输入框为焦点。
测试发现只要点击的位置位于输入框区间内,就算把所有事件都拦截(输入框已经无法绘制出来了),系统键盘照样弹出,真想骂人!!!看来拦截事件是行不通了。
只能上笨办法了,在输入框位置绘制一个遮罩,遮罩只能使用Qt::Tool类型窗口,而且不能有继承或者同父类。创建一个透明按钮绘制在输入框上面只会是一片黑。因为是置顶遮罩,存在界面切换需要隐藏遮罩,所以还定义了一个单例通知类,关于键盘可以看我的另外一篇博客。
#pragma once #include <QLineEdit> #include <QDebug> #include <QTimer> #include <QPoint> #include <QMouseEvent> #include "KeyBoard.h" #ifdef WIN32 #include <windows.h> #endif //代理类,接收/发送信号 class SignalSwitech : public QObject { Q_OBJECT signals: void signalClearFocus(); void signalUpdate(); void signalHideMaskEffect(bool isHide); public: static SignalSwitech* Instance(); void clearFocus() { emit signalClearFocus(); } void setIMM(bool b) { mUseIMM = b; } bool useIMM() { return mUseIMM; } void update() { emit signalUpdate(); }; void hideMaskEffect(bool isHide) { emit signalHideMaskEffect(isHide); } private: SignalSwitech() {}; virtual ~SignalSwitech() {}; private: static SignalSwitech *mInstance; bool mUseIMM = false; //是否使用过IMM来控制键盘弹出/隐藏 }; //遮罩 class MaskEffect : public QWidget { Q_OBJECT public: MaskEffect(QWidget *masked); // 必须无父窗口,所以传给基类为nullptr virtual ~MaskEffect(); public: public slots: void updateView(); void hideMaskEffect(bool isHide); protected: bool eventFilter(QObject* target, QEvent* ev) override; virtual void showEvent(QShowEvent *event) override; private: QWidget *mMaskedWidget = nullptr; //被遮罩控件 QRect mScreenRect; QTimer *mTimer = nullptr; }; //输入框 class FXLineEdit : public QLineEdit { Q_OBJECT public: FXLineEdit(QWidget *parent = nullptr); virtual ~FXLineEdit(); public: /*强制系统键盘为英文输入法*/ void setEnglishInputMethod(bool isEn = false); /*是否开启遮罩*/ void setMaskEffect(bool isEffect = true); /*自定义键盘输入法*/ void setIMMode(int IMMode = 0); /*显示输入框即显示键盘*/ void setStartShowKB(int showKB); /*禁用系统输入法*/ void disableSysIME(); protected: bool eventFilter(QObject* target, QEvent* event) override; void showEvent(QShowEvent *event) override; public: signals: void signalClose(); /*通知系统键盘弹出*/ void signalSysKBShow(const bool& isShow = false); private: #ifdef WIN32 HKL hCurKL = NULL; #endif KeyBoard *mKeyboard = nullptr; int mIMMode = -1;//键盘类型具体可见键盘类KeyBoard.h bool mStartShowKB = false;//首次进入输入框处于焦点状态即显示键盘 bool mIsEnglishIM = false;//是否开启英文输入法 bool mIsEffect = false; //是否开启遮罩 MaskEffect *mMaskEffect = nullptr; };
#include <QApplication> #include <QProcess> #include <QFileInfo> #include <QDesktopWidget> #include <QMainWindow> #include <QDesktopServices> #include "FXLineEdit.h" #ifdef WIN32 #include <imm.h> #pragma comment(lib, "imm32.lib ") #endif SignalSwitech* SignalSwitech::mInstance = nullptr; SignalSwitech* SignalSwitech::Instance() { if (mInstance == nullptr) { mInstance = new SignalSwitech(); } return mInstance; } ///- MaskEffect -/// MaskEffect::MaskEffect(QWidget *masked) : QWidget(nullptr) // 无父窗口,所以传给基类为nullptr { this->setWindowTitle("MaskEffect"); QDesktopWidget* desktopWidget = QApplication::desktop(); mScreenRect = desktopWidget->screenGeometry(); Q_ASSERT(masked != nullptr); mMaskedWidget = masked; this->setAttribute(Qt::WA_DeleteOnClose); //初始化窗口属性 this->setWindowOpacity(0.1); //达到比较好的淡出效果,需要将窗口设置完全透明,否则会有卡顿的效果 this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::FramelessWindowHint | Qt::Tool | Qt::WindowDoesNotAcceptFocus | Qt::WindowStaysOnTopHint); this->setStyleSheet("background: white;"); this->setFocusPolicy(Qt::FocusPolicy::NoFocus); this->installEventFilter(this); connect(SignalSwitech::Instance(), &SignalSwitech::signalUpdate, this, &MaskEffect::updateView); connect(SignalSwitech::Instance(), &SignalSwitech::signalHideMaskEffect, this, &MaskEffect::hideMaskEffect); } void MaskEffect::hideMaskEffect(bool isHide) { if (isHide) { this->hide(); SignalSwitech::Instance()->clearFocus();//清除输入框焦点 } else { this->show(); updateView(); } } MaskEffect:: ~MaskEffect() { disconnect(SignalSwitech::Instance(), &SignalSwitech::signalUpdate, this, &MaskEffect::updateView); disconnect(SignalSwitech::Instance(), &SignalSwitech::signalHideMaskEffect, this, &MaskEffect::hideMaskEffect); this->removeEventFilter(this); } bool MaskEffect::eventFilter(QObject* target, QEvent* ev) { switch (ev->type()) { case QEvent::Paint: case QEvent::Timer: case QEvent::ToolTip: break; default: //qDebug() << "eventFilter" << ev->type(); break; } switch (ev->type()) { //case QEvent::HoverMove: //case QEvent::MouseMove: //case QEvent::InputMethodQuery: //case QEvent::FocusIn: //case QEvent::Enter: //初始化会发送这些事件导致键盘弹出 //case QEvent::TouchBegin: //case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { QPoint p = this->mapFromGlobal(QCursor::pos());//鼠标位置 QMouseEvent me(QMouseEvent::MouseButtonRelease, p, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QCoreApplication::sendEvent(mMaskedWidget, &me); mMaskedWidget->setEnabled(true); mMaskedWidget->setFocus(); } break; default: break; } return QWidget::eventFilter(target, ev); } void MaskEffect::showEvent(QShowEvent *event) { if (mMaskedWidget == nullptr) { return; } QRegion region = mMaskedWidget->visibleRegion(); QRect rect = region.boundingRect(); QPoint p = mMaskedWidget->mapToGlobal(rect.topLeft()); qDebug() << p; qDebug() << rect; this->move(p); this->setFixedSize(rect.size()); } void MaskEffect::updateView() { if (mMaskedWidget == nullptr) { return; } QRegion region = mMaskedWidget->visibleRegion(); QRect rect = region.boundingRect(); QPoint p = mMaskedWidget->mapToGlobal(rect.topLeft()); qDebug() << p; qDebug() << rect; this->move(p); this->setFixedSize(rect.size()); } - FXLineEdit -// FXLineEdit::FXLineEdit(QWidget *parent) : QLineEdit(parent) { this->setObjectName("FXLineEdit"); this->installEventFilter(this); this->setStyleSheet("background-color:rgb(255,255,255);"); //this->setAttribute(Qt::WA_InputMethodEnabled, false); } FXLineEdit::~FXLineEdit() { if (mMaskEffect != nullptr) { delete mMaskEffect; mMaskEffect = nullptr; } this->clearFocus(); this->removeEventFilter(this); #ifdef WIN32 HWND hWnd = ::FindWindow(L"IPTip_Main_Window", NULL); if (hWnd) { ::PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); //关闭键盘 } #endif if (nullptr != mKeyboard) { delete mKeyboard; mKeyboard = nullptr; } } void FXLineEdit::disableSysIME() { #ifdef WIN320 SignalSwitech::Instance()->setIMM(true); // 屏蔽系统键盘 HWND hWnd = (HWND)this->winId(); HIMC _IMC = ImmGetContext(hWnd); if (hWnd && IsWindow(hWnd)) { ImmAssociateContext(hWnd, NULL); ImmSetOpenStatus(_IMC, FALSE); if (!ImmReleaseContext(hWnd, _IMC)) { qDebug() << "ImmReleaseContext call failed!"; } } #endif // WIN32 } void FXLineEdit::setMaskEffect(bool isEffect) { mIsEffect = isEffect; connect(SignalSwitech::Instance(), &SignalSwitech::signalClearFocus, this, [=]() { this->clearFocus(); this->setDisabled(true); if (mKeyboard != nullptr) { mKeyboard->hide(); mKeyboard->close(); delete mKeyboard; mKeyboard = nullptr; } }); } void FXLineEdit::setEnglishInputMethod(bool isEn) { mIsEnglishIM = isEn; } void FXLineEdit::setIMMode(int IMMode) { mIMMode = IMMode; mKeyboard = new KeyBoard(nullptr, IMMode); mKeyboard->BindingEdit(this); } void FXLineEdit::setStartShowKB(int showKB) { mStartShowKB = showKB; } void FXLineEdit::showEvent(QShowEvent *event) { if (mIsEffect) { if (mMaskEffect == nullptr) { mMaskEffect = new MaskEffect(this); mMaskEffect->show(); } } if (this->hasFocus() && mStartShowKB) { mKeyboard->show(); } } bool FXLineEdit::eventFilter(QObject* target, QEvent* ev) { switch (ev->type()) { case QEvent::Paint: case QEvent::Timer: case QEvent::ToolTip: break; default: SignalSwitech::Instance()->update(); qDebug() << "FXLineEdit::eventFilter " << ev->type(); break; } switch (ev->type()) { //case QEvent::TouchBegin: //case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { if (mIsEffect) { //根据鼠标位置设置光标位置 QMouseEvent* me = static_cast<QMouseEvent*>(ev); this->setCursorPosition(this->cursorPositionAt(me->pos())); } if (mIMMode > -1) { #ifdef WIN32 HWND hWnd = ::FindWindow(L"IPTip_Main_Window", NULL); if (hWnd) { ::PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); //关闭键盘 } #endif if (nullptr == mKeyboard) { mKeyboard = new KeyBoard(nullptr, mIMMode); mKeyboard->BindingEdit(this); } mKeyboard->show(); } else if (mIsEnglishIM || this->echoMode() == QLineEdit::Password || this->echoMode() == QLineEdit::PasswordEchoOnEdit)//强制系统键盘为英文输入法 { #ifdef WIN32 if (SignalSwitech::Instance()->useIMM()) { QString programFilesPath(qgetenv("PROGRAMFILES").replace("\\", "/")); QString tabTipPath = QString("%1/Common Files/microsoft shared/ink/TabTip.exe").arg(programFilesPath); if (QFileInfo(tabTipPath).exists()) { QDesktopServices::openUrl(QUrl("file:///" + tabTipPath)); } } hCurKL = GetKeyboardLayout(0); LoadKeyboardLayout((LPCWSTR)QString("0x0409").utf16(), KLF_ACTIVATE); #endif emit signalSysKBShow(true); } } break; default: break; } switch (ev->type()) { case QEvent::Hide: case QEvent::FocusOut: case QEvent::FocusAboutToChange: // 使用此控件界面主动清除输入焦点 { if (mIMMode > -1) { this->setEnabled(false); if (nullptr != mKeyboard) { mKeyboard->hide(); mKeyboard->close(); delete mKeyboard; mKeyboard = nullptr; } } #ifdef WIN32 if (SignalSwitech::Instance()->useIMM()) { HWND hWnd = ::FindWindow(L"IPTip_Main_Window", NULL); if (hWnd) { ::PostMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0); //关闭键盘 } } else if (hCurKL != NULL) { ActivateKeyboardLayout(hCurKL, 0); //还原输入法 } #endif } break; case QEvent::Leave: case QEvent::HoverLeave: //不能用此事件作为输入框失去焦点,因为点击键盘也会发出此消息 break; case QEvent::FocusIn: break; default:break; } return QWidget::eventFilter(target, ev); // 最后将事件交给上层对话框 }
使用
FXLineEdit *lineEdit = new FXLineEdit(this);
lineEdit->setFixedSize(100,60);
lineEdit->setFont(DimensionAdapter::Instance()->getFont(FONT_LIST_CONTENT));
lineEdit->setAutoFillBackground(true);
lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lineEdit->setStyleSheet("background:white;border-width:2px;border-color:black;");
lineEdit->disableSysIME();
lineEdit->setMaskEffect(true);
window 10 可以通过禁用输入法来实现禁止键盘弹出测试发现部分系统下可以
#ifdef WIN32
// 通过禁止所有输入法达到屏蔽系统键盘
HIMC _IMC;
HWND hWnd = (HWND)this->winId();
_IMC = ImmGetContext(hWnd);
if (hWnd && IsWindow(hWnd)) {
ImmAssociateContext(hWnd, NULL);
ImmReleaseContext(hWnd, _IMC);
}
//启用
ImmAssociateContext(hWnd, _IMC);
#endif // WIN32
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。