This step‑by‑step Dev.to tutorial walks you through building a desktop story generator app using Python + Tkinter.
We’ll start small, explain every piece, and gradually assemble the full app—so even if Tkinter feels scary, you’ll be comfortable by the end.
✅ What You’ll Build
A clean Tkinter GUI
Light/Dark theme toggle
AI‑style story generation (rule‑based, no API)
Story history vault
Typing animation for story playback
Export stories to a .txt file
🧩 Prerequisites
Python 3.9+
Basic Python knowledge (functions, lists, strings)
Install Required Package pip install sv-ttk 1️⃣ Imports & Project Setup
We begin by importing everything we’ll need.
import sys
import os
import threading
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sv_ttk
...
This step‑by‑step Dev.to tutorial walks you through building a desktop story generator app using Python + Tkinter.
We’ll start small, explain every piece, and gradually assemble the full app—so even if Tkinter feels scary, you’ll be comfortable by the end.
✅ What You’ll Build
A clean Tkinter GUI
Light/Dark theme toggle
AI‑style story generation (rule‑based, no API)
Story history vault
Typing animation for story playback
Export stories to a .txt file
🧩 Prerequisites
Python 3.9+
Basic Python knowledge (functions, lists, strings)
Install Required Package pip install sv-ttk 1️⃣ Imports & Project Setup
We begin by importing everything we’ll need.
import sys
import os
import threading
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import sv_ttk
import random
import time
🔍 What These Do Module Purpose tkinter GUI framework ttk Modern widgets sv_ttk Light/Dark themes threading Prevent UI freezing random Story variation 2️⃣ Helper Functions 📁 Loading Files Correctly (PyInstaller‑Safe)
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)
✅ This ensures assets work even after packaging the app.
📊 Status Bar Helper
def set_status(msg): status_var.set(msg) root.update_idletasks()
Used to show feedback like “Generating story…”.
3️⃣ Creating the Main Window
root = tk.Tk()
root.title("Personalized AI‑Assisted Story Generator")
root.geometry("850x720")
root.minsize(850, 720)
sv_ttk.set_theme("light")
🪟 This creates the main application window.
4️⃣ Global State Variables
Tkinter uses special variables that automatically sync with widgets.
dark_mode_var = tk.BooleanVar(value=False)
ai_mode_var = tk.BooleanVar(value=True)
story_title_var = tk.StringVar()
story_prompt_var = tk.StringVar()
story_characters_var = tk.StringVar()
story_settings_var = tk.StringVar()
story_plot_var = tk.StringVar()
story_result_var = tk.StringVar(value="")
story_history = []
🧠 These act as the app’s memory.
5️⃣ Light / Dark Theme 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)
🎨 Switches colors dynamically without restarting the app.
6️⃣ Story Data (AI‑Style Building Blocks)
Instead of calling a real AI API, we simulate creativity using lists.
DEFAULT_CHARACTERS = ["a brave knight", "a curious child", "an old wizard"]
DEFAULT_SETTINGS = ["in a distant kingdom", "inside a magical forest"]
DEFAULT_PLOTS = ["faces a great challenge", "discovers a hidden secret"]
RESOLUTIONS = ["overcomes the obstacle", "learns an important lesson"]
✨ Random combinations = infinite stories.
7️⃣ Parsing User Input Safely
def parse_user_input(input_str, default_list):
items = [i.strip() for i in input_str.split(",") if i.strip()]
return items if items else default_list
✔️ Uses defaults if the user leaves fields empty.
8️⃣ Generating a Single Paragraph
def generate_ai_paragraph(title, prompt, characters, settings, plots):
char = random.choice(characters)
setting = random.choice(settings)
plot = random.choice(plots)
return f"{title} begins with {char} {setting}. One day, {char} {plot} related to {prompt}."
🧱 Each paragraph is generated independently.
9️⃣ Building the Full Story
def generate_ai_story(title, prompt, characters_input, settings_input, plot_input, paragraphs=4):
characters = parse_user_input(characters_input, DEFAULT_CHARACTERS)
settings = parse_user_input(settings_input, DEFAULT_SETTINGS)
plots = parse_user_input(plot_input, DEFAULT_PLOTS)
story = []
for _ in range(paragraphs):
story.append(generate_ai_paragraph(title, prompt, characters, settings, plots))
return "\n\n".join(story)
📖 Combines paragraphs into a readable story.
🔟 Preventing UI Freezing (Threading)
def create_story():
threading.Thread(target=_generate_story_thread, daemon=True).start()
💡 Long tasks must run outside the UI thread.
1️⃣1️⃣ Story History Vault
def add_to_history(title, story):
story_history.append((title, story))
history_list.insert(tk.END, title)
🗄 Stores and previews generated stories.
1️⃣2️⃣ Typing Animation Viewer text_widget.after(5, type_char)
⌨️ Simulates a live typing effect—great UX for stories.
1️⃣3️⃣ Export Stories to TXT
with open(file_path, "w", encoding="utf-8") as f:
f.write(story)
📤 Lets users save their work locally.
1️⃣4️⃣ Building the UI Layout
ttk.Label(main, text="Story Title").grid(...)
ttk.Entry(main, textvariable=story_title_var)
📐 Tkinter uses a grid system—rows and columns.
1️⃣5️⃣ Run the App
root.mainloop()
🚀 Starts the event loop and launches the app.
🎉 Final Thoughts
You’ve just built:
A full desktop GUI app
A pseudo‑AI content generator
A reusable Tkinter project template
💡 Next Up?
Replace rules with a real LLM API
Save stories as JSON
Add word count & reading time
Package with PyInstaller