DEV Community

Cover image for 🐍 Building a Random Joke Generator GUI in Python (Step-by-Step with Tkinter)
Mate Technologies
Mate Technologies

Posted on

🐍 Building a Random Joke Generator GUI in Python (Step-by-Step with Tkinter)

In this tutorial, we’ll build a Random Joke Generator desktop app using Python + Tkinter.

You’ll learn how to:

Create a GUI with Tkinter

Use dropdowns, buttons, and listboxes

Generate random jokes

Save data to a file

Handle threading to keep the UI responsive

Add dark mode support 🌙

Beginner-friendly, no prior GUI experience required.

📦 Step 1: Import Required Modules

We’ll start by importing everything we need.

import sys
import os
import threading
import random
Enter fullscreen mode Exit fullscreen mode

Why these?

sys & os → file paths (useful for packaging apps later)

threading → prevents the UI from freezing

random → selects jokes randomly

Now let’s import Tkinter and related UI helpers:

import tkinter as tk
from tkinter import ttk, messagebox, filedialog

tkinter → base GUI toolkit

ttk → modern themed widgets

messagebox → pop-up alerts

filedialog → save files

Optional (but nice): modern theming with sv_ttk.

import sv_ttk

🧰 Step 2: Helper Functions
📁 Resource Path Helper

This helps your app work both normally and when bundled with PyInstaller.

def resource_path(file_name):
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, file_name)
Enter fullscreen mode Exit fullscreen mode

You don’t need this right now—but it’s a great habit.

📢 Status Bar Helper

We’ll use this to show messages like “Generating joke…”.

def set_status(msg):
    status_var.set(msg)
    root.update_idletasks()
Enter fullscreen mode Exit fullscreen mode

🪟 Step 3: Create the Main Application Window

root = tk.Tk()
root.title("Random Joke Generator")
root.geometry("600x500")
root.minsize(600, 500)
Enter fullscreen mode Exit fullscreen mode

This:

Creates the app window

Sets its title

Defines size and minimum resize limits

Apply a modern theme:

sv_ttk.set_theme("light")
Enter fullscreen mode Exit fullscreen mode

🌍 Step 4: Global Variables

Tkinter uses special variable classes that auto-update UI elements.

dark_mode_var = tk.BooleanVar(value=False)
joke_result_var = tk.StringVar(value="")
Enter fullscreen mode Exit fullscreen mode

We’ll also store joke history:

joke_history = []  # (joke_type, joke)
Enter fullscreen mode Exit fullscreen mode

🌗 Step 5: Dark Mode Toggle

def toggle_theme():
    bg = "#2E2E2E" if dark_mode_var.get() else "#FFFFFF"
    fg = "white" if dark_mode_var.get() else "black"

    root.configure(bg=bg)

    for w in ["TFrame", "TLabel", "TLabelframe", "TLabelframe.Label", "TCheckbutton"]:
        style.configure(w, background=bg, foreground=fg)
Enter fullscreen mode Exit fullscreen mode

✔ Uses a checkbox
✔ Updates widget colors dynamically
✔ Beginner-friendly logic

😂 Step 6: Joke Data

JOKES = {
    "Classic": [
        "Why did the scarecrow win an award? Because he was outstanding in his field!",
        "Why don’t scientists trust atoms? Because they make up everything!"
    ],
    "Dad Jokes": [
        "I only know 25 letters of the alphabet… I don’t know y."
    ],
    "Programming": [
        "Why do programmers prefer dark mode? Because light attracts bugs."
    ]
}
Enter fullscreen mode Exit fullscreen mode

🎯 Joke Generator Function

def generate_joke(joke_type):
    jokes = JOKES.get(joke_type, sum(JOKES.values(), []))
    return random.choice(jokes)
Enter fullscreen mode Exit fullscreen mode

If no type is found → it falls back to all jokes.

🧵 Step 7: Threaded Joke Generation
Button Action

def create_joke():
    joke_type = joke_type_var.get()
    if not joke_type:
        messagebox.showwarning("Select Type", "Please select a joke type.")
        return

    set_status("Generating joke...")
    threading.Thread(
        target=_generate_joke_thread,
        args=(joke_type,),
        daemon=True
    ).start()
Enter fullscreen mode Exit fullscreen mode

💡 Threading keeps the UI responsive.

Background Worker

def _generate_joke_thread(joke_type):
    joke = generate_joke(joke_type)
    joke_result_var.set(joke)
    add_to_history(joke_type, joke)
    set_status("Joke generated!")
Enter fullscreen mode Exit fullscreen mode

🗂 Step 8: Joke History Handling

def add_to_history(joke_type, joke):
    joke_history.append((joke_type, joke))
    preview = joke[:80] + "..." if len(joke) > 80 else joke
    history_list.insert(tk.END, f"[{joke_type}] {preview}")
Enter fullscreen mode Exit fullscreen mode

✔ Stores full joke
✔ Displays preview in listbox

📤 Step 9: Export History to a File

def export_history_txt():
    if not joke_history:
        messagebox.showinfo("Empty History", "No jokes to export.")
        return

Enter fullscreen mode Exit fullscreen mode

Choose a save location:

file_path = filedialog.asksaveasfilename(
    defaultextension=".txt",
    filetypes=[("Text Files", "*.txt")]
)
Enter fullscreen mode Exit fullscreen mode

Write to file:

with open(file_path, "w", encoding="utf-8") as f:
    for i, (jtype, joke) in enumerate(joke_history, 1):
        f.write(f"{i}. [{jtype}] {joke}\n\n")
Enter fullscreen mode Exit fullscreen mode

👀 Step 10: View Full Joke in a Popup

def view_selected_joke(event=None):
    index = history_list.curselection()[0]
    _, joke = joke_history[index]

    win = tk.Toplevel(root)
    win.title("Full Joke")

    tk.Label(
        win,
        text=joke,
        wraplength=480,
        font=("Segoe UI", 14)
    ).pack(padx=10, pady=10)
Enter fullscreen mode Exit fullscreen mode

Double-click = full joke view ✨

🎨 Step 11: Styling

style = ttk.Style()
style.theme_use("clam")
style.configure(
    "Action.TButton",
    font=("Segoe UI", 11, "bold"),
    padding=8
)
Enter fullscreen mode Exit fullscreen mode

🧱 Step 12: Build the UI Layout
Title

ttk.Label(
    main,
    text="Random Joke Generator",
    font=("Segoe UI", 22, "bold")
).grid(row=0, column=0)
Enter fullscreen mode Exit fullscreen mode

Dropdown

joke_type_var = tk.StringVar()

ttk.Combobox(
    main,
    textvariable=joke_type_var,
    values=list(JOKES.keys())
).grid(row=2, column=0, sticky="ew")
Enter fullscreen mode Exit fullscreen mode

Buttons

ttk.Button(
    controls,
    text="😂 Generate Joke",
    command=create_joke
).grid(row=0, column=0)

ttk.Button(
    controls,
    text="📤 Export History",
    command=export_history_txt
).grid(row=0, column=1)
Enter fullscreen mode Exit fullscreen mode

▶️ Step 13: Run the App

root.mainloop()
Enter fullscreen mode Exit fullscreen mode

This starts the Tkinter event loop—your app is live! 🎉

🚀 Final Thoughts

You just built a:

Fully functional GUI app

With threading

Dark mode

History management

File exporting

Ideas to extend it:

Add API-based jokes

Add sound effects

Package it as an .exe

Add categories dynamically

Random Joke Generator

Top comments (0)