The Tkinter slider with float values ​​does not work with a language that uses a comma for float

I have the following code:

import Tkinter as tk import locale from Tkinter import * #locale.setlocale(locale.LC_NUMERIC, 'pl_PL') master = tk.Tk() w = tk.Scale(master, from_=0.05, to=0.1, resolution=0.01) w.pack() tk.mainloop() 

And the slider works as it should. It does not slip when I uncomment this line with locale setting. This is likely due to the fact that pl_PL locale uses a comma to separate the float. It could be a mistake. How can I get around this so that I can set the locale correctly?

+5
source share
1 answer

Here is a somewhat inconvenient workaround for this error, using some ideas and code from Brian Oakley, an answer to Dynamically changing the scaling value of tkinter python 2.7 , where Brian shows how to replace a normal display of values ​​with a custom formatted display. Unfortunately, we need to do a little more work, because even when we create Scale with showvalue=False , it is still blocked by floating point numbers that contain commas, even if they don't even display them!

The solution is to make the numbers be integers. This is easy enough to do if the to and from_ are integers with a resolution number, as shown below.

 import Tkinter as tk import locale locale.setlocale(locale.LC_NUMERIC, 'pl_PL.UTF8') class NewScale(tk.Frame): def __init__(self, master=None, **options): tk.Frame.__init__(self, master) # Disable normal value display... options['showvalue'] = False # ... and use custom display instead options['command'] = self._on_scale # Set resolution to 1 and adjust to & from value self.res = options.get('resolution', 1) from_ = int(options.get('from_', 0) / self.res) to = int(options.get('to', 100) / self.res) options.update({'resolution': 1, 'to': to, 'from_': from_}) # This could be improved... if 'digits' in options: self.digits = ['digits'] del options['digits'] else: self.digits = 2 self.scale = tk.Scale(self, **options) self.scale_label = tk.Label(self) orient = options.get('orient', tk.VERTICAL) if orient == tk.VERTICAL: side, fill = 'right', 'y' else: side, fill = 'top', 'x' self.scale.pack(side=side, fill=fill) self.scale_label.pack(side=side) def _on_scale(self, value): value = locale.atof(value) * self.res value = locale.format_string('%.*f', (self.digits, value)) self.scale_label.configure(text=value) if __name__ == '__main__': master = tk.Tk() w = NewScale(master, from_=0.05, to=0.1, resolution=0.01) w.pack(fill='both', expand=True) master.mainloop() 

This code has been tested on Python 2.6.6 and 3.6.0. To run it in Python 3, change import Tkinter as tk to import Tkinter as tk .

The NewScale widget supports the orientation of tk.VERTICAL and tk.HORIZONTAL , with tk.VERTICAL being standard (the same as the normalScale widget). Its support for the digits option is currently quite primitive.


Here are some ways that make NewScale more useful:

 def get(self): return self.scale.get() * self.res def set(self, value): self.scale.set(int(0.5 + value / self.res)) 

To test these methods, change the calling code to:

 if __name__ == '__main__': master = tk.Tk() w = NewScale(master, from_=0.05, to=0.1, resolution=0.01) w.pack(fill='both', expand=True) w.set(0.07) tk.Button(master, text='Print', command=lambda: print(w.get())).pack() master.mainloop() 

And it's probably a good idea to round off the adjusted values ​​of to and from_ to the nearest whole number, rather than trimming them. This can be done by changing their initializers to:

 from_ = int(0.5 + options.get('from_', 0) / self.res) to = int(0.5 + options.get('to', 100) / self.res) 
+5
source

Source: https://habr.com/ru/post/1270170/


All Articles