Moving Current Value#

The tkinter Scale has the ability to display a moving Label with the current scale value. One might think of a Canvas with a moving value, but we shall use an ordinary Label positioned according to the place layout manager. The current Scale value is known, the main unknown is the position of the display Label for any given Scale output, this should correspond to the centre of the slider which is offset to be above the Scale. Since both rel_min and rel_max are known it should be easy to calculate.

Just as with the range values use a relative x value. As the cursor moves so the current value in the display value should change - check what is required by moving the tkinter Scale. To keep the display label updated use the command option on the Scale, this calls up a function that calculates the relative x and simultaneously sets the display labels position and actual display value. Otherwise linking the display label through a tkinter variable, but would show a float number with umpteen decimal places. Every slider movement triggers the function, so a continuously moving and changing display results. Link the SpinBox and Scale through a tkinter variable, then adjust the Spinbox's size to limit the its display.

A simple function is used to calculate the relative x position:

def convert_to_relx(curr_val):
    return ((curr_val - from_val) * (rel_max - rel_min) / (to_val - from_val) \
        + rel_min)

Another function changes the display label:

def display_value(value):
    rel_x = convert_to_relx(float(value))
    disp_lab.place_configure(relx=rel_x)
    disp_lab.configure(text=f'{float(value):.{dig_val}f}')

Note

There are several methods to format text, the latest configuration for Python 3.6 and above is the preferred method. Value (Scale actual value) needs to be converted to a float. The digits option, dig_val is related to the number of decimal places shown. Since a float is being replaced the variable dig_val requires curly brackets.

Show/Hide Code 07ttk_tkinter_shift_value.py

import tkinter as tk
from tkinter import font
import tkinter.ttk as ttk
import numpy as np

from_val = -1
to_val = 1
len_val = 500
res_val = 0.10
tick_val = 0.10
dig_val = 2
bw_val = 1 # trough border width
slider_val = 36
sc_range = abs(to_val - from_val) # scale range

def selh(val):
    sbh.config(text=round(float(scth.get())+0.0049,2))

root = tk.Tk()

root.geometry(str(len_val+150)+"x200+500+500")
s = ttk.Style()
s.theme_use('default')

def_font = font.nametofont('TkDefaultFont')
from_size = def_font.measure(from_val)
to_size = def_font.measure(to_val)

sch = tk.Scale(root, from_=from_val, to=to_val, label='Bogusstuinuous', orient='horizontal',
            resolution=res_val, showvalue=1, tickinterval=tick_val, digits=dig_val,
            length=len_val)
sch.grid(sticky='ew')

sep = ttk.Separator(root, orient='horizontal')
sep.grid(row=1, column=0, columnspan=2)

def convert_to_relx(curr_val):
    return ((curr_val - from_val) * (rel_max - rel_min) / (to_val - from_val) \
            + rel_min)

def display_value(value):
    # position (in pixel) of the center of the slider
    rel_x = convert_to_relx(float(value))
    disp_lab.place_configure(relx=rel_x)
    my_precision = '{:.{}f}'.format
    disp_lab.configure(text=my_precision(float(value), int(dig_val)))

slider = tk.StringVar()
slider.set('0.00')

scth = ttk.Scale(root, from_=from_val, to=to_val, length=len_val,
        command=display_value)

scth.grid(row=2, column=0, sticky='ew', padx=5, pady=15)

rel_min = ((slider_val - from_size) / 2 + bw_val) / len_val
rel_max = 1 - (slider_val /2 - bw_val) / len_val

# using numpy arange instead of range so tick intervals less than 1 can be used
data = np.arange(from_val, to_val+tick_val, tick_val)
data = np.round(data,1)
range_vals = tuple(data)
len_rvs = len(range_vals)

for i, rv in enumerate(range_vals):
    item = ttk.Label(root, text=rv)
    item.place(in_=scth, bordermode='outside',
                relx=(rel_min + i / (len_rvs - 1) * (rel_max - rel_min)) ,
                rely=1, anchor='n')

disp_lab = ttk.Label(root, textvariable = slider)
disp_lab.place(in_=scth, bordermode='outside',
                relx=0.5, rely=0, anchor='s')
display_value(scth.get())

sbh = ttk.Spinbox(root, from_=from_val, to=to_val, textvariable=slider,
                  width=5, increment=res_val)
sbh.grid(row=2, column=1)

root.mainloop()