当主界面有一个QLineEdit被激活时,默认情况下,点击窗口的其它位置不会取消掉QLineEdit的激活状态(即QLineEdit仍然具有焦点),除非是点击按钮一类的控件。
如图,无论怎么点击空白窗口处,QLineEdit会一直处于激活状态。
如果我们希望在鼠标点击其它位置时,QLineEdit失去焦点,那就必须要设置事件过滤器evenFilter,捕捉到所有的鼠标点击事件。
代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QLineEdit>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lineEdit->setFocusPolicy(Qt::ClickFocus);
qApp->installEventFilter(this); //为所有控件添加事件过滤器
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event) {
if(event->type() == QEvent::MouseButtonPress && watched != ui->lineEdit)
{
ui->lineEdit->clearFocus();
this->setFocus();
}
}
这时候在点击非lineEdit的控件或者窗口时,lineEdit将失去焦点,光标也随之消失。
但是,如果在QLineEdit中使用了QCompleter补全,那么情况会变得复杂一些:
如图,当下拉补全框出现以后,如果不选择它,直接点击其它位置,那么QLineEdit的闪烁光标仍然不会消失,这明显不符合我们的开发需求。
这个问题也好解决,我们在clearFocus之前先setFocus就可以了。原因暂时不知道,或许是因为下拉框占据了焦点?????
不过这样做仍然需要点击两次才能让光标消失,第一次只能让下拉框消失,不过这样也是正常的。
代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QLineEdit>
#include <QCompleter>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lineEdit->setFocusPolicy(Qt::ClickFocus);
//添加 QCompleter
QStringList word_list;
word_list<<"Python"<<"Php"<<"C/C++"<<"C#";
QCompleter *completer = new QCompleter(word_list, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);//忽略大小写
ui->lineEdit->setCompleter(completer);
qApp->installEventFilter(this); //为所有控件添加事件过滤器
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event) {
if(event->type() == QEvent::MouseButtonPress && watched != ui->lineEdit)
{
ui->lineEdit->setFocus();
ui->lineEdit->clearFocus();
this->setFocus();
}
return QObject::eventFilter(watched,event);
}
这样其实还是可能会有一个问题:
如图,在实际的项目中,由于用的控件比较多,比较复杂,如果只是简单的判断 watched是否等于QLineEdit,那么可能会出现这样的结果,这不是我们想要的。
最万无一失的办法,判断鼠标点击的位置,是否处于QLineEdit中,如果不是,则去掉焦点:
项目中部分代码如下:
if(event->type() == QEvent::MouseButtonPress){
QMouseEvent *mEvent = static_cast<QMouseEvent*>(event);
QPoint mWindowGlobalPoint(this->mapToGlobal(QPoint(0,0)));
QPoint mouseGlobalPoint(mEvent->globalPos());
QPoint tPoint = mouseGlobalPoint - mWindowGlobalPoint;
//qDebug()<<m_searchWidget->geometry()<< mWindowGlobalPoint << mouseGlobalPoint << tPoint;
if( !m_searchWidget->geometry().contains(tPoint) ){
if(m_isSearching == true){
m_searchWidget->setFocus();
m_searchWidget->clearFocus();
}
}
}
注意:这里是要得到鼠标按下时在主窗口的位置,而不是父窗口的位置。我没有找到怎么直接获取在主窗口的位置,是通过全局位置进行计算得到的。
这个计算好像有点问题,因为geometry是控件相对于父窗口的坐标。后来又发现了一种新的方式,可以获取到点击事件相对于控件父窗口的坐标,然后再判断鼠标相对于控件父窗口的位置是否在控件在其父窗口里面所占的位置即可:
QMouseEvent *mEvent = static_cast<QMouseEvent*>(event);
QWidget *srcParent = static_cast<QWidget*>(sourcePathLine->parent()); //得到sourcePathLine父窗口
QWidget *inTextParent = static_cast<QWidget*>(inputText->parent()); //得到inputText父窗口
QPoint srcPoint = srcParent ->mapFromGlobal(mEvent->globalPos());//得到鼠标点击位置相对于父窗口坐标
QPoint inTextPoint = inTextParent->mapFromGlobal(mEvent->globalPos());//得到鼠标点击位置相对于父窗口坐标
if (!sourcePathLine->geometry().contains(srcPoint)) {
sourcePathLine->deselect();
}
if (!inputText->geometry().contains(inTextPoint)) {
QTextCursor cursor = inputText->textCursor();
cursor.movePosition(QTextCursor::End);
inputText->setTextCursor(cursor);
}
正常情况: