Conflict between Style() and ThemedStyle()

Viewed 1013

I'm using Tkinter and ttk to create a GUI in Python. I want to have two separate themes for the UI that the user can configure. One of these options is the vista theme called using the following code:

from tkinter import Tk
from tkinter.ttk import Style

root = Tk()
root.style = Style()
root.style.theme_use('vista')

Another option is the black theme called using:

from tkinter import Tk
from ttkthemes import ThemedStyle

root = Tk()
root.style = ThemedStyle()
root.style.theme_use('black')

I am having some issues because I want users to be able to switch themes while the program is running. Applying these themes separately (i.e., applying a theme, closing the program and applying the other theme on launch) works fine. I start to encounter problems when calling root.style = ThemedStyle() followed by root.style = Style() somewhere later in the code when switching from the vista theme to the black theme:

    if self.ui_theme == 'Dark':
        self.root.style = ThemedStyle()
        theme = 'black'
        self.root.tk_setPalette(background='#2f3136')
    else:
        self.root.style = Style()
        theme = 'vista'
        self.root.tk_setPalette(background='#f0f0f0')
    self.root.style.theme_use(theme)

On top of that, going from black to vista and back to black again causes the following error:

error reading package index file C:/Python34/Lib/site-packages/ttkthemes/themes/pkgIndex.tcl: Theme plastik already exists

which I assume happens when calling self.root.style = ThemedStyle() twice in the same instance.

Is there a way to get around this without forcing users to restart the application when applying a new theme? Thanks in advance.

1 Answers

Create Style() and ThemeStyle() only once at start and assign to variables.

And later assign variable to root.style.

from tkinter import Tk
from tkinter.ttk import Style, Button
from ttkthemes import ThemedStyle

def style_1():
    print('winxpblue')
    root.style = s
    root.style.theme_use('winxpblue')

def style_2():
    print('black')
    root.style = t
    root.style.theme_use('black')

root = Tk()

s = Style()
t = ThemedStyle()

#print(s.theme_names())
#print(t.theme_names())

Button(root, text="winxpblue", command=style_1).pack()
Button(root, text="black", command=style_2).pack()

root.mainloop()

EDIT: after testing on Linux I see I don't need Style(). I have all themes in ThemedStyle(). Maybe on Windows/MacOS it works the same way.

import tkinter as tk
from tkinter import ttk
import ttkthemes

root = tk.Tk()

root.style = ttkthemes.ThemedStyle()

for i, name in enumerate(sorted(root.style.theme_names())):
    b = ttk.Button(root, text=name, command=lambda name=name:root.style.theme_use(name))
    b.pack(fill='x')

root.mainloop()

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

Related