Goal: Capture and Display User Input
In this chapter you will build a small interface that collects user input, lets the user choose options, and then displays the result. You will use core widgets: Label, Entry, Text, Button, Checkbutton, and Radiobutton. You will also use Tkinter variables (StringVar, IntVar, BooleanVar) to bind widget state to Python values (two-way binding).
Core Widgets and the Options You Will Use
Label: Display text (and later, output)
A Label is for displaying non-editable text. It is often used for field names (like “Name:”) and for showing output. A label’s text can be set directly with the text option, or dynamically via a StringVar using the textvariable option.
text: static text shown by the labeltextvariable: bind the label to aStringVarfor dynamic updateswidth: a fixed width in text units (useful for alignment)
Entry: Single-line input
An Entry is a single-line text input. You can read its value with entry.get() or bind it to a StringVar using the textvariable option for two-way binding.
width: visible character widthstate:"normal"(editable),"disabled"(not editable),"readonly"(not editable but looks like a field; supported byttk.Entry, not classictk.Entry)
Text: Multi-line input/output
A Text widget is for multi-line text. Unlike Entry, it does not bind directly to StringVar. You typically use text_widget.get("1.0", "end-1c") to read and text_widget.insert(...) or text_widget.delete(...) to update.
width: character widthstate:"normal"or"disabled"(useful for read-only output areas)
Button: Trigger actions with command
A Button triggers a Python function when clicked. The function is provided via the command option. The function should be passed without parentheses (you pass the function object, not the result of calling it).
Continue in our app.
You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.
Or continue reading below...Download the app
text: label on the buttoncommand: function to run on clickstate: enable/disable the buttonwidth: optional fixed width
Checkbutton: On/off choice
A Checkbutton represents a boolean choice. It is commonly bound to a BooleanVar (or sometimes an IntVar with 0/1). When the user toggles it, the variable updates automatically; when you set the variable in code, the checkbutton updates automatically.
text: label next to the checkboxvariable: aBooleanVar/IntVarto bind tocommand: optional function called when toggled
Radiobutton: Choose one option from many
Radiobutton widgets work in a group: they share the same variable (usually an IntVar or StringVar), and each radiobutton sets that variable to its own value. This is ideal for “pick one” choices.
text: label for the optionvariable: sharedStringVar/IntVarvalue: the value assigned when selectedcommand: optional function called when selection changes
Tkinter Variables: Two-Way Binding
Tkinter variables are special objects that keep a value and notify widgets when it changes. They are the simplest way to keep UI state and Python state synchronized.
StringVar: stores textIntVar: stores integers (often used for radiobutton groups)BooleanVar: storesTrue/False(often used for checkbuttons)
Key methods:
var.get(): read the current valuevar.set(value): update the value (and the UI updates automatically if bound)
Step-by-Step Build: A Mini Data Capture Interface
You will build a small form that collects a name, an email, a subscription checkbox, a contact preference (radio buttons), and a multi-line note. When the user clicks “Submit”, you will display a formatted summary. You will also add a “Clear” button that resets everything and clears the output.
Step 1: Create variables for binding
We will bind Entry widgets to StringVar, the Checkbutton to a BooleanVar, and the Radiobutton group to a StringVar. We will also use a StringVar for output so we can show results in a label.
Step 2: Create widgets and connect them to variables
Notice how textvariable and variable connect widgets to Tkinter variables. For the multi-line Text widget, we will read and clear it using get/delete because it does not support StringVar directly.
Step 3: Implement submit and clear actions
The “Submit” button reads values from variables (and the Text widget), formats a summary, and writes it to the output variable. The “Clear” button resets variables with .set(...), clears the Text widget, and clears the output.
import tkinter as tk
root = tk.Tk()
root.title("Input Demo")
# --- Tkinter variables (two-way binding) ---
name_var = tk.StringVar(value="")
email_var = tk.StringVar(value="")
subscribe_var = tk.BooleanVar(value=False)
contact_var = tk.StringVar(value="email") # radio group
output_var = tk.StringVar(value="")
# --- Widgets ---
tk.Label(root, text="Name:").grid(row=0, column=0, sticky="w", padx=8, pady=6)
name_entry = tk.Entry(root, textvariable=name_var, width=30)
name_entry.grid(row=0, column=1, sticky="w", padx=8, pady=6)
tk.Label(root, text="Email:").grid(row=1, column=0, sticky="w", padx=8, pady=6)
email_entry = tk.Entry(root, textvariable=email_var, width=30)
email_entry.grid(row=1, column=1, sticky="w", padx=8, pady=6)
subscribe_cb = tk.Checkbutton(root, text="Subscribe to updates", variable=subscribe_var)
subscribe_cb.grid(row=2, column=1, sticky="w", padx=8, pady=6)
tk.Label(root, text="Preferred contact:").grid(row=3, column=0, sticky="w", padx=8, pady=6)
rb_email = tk.Radiobutton(root, text="Email", variable=contact_var, value="email")
rb_phone = tk.Radiobutton(root, text="Phone", variable=contact_var, value="phone")
rb_email.grid(row=3, column=1, sticky="w", padx=8, pady=2)
rb_phone.grid(row=4, column=1, sticky="w", padx=8, pady=2)
tk.Label(root, text="Notes:").grid(row=5, column=0, sticky="nw", padx=8, pady=6)
notes_text = tk.Text(root, width=40, height=6)
notes_text.grid(row=5, column=1, sticky="w", padx=8, pady=6)
# Output shown in a label (read-only by nature)
tk.Label(root, text="Output:").grid(row=6, column=0, sticky="nw", padx=8, pady=6)
output_label = tk.Label(root, textvariable=output_var, width=50, anchor="w", justify="left")
output_label.grid(row=6, column=1, sticky="w", padx=8, pady=6)
# --- Actions ---
def submit():
name = name_var.get().strip()
email = email_var.get().strip()
subscribed = subscribe_var.get()
contact = contact_var.get()
notes = notes_text.get("1.0", "end-1c").strip()
summary = (
f"Name: {name or '(missing)'}\n"
f"Email: {email or '(missing)'}\n"
f"Subscribed: {'Yes' if subscribed else 'No'}\n"
f"Contact via: {contact}\n"
f"Notes: {notes or '(none)'}"
)
output_var.set(summary)
def clear():
name_var.set("")
email_var.set("")
subscribe_var.set(False)
contact_var.set("email")
notes_text.delete("1.0", "end")
output_var.set("")
submit_btn = tk.Button(root, text="Submit", width=12, command=submit)
clear_btn = tk.Button(root, text="Clear", width=12, command=clear)
submit_btn.grid(row=7, column=1, sticky="w", padx=8, pady=10)
clear_btn.grid(row=7, column=1, sticky="w", padx=110, pady=10)
# Optional: put cursor in first field
name_entry.focus_set()
root.mainloop()Reading and Updating Values: Common Patterns
Pattern 1: Read from variables (Entry/Checkbutton/Radiobutton)
When a widget is bound to a Tkinter variable, you typically read the value from the variable, not from the widget.
current_name = name_var.get()
is_subscribed = subscribe_var.get()
contact_choice = contact_var.get()Pattern 2: Update the UI by setting variables
Setting the variable updates all widgets bound to it. This is useful for resets, defaults, and programmatic changes.
name_var.set("Ada Lovelace")
subscribe_var.set(True)
contact_var.set("phone")Pattern 3: Work with Text widget content
The Text widget uses index strings. "1.0" means line 1, character 0. "end" includes a trailing newline, so "end-1c" is commonly used when reading.
notes = notes_text.get("1.0", "end-1c")
notes_text.delete("1.0", "end")
notes_text.insert("1.0", "Prefilled notes...")Pattern 4: Make an output area read-only
A Label is naturally read-only, so it is a simple way to display output. If you want multi-line output with selectable text, you can use a Text widget and disable it after writing.
# Example: write to a Text output and lock it
output_text = tk.Text(root, width=50, height=6)
output_text.insert("1.0", "Hello")
output_text.config(state="disabled")Exercises (Structured)
Exercise 1: Create a data-entry form
Build a form that collects the following:
- First name (
Entrybound toStringVar) - Last name (
Entrybound toStringVar) - Age (
Entrybound toStringVarorIntVar; keep it simple and validate later) - Newsletter opt-in (
Checkbuttonbound toBooleanVar) - Account type (
Radiobuttongroup bound toStringVar, values:"free","pro","team")
Add a “Preview” button that writes a formatted summary to an output Label using textvariable.
Exercise 2: Add a clear/reset button
Add a “Reset” button that:
- Sets all
StringVarvalues to"" - Sets the newsletter
BooleanVartoFalse - Sets the account type variable back to a default (for example
"free") - Clears the output label by setting its
StringVarto""
Make sure you reset by calling .set(...) on variables rather than manually editing widget text.
Exercise 3: Show output in a read-only field
Replace the output label with a read-only output area:
- Option A (simple): keep the
Labeland ensure it can display multiple lines (usejustifyand a reasonablewidth). - Option B (selectable output): use a
Textwidget for output, write the summary into it, then setstate="disabled". When clearing, temporarily setstate="normal", delete the content, then disable again.
# Output Text approach (snippet)
def set_output(text):
output_text.config(state="normal")
output_text.delete("1.0", "end")
output_text.insert("1.0", text)
output_text.config(state="disabled")Widget Options in Practice: text, state, width, command
text
Used by Label, Button, Checkbutton, and Radiobutton to show a caption. For dynamic text, prefer textvariable on labels.
state
Use state to prevent interaction. Common values are "normal" and "disabled". Disabling is useful when you want to lock output or prevent submission until required fields are filled.
submit_btn.config(state="disabled")
submit_btn.config(state="normal")width
width sets a widget’s size in text units (characters). It helps keep forms aligned and readable.
command
command connects a button (and optionally check/radio widgets) to behavior. Keep the callback focused: read state, compute result, update output.
def on_toggle():
output_var.set(f"Subscribed: {subscribe_var.get()}")
subscribe_cb.config(command=on_toggle)