🎯 Bravura - Integration Guide

Back to Documentation Hub

🎯 Bravura - Integration Guide

Easy Integration for Real Applications

This guide shows how to integrate the Bravura features into your real applications with minimal effort.

📦 Required Dependencies

For full functionality, install these optional libraries:


# For enhanced NVIDIA GPU detection
pip install GPUtil

# For Windows WMI support (enhanced GPU detection)
pip install pywin32

# For system information
pip install psutil

Note: The toolkit works without these libraries but provides enhanced functionality when they're installed.

---

⏱️ Timer & ETA System Integration

Quick Integration


from bravura import get_audio_analyzer_framework

# Get framework class and create instance
AppClass = get_audio_analyzer_framework()
app = AppClass()

class YourApplication(AnalysisGUIFramework):
    def your_real_processing_function(self):
        # Start timer when beginning work
        self._start_timer()

        total_items = 100
        for i, item in enumerate(your_data):
            # Your real processing here
            result = process_item(item)

            # Update progress with ETA calculation
            progress = (i + 1) / total_items * 100
            self._update_progress_with_eta(progress, f"Processing {item.name}...")

        # Timer automatically shows completion time

Advanced Integration


def your_batch_processing(self, files):
    """Example: Process multiple files with timer and ETA."""
    self._start_timer()

    total_files = len(files)
    for i, file_path in enumerate(files):
        # Real file processing
        try:
            result = your_file_processor(file_path)

            # Update with meaningful progress
            progress = ((i + 1) / total_files) * 100
            filename = os.path.basename(file_path)
            self._update_progress_with_eta(progress, f"Processed {filename}")

        except Exception as e:
            self._log_message(f"❌ Error processing {file_path}: {e}")

    # Timer automatically resets after completion display

---

🖥️ GPU Detection & Diagnostics Integration

Automatic GPU Detection

The toolkit automatically detects GPUs when initialized. No code changes needed!

Using GPU Information in Your Code


class YourApplication(AnalysisGUIFramework):
    def check_gpu_capability(self):
        """Check if GPU acceleration is available for your app."""
        if self.use_gpu_var.get() and self.detected_gpus:
            primary_gpu = self.primary_gpu

            # Check GPU memory for your requirements
            if 'memory_total' in primary_gpu:
                gpu_memory_mb = primary_gpu['memory_total']
                if gpu_memory_mb >= 4000:  # 4GB minimum
                    return True
                else:
                    self._log_message(f"⚠️ GPU has {gpu_memory_mb}MB, need 4GB minimum")

            return True  # GPU available
        return False  # Use CPU processing

    def your_gpu_accelerated_function(self):
        """Example GPU-accelerated processing."""
        if self.check_gpu_capability():
            # Use GPU processing
            self._log_message(f"🔥 Using GPU: {self.primary_gpu['name']}")
            return self.gpu_process_data()
        else:
            # Fallback to CPU
            self._log_message("⚡ Using CPU processing")
            return self.cpu_process_data()

GPU Diagnostics for Debugging


def debug_gpu_issues(self):
    """Get detailed GPU info for troubleshooting."""
    # This runs the same diagnostics as the button
    diagnostics = self._get_comprehensive_gpu_diagnostics()

    # Access specific information
    if diagnostics['detected_gpus']:
        for gpu in diagnostics['detected_gpus']:
            print(f"GPU: {gpu['name']}")
            print(f"Memory: {gpu.get('memory_total', 'Unknown')} MB")
            print(f"Driver: {gpu.get('driver', 'Unknown')}")

    return diagnostics

---

🎨 Real Application Examples

Example 1: Audio Processing Application


class AudioProcessor(AnalysisGUIFramework):
    def process_audio_files(self, file_paths):
        self._start_timer()

        for i, file_path in enumerate(file_paths):
            # Real audio processing
            audio_data = load_audio(file_path)

            if self.check_gpu_capability():
                # GPU-accelerated spectral analysis
                features = gpu_extract_features(audio_data)
            else:
                # CPU fallback
                features = cpu_extract_features(audio_data)

            # Update progress
            progress = ((i + 1) / len(file_paths)) * 100
            filename = os.path.basename(file_path)
            self._update_progress_with_eta(progress, f"Analyzing {filename}")

Example 2: Image Processing Application


class ImageProcessor(AnalysisGUIFramework):
    def batch_image_processing(self, images):
        self._start_timer()

        # Check GPU memory requirements
        if self.use_gpu_var.get() and self.primary_gpu:
            gpu_memory = self.primary_gpu.get('memory_total', 0)
            if gpu_memory < 2000:  # Need 2GB for image processing
                self._log_message("⚠️ Insufficient GPU memory, using CPU")
                self.use_gpu_var.set(False)

        for i, image_path in enumerate(images):
            # Real image processing
            if self.use_gpu_var.get():
                result = gpu_process_image(image_path)
            else:
                result = cpu_process_image(image_path)

            # Update with ETA
            progress = ((i + 1) / len(images)) * 100
            self._update_progress_with_eta(progress, f"Processing image {i+1}")

