Solution given by basslo does not work for me. I also need to reimplement the valueFromText method. Otherwise, when I press the enter key in the DoubleSpinBox, the value is set to 0.
Here is the class
doublespinboxwithcommasandpoints.h
#ifndef DOUBLESPINBOWITHCOMMASANDPOINTS_H
#define DOUBLESPINBOWITHCOMMASANDPOINTS_H
#include <QDoubleSpinBox>
#include <QRegularExpressionValidator>
class DoubleSpinBoxWithCommasAndPoints : public QDoubleSpinBox
{
Q_OBJECT
public:
explicit DoubleSpinBoxWithCommasAndPoints(QWidget* parent = nullptr);
virtual ~DoubleSpinBoxWithCommasAndPoints();
QValidator::State validate(QString & text, int & pos) const override;
qreal valueFromText(const QString &text) const override;
void showEvent(QShowEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
private:
QRegularExpressionValidator* m_validator;
QString current_suffix;
};
#endif // DOUBLESPINBOWITHCOMMASANDPOINTS_H
doublespinboxwithcommasandpoints.cpp
#include "doublespinboxwithcommasandpoints.h"
DoubleSpinBoxWithCommasAndPoints::DoubleSpinBoxWithCommasAndPoints(QWidget *parent)
: QDoubleSpinBox(parent)
, m_validator(nullptr)
, m_current_suffix(QString())
{
// validate positive or negative number written with "." or ","
// and that may have a suffix at the end
// also matches empty string "(?![\\s\\S]\r\n)" to allow user to clear the whole field
const QString regex = QStringLiteral("((?![\\s\\S]\r\n)|-?\\d{1,}(?:[,.]{1})?\\d*\\s*)");
m_validator = new QRegularExpressionValidator(QRegularExpression(regex), this);
// check if a suffix is present
// connect is triggered when setSuffix() is called
connect(this, &DoubleSpinBoxWithCommasAndPoints::textChanged,
this, [this](){
if(suffix().isEmpty())
return;
if(m_current_suffix.localeAwareCompare(suffix()) == 0)
return;
m_current_suffix = suffix();
QString previous_regex = m_validator->regularExpression().pattern();
// remove the ending ")"
previous_regex.chop(1);
QString new_regex = previous_regex +
QStringLiteral("(?:") + m_current_suffix + QStringLiteral(")?)");
m_validator->setRegularExpression(QRegularExpression(new_regex));
});
}
DoubleSpinBoxWithCommasAndPoints::~DoubleSpinBoxWithCommasAndPoints()
{
delete m_validator;
}
QValidator::State DoubleSpinBoxWithCommasAndPoints::validate(QString &text, int &pos) const
{
return m_validator->validate(text, pos);
}
qreal DoubleSpinBoxWithCommasAndPoints::valueFromText(const QString &text) const
{
QString temp = text;
temp.replace(QStringLiteral(","), QStringLiteral(".")); // replace comma with dot before toDouble()
temp.remove(suffix()); // remove "°" at the end of the value
return temp.toDouble();
}
void DoubleSpinBoxWithCommasAndPoints::showEvent(QShowEvent *event)
{
// need to call manually textChanged(const QString &text)
// otherwise the new regex may not be taken into account directly
Q_EMIT textChanged(text());
QDoubleSpinBox::showEvent(event);
}
void DoubleSpinBoxWithCommasAndPoints::wheelEvent(QWheelEvent *event)
{
// Prevent value from changing when user scrolls
event->ignore();
}
Few points:
- this code works with Qt6
- the regular expression accepts negative numbers as well
- the regular expression accepts numbers without comma/point
- the regular expression supports suffix (code can be adapted to also support prefix)
- the regular expression matchs empty string which allows users to clear the whole field
- the mouse wheel has been disabled to avoid user to change value when scrolling (comment
wheelEvent(QWheelEvent *event)
if you want to keep it).