Bravura SDK - Common Mistakes and How to Avoid Them

Back to Documentation Hub

Bravura SDK - Common Mistakes and How to Avoid Them

This guide covers the most common mistakes developers make when using the Bravura SDK and shows the correct patterns.

---

Table of Contents

  1. Theme Management Mistakes
  2. Button Sizing Issues
  3. Import Errors
  4. Widget Styling Problems
  5. Background Integration
  6. Performance Issues

---

Theme Management Mistakes

❌ Mistake #1: Manual `ttk.Style` Configuration

WRONG:


# This is the most common mistake!
style = ttk.Style()
style.configure("TFrame", background="#0F141B")
style.configure("TLabel", foreground="#E8EEF4")
style.configure("TEntry", fieldbackground="#131A22")
# ... 50 more lines of manual styling ...

Why it's wrong:

CORRECT:


from bravura.themes.theme_manager import ProfessionalThemeManager

# Initialize theme manager
self.theme_manager = ProfessionalThemeManager(self)

# Apply theme - ONE LINE!
self.theme_manager.apply_theme("wigley_site")

# That's it! All widgets are now professionally styled.

What this does:

---

❌ Mistake #2: Applying Theme After Widget Creation

WRONG:


def __init__(self):
    self.root = tk.Tk()
    self.create_ui()  # Widgets created FIRST

    # Theme applied AFTER widgets exist
    self.theme_manager = ProfessionalThemeManager(self)
    self.theme_manager.apply_theme("wigley_site")  # Too late!

Why it's wrong:

CORRECT:


def __init__(self):
    self.root = tk.Tk()

    # Apply theme BEFORE creating widgets
    self.theme_manager = ProfessionalThemeManager(self)
    self.theme_manager.apply_theme("wigley_site")

    # NOW create widgets - they'll get the theme automatically
    self.create_ui()

---

❌ Mistake #3: Hardcoding Colors

WRONG:


# Hardcoded colors break when themes change
frame = ttk.Frame(self.root)
frame.configure(background="#0F141B")  # Hardcoded!

label = ttk.Label(frame, text="Hello")
label.configure(foreground="#E8EEF4")  # Hardcoded!

CORRECT:


# Let ThemeManager handle colors
frame = ttk.Frame(self.root)
# No manual color configuration needed!

label = ttk.Label(frame, text="Hello")
# ThemeManager sets the correct colors automatically

If you MUST set colors, use theme tokens:


from bravura.themes.theme_tokens import WIGLEY_SITE_TOKENS

# Use theme tokens instead of hardcoded values
bg_color = WIGLEY_SITE_TOKENS["surface_1"]
text_color = WIGLEY_SITE_TOKENS["text_primary"]

---

Button Sizing Issues

❌ Mistake #4: No Width Specified

WRONG:


# Button sizes based on text only - inconsistent widths
save_btn = PremiumButton(parent, text="Save", command=self.save)
connect_btn = PremiumButton(parent, text="Connect to Database", command=self.connect)
# Result: Buttons have wildly different widths

CORRECT:


# Specify consistent widths for professional appearance
save_btn = PremiumButton(
    parent,
    text="Save",
    command=self.save,
    width=18  # Consistent width
)

connect_btn = PremiumButton(
    parent,
    text="Connect to Database",
    command=self.connect,
    width=18  # Same width - looks professional
)

Recommended widths:

---

❌ Mistake #5: Wrong Button Type for Context

WRONG:


# Using PremiumButton for everything
toolbar_btn = PremiumButton(toolbar, text="Refresh", ...)  # Too big!
menu_btn = PremiumButton(menu, text="Settings", ...)  # Too big!

CORRECT:


from bravura.components import PremiumButton, CompactPremiumButton

# Use PremiumButton for PRIMARY actions
save_btn = PremiumButton(header, text="Save Document", width=18)

# Use CompactPremiumButton for TOOLBARS and UTILITIES
toolbar_btn = CompactPremiumButton(toolbar, text="Refresh", width=12)
menu_btn = CompactPremiumButton(menu, text="Settings", width=12)

Or use ButtonFactory for automatic selection:


from bravura.components import ButtonFactory

# Automatically selects the right button type
hero_btn = ButtonFactory.create(header, text="Save", context="hero")  # → PremiumButton
toolbar_btn = ButtonFactory.create(toolbar, text="Refresh", context="toolbar")  # → CompactPremiumButton

---

Import Errors

❌ Mistake #6: Incorrect Import Paths

WRONG:


# Wrong import paths
from bravura import PremiumButton  # ❌ Wrong!
from bravura import ThemeManager  # ❌ Wrong!
from bravura.themes import ProfessionalThemeManager  # ❌ Wrong!

CORRECT:


# Correct import paths
from bravura.components import PremiumButton
from bravura.components import CompactPremiumButton
from bravura.components import AmbientBackground
from bravura.themes.theme_manager import ProfessionalThemeManager

Convenience import (everything in one place):


# Import multiple components at once
from bravura.components import (
    PremiumButton,
    CompactPremiumButton,
    AmbientBackground,
    ButtonFactory,
    ToolTip
)