---

🔧 Customization Tips

Custom GPU Requirements


def check_custom_gpu_requirements(self):
    """Check if GPU meets your specific requirements."""
    if not self.detected_gpus:
        return False

    gpu = self.primary_gpu

    # Check NVIDIA GPU for CUDA
    if gpu.get('type') == 'NVIDIA':
        # Check for specific compute capability, memory, etc.
        memory_gb = gpu.get('memory_total', 0) / 1024
        if memory_gb >= 8:  # Need 8GB for your application
            return True

    return False

Custom Progress Messages


def update_custom_progress(self, current, total, operation):
    """Custom progress updates with your terminology."""
    progress = (current / total) * 100
    message = f"{operation}: {current}/{total} items"
    self._update_progress_with_eta(progress, message)

---

🚀 Best Practices

1. Always Provide Fallbacks


# Good: Always have CPU fallback
if self.use_gpu_var.get() and self.check_gpu_capability():
    result = gpu_process()
else:
    result = cpu_process()

# Bad: Assuming GPU is always available
result = gpu_process()  # Will fail if no GPU

2. Use Meaningful Progress Updates


# Good: Descriptive messages
self._update_progress_with_eta(45, "Extracting features from audio segment 3/7")

# Bad: Generic messages
self._update_progress_with_eta(45, "Processing...")

3. Handle GPU Memory Limits


def check_memory_requirements(self, data_size_mb):
    """Check if GPU has enough memory for processing."""
    if self.primary_gpu and 'memory_free' in self.primary_gpu:
        free_memory = self.primary_gpu['memory_free']
        return free_memory > (data_size_mb * 1.2)  # 20% safety margin
    return False

---

📚 Additional Resources

---

🆘 Common Issues & Solutions

GPU Not Detected

  1. Install libraries: pip install GPUtil pywin32
  2. Update drivers: Ensure GPU drivers are current
  3. Check permissions: Run as administrator if needed
  4. Verify hardware: GPU might not support acceleration

Timer/ETA Issues

  1. Call _start_timer() before starting work
  2. Use _update_progress_with_eta() instead of manual updates
  3. Don't call _reset_timer() manually (auto-resets)

Performance Issues

  1. Limit progress updates: Don't update every iteration
  2. Use background processing: Consider threading for long operations
  3. Batch operations: Process multiple items between updates

---

🎯 Button Component Integration

Quick Start

Step 1: Apply Bravura Theme


from bravura.themes import apply_theme

# Apply theme to style all widgets
apply_theme(root, "wigley_site")

Step 2: Enhance Hero Actions


from bravura.components import PremiumButton

# Primary save action
save_btn = PremiumButton(
    header_frame,
    text="💾 Save Project",
    command=self.save_project,
    style="primary",
    loading=False  # Set to True during save operation
)
save_btn.pack(side=tk.RIGHT, padx=10)

Step 3: Use Compact Buttons for Dense UIs


from bravura.components import CompactPremiumButton

# Toolbar button
refresh_btn = CompactPremiumButton(
    toolbar,
    text="Refresh",
    width=12,  # Character-based width
    style="primary"
)

Step 4: Or Use Factory for Automatic Selection


from bravura.components import ButtonFactory

# Automatically picks right component
hero_btn = ButtonFactory.create(
    parent,
    text="Save",
    context="hero"  # Creates PremiumButton
)

toolbar_btn = ButtonFactory.create(
    parent,
    text="Bold",
    context="toolbar",  # Creates CompactPremiumButton
    width=8
)

Integration Strategies

Strategy 1: Selective Enhancement (Recommended)

When: Enhancing existing application with Bravura buttons

Steps:

  1. Apply Bravura theme globally
  2. Identify 1-3 hero actions per page
  3. Replace hero actions with PremiumButton
  4. Keep other buttons as themed ttk.Button

Example:


class ExistingApp:
    def integrate_bravura(self):
        # Step 1: Apply theme
        apply_theme(self.root, "wigley_site")

        # Step 2: Enhance hero action
        # Before: ttk.Button(self.header, text="Save")
        # After:
        self.save_btn = PremiumButton(
            self.header,
            text="💾 Save Project",
            command=self.save,
            style="primary"
        )

        # Step 3: Keep toolbar buttons as ttk.Button
        # They're automatically styled by the theme
        for action in ["Bold", "Italic", "Underline"]:
            btn = ttk.Button(
                self.toolbar,
                text=action,
                width=8
            )
            btn.pack(side=tk.LEFT, padx=2)

