Question

I've searched all over, but have yet to find a simple example showing how to change a minor element of a ttk widget style and applying it dynamically (after widget creation).

I have some ttk checkbuttons representing some configuration items, and a ttk button used to update a remote system. The checkbuttons are initialized to the state of the remote system.

If the user modifies any of the checkbuttons, I want both the checkbutton text and the update button text to become red, to remind the user that the checkbutton state no longer matches the remote state, and that the update button should be pressed to send the modified configuration to the remote system.

When the update button is pressed, the text color of the update button and all checkbuttons reverts to black.

I know this is possible (and is probably easy), but how?

Edit: Modifying the background color would also be OK.

Was it helpful?

Solution

You will need to create a custom style, and then apply that style to the widget. To create a custom style, first get an instance of ttk.Style, and then use the configure method to derive a new style from an existing one. The following example creates a new style named "Red.TCheckbutton":

style = ttk.Style()
style.configure("Red.TCheckbutton", foreground="red")

Next, you simply associate this style with the widget when you want the color to change:

my_checkbutton.configure(style="Red.TCheckbutton")

The best resource for learning how to work with the ttk styles is tkdocs.com. Specifically, https://www.tkdocs.com/tutorial/styles.html.

Here's a complete working example:

import ttk
import Tkinter as tk

class ExampleApp(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        self.var1 = tk.StringVar()
        self.var2 = tk.StringVar()

        f1 = ttk.Frame(self)
        red_button = ttk.Button(f1, text="Red", command=self.make_red)
        default_button = ttk.Button(f1, text="Default", command=self.make_default)

        red_button.pack(side="left")
        default_button.pack(side="left")

        f2 = ttk.Frame(self)
        self.cb_one = ttk.Checkbutton(f2, text="Option 1", variable=self.var1,
                                      onvalue=1, offvalue=0)
        self.cb_two  = ttk.Checkbutton(f2, text="Option 2", variable=self.var2,
                                       onvalue=1, offvalue=0)
        self.cb_one.pack(side="left")
        self.cb_two.pack(side="left")

        f1.pack(side="top", fill="x")
        f2.pack(side="top", fill="x")

        style = ttk.Style()
        style.configure("Red.TCheckbutton", foreground="red")

    def make_red(self):
        self.cb_one.configure(style="Red.TCheckbutton")
        self.cb_two.configure(style="Red.TCheckbutton")

    def make_default(self):
        self.cb_one.configure(style="TCheckbutton")
        self.cb_two.configure(style="TCheckbutton")


if __name__ == "__main__":
    root = tk.Tk()
    ExampleApp(root).pack(fill="both", expand=True)
    root.mainloop()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top