Tkinter Button Widget
Create Button Widget
A button widget is usually placed in another widget like root window, frame, etc. Buttons can contain text, bitmaps, images.
# import tkinter module import tkinter as tk # create a root window that will host the button # root, an instance of the tkinter.Tk class, is a top-level widget root = tk.Tk() # create a button widget, an instance of the tkinter.Button class button = tk.Button(root, text="Go") # pack the button so that it is visible in the window button.pack() # start the GUI event loop root.mainloop()
Buttons and Callbacks
The purpose of a tkinter button is to perform an action in response to user interaction with graphical interface elements. For example, confirm the completion of the form, start or stop the process.
We can associate a function call with a button click in tkinter. When a button is pressed, the corresponding function is triggered.
Such a function is usually passed as an argument with a command
parameter when creating a button and is called a callback.
Button With Command
import tkinter as tk def callback(): # do some important things print("callback") root = tk.Tk() button = tk.Button(root, text="Go", command=callback) button.pack() root.mainloop()
Button With Event Binding
Another option is to add a callback function as a handler for a specific event.
In this case, the callback function requires an event
parameter. This parameter represents an instance of the tkinter Event class.
The event
is a container for event properties. It can provide some useful information and access to the event widget.
import tkinter as tk def callback(event): """This function is an event handler.""" # do some important things print(event) print(event.widget, event.widget["state"]) root = tk.Tk() button = tk.Button(root, text="Go") button.pack() # leftmost button click event button.bind("<Button-1>", callback) root.mainloop()
Button and Functions With Arguments
Sometimes we need to pass specific values to a callback for further processing.
If we do command=callback(values)
, the function will simply be executed by the Python interpreter just before we click the button.
Lambda, an anonymous inline function, is most often used to pass the required values. The syntax for creating this function is lambda [parameters]: expression
. The callback(values)
is specified instead of expression
. When we click on the button, the lambda function is called, which in turn calls the callback.
import tkinter as tk def callback1(arg): print(arg) def callback2(event, arg): # event parameter is required anyway print(arg) command_text = "Command callback." event_text = "Event callback." root = tk.Tk() button = tk.Button(root, text="Go", command=lambda: callback1(command_text)) # or like this: #button = tk.Button(root, text="Go", #command=lambda arg=command_text: callback1(arg)) button.pack() # leftmost button click event button.bind("<Button-1>", lambda event, arg=event_text: callback2(event, arg)) # or like this: #button.bind("<Button-1>", #lambda event: callback2(event, event_text)) root.mainloop()
Button Options
Buttons can accept additional configuration options that can change their appearance and behavior.
Some of these options have default values such as background and foreground colors, highlight options, font, borderwidth, justify, padx, pady, relief, state, and others.
Button Widget Options
Standard options:
activebackground, activeforeground, anchor,
background (or bg), bitmap, borderwidth (or bd), compound, cursor,
disabledforeground, font, foreground (or fg),
highlightbackground, highlightcolor,
highlightthickness, image, justify,
padx, pady, relief, repeatdelay,
repeatinterval, takefocus, text,
textvariable, underline, wraplength
Widget-specific options:
command, default, height,
overrelief, state, width
Button commands:
cget, configure (or config), flash, invoke
See details: Tcl8.6/Tk8.6 Button man page. The effect of using the options may differ depending on the platform.
We can change the state and style properties of the button after it has been created.
import tkinter as tk def callback(): # set or update options after creating the button button["text"] = "Disabled!" # update multiple options button.config(state="disabled", relief="flat", disabledforeground="black", background="red") root = tk.Tk() # set options button = tk.Button(root, text="Go", background="blue", foreground="white") button.pack() # set or update options after creating the button button["command"] = callback # get option values print(button.config()) # all options print(button["background"]) print(button.cget("relief")) root.mainloop()
The tk.Button has three states: "normal"
, "active"
, or "disabled"
.
button["option"]
is Python feature. See def cget
, __getitem__
, __setitem__
in the Misc class in the tkinter source.
The implementation of __getitem__
and __setitem__
allows us to get the value of an option by key or set a new value for an option, respectively. Tkinter widgets inherit methods from this class.
The tkinter Button class also inherits many data attributes and methods from other classes. We can view a list of them using print(dir(button))
.
Background, Foreground, Font
There are several ways to specify colors and fonts for a tkinter button. For colors, you can use a symbolic color name or an RGB value (#FF5 or #FEF65B). The font can be a tuple of font settings or a named object of the Font class.
Some color and font family names are system-specific.
import tkinter as tk from tkinter import font root = tk.Tk() # a) Font tuple # family, size, weight, slant, "underline", and "overstrike" left_button_font = ("Calibri", 10, "bold") # b) Font object # available font families - print(font.families()) right_button_font = font.Font(family="Courier", size=10, weight="bold", slant="italic", underline=1, name="RightButtonFont") left_button = tk.Button(root, text="Left button", background="#AAAFFF", foreground="black", font=left_button_font) left_button.pack(fill="x", side="left", expand=True, padx=10, pady=10) right_button = tk.Button(root, text="Right button", background="grey", foreground="#FFFAAA", font=right_button_font) right_button.pack(fill="x", side="right", expand=True, padx=10, pady=10) root.mainloop()
Padding, Relief, Border
We can use the padx
and pady
options to add padding to the content of the tkinter button. The padx
value indicates how much extra space we want for the widget in the X direction. The pady
value indicates how much extra space we want for the widget in the Y direction. These are internal button paddings.
To visually separate the button from other elements, we can also use the padx
and pady
options of the geometry manager (pack or grid). These are will be external button paddings.
We can set two values, for each direction x and y, in pack or grid geometry managers.
import tkinter as tk root = tk.Tk() root.geometry("500x100") # paddings and borderwidth in pixels frame = tk.Frame(root, background="white") frame.pack() # padx, pady - paddings from content(text) to button borders button1 = tk.Button(frame, text="B1", background="green", borderwidth=5, # one value for each direction x and y # left - 5, right - 5 # top - 5, bottom - 5 padx=5, pady=5) button1.pack(side="left") # padx, pady - paddings from content(text) to button borders button2 = tk.Button(frame, text="B2", background="green", borderwidth=10, # one value for each direction x and y # left - 20, right - 20 # top - 5, bottom - 5 padx=20, pady=5) button2.pack(side="left") # button with external paddings button3 = tk.Button(frame, text="B3", background="green", borderwidth=5, padx=5, pady=5) # two values for each direction x and y # left - 10, right - 50 # top - 0, bottom - 20 button3.pack(side="left", padx=[10, 50], pady=[0, 20]) # button with external paddings button4 = tk.Button(frame, text="B4", background="green", borderwidth=5, padx=15, pady=5) # two values for x direction # left - 0, right - 5 # top - 10, bottom - 10 button4.pack(side="left", padx=[0, 5], pady=10) root.mainloop()
We can use the borderwidth
and relief
options to create a 3D effect around the button. The appearance of the border depends on the value of the relief
option.
The following example creates tkinter buttons in a loop to showcase relief
styles.
import tkinter as tk root = tk.Tk() root.config(background="lightyellow") # all relief styles relief_styles = [ "raised", "sunken", "flat", "ridge", "solid", "groove" ] row = 0 # put the buttons in one line column = 0 # but in different columns # create table-like structure # paddings and borderwidth in pixels for i in relief_styles: button = tk.Button(root, text=i, background="lightgreen", borderwidth=10, relief=i, # paddings from content(text) to button borders padx=5, pady=3) # use grid geometry manager button.grid(row=row, column=column, # paddings from content(button) to grid cell borders padx=10, pady=10) column += 1 root.mainloop()
Button With Image
The buttons can display text and/or an image. To specify how the image should be positioned relative to the text, we need to use the compound
option.
import tkinter as tk root = tk.Tk() root.config(background="silver") # png 16x16 python_image = tk.PhotoImage(file="python.png") # png 100x100 cat_image = tk.PhotoImage(file="cat.png") cat_image_subsample = cat_image.subsample(x=3, y=3) # button with text and image on the left side button1 = tk.Button(root, text="Python", image=python_image, compound="left", padx=5, font=("Courier", 10)) button1.pack(padx=10, pady=10, side="left") # button with reduced image button2 = tk.Button(root, borderwidth=5, image=cat_image_subsample, relief="groove") button2.pack(padx=10, pady=10, side="left") # button that looks like an image with a border label = tk.LabelFrame(root, background="white") label.pack(padx=10, pady=10, side="left") button3 = tk.Button(label, image=cat_image, borderwidth=0, cursor="hand2", highlightthickness=0) button3.pack(padx=5, pady=5) # make a white border around # button with sizes and text on the image button4 = tk.Button(root, text="CATS", # compound="center" - text on image image=cat_image, compound="center", borderwidth=3, height=30, width=60, foreground="white", font=("Calibri", 10, "bold")) button4.pack(padx=10, pady=10, side="left") root.mainloop()
The images used in the example:
Buttons and Place Geometry Manager
There is also a third geometry manager - place. It provides absolute or relative placement of widgets in some container, root window, or other widget. A button can be positioned using specific x and y coordinates in the container window.
The place geometry manager can be useful if we need to place a button relative to another window element. For example, in forms or custom dialog boxes. We can combine the absolute and relative options.
import tkinter as tk root = tk.Tk() root.geometry("250x150") root.config(background="lightgreen") entry1 = tk.Entry(root) entry1.place(x=10, y=10) button1 = tk.Button(root, text="B1") # placed relative to the entry1 button1.place(in_= entry1, bordermode="outside", relx=1.1, rely=0, width=50, relheight=1.0) entry2 = tk.Entry(root) entry2.place(x=10, y=60) button2 = tk.Button(root, text="B2") # placed relative to the entry2 button2.place(in_= entry2, bordermode="outside", anchor="center", relx=0.5, rely=2, width=50, relheight=1.0) root.mainloop()
Another case where we can use place()
is when we need to overlay a button on another window element.
import tkinter as tk root = tk.Tk() root.geometry("500x150") root.config(background="lightgreen") label = tk.Label(root, background="white", width=50, height=5) label.pack(side="top", pady=20) button = tk.Button(root, text="Button", relief="flat", overrelief="ridge", background="#E5E0D8", borderwidth=5) # button in the upper right corner of the label button.place(in_=label, anchor="ne", relx=1.0, rely=0) root.mainloop()
If we use place, we need to calculate the position of each widget in pixels. Widgets must fit each other and the root window. Using a grid for complex window layouts is more maintainable.