Back to Blog
Guide

Migrating from Tkinter to Bravura: Step-by-Step Guide

You've built a functional Python desktop application with Tkinter. It works. But every time you look at it, you know it could look and feel so much better. Your users know it too. The good news: you don't have to start over. This guide walks you through migrating an existing Tkinter application to Bravura, one component at a time, without rewriting your entire codebase.

Why Migrate?

Tkinter ships with Python. It's stable, well-documented, and gets the job done. So why consider migrating at all?

The honest answer: Tkinter was designed in the 1990s. While it still works, user expectations have changed dramatically. Your users interact with polished, animated, dark-mode-friendly interfaces every day. Tkinter's default widgets don't meet that bar, and the effort required to force them there is often greater than the effort of migrating.

Here's what a migration to Bravura gives you without any extra work:

Key Principle

Migration doesn't have to be all-or-nothing. Bravura is built on top of Tkinter, so you can migrate incrementally — one widget, one window, or one feature at a time. Your existing code continues to work while you upgrade around it.

Before You Start: Assess Your Application

Not every Tkinter application needs the same migration path. Before writing any code, answer these questions:

  1. How many windows does your application have? A single-window app can be migrated in an afternoon. A complex multi-window app with dialogs, wizards, and preferences may take several sessions.
  2. Do you use ttk widgets or plain tk? If you're already using ttk.Button, ttk.Entry, etc., migration is smoother because Bravura follows similar patterns.
  3. Do you have threading? If you've built your own threading system, you can eventually replace it with Bravura's built-in workers, but there's no rush.
  4. How much custom drawing do you do? Canvas-heavy applications (charts, diagrams) require more careful migration than form-based apps.

Step 1: Install Bravura

Bravura installs like any Python package. Assuming you have a valid license key:

Terminal pip install bravura

After installation, verify it's working:

Python import bravura print(bravura.__version__) # Expected: 2.x.x

If the import succeeds, you're ready to start migrating.

Step 2: Replace the Root Window

The simplest and highest-impact first step is replacing your Tkinter root window with a Bravura themed window. This single change affects every widget in your application.

