前言
在项目中,遇到了在通过焦点事件调用系统输入法显示异常的情况,后来发现问题发生在焦点事件上,在调用输入法以及关闭输入法的时候出现了焦点的转移,这就导致输入法一直被调用。
就特意研究了一下Qt的焦点事件,以及通过QLineEdit进行一些测试操作。
焦点事件
在应用程序中,都会有一个当前窗口,即当前获得焦点事件的窗口,这个窗口可以接受键盘的输入。
焦点事件分为FocusIn和FocusOut,也就是获得焦点和失去焦点两种情况。
QLineEdit焦点事件测试
接下来就是测试了,为了结果的可靠性,这里分为两种方式进行验证:事件过滤器、重写QLineEdit。
使用事件过滤器的方式
源码如下:
#include "QLineEdtFocusEventTest.h"
#include "windows.h"
#include <QMessageBox>
QLineEdtFocusEventTest::QLineEdtFocusEventTest(QWidget *parent)
: QMainWindow(parent)
, m_pMessageBox(new QMessageBox(this))
{
ui.setupUi(this);
ui.lineEdit->installEventFilter(this);
ui.lineEdit->setFocusPolicy(Qt::ClickFocus);
}
bool QLineEdtFocusEventTest::eventFilter(QObject * watched, QEvent * event)
{
static int inTime = 0;
static int outTime = 0;
if (ui.lineEdit == watched)
{
if (event->type() == QEvent::FocusIn)
{
ShellExecute(NULL, L"open", L"C:/Program Files/Common Files/Microsoft Shared/ink/TabTip.exe", NULL, NULL, SW_SHOWNA);
ui.intimeLbl->setText(QString::number(++inTime));
}
else if (event->type() == QEvent::FocusOut)
{
ui.outtimeLbl->setText(QString::number(++outTime));
DWORD WM_DESKBAND_CLICKED = ::RegisterWindowMessage(L"TabletInputPanelDeskBandClicked");
HWND hWnd = ::FindWindow(L"IPTip_Main_Window", NULL);
if (hWnd != NULL && ::IsWindowVisible(hWnd))
{
::PostMessage(hWnd, WM_DESKBAND_CLICKED, 0, 0);
}
}
}
return QMainWindow::eventFilter(watched, event);
}
测试的结果为,在点击QLineEdit文本框的时候,会触发FocusIn事件,然后就会调出输入法;但是在调用输入法的过程中,QLineEdit将会触发FocusOut失去焦点事件;在关闭输入法之后,又会触发QLineEdit的FocusIn事件,如此循环往复。
重写QLineEdit的方式
源码如下:
#pragma once
#include <QLineEdit>
class MyLineEdt : public QLineEdit
{
Q_OBJECT
signals:
void fin();
void fout();
public:
MyLineEdt(QWidget *parent = nullptr);
~MyLineEdt();
protected:
virtual void focusInEvent(QFocusEvent *e) override;
virtual void focusOutEvent(QFocusEvent *e) override;
};
#include "MyLineEdt.h"
#include <QMessageBox>
#include "windows.h"
MyLineEdt::MyLineEdt(QWidget *parent)
: QLineEdit(parent)
{
}
MyLineEdt::~MyLineEdt()
{
}
void MyLineEdt::focusInEvent(QFocusEvent * e)
{
emit fin();
ShellExecute(NULL, L"open", L"osk.exe", NULL, NULL, SW_SHOWNORMAL);
}
void MyLineEdt::focusOutEvent(QFocusEvent *e)
{
emit fout();
DWORD WM_DESKBAND_CLICKED = ::RegisterWindowMessage(L"TabletInputPanelDeskBandClicked");
HWND hWnd = ::FindWindow(L"IPTip_Main_Window", NULL);
if (hWnd != NULL && ::IsWindowVisible(hWnd))
{
::PostMessage(hWnd, WM_DESKBAND_CLICKED, 0, 0);
}
}
#include "QLineEdtFocusEventTest.h"
#include "windows.h"
#include <QMessageBox>
QLineEdtFocusEventTest::QLineEdtFocusEventTest(QWidget *parent)
: QMainWindow(parent)
, m_pMessageBox(new QMessageBox(this))
{
ui.setupUi(this);
ui.lineEdit->setFocusPolicy(Qt::ClickFocus);
connect(ui.lineEdit, SIGNAL(fin()), this, SLOT(onfin()));
connect(ui.lineEdit, SIGNAL(fout()), this, SLOT(onfout()));
}
void QLineEdtFocusEventTest::onfout()
{
static int i{ 1 };
ui.outtimeLbl->setText(QString::number(i++));
}
void QLineEdtFocusEventTest::onfin()
{
static int i{ 1 };
ui.intimeLbl->setText(QString::number(i++));
}
测试结果同使用事件过滤器的方式相同。
操作系统对于焦点事件的影响
后为了严谨性,更换了操作系统进行测试,当前使用的是Windows10操作系统,现更换为Windows7操作系统。
后发现在Windows7操作系统中,在调用输入法的过程中没有丢失焦点。
我当时的表情就是这样的:ヾ(。ꏿ﹏ꏿ)ノ゙。
原因未知,没有查到这方面的资料,如果读者知晓这方面的原因的话,还请在评论区留言,不胜感谢。
结论
在Windows10操作系统中,如果涉及到调用其他软件或界面的情况,最好不要采用焦点事件的方式,在Windows7中倒是没有这个顾忌。