Anonymous
Anonymous

Reputation: 754

How can I have Python TTK use the Windows OS default progress bar theme?

How in TTK can I use the OS default loader theme instead of the tkinter one?

Loading - Known

Loading - Unknown

This is an example of a normal progress bar.

from tkinter import *
from tkinter.ttk import *

root = Tk()
root.geometry('400x250+1000+300')

progress_bar = Progressbar(root, orient=HORIZONTAL, length=100, mode='indeterminate')
progress_bar.pack(expand=True)
progress_bar.start()

root.mainloop()

I get a progress bar, but it isn't themed like the OS default progress bar is.

TTK-themed progress bar

I thought that perhaps a style could make it look like that, so I listed the styles:

Style().theme_names() # ('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')

I tried each one like so:

from tkinter import *
from tkinter.ttk import *

root = Tk()
root.geometry('400x250+1000+300')

os_default_style = Style()
os_default_style.theme_use('THEME')
os_default_style.configure('osdefault.Horizontal.TProgressbar')
progress_bar = Progressbar(root, orient=HORIZONTAL, length=100, mode='indeterminate', style='osdefault.Horizontal.TProgressbar')
progress_bar.pack(expand=True)
progress_bar.start()

root.mainloop()

They produce ones that are similar, but none are the system. How do I make it look exactly like one used by the system?

Upvotes: 1

Views: 1489

Answers (3)

PCM
PCM

Reputation: 3021

Try this -

from tkinter import *
from tkinter import ttk

root = Tk()

s = ttk.Style()
s.theme_use('winnative')
s.configure("Blue.Horizontal.TProgressbar", foreground='white',
            background='blue')
P1 = ttk.Progressbar(root, style="Blue.Horizontal.TProgressbar",
                     orient="horizontal", length=600, mode="indeterminate",
                     maximum=4, value=1)
P1.pack()

root.mainloop()

Upvotes: 0

ASI
ASI

Reputation: 344

I think is a little bit case sensitive the "default OS theme"... xpnative is the close to the native one and almost fool the eyes. I created an test to see the differences (note I use windows 7) and the result for default OS style reveal like xpnative is the winner. vista look same but is a little bigger that is all. Now if OS use simple theme, this two will not work, but other will do... For windows 10, classic tkinter theme is close to this OS theme, but tkinter.ttk will do same thing on windows 10... Is to sensitive this subject. Just on windows are some obstacles, I even do not mentioned Linux... Theme is not so important, if your project is making the job right and is close enough to default theme of the user OS from my view point is more than perfect.

Here is my test:

# Import
import tkinter as tk
import tkinter.ttk as ttk

# Logic
class Main:
    def __init__(self, master):
        self.master = master

        # Create the progress bar
        self.progress = ttk.Progressbar(self.master, value=0)
        self.progress.pack(expand=False, fill="x", side="top", padx=5, pady=5)
        self.progress.start()

        # Create two layers for the theme
        self.default = self.Layer("Default")    # for default foundet ones
        self.custom = self.Layer("Custom")      # for manual input and debug purpose

        # Create the entry and applay elements for the "custom layer"
        self.entry = ttk.Entry(self.custom)
        ttk.Button(self.custom, text="Apply...", width=15, command=lambda:self.ChangeTheme(self.entry.get().strip())
                   ).pack(side="right")
        self.entry.pack(expand=True, fill="x", side="left")

        # Get a list of all default themes and create a button for each one
        for theme in ttk.Style().theme_names(): self.ThemeDefault(theme)

    def ThemeDefault(self, themeName:str) -> None:
        ttk.Button(self.default, text=themeName, width=15, command=lambda:self.ChangeTheme(themeName)).pack(side="left")

    def Layer(self, text:str) -> tk.Frame:
        frame = tk.Frame(self.master)
        label = tk.Label(frame, text=text, width=7, anchor="w")
        frame.pack(expand=False, fill="x", side="top", padx=5, pady=5)
        label.pack(side="left")
        return frame

    def ChangeTheme(self, themeName:str) -> None:
        try: ttk.Style(self.master).theme_use(themeName)
        except Exception as e: print(f">> EXCEPTION // {e}")

# Run if this file is the main opened one
if __name__ == "__main__":
    root = tk.Tk()
    Main(root)
    root.mainloop()

This is what is look like the resoult. enter image description here

Upvotes: 4

Minion Jim
Minion Jim

Reputation: 1279

Unfortunately, a 'truly native' widget is not possible in Tk. As you can see in the source, a theme simply sets a bunch of settings and it does not do anything you couldn't do yourself. However, finding a good theme will generally do a 'good enough' job (see ASI's answer for more details on this).

If you don't believe me, take a look at the ProgressbarDoLayout method (and related methods - found here) and you can see that Tk is handling the drawing itself and giving very little to the native software.

Upvotes: 1

Related Questions