Before (Tkinter) import tkinter as tk root = tk.Tk() root.title("My Application") root.geometry("800x600") # ... your widgets here ... root.mainloop()
After (Bravura) from bravura import BravuraApp app = BravuraApp( title="My Application", size=(800, 600), theme="ocean" # Or: cyberpunk, forest, midnight, etc. ) # ... your widgets here (they still work!) ... app.run()

That's it for step one. Your existing Tkinter widgets will inherit the Bravura theme's color scheme automatically. They won't have full Bravura styling yet, but they'll look noticeably better than they did with Tkinter's defaults.

Common Pitfall

If you've hardcoded colors in your widgets (e.g., bg="#ffffff"), those hardcoded values will override Bravura's theme. Remove explicit color arguments to let the theme take over. You can always customize later.

Step 3: Migrate Widgets Incrementally

Now comes the real work, but it's straightforward. Replace Tkinter widgets with Bravura equivalents one at a time. The API is intentionally similar, so most replacements are near-mechanical.

Tkinter Widget Bravura Widget Key Improvement
tk.Button bravura.Button Hover animations, rounded corners, gradient support
tk.Entry bravura.Entry Placeholder text, focus glow, validation states
tk.Label bravura.Label Theme-aware colors, weight variants
tk.Frame bravura.Card Rounded corners, shadow, border effects
tk.Listbox bravura.List Smooth scrolling, selection animations
tk.Progressbar bravura.ProgressBar 60 FPS animation, ETA, gradient fills
tk.Scrollbar bravura.ScrollView Auto-hiding, smooth momentum scrolling

Example: Migrating a Login Form

Before (Tkinter) username_label = tk.Label(frame, text="Username:") username_label.pack() username_entry = tk.Entry(frame, width=30) username_entry.pack() password_label = tk.Label(frame, text="Password:") password_label.pack() password_entry = tk.Entry(frame, show="*", width=30) password_entry.pack() login_btn = tk.Button(frame, text="Log In", command=login) login_btn.pack(pady=10)
After (Bravura) card = bravura.Card(frame, padding=24) card.pack(padx=20, pady=20) username_entry = bravura.Entry( card, placeholder="Username", width=300 ) username_entry.pack(pady=(0, 12)) password_entry = bravura.Entry( card, placeholder="Password", password=True, width=300 ) password_entry.pack(pady=(0, 16)) login_btn = bravura.Button( card, text="Log In", command=login, style="primary" ) login_btn.pack()

Notice the improvements: labels are replaced by placeholders (cleaner layout), the frame becomes a Card (visual elevation), and the button gets a predefined "primary" style. The total line count is similar, but the result looks dramatically different.

Step 4: Replace Threading with Bravura Workers

If your application does background work (file processing, API calls, database queries), you've probably written custom threading code with threading.Thread and queue.Queue. This works, but it's error-prone and repetitive.

Bravura's worker system handles the boilerplate:

Before (Manual Threading) import threading from queue import Queue def process_files(files): q = Queue() def worker(): for i, f in enumerate(files): process(f) q.put(("progress", (i+1)/len(files)*100)) q.put(("done", None)) t = threading.Thread(target=worker, daemon=True) t.start() def check_queue(): while not q.empty(): msg_type, value = q.get() if msg_type == "progress": progress_bar["value"] = value elif msg_type == "done": status_label.config(text="Complete!") return root.after(100, check_queue) check_queue()
After (Bravura Worker) from bravura import BackgroundWorker worker = BackgroundWorker( task=process, items=files, on_progress=lambda p: progress_bar.set(p), on_complete=lambda: status_label.set("Complete!"), on_error=lambda e: show_error(e) ) worker.start()

Bravura's workers handle thread lifecycle, progress callbacks, error handling, and cancellation. The result is less code, fewer bugs, and a better user experience.

Step 5: Add Themes and Polish

Once your widgets are migrated, spend time on the details that separate professional software from hobby projects:

Theme Switching # Let users switch themes at runtime theme_selector = bravura.ThemeSelector( app, themes=["ocean", "cyberpunk", "forest", "midnight"], on_change=lambda theme: app.set_theme(theme) ) theme_selector.pack()

Migration Checklist

Use this checklist to track your progress. A typical application can be fully migrated in 1–3 days:

  1. Replace root windowtk.Tk() to BravuraApp() (30 minutes)
  2. Remove hardcoded colors — Delete explicit bg=, fg= arguments (1 hour)
  3. Migrate buttons and entries — Highest visual impact (1–2 hours)
  4. Migrate frames to cards — Add visual elevation (30 minutes)
  5. Replace progress bars — Add animation and ETA (30 minutes)
  6. Migrate threading — Replace manual threads with workers (1–2 hours)
  7. Add theme support — Enable dark/light mode switching (30 minutes)
  8. Polish and test — Cross-platform testing, edge cases (2–4 hours)

Total estimated time: 6–12 hours for a typical single-window application.

The Incremental Advantage

You don't have to do this all at once. Because Bravura is built on Tkinter, your old widgets and new widgets coexist peacefully. Migrate your most visible screens first, ship the update, and continue migrating at your own pace. Your users see improvements immediately while you maintain stability.

Common Questions

Will my existing Tkinter code break?

No. Bravura extends Tkinter rather than replacing it. Your existing tk and ttk widgets continue to work inside a Bravura application. You can mix and match freely during migration.

What about third-party Tkinter libraries?

Libraries like tkinterdnd2, tkcalendar, and tksheet all work with Bravura since they're built on Tkinter too. They'll inherit basic theme colors from Bravura, though they won't get Bravura-specific styling.

How does licensing work?

Bravura uses a one-time purchase model. Standard ($49.99/mo or $1,999.99 one-time) covers individual developers. Professional and Enterprise tiers are available for teams. No recurring royalties on applications you build.

What if I need help?

Every Bravura license includes access to documentation, code examples, and email support. Professional and Enterprise tiers include priority support with faster response times.

The Bottom Line

Migrating from Tkinter to Bravura isn't a rewrite. It's an upgrade. Your application logic stays the same. Your architecture stays the same. You're replacing the visual layer with something modern, while gaining professional infrastructure (threading, progress, GPU acceleration) that would take hundreds of hours to build yourself.

Start with the root window. Replace a few widgets. See the difference. Then decide how far you want to take it.

Ready to Upgrade Your Application?

See what Bravura can do for your Python desktop app. Browse themes, explore components, and start building something your users will love.

Explore Bravura SDK
WS

Wigley Studios

Founder of Wigley Studios. Building developer tools that make Python desktop development faster and more enjoyable.

Previous: Tkinter vs Bravura Next: Custom vs Pre-Made Kits