Skip to content

Make SpinBox locale-aware#3413

Closed
oyvindlr wants to merge 11 commits intopyqtgraph:masterfrom
oyvindlr:locale_dependent_spinbox
Closed

Make SpinBox locale-aware#3413
oyvindlr wants to merge 11 commits intopyqtgraph:masterfrom
oyvindlr:locale_dependent_spinbox

Conversation

@oyvindlr
Copy link
Copy Markdown
Contributor

@oyvindlr oyvindlr commented Nov 7, 2025

Spinboxes in Qt are locale-aware, in the sense that they use a period or a comma as a decimal separator depending on locale. This pull request fixes pyqtgraph's Si-scaling spinbox so it acts the same way.

@pijyoi
Copy link
Copy Markdown
Contributor

pijyoi commented Nov 7, 2025

from PyQt6 import QtCore

print('Qt Version', QtCore.QT_VERSION_STR)

loc_def = QtCore.QLocale('en')
loc_eur = QtCore.QLocale('de')

numbers = [123.456789, 123456.789, 123456789.]

for number in numbers:
    s1 = loc_def.toString(number, 'g')
    s2 = loc_eur.toString(number, 'g')
    print(f'{s1}     {s2}')

Qt6 versions up to 6.8.x seem to have a bug in capitalizing the exponent character even though 'g' (and not 'G') was specified.

Qt Version 6.2.3
123.457     123,457
123,457     123.457
1.23457E+08     1,23457E+08

Qt Version 6.8.2
123.457     123,457
123,457     123.457
1.23457E+08     1,23457E+08

Qt Version 6.9.0
123.457     123,457
123,457     123.457
1.23457e+08     1,23457e+08

Another issue exposed here is that there's also the https://doc.qt.io/qt-6/qlocale.html#groupSeparator that is locale dependent.

@pijyoi
Copy link
Copy Markdown
Contributor

pijyoi commented Nov 8, 2025

Relevant points:

  1. from https://www.qt.io/blog/teaching-qlocale-more-about-number-formats (2020)
    Locale now [respects the case] of the exponent separator provided by CLDR; so, for instance, many locales now represent a million, in floating-point 'e' format, as 1E+06 instead of 1e+06.
  2. fixed in https://code.qt.io/cgit/qt/qtbase.git/commit/?id=05c8a48612be38a3c50bb5ed9daf1adfc221b9f2 (2025-03)

The fix is also backported to 6.8 and 6.5, but that won't be in the pypi wheels.

@oyvindlr
Copy link
Copy Markdown
Contributor Author

@pijyoi , that's some thorough investigation for the CI-failure! I've updated the tests to expect failure for old versions of Qt.

Regarding group separator, I did consider it. But it's not supported in the standard Qt DoubleSpinBox, it wasn't implemented in the previous version of this SpinBox, and I felt it would be too complex to implement for a niche feature of a niche GUI-component.

(0, '0 mV', dict(suffix='V', dec=True, siPrefix=True, minStep=15e-3)),
])
def test_SpinBox_formatting(value, expected_text, opts):
if 'e' in expected_text and compare_semantic_versions(pg.Qt.QtVersion, '6.9.0') < 0:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The capitalized-'E' bug is not present in Qt5.

@pijyoi
Copy link
Copy Markdown
Contributor

pijyoi commented Nov 11, 2025

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore

def display():
    print(spinbox.value())

pg.mkQApp()
spinbox = pg.SpinBox(value=123456.789, step=1)
spinbox.setLocale(QtCore.QLocale('en'))
spinbox.sigValueChanged.connect(display)
spinbox.setMinimumHeight(40)
spinbox.show()
pg.exec()

On startup, the string "123,456" is displayed. (group separator has been added by Qt)
You can press the up and down arrows, it works fine.
Now let's say I edit the number, changing it from "123,456" to "123,499" and then press ENTER. The value changes to 12.0

So this means that the user, when entering numbers manually, must remove any group separators from the existing displayed string value.

@oyvindlr
Copy link
Copy Markdown
Contributor Author

Fixed the group separator issue by removing group separators from the number string produced by QLocale.toString() (the python float formatter didn't add these, so this was a new issue).
Also made tests run normally without xfail for qt < 6.
There was one CI failure for ubuntu-latest, pyside, python 3.10, but it seems unrelated to this PR:

FAILED pyqtgraph/examples/test_examples.py::testExamples[ MouseSelection.py - PySide2 ] - Failed:

Traceback (most recent call last):
File "/home/runner/work/pyqtgraph/pyqtgraph/pyqtgraph/Qt/OpenGLHelpers.py", line 109, in initializeGL
if not ctx.isOpenGLES() and ctx.format().version() >= (3, 1):
AttributeError: 'PySide2.QtGui.QOpenGLExtraFunctions' object has no attribute 'isOpenGLES'

Failed MouseSelection Example Test Located in MouseSelection.py

def paint(self, *args):
...

def paint(self, *args): ...

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.
@oyvindlr
Copy link
Copy Markdown
Contributor Author

And now I screwed the whole PR up because I tried to merge this branch on my fork onto another branch on my fork, and there were conflicts.

@oyvindlr oyvindlr force-pushed the locale_dependent_spinbox branch from 733099c to e7b542b Compare November 11, 2025 14:09
@oyvindlr oyvindlr closed this Nov 11, 2025
@oyvindlr oyvindlr mentioned this pull request Nov 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants