jpo38
jpo38

Reputation: 21514

How to make a French keyboard's dot key (numeric keypad) work as input with Qt?

I'm designing a C++/Qt application. I'm with a French keyboard on a French Windows environment.

When I try to type a decimal number in a QDoubleSpinBox control, pressing the dot numeric keypad button does nothing....I would expect it to insert a decimal separator!

Here is a very simple Qt program isolating the problem:

main.cpp:

#include <QApplication>
#include <QVBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QDialog>

class Dialog : public QDialog
{
public:
    Dialog()
    {
        QVBoxLayout* layout = new QVBoxLayout( this );

        layout->addWidget( new QLabel( QLocale().toString( 3.14 ), this ) );
        layout->addWidget( new QDoubleSpinBox( this ) );
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Dialog w;
    w.show();

    return a.exec();
}

I compiled it with Visual Studio 2010 and 5.2.1 on a French PC.

When the dialog opens:

enter image description here

Then:

I'm looking for a gloabl solution (at QApplication level), not something at QSpinBox level because I have many of them in my original project.

Upvotes: 2

Views: 1991

Answers (2)

David Faure
David Faure

Reputation: 1997

Until https://bugreports.qt.io/browse/QTBUG-41256 is fixed, the solution is an application-global event filter, so that any use of the '.' key on the numeric keyboard (and only there) is turned into a ',' -- on systems where the default locale uses ',' as decimal separator.

class GlobalEventFilter : public QObject
{
public:
    explicit GlobalEventFilter(QObject *parent) : QObject(parent) {}
    bool eventFilter(QObject *obj, QEvent *ev) override {
        if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::KeyRelease) {
            QKeyEvent *kev = static_cast<QKeyEvent *>(ev);
            if (kev->key() == Qt::Key_Period && (kev->modifiers() & Qt::KeypadModifier)) {
                QChar decimalPoint = QLocale().decimalPoint();
                if (decimalPoint == QLatin1Char(',')) {
                    QKeyEvent modifiedKeyEvent(kev->type(), Qt::Key_Comma, kev->modifiers(), QString(decimalPoint), kev->isAutoRepeat(), kev->count());
                    qApp->sendEvent(obj, &modifiedKeyEvent);
                    return true;
                }
            }
        }
        return false;
    }
};

And in your main(), add qApp->installEventFilter(new GlobalEventFilter(qApp));.

I tested this to work on a French Linux system.

Upvotes: 6

TheDarkKnight
TheDarkKnight

Reputation: 27621

I believe you should be using QDoubleSpinBox, instead of QSpinBox. As the documentation for QSpinBox states:

use QDoubleSpinBox for floating point values.

As you can see from QDoubleSpinBox::textFromValue

This virtual function is used by the spin box whenever it needs to display the given value. The default implementation returns a string containing value printed using QWidget::locale().toString(value, QLatin1Char('f'), decimals()) and will remove the thousand separator.

Upvotes: -1

Related Questions