How to set tkinter scale slider's color?
To achieve what you want, we have to use a ttk style, so we need to use a ttk.Scale
, however, it does not accept all the options of the tk.Scale
you are using. Therefore, I suggest you to use the TickScale
from the ttkwidgets module (See documentation here). This way you can combine the tk.Scale
options with the ttk styling.
The idea is to:
create images of the desired color for the slider, e.g. with
tk.PhotoImage
:img_slider = tk.PhotoImage(width=30, height=15)img_slider.put("{<pixel_color> ... <pixel_color>} {<second line>} ...")
I used a basic rectangle, but you can also load a more elaborated image if you wish.
create the colored slider theme element:
style.element_create('custom.Horizontal.Scale.slider', 'image', img_slider, ('active', img_slider_active))
I also used a different image
img_slider_active
, to highlight the slider when the cursor is on it.Use the new element in a custom style
style.layout('custom.Horizontal.TScale', [('Horizontal.Scale.trough', {'sticky': 'nswe', 'children': [('custom.Horizontal.Scale.slider', {'side': 'left', 'sticky': ''})]})])
- Apply the custom style to your
TickScale
widget. Since theTickScale
is based on attk.Scale
, you need to use the style to set the background, foreground and troughcolor options, see full code below.
import tkinter as tkfrom tkinter import ttkfrom ttkwidgets import TickScaledef set_img_color(img, color): """Change color of PhotoImage img.""" pixel_line = "{" + " ".join(color for i in range(img.width())) + "}" pixels = " ".join(pixel_line for i in range(img.height())) img.put(pixels)root = tk.Tk()# create images used for the themeslider_width = 30slider_height = 15# normal sliderimg_slider = tk.PhotoImage('img_slider', width=slider_width, height=slider_height, master=root)set_img_color(img_slider, "red")# active sliderimg_slider_active = tk.PhotoImage('img_slider_active', width=slider_width, height=slider_height, master=root)set_img_color(img_slider_active, '#1065BF')style = ttk.Style(root)style.theme_use('clam')# create scale elementstyle.element_create('custom.Horizontal.Scale.slider', 'image', img_slider, ('active', img_slider_active))# create custom layoutstyle.layout('custom.Horizontal.TScale', [('Horizontal.Scale.trough', {'sticky': 'nswe', 'children': [('custom.Horizontal.Scale.slider', {'side': 'left', 'sticky': ''})]})])style.configure('custom.Horizontal.TScale', background='black', foreground='grey', troughcolor='#73B5FA')scale = TickScale(root, from_=0, to=100, tickinterval=100, orient="horizontal", style='custom.Horizontal.TScale')scale.pack(fill='x')root.mainloop()
slider.configure(foreground=color)
draws a rectangle around the slider, which distinguishes it from the trough. Setting the foreground color the same as the background color creates a difficult to find slider, as you stated.
Another option is to use a different theme (https://tkdocs.com/tutorial/styles.html). The snippet below allows you to see how your slider would look with different themes:
import tkinter as tkfrom tkinter import ttkclass App(tk.Tk): def __init__(self): super().__init__() # root window self.title('Theme Demo') self.geometry('400x300') self.style = ttk.Style(self) # label label = ttk.Label(self, text='Name:') label.grid(column=0, row=0, padx=10, pady=10, sticky='w') # scale slider = ttk.Scale(self, from_=1, to=10) slider.grid(column=1, row=0, padx=10, pady=10, sticky='w') # button btn = ttk.Button(self, text='Show') btn.grid(column=2, row=0, padx=10, pady=10, sticky='w') # radio button self.selected_theme = tk.StringVar() theme_frame = ttk.LabelFrame(self, text='Themes') theme_frame.grid(padx=10, pady=10, ipadx=20, ipady=20, sticky='w') for theme_name in self.style.theme_names(): rb = ttk.Radiobutton( theme_frame, text=theme_name, value=theme_name, variable=self.selected_theme, command=self.change_theme) rb.pack(expand=True, fill='both') def change_theme(self): self.style.theme_use(self.selected_theme.get())if __name__ == "__main__": app = App() app.mainloop()