---

❌ Mistake #7: Forgetting to Add SDK to Path

WRONG:


# Trying to import without SDK in path
from bravura.components import PremiumButton  # ModuleNotFoundError!

CORRECT (Installed via pip):


# If installed via pip, imports work automatically
from bravura.components import PremiumButton

CORRECT (Development/Source):


import sys
from pathlib import Path

# Add Bravura to path
bravura_path = Path(__file__).parent / "Bravura" / "src"
if bravura_path.exists():
    sys.path.insert(0, str(bravura_path))

# Now imports work
from bravura.components import PremiumButton

---

Widget Styling Problems

❌ Mistake #8: Mixing `tk` and `ttk` Widgets

WRONG:


# Mixing tk and ttk widgets - inconsistent styling
frame = tk.Frame(self.root)  # tk widget - won't get theme!
label = ttk.Label(frame, text="Hello")  # ttk widget - gets theme

Problem: tk.Frame doesn't support ttk.Style, so it won't match the theme.

CORRECT:


# Use ttk widgets exclusively for consistent theming
frame = ttk.Frame(self.root)  # ttk widget - gets theme!
label = ttk.Label(frame, text="Hello")  # ttk widget - gets theme!

Exception: Use tk widgets only when you need features not available in ttk:


# tk.Text is fine - ttk doesn't have a Text widget
text_widget = tk.Text(parent, bg="#131A22", fg="#E8EEF4")

---

❌ Mistake #9: Not Configuring `tk.Text` Manually

WRONG:


# tk.Text doesn't get automatic theming
text_widget = tk.Text(parent)  # White background, black text - doesn't match theme!

CORRECT:


# Manually configure tk.Text to match theme
text_widget = tk.Text(
    parent,
    bg="#131A22",  # Dark background
    fg="#E8EEF4",  # Light text
    insertbackground="#E8EEF4",  # Light cursor
    selectbackground="#20C6B7",  # Teal selection
    selectforeground="#FFFFFF",  # White selected text
    font=("Consolas", 10)
)

Or use theme tokens:


from bravura.themes.theme_tokens import WIGLEY_SITE_TOKENS

text_widget = tk.Text(
    parent,
    bg=WIGLEY_SITE_TOKENS["surface_2"],
    fg=WIGLEY_SITE_TOKENS["text_primary"],
    insertbackground=WIGLEY_SITE_TOKENS["text_primary"],
    selectbackground=WIGLEY_SITE_TOKENS["teal"],
    selectforeground="#FFFFFF"
)

---

Background Integration

❌ Mistake #10: Creating Background After Widgets

WRONG:


def create_ui(self):
    # Create widgets first
    self.frame = ttk.Frame(self.root)
    self.frame.pack(fill="both", expand=True)

    # Create background AFTER - won't be visible!
    self.ambient_bg = AmbientBackground(self.root, ...)

Why it's wrong:

CORRECT:


def __init__(self):
    self.root = tk.Tk()

    # Apply theme
    self.theme_manager = ProfessionalThemeManager(self)
    self.theme_manager.apply_theme("wigley_site")

    # Create background FIRST (before widgets)
    self.ambient_bg = AmbientBackground(
        self.root,
        enable_animation=True,
        glow_effects=True
    )

    # Set root background to match
    self.root.configure(bg="#0B1115")

    # NOW create widgets - they'll appear on top of background
    self.create_ui()

---

❌ Mistake #11: Opaque Frames Blocking Background

WRONG:


# Opaque frames completely block ambient background
frame = ttk.Frame(self.root, style="TFrame")  # Completely opaque!

Problem: ttk frames are opaque by default, hiding the ambient background.

SOLUTION:

The theme already handles frame transparency! Just use standard ttk.Frame:


# Theme manager configures frames with proper backgrounds
frame = ttk.Frame(self.root)
# Background shows through at window edges and between widgets

If you need more transparency, use a tk.Canvas:


# For truly transparent areas
canvas = tk.Canvas(
    self.root,
    bg="#0B1115",
    highlightthickness=0
)
canvas.pack(fill="both", expand=True)

---

Performance Issues

❌ Mistake #12: Ambient Background Without Theme Colors

WRONG:


# Missing theme_tokens = particles won't adapt to themes
ambient_bg = AmbientBackground(
    self.root,
    enable_animation=True,
    particle_count=20
    # Missing theme_tokens parameter!
)

Problem: Without theme_tokens, particles use hardcoded colors that don't match your theme.

CORRECT:


# Pass theme colors for theme-aware particles
ambient_bg = AmbientBackground(
    self.root,
    width=800,
    height=600,
    theme_tokens=self.theme_manager.get_current_theme_colors(),  # Essential!
    enable_animation=True,
    particle_count=20,
    glow_effects=True
)

When theme changes, update theme tokens instantly:


