How to Create Menus and Status Bars in Python Tkinter
Posted by Al Sweigart in misc
Tkinter is a GUI framework that comes with Python, so it's ideal if you want to create desktop apps that don't rely on downloading third-party packages for a graphical user interface. While Tkinter is rather old fashioned, it's still ideal for simple interfaces and just getting the job done. This blog post has direct examples of the code to create menu and status bars that you can copy and paste into your own apps.
Basic Menu Example
Here's the complete source code for a program that has simple File, New, Open, and Exit menu items. There's also a separator line in the menu.
import tkinter as tk
from tkinter import messagebox
def some_function():
# This function is called when some menu items are clicked.
messagebox.showinfo("Menu Demo", "some_function() was called.")
def exit_app():
# This function closes the entire application.
# root.quit() ends the tkinter event loop.
root.quit()
# ---------------- Main Application Window ---------------- #
# Create the main window where everything lives.
root = tk.Tk()
root.title("Basic Menu Demo") # Window title at the top
root.geometry("400x300") # Width = 400 pixels, Height = 300 pixels
# ---------- Menu Bar (the strip at the top of the window) ---------- #
# Create a Menu object, which will hold all the dropdown menus.
menubar = tk.Menu(root)
# tkinter has a "tear off" feature for menus by default that
# isn't used in mainstream software, so we'll disable it.
# (The tear off feature doesn't work at all on macOS.)
file_menu = tk.Menu(menubar, tearoff=1) # tearoff=0 removes the dashed line at the top
file_menu.add_command(label="New", command=some_function) # "New" item
file_menu.add_command(label="Open", command=some_function) # "Open" item
file_menu.add_separator() # Adds a dividing line
file_menu.add_command(label="Exit", command=exit_app) # "Exit" item
menubar.add_cascade(label="File", menu=file_menu) # Attach File menu to menubar
# Attach the menubar to the window so it actually shows up.
root.config(menu=menubar)
# ---------------- Main Loop ---------------- #
# This line starts the tkinter event loop, which waits for the user
# to click buttons, menus, or close the window. Without this, the
# window would open and close instantly.
root.mainloop()
When you run the program, it will look like this:
TODO
Checkbox and Radio Button Menu Item Examples
Menu items can also have check boxes to signify their enabled/disabled state. You can also have one (and only one) menu item of a group checked, where clicking another item automatically unchecks the currently checked menu item. Here's a program that has a menu with checkbox and radio button menu items:
import tkinter as tk
from tkinter import messagebox
# ---------------- Functions that are called when menu items are clicked ---------------- #
def some_function():
# This function is called when some menu items are clicked.
messagebox.showinfo("Menu Demo", "some_function() was called.")
def exit_app():
# This function closes the entire application.
# root.quit() ends the tkinter event loop.
root.quit()
def toggle_func():
# This function shows or hides the status bar depending on
# whether the checkbutton in the View menu is checked.
messagebox.showinfo("Menu Demo", f"Menu item checked == {toggle_setting.get()}")
def change_theme():
# This function runs when a radiobutton in the Theme menu is clicked.
# Only one theme can be selected at a time.
selected = theme_choice.get()
messagebox.showinfo("Theme Selected", f"You chose: {selected}")
# ---------------- Main Application Window ---------------- #
# Create the main window where everything lives.
root = tk.Tk()
root.title("Checkbox and Radio Button Menu Demo") # Window title at the top
root.geometry("400x300") # Width = 400 pixels, Height = 300 pixels
# ---------------- Menu Bar (the strip at the top of the window) ---------------- #
# Create a Menu object, which will hold all the dropdown menus.
menubar = tk.Menu(root)
# --- File menu ---
file_menu = tk.Menu(menubar, tearoff=0) # tearoff=0 removes the dashed line at the top
file_menu.add_command(label="New", command=some_function) # "New" item
file_menu.add_command(label="Open", command=some_function) # "Open" item
file_menu.add_separator() # Adds a dividing line
file_menu.add_command(label="Exit", command=exit_app) # "Exit" item
menubar.add_cascade(label="File", menu=file_menu) # Attach File menu to menubar
# --- View menu with a checkbutton ---
view_menu = tk.Menu(menubar, tearoff=0)
# BooleanVar is a tkinter variable type that can only be True/False.
# It is linked to the checkbutton so we know if it is checked or not.
toggle_setting = tk.BooleanVar(value=True)
view_menu.add_checkbutton(
label="Checkbox Menu Item", # What the menu item says
onvalue=True, offvalue=False, # Values for checked/unchecked
variable=toggle_setting, # Link this menu item to the BooleanVar
command=toggle_func # Function to run when clicked
)
menubar.add_cascade(label="View", menu=view_menu)
# --- Theme menu with radiobuttons ---
theme_menu = tk.Menu(menubar, tearoff=0)
# StringVar is another tkinter variable type that stores text.
# It will store the name of the currently selected theme.
theme_choice = tk.StringVar(value="A")
theme_menu.add_radiobutton(label="Option A", variable=theme_choice,
value="A", command=change_theme)
theme_menu.add_radiobutton(label="Option B", variable=theme_choice,
value="B", command=change_theme)
theme_menu.add_radiobutton(label="Option C", variable=theme_choice,
value="C", command=change_theme)
menubar.add_cascade(label="Theme", menu=theme_menu)
# Attach the menubar to the window so it actually shows up.
root.config(menu=menubar)
# ---------------- Main Loop ---------------- #
# This line starts the tkinter event loop, which waits for the user
# to click buttons, menus, or close the window. Without this, the
# window would open and close instantly.
root.mainloop()
Note that on macOS, the operating system automatically inserts a "Show Tab Bar", "Show All Tabs", and "Enter Full Screen" menu items under any menu named "View".
When you run the program, it will look like this:
TODO
Submenu Example
The menu items themselves can have submenus with menu items. Here's an example program:
import tkinter as tk
from tkinter import messagebox
# ---------------- Main Application Window ---------------- #
# Create the main window where everything lives.
root = tk.Tk()
root.title("Submenu Demo") # Window title at the top
root.geometry("400x300") # Width = 400 pixels, Height = 300 pixels
# ---------------- Menu Bar (the strip at the top of the window) ---------------- #
# Create a Menu object, which will hold all the dropdown menus.
menubar = tk.Menu(root)
main_menu = tk.Menu(menubar, tearoff=0)
# --- Submenu 1 ---
submenu1 = tk.Menu(main_menu, tearoff=0)
submenu1.add_command(label="Option 1A", command=lambda: messagebox.showinfo("Action", f"You chose: 1A"))
submenu1.add_command(label="Option 1B", command=lambda: messagebox.showinfo("Action", f"You chose: 1B"))
# Add submenu1 to the main menu
main_menu.add_cascade(label="Submenu 1", menu=submenu1)
# --- Submenu 2 ---
submenu2 = tk.Menu(main_menu, tearoff=0)
submenu2.add_command(label="Option 2A", command=lambda: messagebox.showinfo("Action", f"You chose: 2A"))
submenu2.add_command(label="Option 2B", command=lambda: messagebox.showinfo("Action", f"You chose: 2B"))
# Add submenu2 to the main menu
main_menu.add_cascade(label="Submenu 2", menu=submenu2)
# Add the main menu to the menubar
menubar.add_cascade(label="Main", menu=main_menu)
# Attach the menubar to the root window
root.config(menu=menubar)
root.mainloop()
When you run the program, it will look like this:
TODO
Basic Status Bar Example
A status bar is a row at the bottom of the window that can display text. It's good for providing some helpful status information. Here's a program that creates a window with a status bar.
import tkinter as tk
# Counter starts at 0
counter = 0
def increment_counter():
"""Increase the counter value by 1 and update the status bar text."""
global counter
counter += 1
statusbar.config(text=f"Counter: {counter}")
# ---------------- Main Application Window ---------------- #
# Create the main window.
root = tk.Tk()
root.title("Status Bar Demo")
root.geometry("300x150")
# --------- Status Bar (a label at the bottom of the window) -------- #
# Status bar at the bottom.
# relief can also be set to tk.FLAT, tk.RAISED, tk.GROOVE, or tk.RIDGE
# anchor=tk.E will make it right-aligned ("east").
# side=tk.TOP is possible but unconventional.
# side=tk.LEFT and side=tk.RIGHT is rather ugly.
statusbar = tk.Label(root, text=f"Counter: {counter}",
bd=1, relief=tk.SUNKEN, anchor=tk.W)
statusbar.pack(side=tk.BOTTOM, fill=tk.X)
# Button to call increment_counter() when clicked.
increment_button = tk.Button(root, text="Increment the Counter",
command=increment_counter)
increment_button.pack(pady=20)
# ---------------- Main Loop ---------------- #
# This line starts the tkinter event loop, which waits for the user
# to click buttons, menus, or close the window. Without this, the
# window would open and close instantly.
root.mainloop()
When you run the program, it will look like this:
TODO