Skip to content

Commit 4197fd5

Browse files
committed
Update NumericlLineEdit to allow empty values
1 parent 562d611 commit 4197fd5

12 files changed

Lines changed: 407 additions & 36 deletions

src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ set(SOURCES
170170
qfixedsizedialog.cpp
171171
qhexvalidator.cpp
172172
qint64validator.cpp
173+
qdoublevalidatorex.cpp
174+
qintvalidatorex.cpp
173175
quintvalidator.cpp
174176
recentfileactionlist.cpp
175177
tscrollarea.cpp
@@ -279,6 +281,8 @@ set(HEADERS
279281
qfixedsizedialog.h
280282
qhexvalidator.h
281283
qint64validator.h
284+
qdoublevalidatorex.h
285+
qintvalidatorex.h
282286
qmodbusadu.h
283287
qmodbusadurtu.h
284288
qcountedset.h

src/controls/numericlineedit.cpp

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "qhexvalidator.h"
1313
#include "quintvalidator.h"
1414
#include "qint64validator.h"
15+
#include "qintvalidatorex.h"
16+
#include "qdoublevalidatorex.h"
1517
#include "numericlineedit.h"
1618

1719
namespace
@@ -72,11 +74,10 @@ NumericLineEdit::NumericLineEdit(QWidget* parent)
7274
,_hexButtonVisible(false)
7375
,_allowEmptyValue(false)
7476
{
75-
connect(_hexButton, &QToolButton::toggled, this, &NumericLineEdit::on_hexViewToggled);
76-
7777
setInputMode(Int32Mode);
7878
setValue(0);
7979

80+
connect(_hexButton, &QToolButton::toggled, this, &NumericLineEdit::on_hexViewToggled);
8081
connect(this, &QLineEdit::editingFinished, this, &NumericLineEdit::on_editingFinished);
8182
connect(this, &QLineEdit::textChanged, this, &NumericLineEdit::on_textChanged);
8283
connect(this, &NumericLineEdit::rangeChanged, this, &NumericLineEdit::on_rangeChanged);
@@ -96,11 +97,10 @@ NumericLineEdit::NumericLineEdit(NumericLineEdit::InputMode mode, QWidget *paren
9697
,_hexButtonVisible(false)
9798
,_allowEmptyValue(false)
9899
{
99-
connect(_hexButton, &QToolButton::toggled, this, &NumericLineEdit::on_hexViewToggled);
100-
101100
setInputMode(mode);
102101
setValue(0);
103102

103+
connect(_hexButton, &QToolButton::toggled, this, &NumericLineEdit::on_hexViewToggled);
104104
connect(this, &QLineEdit::editingFinished, this, &NumericLineEdit::on_editingFinished);
105105
connect(this, &QLineEdit::textChanged, this, &NumericLineEdit::on_textChanged);
106106
connect(this, &NumericLineEdit::rangeChanged, this, &NumericLineEdit::on_rangeChanged);
@@ -260,8 +260,7 @@ void NumericLineEdit::updateButtons()
260260
const bool hexVisible = _hexButtonVisible && isHexViewApplicable();
261261
_hexButton->setVisible(hexVisible);
262262

263-
if(hexVisible)
264-
{
263+
if(hexVisible) {
265264
_hexButton->setGeometry(width() - h - 4, 4, h, h);
266265
_hexButton->setIconSize(QSize(h, h));
267266
}
@@ -304,8 +303,7 @@ void NumericLineEdit::setAllowEmptyValue(bool allow)
304303
{
305304
_allowEmptyValue = allow;
306305
setClearButtonEnabled(allow);
307-
if(!allow && !_value.isValid())
308-
internalSetValue(_minValue);
306+
clear();
309307
}
310308

311309
///
@@ -317,12 +315,16 @@ bool NumericLineEdit::isEmpty() const
317315
}
318316

319317
///
320-
/// \brief NumericLineEdit::clearValue
318+
/// \brief NumericLineEdit::clear
321319
///
322-
void NumericLineEdit::clearValue()
320+
void NumericLineEdit::clear()
323321
{
324-
if(_allowEmptyValue)
322+
if(_allowEmptyValue) {
325323
internalSetValue(QVariant());
324+
return;
325+
}
326+
327+
internalSetValue(0);
326328
}
327329

328330
///
@@ -335,8 +337,10 @@ void NumericLineEdit::internalSetValue(QVariant value)
335337
{
336338
const auto oldValue = _value;
337339
_value = QVariant();
340+
338341
if(!QLineEdit::text().isEmpty())
339342
QLineEdit::setText(QString());
343+
340344
if(oldValue.isValid())
341345
{
342346
emit valueChanged(_value);
@@ -617,11 +621,16 @@ void NumericLineEdit::updateValue()
617621
///
618622
void NumericLineEdit::focusInEvent(QFocusEvent* e)
619623
{
620-
internalSetValue(_value); // sets text without "0x" prefix first
621-
// Reduce max length after text is updated to avoid truncation via setMaxLength
622-
if(_inputMode == HexMode || _hexView)
624+
QSignalBlocker blocker(this);
625+
626+
// Reduce max length before text is updated to avoid truncation via setMaxLength
627+
if(_inputMode == HexMode || _hexView) {
623628
setMaxLength(_leadingZeroWidth);
629+
}
630+
internalSetValue(_value); // sets text without "0x" prefix first
631+
624632
QLineEdit::focusInEvent(e);
633+
QLineEdit::selectAll();
625634
}
626635

627636
///
@@ -631,8 +640,10 @@ void NumericLineEdit::focusInEvent(QFocusEvent* e)
631640
void NumericLineEdit::focusOutEvent(QFocusEvent* e)
632641
{
633642
// Restore max length before updateValue so setText("0x...") is not truncated
634-
if(_inputMode == HexMode || _hexView)
643+
if(_inputMode == HexMode || _hexView) {
635644
setMaxLength(_leadingZeroWidth + 2);
645+
}
646+
636647
updateValue();
637648
QLineEdit::focusOutEvent(e);
638649
}
@@ -643,6 +654,8 @@ void NumericLineEdit::focusOutEvent(QFocusEvent* e)
643654
///
644655
void NumericLineEdit::keyPressEvent(QKeyEvent* e)
645656
{
657+
if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
658+
updateValue();
646659
QLineEdit::keyPressEvent(e);
647660
}
648661

@@ -821,13 +834,13 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
821834
{
822835
_leadingZeroWidth = qMax(1, (int)QString::number(static_cast<uint>(top.toInt()), 16).length());
823836
setMaxLength(_leadingZeroWidth + 2); // +2 for "0x"
824-
setValidator(new QHexValidator(this));
837+
setValidator(new QHexValidator(this, _allowEmptyValue));
825838
}
826839
else
827840
{
828841
const int nums = QString::number(top.toInt()).length();
829842
setMaxLength(qMax(2, nums + 1));
830-
setValidator(new QIntValidator(bottom.toInt(), top.toInt(), this));
843+
setValidator(new QIntValidatorEx(bottom.toInt(), top.toInt(), _allowEmptyValue, this));
831844
}
832845
}
833846
break;
@@ -838,14 +851,14 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
838851
{
839852
_leadingZeroWidth = qMax(1, (int)QString::number(top.toUInt(), 16).length());
840853
setMaxLength(_leadingZeroWidth + 2); // +2 for "0x"
841-
setValidator(new QHexValidator(this));
854+
setValidator(new QHexValidator(this, _allowEmptyValue));
842855
}
843856
else
844857
{
845858
const int nums = QString::number(top.toUInt()).length();
846859
_leadingZeroWidth = qMax(1, nums);
847860
setMaxLength(qMax(1, nums));
848-
setValidator(new QUIntValidator(bottom.toUInt(), top.toUInt(), this));
861+
setValidator(new QUIntValidator(bottom.toUInt(), top.toUInt(), _allowEmptyValue, this));
849862
}
850863
}
851864
break;
@@ -855,7 +868,7 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
855868
const int nums = QString::number(top.toUInt(), 16).length();
856869
_leadingZeroWidth = qMax(1, nums);
857870
setMaxLength(qMax(1, nums + 2));
858-
setValidator(new QHexValidator(bottom.toUInt(), top.toUInt(), this));
871+
setValidator(new QHexValidator(bottom.toUInt(), top.toUInt(), this, _allowEmptyValue));
859872
}
860873
break;
861874

@@ -866,7 +879,7 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
866879
case FloatMode:
867880
case DoubleMode:
868881
setMaxLength(INT16_MAX);
869-
setValidator(new QDoubleValidator(bottom.toDouble(), top.toDouble(), 6, this));
882+
setValidator(new QDoubleValidatorEx(bottom.toDouble(), top.toDouble(), 6, _allowEmptyValue, this));
870883
break;
871884

872885
case Int64Mode:
@@ -880,7 +893,7 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
880893
{
881894
const int nums = QString::number(top.toLongLong()).length();
882895
setMaxLength(qMax(2, nums + 1));
883-
setValidator(new QInt64Validator(bottom.toLongLong(), top.toLongLong(), this));
896+
setValidator(new QInt64Validator(bottom.toLongLong(), top.toLongLong(), _allowEmptyValue, this));
884897
}
885898
}
886899
break;
@@ -897,7 +910,7 @@ void NumericLineEdit::on_rangeChanged(const QVariant& bottom, const QVariant& to
897910
const int nums = QString::number(top.toULongLong()).length();
898911
_leadingZeroWidth = qMax(1, nums);
899912
setMaxLength(qMax(1, nums));
900-
setValidator(new QUIntValidator(bottom.toULongLong(), top.toULongLong(), this));
913+
setValidator(new QUIntValidator(bottom.toULongLong(), top.toULongLong(), _allowEmptyValue, this));
901914
}
902915
}
903916
break;

src/controls/numericlineedit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class NumericLineEdit : public QLineEdit
7575
void setAllowEmptyValue(bool allow);
7676

7777
bool isEmpty() const;
78-
void clearValue();
78+
void clear();
7979

8080
signals:
8181
void valueChanged(const QVariant& newValue);

src/qhexvalidator.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
///
44
/// \brief QHexValidator::QHexValidator
55
/// \param parent
6+
/// \param allowEmpty
67
///
7-
QHexValidator::QHexValidator(QObject *parent)
8+
QHexValidator::QHexValidator(QObject *parent, bool allowEmpty)
89
: QIntValidator{parent}
10+
, _allowEmpty(allowEmpty)
911
{
1012
}
1113

12-
QHexValidator::QHexValidator(int bottom, int top, QObject* parent)
14+
QHexValidator::QHexValidator(int bottom, int top, QObject* parent, bool allowEmpty)
1315
: QIntValidator(bottom, top, parent)
16+
, _allowEmpty(allowEmpty)
1417
{
1518
}
1619

@@ -21,10 +24,14 @@ QHexValidator::QHexValidator(int bottom, int top, QObject* parent)
2124
///
2225
QHexValidator::State QHexValidator::validate(QString& input, int&) const
2326
{
27+
if(input.isEmpty()) {
28+
return _allowEmpty ? QValidator::Acceptable : QValidator::Intermediate;
29+
}
30+
2431
bool ok = false;
2532
input.toInt(&ok, 16);
2633

27-
if (ok || input.isEmpty())
34+
if(ok)
2835
{
2936
return QValidator::Acceptable;
3037
}

src/qhexvalidator.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
#ifndef QHEXVALIDATOR_H
22
#define QHEXVALIDATOR_H
33

4-
#include <QValidator>
4+
#include <QIntValidator>
55

66
///
77
/// \brief The QHexValidator class
88
///
99
class QHexValidator : public QIntValidator
1010
{
1111
public:
12-
explicit QHexValidator(QObject *parent = nullptr);
13-
QHexValidator(int bottom, int top, QObject* parent = nullptr);
12+
explicit QHexValidator(QObject *parent = nullptr, bool allowEmpty = false);
13+
QHexValidator(int bottom, int top, QObject* parent = nullptr, bool allowEmpty = false);
1414

1515
State validate(QString &, int &) const override;
16+
17+
private:
18+
bool _allowEmpty = false;
1619
};
1720

1821
#endif // QHEXVALIDATOR_H

src/qint64validator.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,21 @@ QInt64Validator::QInt64Validator(qint64 bottom, qint64 top, QObject *parent)
2222
,_bottom(bottom)
2323
,_top(top)
2424
{
25+
}
2526

27+
///
28+
/// \brief QInt64Validator::QInt64Validator
29+
/// \param bottom
30+
/// \param top
31+
/// \param allowEmpty
32+
/// \param parent
33+
///
34+
QInt64Validator::QInt64Validator(qint64 bottom, qint64 top, bool allowEmpty, QObject *parent)
35+
: QValidator(parent)
36+
,_bottom(bottom)
37+
,_top(top)
38+
,_allowEmpty(allowEmpty)
39+
{
2640
}
2741

2842
///
@@ -31,6 +45,9 @@ QInt64Validator::QInt64Validator(qint64 bottom, qint64 top, QObject *parent)
3145
///
3246
QValidator::State QInt64Validator::validate(QString& input, int &) const
3347
{
48+
if(input.isEmpty())
49+
return _allowEmpty ? QValidator::Acceptable : QValidator::Intermediate;
50+
3451
bool ok = false;
3552
const auto value = input.toLongLong(&ok, 10);
3653

@@ -41,3 +58,15 @@ QValidator::State QInt64Validator::validate(QString& input, int &) const
4158

4259
return QValidator::Invalid;
4360
}
61+
62+
///
63+
/// \brief QInt64Validator::fixup
64+
/// \param input
65+
///
66+
void QInt64Validator::fixup(QString& input) const
67+
{
68+
if(_allowEmpty && input.isEmpty())
69+
return;
70+
71+
QValidator::fixup(input);
72+
}

src/qint64validator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ class QInt64Validator : public QValidator
1313
public:
1414
explicit QInt64Validator(QObject *parent = nullptr);
1515
QInt64Validator(qint64 bottom, qint64 top, QObject *parent = nullptr);
16+
QInt64Validator(qint64 bottom, qint64 top, bool allowEmpty, QObject *parent = nullptr);
1617

1718
State validate(QString &, int &) const override;
19+
void fixup(QString& input) const override;
1820

1921
private:
2022
qint64 _bottom;
2123
qint64 _top;
24+
bool _allowEmpty = false;
2225
};
2326

2427
#endif // QINT64VALIDATOR_H

src/quintvalidator.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,21 @@ QUIntValidator::QUIntValidator(quint64 bottom, quint64 top, QObject *parent)
2222
,_bottom(bottom)
2323
,_top(top)
2424
{
25+
}
2526

27+
///
28+
/// \brief QUIntValidator::QUIntValidator
29+
/// \param bottom
30+
/// \param top
31+
/// \param allowEmpty
32+
/// \param parent
33+
///
34+
QUIntValidator::QUIntValidator(quint64 bottom, quint64 top, bool allowEmpty, QObject *parent)
35+
: QValidator(parent)
36+
,_bottom(bottom)
37+
,_top(top)
38+
,_allowEmpty(allowEmpty)
39+
{
2640
}
2741

2842
///
@@ -32,7 +46,7 @@ QUIntValidator::QUIntValidator(quint64 bottom, quint64 top, QObject *parent)
3246
QValidator::State QUIntValidator::validate(QString& input, int &) const
3347
{
3448
if(input.isEmpty())
35-
return QValidator::Intermediate;
49+
return _allowEmpty ? QValidator::Acceptable : QValidator::Intermediate;
3650

3751
bool ok = false;
3852
const auto value = input.toULongLong(&ok, 10);
@@ -51,9 +65,11 @@ QValidator::State QUIntValidator::validate(QString& input, int &) const
5165
///
5266
void QUIntValidator::fixup(QString& input) const
5367
{
68+
if(_allowEmpty && input.isEmpty())
69+
return;
70+
5471
QValidator::fixup(input);
5572

56-
if(input.isEmpty()) {
73+
if(input.isEmpty())
5774
input = QString::number(_bottom);
58-
}
5975
}

0 commit comments

Comments
 (0)