Open df194108-eece-4593-bf39-e3b1b0ac3325 opened 4 years ago
This issue occurs when a locale is set that uses comma as decimal separator (e.g. locale.setlocale(locale.LC_NUMERIC, 'de_DE.utf8')). I have a tkinter.Spinbox with increment=0.1 connected to a tkinter.DoubleVar. When I change the value of the Spinbox using the arrow buttons and subsequently try to read out the variable with tkinter.DoubleVar.get(), my code throws the follwoing error: _tkinter.TclError: expected floating-point number but got "0,1".
Here is a minimal code example:
-------------
import tkinter
import locale
locale.setlocale(locale.LC_NUMERIC, 'de_DE.utf8')
class TestDoubleVar():
def __init__(self):
root = tkinter.Tk()
self.var = tkinter.DoubleVar()
self.var.set(0.8)
number = tkinter.Spinbox(
root,
from_=0, to=1, increment=0.1,
textvariable=self.var,
command=self.update,
width=4
)
number.pack(side=tkinter.LEFT)
root.mainloop()
def update(self, *args):
print(float(self.var.get()))
if __name__ == '__main__':
TestDoubleVar()
Actual result: the code throws an error
Expected result: the code should print the values of the DoubleVar even with a locale set that uses comma as the decimal separator.
n.b. the problem also occurs with tkinter.Scale
I just found the following code in lines 314-320 of tkinter/ttk.py, which are clearly not localization-aware:
def _to_number(x):
if isinstance(x, str):
if '.' in x:
x = float(x)
else:
x = int(x)
return x
I'll keep looking for similar stuff and add a pull request once I think I have nailed down the issue I'll look for something similar in
Is this a problem exclusive to tkinter? I ran the following code, and it appears to be an issue with the builtin 'float' method:
>>> import locale
>>> locale.setlocale(locale.LC_NUMERIC, 'de_DE.utf8')
'de_DE.utf8'
>>> float("1,2")
ValueError: could not convert string to float: '1,2'
I have somehow managed to corrupt my locales so I would appreciate if you could try on your machine as well (is it just me?!).
I wrote a longer explanation but BPO and Chrome ate it.
The issue is that DoubleVar is not locale aware. I don't know what should be the actual fix but the following may be a useful workaround (It works on my system):
import tkinter
import locale
import sys
locale.setlocale(locale.LC_NUMERIC, 'de_DE')
class Var(tkinter.DoubleVar):
def get(self):
return locale.atof(self._tk.globalgetvar(self._name))
class TestDoubleVar():
def __init__(self):
root = tkinter.Tk()
self.var = Var()
self.var.set(0.8)
number = tkinter.Spinbox(
root,
from_=0, to=1, increment=0.1,
textvariable=self.var,
command=self.update,
width=4
)
number.pack(side=tkinter.LEFT)
root.mainloop()
def update(self, *args):
print(self.var.get())
if __name__ == '__main__':
TestDoubleVar()
See also bpo-12558 which exposes the other side of the same issue.
Las time I looked at it, it was inherently a Tcl issue. In some places it uses locale-dependent formatting of floating point numbers, but locale-unaware parsing, or vice versa.
Setting the locale results in buggy behaviour of spin boxes with non-integer content::
locale.setlocale(locale.LC_ALL, 'pl_PL') # any locale with the comma as a decimal separator
variable = tk.DoubleVar(0.5)
spinbox = ttk.Spinbox(self, from_=0, to=10, increment=0.1, format = "%.1f", textvariable = variable)
The first click on the up/down arrows works correctly (?), any futher manipulation lock the spin box between 0,0 and 0,1 (comma as the decimal separator).
The simple workaround:
locale.setlocale(locale.LC_ALL, 'pl_PL') # any locale with the comma as a decimal separator
locale.setlocale(locale.LC_NUMERIC, 'en_US') # the dot is the decimal separator again
makes spin boxes fully useable, but... this is no solution when l18n must be used.
The suggested subclassing DoubleVar:
class Var(tkinter.DoubleVar):
def get(self):
return locale.atof(self._tk.globalgetvar(self._name))
does not work in my program (CPython 3.9).
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at = None created_at =
labels = ['3.7', 'type-bug', 'expert-tkinter']
title = 'setting a locale that uses comma as decimal separator breaks tkinter.DoubleVar'
updated_at =
user = 'https://github.com/thawn'
```
bugs.python.org fields:
```python
activity =
actor = 'serhiy.storchaka'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Tkinter']
creation =
creator = 'thawn'
dependencies = []
files = ['48943']
hgrepos = []
issue_num = 39827
keywords = []
message_count = 5.0
messages = ['363184', '363371', '371394', '400005', '400023']
nosy_count = 4.0
nosy_names = ['serhiy.storchaka', 'thawn', 'epaine', 'andrei.avk']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue39827'
versions = ['Python 3.7']
```