DEV Community

Mate Technologies
Mate Technologies

Posted on

🧩 Build a Pattern History Printer GUI App with Python & Tkinter (Step-by-Step)

In this tutorial, we’ll build a desktop GUI app using Python + Tkinter that:

Generates text patterns (pyramid, triangle, inverted pyramid)

Stores every generated pattern in a history list

Lets users preview previous patterns

Exports pattern history to a .txt file

Supports light/dark mode

This guide is written for beginners, so we’ll build the app piece by piece.

🛠 Prerequisites

Before we start, make sure you have:

Python 3.9+

Basic Python knowledge (functions, loops)

Tkinter (comes with Python)

sv_ttk for modern themes

Install sv_ttk if needed:

pip install sv-ttk

1️⃣ Import Required Modules

We start by importing all the libraries we’ll need.

import sys
import os
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sv_ttk
Enter fullscreen mode Exit fullscreen mode

What these do:

tkinter → GUI framework

ttk → modern widgets

messagebox → pop-up alerts

filedialog → file save dialog

sv_ttk → clean light/dark themes

2️⃣ Helper Functions
🔹 Resource Path Helper (for packaging support)

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

This makes your app PyInstaller-friendly if you later convert it into an .exe.

🔹 Status Bar Helper

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

This updates the status bar text instantly without freezing the UI.

3️⃣ Create the Main App Window

root = tk.Tk()
root.title("Pattern History Printer")
root.geometry("600x700")
root.minsize(600, 700)

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

We define:

App title

Default size

Minimum size

Light theme using sv_ttk

4️⃣ Global Variables & State

dark_mode_var = tk.BooleanVar(value=False)
rows_var = tk.StringVar(value="5")
pattern_type_var = tk.StringVar(value="Pyramid")
pattern_history = []
Enter fullscreen mode Exit fullscreen mode

Why use StringVar / BooleanVar?

They automatically sync UI widgets with Python variables.

5️⃣ Dark Mode Toggle Logic

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)

    rows_entry.configure(background=bg, foreground=fg)
Enter fullscreen mode Exit fullscreen mode

This function dynamically:

Switches background colors

Updates text color

Keeps widgets readable in dark mode

6️⃣ Pattern Generation Logic

def generate_pattern():
    try:
        rows = int(rows_var.get())
        if rows < 1:
            raise ValueError
    except ValueError:
        messagebox.showerror("Invalid Input", "Please enter a valid positive integer.")
        return
Enter fullscreen mode Exit fullscreen mode

Input validation:

Ensures rows is a positive integer

Shows an error dialog if invalid

🔹 Generate Different Patterns

    p_type = pattern_type_var.get()
    pattern_lines = []

    if p_type == "Pyramid":
        for i in range(1, rows + 1):
            pattern_lines.append(" " * (rows - i) + "*" * (2 * i - 1))

    elif p_type == "Right Triangle":
        for i in range(1, rows + 1):
            pattern_lines.append("*" * i)

    elif p_type == "Inverted Pyramid":
        for i in range(rows, 0, -1):
            pattern_lines.append(" " * (rows - i) + "*" * (2 * i - 1))
Enter fullscreen mode Exit fullscreen mode

Each pattern is built line-by-line, then joined into a single string.

🔹 Save to History

    pattern_str = "\n".join(pattern_lines)
    add_to_history(p_type, rows, pattern_str)
    set_status("Pattern generated! Click a history entry to view details.")
Enter fullscreen mode Exit fullscreen mode

7️⃣ Pattern History Management
🔹 Add to History List

def add_to_history(p_type, rows, pattern_str):
    pattern_history.append((p_type, rows, pattern_str))
    preview = f"{p_type} | Rows: {rows}"
    history_list.insert(tk.END, preview)
Enter fullscreen mode Exit fullscreen mode

We store:

Pattern type

Number of rows

Full pattern text

8️⃣ Export History to a Text File

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

    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("Text Files", "*.txt")],
        title="Export Pattern History"
    )

    with open(file_path, "w", encoding="utf-8") as f:
        f.write("Pattern History\n")
        f.write("=" * 40 + "\n\n")
        for i, (ptype, rows, pstr) in enumerate(pattern_history, 1):
            f.write(f"{i}. {ptype} | Rows: {rows}\n")
            f.write(pstr + "\n\n")
Enter fullscreen mode Exit fullscreen mode

This creates a clean, readable export file.

9️⃣ View Pattern Details in a New Window

def view_selected_history(event=None):
    selection = history_list.curselection()
    if not selection:
        messagebox.showinfo("No Selection", "Please select a pattern.")
        return

    history_window = tk.Toplevel(root)
    history_window.title(f"{p_type} | Rows: {rows}")
    history_window.geometry("500x400")

    text_widget = tk.Text(frame, wrap="none", font=("Consolas", 12))
    text_widget.insert(tk.END, pattern_str)
    text_widget.configure(state="disabled")
Enter fullscreen mode Exit fullscreen mode

This opens a read-only preview window for each saved pattern.

🔟 Styling & Status Bar

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

status_var = tk.StringVar(value="Ready")
ttk.Label(root, textvariable=status_var, anchor="w").pack(side=tk.BOTTOM, fill="x")
Enter fullscreen mode Exit fullscreen mode

1️⃣1️⃣ UI Layout (Inputs, Buttons & History)

We organize the layout using ttk.Frame, grid(), and pack() for a responsive design.

Key widgets:

Entry for rows

ComboBox for pattern type

Buttons for generate/export

Listbox for history

Dark mode toggle

1️⃣2️⃣ Run the App

root.mainloop()
Enter fullscreen mode Exit fullscreen mode

This starts the Tkinter event loop and launches the app 🚀

🎉 Final Result

You now have a fully functional desktop app that:

Generates patterns

Tracks history

Supports dark mode

Exports data

Uses clean UI themes

Pattern History Printer

Top comments (0)