识别QLineEdit是否失去焦点

时间:2017-06-28 08:37:09

标签: qt focus qlineedit qvalidator

在我的一个项目中,我有一系列QLineEdit小部件,它们应该接受一个位于特定范围内的双重数字。出于某些原因,我无法使用QDoubleSpinBox

现在我正在使用QDoubleValidator检查我的号码是否在给定范围内。不幸的是,仅当editingFinished给出QValidator时才会发出信号QValidator::Acceptable

现在假设我可能有一系列这样的QLineEdit小部件。在一个我输入一个错误的数字,然后我将焦点切换到另一个小部件。用户在QLineEdit内留下了错误的值。

我希望的行为是将焦点设置为包含错误输入并发出警告的窗口小部件。

由于某些原因,我未能实现此功能。甚至在我查阅了Qt文档之后。

这是我的完整代码。

ValidatedDoubleEditorWidget.h

#pragma once

#include <QWidget>

namespace Ui {
    class validatedDoubleEditorWidget;
}

class QDoubleValidator;

    class ValidatedDoubleEditorWidget : public QWidget {
        Q_OBJECT
    public:
        ValidatedDoubleEditorWidget(double min, double max, double value);

        double getValue() const;
        void setValue(const double value);

    private slots:
        void on_lineEdit_editingFinished();

    protected:
        virtual void focusOutEvent(QFocusEvent *event) override;


        virtual void focusInEvent(QFocusEvent *event) override;

    private:
        Ui::validatedDoubleEditorWidget* mWidget = nullptr;
        double mValue = 0.;
        double mMin = 0.;
        double mMax = 0.;
        QDoubleValidator* mValidator = nullptr;

    };

ValidatedDoubleEditorWidget.cpp

#include "ValidatedDoubleEditorWidget.h"
#include <QDoubleValidator>
#include <QMessageBox>
#include <QDebug>
#include "ui_ValidatedDoubleEditorWidget.h"

ValidatedDoubleEditorWidget::ValidatedDoubleEditorWidget(double min, double max, double value)
{
    mWidget = new Ui::validatedDoubleEditorWidget;
    mWidget->setupUi(this);
    mValue = value;
    mWidget->lineEdit->setText(QString("%1").arg(value));
    mValidator = new QDoubleValidator(min, max, 20, this);
    mWidget->lineEdit->setValidator(mValidator);
    setFocusProxy(mWidget->lineEdit);
    setFocusPolicy(Qt::StrongFocus);
}

double ValidatedDoubleEditorWidget::getValue() const
{
    return mValue;
}

void ValidatedDoubleEditorWidget::setValue(const double value)
{
    mValue = value;
    mWidget->lineEdit->setText(QString("%1").arg(value));
}


void ValidatedDoubleEditorWidget::on_lineEdit_editingFinished()
{
    QString text = mWidget->lineEdit->text();
    qDebug() << "Editing finished";
    bool ok;
    double value = text.toDouble(&ok);
    if (!ok) {
        //
    }
    else {
        mValue = value;
    }
}

void ValidatedDoubleEditorWidget::focusOutEvent(QFocusEvent *event)
{
    qDebug() << "OutFocus";
    QString text = mWidget->lineEdit->text();
    int i;
    auto state=mValidator->validate(text, i);
    if (state != QValidator::Acceptable) {
        QMessageBox::warning(this, tr("Invalid Input!"), tr("Please check your input."), QMessageBox::Ok); 
        mWidget->lineEdit->setText(QString("%1").arg(mValue));
        mWidget->lineEdit->setFocus();
    }

}

void ValidatedDoubleEditorWidget::focusInEvent(QFocusEvent *event)
{
    qDebug() << "InFocus";
}

TestRunner.cpp

#include <QApplication>
#include <QMap>
#include <QFrame>
#include <QHBoxLayout>
#include "ValidatedDoubleEditorWidget.h"

int main(int argc, char** args) {
    QApplication app(argc, args);
    QFrame frame;
    frame.setLayout(new QHBoxLayout);
    frame.layout()->addWidget(new ValidatedDoubleEditorWidget(-1., 4., 1.));
    frame.layout()->addWidget(new ValidatedDoubleEditorWidget(-2., 4., 5.));

    frame.show();
    app.exec();
    return 0;
}

2 个答案:

答案 0 :(得分:1)

SetFocusProxy()并不意味着父窗口小部件将获得子窗口小部件的焦点事件。这意味着当父项被赋予焦点时,子窗口小部件将获得焦点。

因此,在您的情况下,您的focusIn()和focusOut()事件处理程序用于父窗口小部件,但父窗口小部件已被赋予行编辑作为其焦点代理,这意味着行编辑将是您要检查的窗口小部件专注于进出事件。

检测行编辑的相关焦点进出事件的一种方法是使用事件过滤器。基本上WidgetA可以在WidgetB上安装一个事件过滤器,然后在WidgetB即将撤销事件时(例如关注或关注事件)通知。

因此,在您的情况下,您可以在构造函数中为ValidatedDoubleEditorWidget类的行编辑安装事件过滤器,如下所示:

mWidget->lineEdit->installEventFilter( this );

然后你可以添加事件过滤器实现(再次到你的ValidatedDoubleEditorWidget类):

// Declaration
virtual bool eventFilter(QObject *watched, QEvent *event) override;

// Implementation
bool ValidatedDoubleEditorWidget::eventFilter(QObject *watched, QEvent *event)
{
    if( event->type() == QEvent::FocusIn ) {

        qDebug() << "Line edit focus in event";
    }

    else if( event->type() == QEvent::FocusOut ) {

        qDebug() << "Line edit focus out event";
    }
    return false; // We return false to ignore the event and allow the child to recieve the event normally
}

这应该可以让您检测到ValidatedDoubleEditorWidget何时失去焦点并且不包含有效输入。

答案 1 :(得分:1)

您可以继承QLineEdit并重新实现focusOutEvent方法。调用QLineEdit::hasAcceptableInput检查输入是否有效。如果不是,您可以致电setFocus重新获得输入焦点。您还可以显示警告对话框或发出一些信号。这是一个例子:

#include <QtWidgets>

class CustomLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    CustomLineEdit(QWidget *parent = nullptr) : QLineEdit(parent){}
protected:
    void focusOutEvent(QFocusEvent *event)
    {
        QLineEdit::focusOutEvent(event);
        if(!hasAcceptableInput())
        {
            setFocus();
            emit validationError();
        }
    }
signals:
    void validationError();
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow m;
    m.setCentralWidget(new QWidget);
    m.centralWidget()->setLayout(new QVBoxLayout);

    QDoubleValidator d_validator(0, 10, 2);
    CustomLineEdit l1;
    CustomLineEdit l2;
    l1.setValidator(&d_validator);
    l2.setValidator(&d_validator);

    QObject::connect(&l1, &CustomLineEdit::validationError, [=]{qDebug() << "Validation error!";});
    QObject::connect(&l2, &CustomLineEdit::validationError, [=]{qDebug() << "Validation error!";});

    m.centralWidget()->layout()->addWidget(&l1);
    m.centralWidget()->layout()->addWidget(&l2);

    m.show();
    return a.exec();
}

#include "main.moc"