Is it possible to have a standard style for a widget?
Asked Answered
C

2

5

I want all of the buttons in my gui to have the same style. Right now I manually write in the attributes I want but it takes up so much space. Also, if I wanted to change the style I would have to go to every single button. Is it possible to have a style i define once and then reference it when making all buttons? Something like the following:

basic_style = 
     {'background': 'blue',
     'foreground':'white', 
     'font':'Helvetica 8 bold'} 

self.btn = tk.Button(text = 'Hello', style = basic_style)

I know its possible to do something like this:

self.btn['text'] = 'Bye'

but that still doesn't help me much.

Cancer answered 6/9, 2018 at 18:44 Comment(1)
Have you looked into ttk. It has a style system that lets you control the base style for ttk widgets.Sartin
E
9

There are at least four ways I can think of to do this: using the option database, passing dictionaries of options, using ttk, and creating custom classes.

Using the option database

There are several ways to accomplish what you want. The original support for this is based on the X11 windowing system option database. Every widget has a class, and every class can have it's options set.

You do this through the option_set method of the root window (as well as option_readfile), specifying a pattern, and the default value.

Example:

import tkinter as tk

root = tk.Tk()

root.option_add("*Font", "Helvetica 8 bold")
root.option_add("*Background", "blue")
root.option_add("*Foreground", "white")

button1 = tk.Button(root, text="Hello", command=lambda: print("Hello"))
button2 = tk.Button(root, text="World", command=lambda: print("world"))

button1.pack()
button2.pack()

root.mainloop()

Note: you must do this after creating the root window but before creating any widgets you want to be affected by this.

How to use the option database can be a bit complex, though it does make it possible to compute entire themes if you're willing to take the time to do it. One of the best -- though oldest -- descriptions comes straight from one of the core developers of tcl/tk here: http://www.cs.man.ac.uk/~fellowsd/tcl/option-tutorial.html. This requires a little bit of mental gymnastics to translate the tcl/tk code to python/tkinter, but the python docs describe how to do that (see Mapping basic tk into tkinter

Using dictionaries.

You can indeed pass in a dictionary of options, with a couple of small caveats. This dictionary must be the first argument after the parent, and it must be before any other keyword arguments.

Example:

import tkinter as tk

basic_style = {'background': 'blue', 'foreground': 'white', 'font': 'Helvetica 8 bold'}

root = tk.Tk()
button1 = tk.Button(root, basic_style, text="Hello", command=lambda: print("Hello"))
button2 = tk.Button(root, basic_style, text="World", command=lambda: print("world"))

button1.pack()
button2.pack()

root.mainloop()

I don't if this is documented anywhere, but you can see that it's supported by looking at the actual tkinter code.

Using the ttk widgets

"ttk" stands for "themed tk". The whole idea was to re-implement tk with the ability to apply themes. ttk has most of the same widgets as tkinter, plus a few that it doesn't have (for example, the treeview widget).

Example:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()

style = ttk.Style()
style.configure('Custom.TButton',
                background="blue", foreground="white",
                font='Helvetica 8 bold')

button1 = ttk.Button(root, text='Hello', style='Custom.TButton')
button2 = ttk.Button(root, text='Hello', style='Custom.TButton')

button1.pack()
button2.pack()

root.mainloop()

Unfortunately, there's almost no good documentation on how to configure the themes. It's a bit confusing and non-standard, but the results can be quite polished if you're willing to put in the effort.

The best resource for learning how to create themes is in the Styles and Themes section of tkdocs.com

Creating custom classes

Finally, a fourth option is to create custom classes. Your classes can inherit from the built-in classes and force options to be set if not provided.

Example:

import tkinter as tk

class CustomButton(tk.Button):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault("background", "blue")
        kwargs.setdefault("foreground", "white")
        kwargs.setdefault("font", "Helvetica 8 bold")

        super().__init__(*args, **kwargs)

root = tk.Tk()

button1 = CustomButton(root, text="Hello", command=lambda: print("Hello"))
button2 = CustomButton(root, text="World", command=lambda: print("world"))

button1.pack()
button2.pack()

root.mainloop()
Experiment answered 6/9, 2018 at 19:29 Comment(0)
L
2

Yes, it's even easier than you imagine. Just use dictionary unpacking:

basic_style = 
     {'background': 'blue',
     'foreground':'white', 
     'font':'Helvetica 8 bold'} 

self.btn = tk.Button(text = 'Hello', **basic_style)

Another popular option is to make a subclass with the style you want, and perhaps other features such as tooltips or style dependant on values or anything else.

class Justine(tk.Button):
    def __init__(self, master=None, **kwargs):
        tk.Button.__init__(self, master, 
            background = 'blue',
            foreground = 'white', 
            font = 'Helvetica 8 bold',
            **kwargs)

self.btn = Justine(text = 'Hello')
Lys answered 6/9, 2018 at 19:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.