[Tkinter-discuss] Toggle buttons

Mark Summerfield list at qtrac.plus.com
Tue Jul 24 17:05:01 CEST 2012


Hi Jane,

On Tue, 24 Jul 2012 13:45:38 +0000 (UTC)
Jane <jgriscti at gmail.com> wrote:
> Mark Summerfield <list <at> qtrac.plus.com> writes:
> 
> > 
> > Hi,
> > 
> > I want to create a toggle button, i.e., a button that when clicked goes
> > down (if it is up) and goes up (if it is down).
> > 
> > One easy way to achieve this is to set the button's style to
> > "Toolbutton" (see self.toggle2). But unfortunately, that gets rid of
> > the button's relief so it looks out of place amongst other non-toggling
> > buttons.
> > 
> > I solved if for Linux using a custom style (see self.toggle3). But this
> > doesn't work on Windows and I can't figure out how to solve it.
> > 
> > Can anyone suggest a solution?
[snip]

> Hi ... 
> 
> Found that setting the ttk.Checkbutton style to 'TButton' forces it to
> appear as themed button; then, on selection, changing it to 'Toolbutton'
> gives it a 'sunken' appearance. Works ok under Windows 7.
> 
>     cb1 = ttk.Checkbutton(f, style='Demo.TButton',
>                              image=(self.noletters, 'selected',
> self.letters), command=lambda: self._cb_value_changed(cb1))
> 
>     def _cb_value_changed(self, cb):
>         # if a checkbutton is selected, use the 'Toolbutton' 
>         # style to make it appear 'sunken'
>         if 'selected' in cb.state():
>             cb['style'] = 'Demo.Toolbutton'
>         else:
>             cb['style'] = 'Demo.TButton'

I tried your idea on Windows 7 & Linux (& a slightly simplified version
which did the same). Yes, it correctly changes the appearance between
raised and sunken: but in the sunken state the width of the button
shrinks to fit the text -- and there's no width property for styled
buttons:-(

Here's the code:

############################################################
import tkinter.ttk

class Window(tkinter.ttk.Frame):

    def __init__(self, master=None):
        super().__init__(master)
        self.toggle1 = tkinter.ttk.Button(self, text="Off (1)",
                command=lambda *args: self.toggle(self.toggle1, 1))
        self.toggle1.pack(padx=5, pady=5)
        self.toggle2 = tkinter.ttk.Button(self, text="Off (2)",
		style="Toolbutton",
		command=lambda *args: self.toggle(self.toggle2, 2))
        self.toggle2.pack(padx=5, pady=5)
        self.toggle3 = tkinter.ttk.Button(self, text="Off (3)", 
                command=lambda *args: self.toggle(self.toggle3, 3))
        self.toggle3.pack(padx=5, pady=5)
        style = tkinter.ttk.Style()
        style.configure("Toggle.TButton")
        style.map("Toggle.TButton", relief=[("pressed", "sunken"),
            ("selected", "sunken"), ("!selected", "raised")])
        self.toggle3.config(style="Toggle.TButton")
        self.toggle4 = tkinter.ttk.Checkbutton(self,
                style="Toggle.TButton", text="Off (4)",
                command=lambda *args: self.toggle_style(self.toggle4, 4))
        self.toggle4.pack(padx=5, pady=5)
        tkinter.ttk.Button(self, text="Quit",
                command=self.master.destroy).pack(padx=5, pady=5)
        self.pack()

    def toggle_style(self, button, number):
        if button.instate(("selected",)):
            button.config(text="Off ({})".format(number))
            button.config(style="Toolbutton")
        else:
            button.config(text="On ({})".format(number))
            button.config(style="Toggle.TButton")

    def toggle(self, button, number):
        if button.instate(("!selected",)):
            button.state(("selected",))
            button.config(text="On ({})".format(number))
        else:
            button.state(("!selected",))
            button.config(text="Off ({})".format(number))

window = Window()
window.master.title("Toggle")
window.master.mainloop()
############################################################


-- 
Mark Summerfield, Qtrac Ltd, www.qtrac.eu
    C++, Python, Qt, PyQt - training and consultancy
        "Programming in Go" - ISBN 0321774639
            http://www.qtrac.eu/gobook.html


More information about the Tkinter-discuss mailing list