def change_theme(self, new_theme):
    # Apply new theme
    self.theme_manager.apply_theme(new_theme)

    # Update ambient background colors instantly (NEW in v1.0.0)
    if hasattr(self, 'ambient_bg') and self.ambient_bg:
        self.ambient_bg.set_theme_tokens(
            self.theme_manager.get_current_theme_colors()  # New colors!
        )
    # 10x faster than recreation, no visual flicker!

---

❌ Mistake #13: Too Many Animated Particles

WRONG:


# Too many particles = unnecessary
ambient_bg = AmbientBackground(
    self.root,
    theme_tokens=theme_colors,
    enable_animation=True,
    particle_count=100,  # Excessive (60 is max)
    animation_speed="fast"
)

CORRECT:


# Optimal particle count with buttery-smooth 60 FPS performance
ambient_bg = AmbientBackground(
    self.root,
    theme_tokens=self.theme_manager.get_current_theme_colors(),
    enable_animation=True,
    particle_count=30,  # Sweet spot for visual richness
    animation_speed="medium",  # Fixed 60 FPS animation
    glow_effects=True
)
# Runs at smooth 60 FPS with <2% CPU usage even at 30-40 particles!

Recommended particle counts (all run smoothly at 60 FPS):

Performance Note: Thanks to optimized 60 FPS rendering with harmonic easing, even 40 particles maintain buttery-smooth animation with minimal CPU impact. The animation speed parameter only affects drift velocity, not smoothness - it's always 60 FPS!

---

❌ Mistake #14: Not Disabling Animations for Accessibility

WRONG:


# Always animating - can cause motion sickness
ambient_bg = AmbientBackground(
    self.root,
    enable_animation=True  # Always on
)

CORRECT:


# Respect user preferences for reduced motion
import platform

# Check system preferences (simplified)
reduced_motion = False  # Get from system settings

ambient_bg = AmbientBackground(
    self.root,
    enable_animation=not reduced_motion,  # Disable if user prefers
    animation_speed="slow" if not reduced_motion else None,
    glow_effects=True
)

---

❌ Mistake #15: Starting GlowingProgressBar Animation Too Early

WRONG:


from bravura.components import GlowingProgressBar, GlowingProgressManager

manager = GlowingProgressManager(root)
bar = GlowingProgressBar(
    parent=container,
    manager=manager,
    bar_type="rainbow",
    width=500
)
bar.pack()

# This silently fails! Canvas not initialized yet
bar.start_glow_animation()  # ❌ Too early!
bar.set_progress(50)

Why it's wrong:

CORRECT:


from bravura.components import GlowingProgressBar, GlowingProgressManager

manager = GlowingProgressManager(root)
bar = GlowingProgressBar(
    parent=container,
    manager=manager,
    bar_type="rainbow",
    width=500
)
bar.pack()

# Wait for canvas initialization before starting animation
def start_animation():
    bar.start_glow_animation()
    bar.set_progress(50)

root.after(100, start_animation)  # ✅ Delay allows canvas to initialize

Alternative Pattern (for immediate display):


# Create bar and pack it
bar = GlowingProgressBar(parent, manager, bar_type="rainbow", width=500)
bar.pack()

# Set initial state immediately (will show once canvas initializes)
bar.set_progress(50)
bar.set_label_text("Processing...")

# Start animation with delay
root.after(100, bar.start_glow_animation)  # ✅ Clean one-liner

When to use this pattern:

When you DON'T need the delay:

Technical Details:

The GlowingProgressBar creates canvas elements asynchronously:


# In glowing_progress_bar.py source
def _create_widgets(self):
    # ...canvas creation...
    # Initialize canvas elements AFTER a delay
    self.parent.after(1, self._initialize_canvas_elements)

This design allows the widget to be fully rendered before drawing, but requires animations to wait for initialization.

---

Quick Reference: Do's and Don'ts

DO ✅

Do Why
Use `ProfessionalThemeManager` Handles ALL theming automatically
Apply theme BEFORE creating widgets Ensures consistent styling
Specify button widths Professional, consistent appearance
Use `CompactPremiumButton` for toolbars Space-efficient, appropriate sizing
Create `AmbientBackground` FIRST Must render behind widgets
Use `ttk` widgets Get automatic theming
Use theme tokens for colors Maintains consistency when themes change

DON'T ❌

Don't Why
Manually configure `ttk.Style` ThemeManager handles this
Hardcode colors Breaks theme switching
Mix `tk` and `ttk` randomly Inconsistent styling
Use `PremiumButton` everywhere Wrong button for toolbars
Create background after widgets Won't be visible
Use 100+ particles Performance issues
Ignore accessibility Motion sickness, contrast issues

---

Summary Checklist

Before releasing your Bravura application, verify:

---

Getting Help

If you're still having issues:

  1. Check the Quick Start Guide: QUICK_START.md
  2. Review the POC: Local Server Management Tools/hostinger_database_manager_bravura_poc.py
  3. Run the Component Catalog: See all components in action
  4. Contact Support: support@wigleystudios.com

---

Remember: The Bravura SDK is designed to make your life EASIER. If you find yourself writing lots of manual styling code, you're probably doing it wrong! Let ThemeManager and the premium components do the work for you.

Happy coding! 🚀