Result: Clear visual hierarchy with minimal code changes

Strategy 2: Comprehensive Enhancement

When: Building new application or major UI overhaul

Steps:

  1. Use ButtonFactory for all buttons
  2. Specify appropriate context for each button
  3. Let factory select optimal component

Example:


class NewApp:
    def create_ui(self):
        # Hero action
        self.save_btn = ButtonFactory.create_hero(
            self.header,
            text="💾 Save Project",
            command=self.save
        )

        # Toolbar actions
        for action in ["Bold", "Italic", "Underline"]:
            btn = ButtonFactory.create_toolbar(
                self.toolbar,
                text=action,
                command=lambda a=action: self.format(a),
                width=8
            )
            btn.pack(side=tk.LEFT, padx=2)

        # Form buttons
        ok_btn = ButtonFactory.create_form(
            self.form,
            text="OK",
            command=self.on_ok,
            width=10,
            style="success"
        )

        cancel_btn = ButtonFactory.create_form(
            self.form,
            text="Cancel",
            command=self.on_cancel,
            width=10,
            style="secondary"
        )

Result: Consistent, professional appearance throughout application

Component Selection Guide

Use PremiumButton when:

Use CompactPremiumButton when:

Use themed ttk.Button when:

Use ButtonFactory when:

Common Patterns

Pattern 1: Application with Toolbar


class ToolbarApp:
    def create_ui(self):
        # Header with hero action
        self.header = tk.Frame(self.root)
        self.save_btn = ButtonFactory.create_hero(
            self.header,
            text="💾 Save",
            command=self.save
        )

        # Toolbar with compact actions
        self.toolbar = tk.Frame(self.root)
        actions = ["Bold", "Italic", "Underline", "Color", "Size"]
        for action in actions:
            ButtonFactory.create_toolbar(
                self.toolbar,
                text=action,
                width=8
            ).pack(side=tk.LEFT, padx=2)

Pattern 2: Form Dialog


class FormDialog:
    def create_buttons(self):
        button_frame = tk.Frame(self.dialog)

        # Use CompactPremiumButton for uniform sizing
        ok_btn = CompactPremiumButton(
            button_frame,
            text="OK",
            command=self.on_ok,
            width=10,
            style="success"
        )
        ok_btn.pack(side=tk.LEFT, padx=5)

        cancel_btn = CompactPremiumButton(
            button_frame,
            text="Cancel",
            command=self.on_cancel,
            width=10,
            style="secondary"
        )
        cancel_btn.pack(side=tk.LEFT, padx=5)

Pattern 3: Data Management Interface


class DataManager:
    def create_ui(self):
        # Primary action
        process_btn = PremiumButton(
            self.main_frame,
            text="🚀 Process Data",
            command=self.process_data,
            style="primary"
        )

        # Table actions
        actions_frame = tk.Frame(self.root)
        for action in ["Add", "Edit", "Delete", "Export"]:
            CompactPremiumButton(
                actions_frame,
                text=action,
                width=8
            ).pack(side=tk.LEFT, padx=2)

    def process_data(self):
        # Show loading during operation
        self.process_btn.set_loading(True)
        # ... process data ...
        self.process_btn.set_loading(False)

Loading State Integration

PremiumButton supports loading states for long-running operations:


def save_project(self):
    # Show loading
    self.save_btn.set_loading(True)

    try:
        # Perform save operation
        result = self.perform_save()

        if result.success:
            self.log_success("✅ Project saved successfully")
        else:
            self.log_error(f"❌ Save failed: {result.error}")

    finally:
        # Hide loading
        self.save_btn.set_loading(False)

Migration Checklist

When integrating Bravura buttons into existing application:

Anti-Patterns to Avoid

❌ DON'T: Replace every button with PremiumButton


# This creates visual chaos
for button_text in all_buttons:
    PremiumButton(parent, text=button_text)  # Too many hero buttons!

✅ DO: Use appropriate component for each context


# Clear hierarchy
hero = PremiumButton(header, text="Save")  # 1-3 per page
toolbar = CompactPremiumButton(toolbar, text="Bold", width=8)  # Many per page
form = ttk.Button(form, text="Cancel")  # Themed automatically

❌ DON'T: Fight button sizes with overrides


# Trying to make PremiumButton small
btn = PremiumButton(
    toolbar,
    text="Bold",
    padx=1,
    pady=0,
    font=("Arial", 8)  # Still looks wrong!
)

✅ DO: Use the right component


# Designed for this use case
btn = CompactPremiumButton(
    toolbar,
    text="Bold",
    width=8  # Perfect fit!
)

Further Reading

---

Ready to integrate? Start with copying the examples above into your application!