Simple Tkinter Toggle Button

HiHe 1 Tallied Votes 21K Views Share

A simple way to create a toggle button for the Tkinter Python GUI toolkit.

# use config() to create a Tkinter toggle button

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def toggle():
    '''
    use
    t_btn.config('text')[-1]
    to get the present state of the toggle button
    '''
    if t_btn.config('text')[-1] == 'True':
        t_btn.config(text='False')
    else:
        t_btn.config(text='True')

root = tk.Tk()

t_btn = tk.Button(text="True", width=12, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Nice approach! Here is another option to do this ...

''' tk_button_toggle2.py
use a list default argument to create a Tkinter toggle button
'''

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def toggle(tog=[0]):
    '''
    a list default argument has a fixed address
    '''
    tog[0] = not tog[0]
    if tog[0]:
        t_btn.config(text='False')
    else:
        t_btn.config(text='True')

root = tk.Tk()

t_btn = tk.Button(text="True", width=12, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
commented: Good stuff. +1
woooee 814 Nearly a Posting Maven

So we are spending our time on simple toggles huh. This uses a list so the function has access to the previous setting. I was too lazy to create a class with an instance variable.

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk

def toggle():
    index_dict={"True": "False", "False": "True"}
    index[0] = index_dict[index[0]]
    t_btn['text'] = index[0]

root = tk.Tk()
index=["True"]
t_btn = tk.Button(text=index[0], width=12, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Just one more ...

''' tk_button_toggle4.py
using itertools.cycle() to create a Tkinter toggle button
'''

import itertools
try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk


def toggle():
    #global icycle
    # works with Python27 and Python3
    state = next(icycle)
    t_btn['text'] = str(state)

root = tk.Tk()
icycle = itertools.cycle([False, True])
t_btn = tk.Button(text="True", width=12, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
Gribouillis 1,391 Programming Explorer Team Colleague

This deserves an answer:

''' tk_button_toggle5.py
'''

from functools import partial
import itertools
import sys
python2 = sys.version_info[0] == 2
tk = __import__("tT"[python2] + "kinter")

def toggle(button):
    button.state = not button.state
    button['text'] = str(button.state)

def new_btn(state):
    btn = tk.Button(width=12)
    btn.state = bool(state)
    btn.config(text= str(btn.state), command = partial(toggle, btn))
    btn.pack(pady=5)
    return btn    

root = tk.Tk()
for x in (1, 0, 1):
    new_btn(x)

root.mainloop()

Notice that btn.state can now be accessed directly.

Lardmeister 461 Posting Virtuoso

Vegaseat's code more elegant:

''' tk_button_toggle6.py
using itertools.cycle() to create a Tkinter toggle button
'''

import itertools
try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk


def toggle(icycle=itertools.cycle([False, True])):
    state = next(icycle)
    t_btn['text'] = str(state)

root = tk.Tk()

t_btn = tk.Button(text="True", width=12, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
BustACode 15 Light Poster

This can be accomplised in one line using "lambda" and a one line "if/else" statement:

t_btn = tk.Button(root, text="True", width=12, command = lambda: t_btn.config(text="False") if t_btn.config('text')[-1] == 'True' else t_btn.config(text="True"))

BustACode 15 Light Poster

You can do it with images as well:

    from Tkinter import *
    root=Tk()
    c=Button(root,justify = LEFT, command = lambda: c.config(text="False", image = io_LEDRedOff) if c.config('text')[-1] == 'True' else c.config(text="True", image = io_LEDRedOn))
    io_LEDRedOn=PhotoImage(file="LED-Red-On.gif")
    io_LEDRedOff=PhotoImage(file="LED-Red-Off.gif")
    c.config(text = "False", image=io_LEDRedOff, width="15",height="15")
    c.pack(side=RIGHT)

    root.mainloop()

NOTE: Images in code are here: http://i.imgur.com/uMzb0g9.gif
http://i.imgur.com/bFo9AtY.gif

martineau 19 Newbie Poster

@vegaseat: Generally speaking, using mutable default arguments is considered a poor Python programming practice.

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

@martineau: Since you are the expert in good Python programming, what is your solution? Show us what you got!

rproffitt commented: “SHOW ME WHAT YOU GOT! I WANT TO SEE WHAT YOU GOT!" - Cromulons. +15
martineau 19 Newbie Poster

@vegaseat: OK. Your approach could be improved by doing it like this:

from functools import partial

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk  # Python 3

def toggle(tog):
    """ Use passed mutable argument to track button's status.
    """
    tog[0] = not tog[0]
    t_btn.config(text='True' if tog[0] else 'False')

root = tk.Tk()
t_btn = tk.Button(text="False", width=12, command=partial(toggle, [False]))
t_btn.pack(pady=5)
root.mainloop()

Another approach would be to use a function attribute:

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk  # Python 3

def toggle():
    """ Use function attribute to track button's status.
    """
    toggle.status = not toggle.status
    t_btn.config(text='True' if toggle.status else 'False')

root = tk.Tk()
t_btn = tk.Button(text="False", width=12, command=toggle)
toggle.status = False  # Initialize function attribute.
t_btn.pack(pady=5)
root.mainloop()
martineau 19 Newbie Poster

@vegaseat: Here's yet another way to do it using a tkinter Variable widget:

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk  # Python 3

def toggle():
    """ Update toggle Button's text based on the current value of the
        control variable assocated with it.
    """
    t_btn.config(text=btn_var.get())

root = tk.Tk()
btn_var = tk.StringVar(root, 'False')
t_btn = tk.Checkbutton(root, text=btn_var.get(), width=12, variable=btn_var,
                       offvalue='False', onvalue='True', indicator=False,
                       command=toggle)
t_btn.pack(pady=5)
root.mainloop()

Note that in actual usage, the CheckButton and StringVar should be made members of a custom class so they can be treated as a unit.

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Very nice, thanks martineau!
Got to testdrive your ideas. Right now I am working with an ACER Chromebook 15 and doing Python code is a little tough.
Will get to my trusty iMac soon.

martineau 19 Newbie Poster

@vegaseat: Thanks. I wasn't quite satisfied and so worked on it a little more. Below is an even simpler version which makes more use of the built-in tk.Checkbutton class' capabilities—so no longer requires a toggle() function. If you do want to execute something when it's clicked for other reasons, just add a command= argument when constructing the Checkbutton.

As I mentioned before, the control variable StringVar and Checkbutton widgets should be made members of a custom class. In my own application I derived a class ToggleButton(tk.Checkbutton) subclass to encapsulate them, but in the code below they're just two independent (global) widgets.

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk  # Python 3

root = tk.Tk()
LABEL0, LABEL1 = 'Pause', 'Resume'
btn_var = tk.StringVar(root, LABEL0)
t_btn = tk.Checkbutton(root, textvariable=btn_var, width=12, variable=btn_var,
                       offvalue=LABEL0, onvalue=LABEL1, indicator=False)
t_btn.pack(pady=5)
root.mainloop()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.