Theming Examples

This section demonstrates how to apply and customize themes in ThreePaneWindows applications.

Basic Theme Application

Apply built-in themes to your layouts. Important: To see theme effects, you must apply theme colors to your content widgets:

import tkinter as tk
from threepanewindows import EnhancedDockableThreePaneWindow, PaneConfig

def create_themed_example():
    root = tk.Tk()
    root.title("Themed Three-Pane Window")
    root.geometry("1000x600")

    # Store window reference to access theme manager
    window_ref = [None]

    def build_themed_content(frame, title):
        """Build content that properly uses theme colors."""
        # Get current theme
        theme = window_ref[0].theme_manager.get_current_theme() if window_ref[0] else None

        # Apply theme background to frame
        if theme:
            frame.configure(bg=theme.colors.panel_content_bg)

        # Themed title
        title_label = tk.Label(frame, text=title, font=("Arial", 12, "bold"))
        if theme:
            title_label.configure(
                bg=theme.colors.panel_content_bg,
                fg=theme.colors.primary_text
            )
        title_label.pack(pady=10)

        # Themed content area
        content_frame = tk.Frame(frame)
        if theme:
            content_frame.configure(bg=theme.colors.panel_content_bg)
        content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Themed label
        sample_label = tk.Label(content_frame, text="This content uses theme colors!",
                               font=("Arial", 10))
        if theme:
            sample_label.configure(
                bg=theme.colors.panel_content_bg,
                fg=theme.colors.secondary_text
            )
        sample_label.pack(pady=5)

        # Themed buttons
        for i in range(3):
            btn = tk.Button(content_frame, text=f"Themed Button {i+1}",
                          font=("Arial", 10), width=15)
            if theme:
                btn.configure(
                    bg=theme.colors.button_bg,
                    fg=theme.colors.button_fg,
                    activebackground=theme.colors.button_hover,
                    relief="flat"
                )
            btn.pack(pady=2)

        # Themed text area
        text_area = tk.Text(content_frame, height=4, font=("Arial", 10))
        if theme:
            text_area.configure(
                bg=theme.colors.secondary_bg,
                fg=theme.colors.primary_text,
                insertbackground=theme.colors.primary_text,
                selectbackground=theme.colors.accent_bg
            )
        text_area.pack(fill=tk.X, pady=5)
        text_area.insert("1.0", f"Themed text area in {title}")

    def create_window_with_theme(theme_name):
        """Create window with specified theme."""
        # Clear existing window
        for widget in root.winfo_children():
            if isinstance(widget, EnhancedDockableThreePaneWindow):
                widget.destroy()

        # Configure panes
        left_config = PaneConfig(title="Navigation", icon="🧭", default_width=200)
        center_config = PaneConfig(title="Content", icon="📝")
        right_config = PaneConfig(title="Tools", icon="🔧", default_width=180)

        # Create window with theme
        window = EnhancedDockableThreePaneWindow(
            root,
            left_config=left_config,
            center_config=center_config,
            right_config=right_config,
            left_builder=lambda f: build_themed_content(f, "Navigation Panel"),
            center_builder=lambda f: build_themed_content(f, "Main Content"),
            right_builder=lambda f: build_themed_content(f, "Tool Panel"),
            theme_name=theme_name
        )

        window_ref[0] = window  # Store reference
        window.pack(fill=tk.BOTH, expand=True)
        return window

    # Create initial window
    window = create_window_with_theme("light")

    # Theme switcher
    control_frame = tk.Frame(root, bg="#f0f0f0")
    control_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=5)

    tk.Label(control_frame, text="Theme:", font=("Arial", 10, "bold"),
            bg="#f0f0f0").pack(side=tk.LEFT, padx=10)

    for theme_name in ["light", "dark", "blue"]:
        btn = tk.Button(control_frame, text=theme_name.title(),
                       command=lambda t=theme_name: create_window_with_theme(t))
        btn.pack(side=tk.LEFT, padx=5)

    return root

if __name__ == "__main__":
    app = create_themed_example()
    app.mainloop()

Theme Comparison Demo

Compare different built-in themes:

import tkinter as tk
from tkinter import ttk
from threepanewindows import EnhancedDockableThreePaneWindow, PaneConfig

class ThemeComparisonDemo:
    """Demo application showing different themes."""

    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Theme Comparison Demo")
        self.root.geometry("1200x800")

        self.current_theme = "blue"
        self.setup_ui()

    def setup_ui(self):
        """Set up the user interface."""
        # Theme selector toolbar
        toolbar = tk.Frame(self.root, bg="#f0f0f0", height=40)
        toolbar.pack(fill=tk.X)
        toolbar.pack_propagate(False)

        tk.Label(toolbar, text="Theme:", font=("Arial", 10, "bold"),
                bg="#f0f0f0").pack(side=tk.LEFT, padx=10, pady=10)

        # Theme buttons
        themes = [
            ("Blue Professional", "blue", "#3498DB"),
            ("Dark Modern", "dark", "#2C3E50"),
            ("Light Clean", "light", "#ECF0F1"),
            ("Green Nature", "green", "#27AE60"),
            ("Purple Creative", "purple", "#9B59B6")
        ]

        for theme_name, theme_key, color in themes:
            btn = tk.Button(toolbar, text=theme_name, bg=color, fg="white",
                          font=("Arial", 9), relief="flat", padx=15,
                          command=lambda t=theme_key: self.change_theme(t))
            btn.pack(side=tk.LEFT, padx=2, pady=5)

        # Create the main window
        self.create_main_window()

    def create_main_window(self):
        """Create the main three-pane window."""
        # Configure panes
        left_config = PaneConfig(
            title="File Explorer",
            icon="📁",
            default_width=250,
            detachable=True
        )

        center_config = PaneConfig(
            title="Code Editor",
            icon="📝",
            detachable=False
        )

        right_config = PaneConfig(
            title="Properties",
            icon="🔧",
            default_width=200,
            detachable=True
        )

        # Create enhanced window
        self.window = EnhancedDockableThreePaneWindow(
            self.root,
            left_config=left_config,
            center_config=center_config,
            right_config=right_config,
            left_builder=self.build_file_explorer,
            center_builder=self.build_code_editor,
            right_builder=self.build_properties,
            theme_name=self.current_theme
        )
        self.window.pack(fill=tk.BOTH, expand=True)

    def build_file_explorer(self, frame):
        """Build file explorer content."""
        # Header
        header = tk.Frame(frame, height=30)
        header.pack(fill=tk.X, padx=5, pady=5)
        header.pack_propagate(False)

        tk.Label(header, text="📁 Project Files",
                font=("Arial", 11, "bold")).pack(side=tk.LEFT, pady=5)

        # File tree
        tree_frame = tk.Frame(frame)
        tree_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        file_tree = ttk.Treeview(tree_frame)
        scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=file_tree.yview)
        file_tree.configure(yscrollcommand=scrollbar.set)

        file_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # Sample file structure
        project = file_tree.insert("", "end", text="📁 ThemeDemo", open=True)
        src = file_tree.insert(project, "end", text="📁 src", open=True)
        file_tree.insert(src, "end", text="📄 main.py")
        file_tree.insert(src, "end", text="📄 themes.py")
        file_tree.insert(src, "end", text="📄 utils.py")

        styles = file_tree.insert(project, "end", text="📁 styles")
        file_tree.insert(styles, "end", text="🎨 blue.css")
        file_tree.insert(styles, "end", text="🎨 dark.css")
        file_tree.insert(styles, "end", text="🎨 light.css")

    def build_code_editor(self, frame):
        """Build code editor content."""
        # Editor header
        header = tk.Frame(frame, height=35)
        header.pack(fill=tk.X)
        header.pack_propagate(False)

        tk.Label(header, text="📝 themes.py", font=("Arial", 11, "bold")).pack(
            side=tk.LEFT, padx=10, pady=8)

        # Editor area
        editor_frame = tk.Frame(frame)
        editor_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Code editor
        code_editor = tk.Text(editor_frame, wrap=tk.NONE, font=("Consolas", 11))

        # Scrollbars
        v_scroll = tk.Scrollbar(editor_frame, orient=tk.VERTICAL, command=code_editor.yview)
        h_scroll = tk.Scrollbar(editor_frame, orient=tk.HORIZONTAL, command=code_editor.xview)
        code_editor.configure(yscrollcommand=v_scroll.set, xscrollcommand=h_scroll.set)

        code_editor.grid(row=0, column=0, sticky="nsew")
        v_scroll.grid(row=0, column=1, sticky="ns")
        h_scroll.grid(row=1, column=0, sticky="ew")

        editor_frame.grid_rowconfigure(0, weight=1)
        editor_frame.grid_columnconfigure(0, weight=1)

        # Sample theme code
        sample_code = '''"""

Theme configuration for ThreePaneWindows. “””

THEMES = {
“blue”: {

“primary”: “#3498DB”, “secondary”: “#2980B9”, “background”: “#ECF0F1”, “text”: “#2C3E50”, “accent”: “#E74C3C”

},

“dark”: {

“primary”: “#2C3E50”, “secondary”: “#34495E”, “background”: “#1E1E1E”, “text”: “#ECF0F1”, “accent”: “#E67E22”

},

“light”: {

“primary”: “#BDC3C7”, “secondary”: “#95A5A6”, “background”: “#FFFFFF”, “text”: “#2C3E50”, “accent”: “#3498DB”

}

}

def apply_theme(window, theme_name):

“””Apply a theme to the window.””” if theme_name in THEMES:

theme = THEMES[theme_name] window.configure_theme(theme) return True

return False’’’

code_editor.insert(“1.0”, sample_code)

def build_properties(self, frame):

“””Build properties panel content.””” tk.Label(frame, text=”🎨 Theme Properties”,

font=(“Arial”, 11, “bold”)).pack(pady=10)

# Theme info info_frame = tk.LabelFrame(frame, text=”Current Theme”,

font=(“Arial”, 10, “bold”))

info_frame.pack(fill=tk.X, padx=10, pady=10)

self.theme_info_label = tk.Label(info_frame, text=f”Theme: {self.current_theme.title()}”,

font=(“Arial”, 10))

self.theme_info_label.pack(pady=5)

# Color palette palette_frame = tk.LabelFrame(frame, text=”Color Palette”,

font=(“Arial”, 10, “bold”))

palette_frame.pack(fill=tk.X, padx=10, pady=10)

# Sample color swatches colors = self.get_theme_colors(self.current_theme) self.color_swatches = []

for color_name, color_value in colors.items():

swatch_frame = tk.Frame(palette_frame) swatch_frame.pack(fill=tk.X, padx=5, pady=2)

color_box = tk.Frame(swatch_frame, bg=color_value, width=20, height=20) color_box.pack(side=tk.LEFT, padx=5) color_box.pack_propagate(False)

tk.Label(swatch_frame, text=f”{color_name}: {color_value}”,

font=(“Arial”, 9)).pack(side=tk.LEFT, padx=5)

self.color_swatches.append((color_box, color_name))

# Theme features features_frame = tk.LabelFrame(frame, text=”Features”,

font=(“Arial”, 10, “bold”))

features_frame.pack(fill=tk.X, padx=10, pady=10)

features = [

“✓ Professional appearance”, “✓ Consistent color scheme”, “✓ Optimized contrast”, “✓ Modern design”, “✓ Easy customization”

]

for feature in features:
tk.Label(features_frame, text=feature, font=(“Arial”, 9),

anchor=”w”).pack(fill=tk.X, padx=5, pady=1)

def get_theme_colors(self, theme_name):

“””Get colors for a theme.””” theme_colors = {

“blue”: {

“Primary”: “#3498DB”, “Secondary”: “#2980B9”, “Background”: “#ECF0F1”, “Text”: “#2C3E50”, “Accent”: “#E74C3C”

}, “dark”: {

“Primary”: “#2C3E50”, “Secondary”: “#34495E”, “Background”: “#1E1E1E”, “Text”: “#ECF0F1”, “Accent”: “#E67E22”

}, “light”: {

“Primary”: “#BDC3C7”, “Secondary”: “#95A5A6”, “Background”: “#FFFFFF”, “Text”: “#2C3E50”, “Accent”: “#3498DB”

}, “green”: {

“Primary”: “#27AE60”, “Secondary”: “#229954”, “Background”: “#E8F8F5”, “Text”: “#1B4F3C”, “Accent”: “#F39C12”

}, “purple”: {

“Primary”: “#9B59B6”, “Secondary”: “#8E44AD”, “Background”: “#F4ECF7”, “Text”: “#4A235A”, “Accent”: “#E67E22”

}

} return theme_colors.get(theme_name, theme_colors[“blue”])

def change_theme(self, theme_name):

“””Change the current theme.””” self.current_theme = theme_name

# Destroy and recreate the window with new theme self.window.destroy() self.create_main_window()

# Update theme info if properties panel exists if hasattr(self, ‘theme_info_label’):

self.theme_info_label.config(text=f”Theme: {theme_name.title()}”)

def run(self):

“””Run the demo application.””” self.root.mainloop()

if __name__ == “__main__”:

demo = ThemeComparisonDemo() demo.run()

Custom Theme Creation

Create your own custom themes:

import tkinter as tk
from threepanewindows import EnhancedDockableThreePaneWindow, PaneConfig

def create_custom_theme_example():
    """Example of creating custom themes."""

    class CustomThemeWindow(EnhancedDockableThreePaneWindow):
        """Extended window with custom theme support."""

        def __init__(self, parent, **kwargs):
            # Define custom themes
            self.custom_themes = {
                "ocean": {
                    "primary": "#006994",
                    "secondary": "#004d6b",
                    "background": "#e6f3ff",
                    "text": "#003d52",
                    "accent": "#ff6b35",
                    "panel_bg": "#cce7ff",
                    "border": "#0080b3"
                },
                "sunset": {
                    "primary": "#ff6b35",
                    "secondary": "#e55a2b",
                    "background": "#fff5f0",
                    "text": "#8b2500",
                    "accent": "#4ecdc4",
                    "panel_bg": "#ffe6d9",
                    "border": "#ff8c5a"
                },
                "forest": {
                    "primary": "#2d5016",
                    "secondary": "#1e3610",
                    "background": "#f0f8e8",
                    "text": "#1a2e0d",
                    "accent": "#ff9500",
                    "panel_bg": "#e1f0d4",
                    "border": "#4a7c2a"
                }
            }

            super().__init__(parent, **kwargs)

        def apply_custom_theme(self, theme_name):
            """Apply a custom theme."""
            if theme_name in self.custom_themes:
                theme = self.custom_themes[theme_name]
                self.configure_custom_colors(theme)

        def configure_custom_colors(self, theme):
            """Configure colors based on theme."""
            # Apply theme colors to the window
            self.configure(bg=theme["background"])

            # Apply to pane headers if they exist
            for pane in [self.left_pane, self.center_pane, self.right_pane]:
                if hasattr(pane, 'header'):
                    pane.header.configure(bg=theme["primary"], fg="white")

            # Apply to content areas
            for pane in [self.left_pane, self.center_pane, self.right_pane]:
                if hasattr(pane, 'content_frame'):
                    pane.content_frame.configure(bg=theme["panel_bg"])

    root = tk.Tk()
    root.title("Custom Theme Example")
    root.geometry("1000x600")

    def build_theme_demo(frame, theme_name):
        """Build content to demonstrate the theme."""
        # Theme header
        header = tk.Frame(frame, height=40)
        header.pack(fill=tk.X, padx=5, pady=5)
        header.pack_propagate(False)

        tk.Label(header, text=f"🎨 {theme_name.title()} Theme",
                font=("Arial", 12, "bold")).pack(pady=10)

        # Sample content
        content_frame = tk.Frame(frame)
        content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Sample widgets to show theme colors
        tk.Label(content_frame, text="Sample Text",
                font=("Arial", 11)).pack(pady=5)

        btn_frame = tk.Frame(content_frame)
        btn_frame.pack(pady=10)

        tk.Button(btn_frame, text="Primary Button",
                 font=("Arial", 10)).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="Secondary Button",
                 font=("Arial", 10)).pack(side=tk.LEFT, padx=5)

        # Sample list
        listbox = tk.Listbox(content_frame, height=6)
        listbox.pack(fill=tk.X, pady=10)

        for i in range(5):
            listbox.insert(tk.END, f"Sample Item {i+1}")

    # Configure panes
    left_config = PaneConfig(title="Ocean Theme", icon="🌊", default_width=200)
    center_config = PaneConfig(title="Sunset Theme", icon="🌅")
    right_config = PaneConfig(title="Forest Theme", icon="🌲", default_width=200)

    # Create custom themed window
    window = CustomThemeWindow(
        root,
        left_config=left_config,
        center_config=center_config,
        right_config=right_config,
        left_builder=lambda f: build_theme_demo(f, "ocean"),
        center_builder=lambda f: build_theme_demo(f, "sunset"),
        right_builder=lambda f: build_theme_demo(f, "forest")
    )
    window.pack(fill=tk.BOTH, expand=True)

    # Theme selector
    theme_frame = tk.Frame(root, bg="#f0f0f0", height=35)
    theme_frame.pack(fill=tk.X)
    theme_frame.pack_propagate(False)

    tk.Label(theme_frame, text="Custom Themes:", font=("Arial", 10, "bold"),
            bg="#f0f0f0").pack(side=tk.LEFT, padx=10, pady=8)

    themes = [("Ocean", "ocean"), ("Sunset", "sunset"), ("Forest", "forest")]
    for theme_name, theme_key in themes:
        btn = tk.Button(theme_frame, text=theme_name, font=("Arial", 9),
                      command=lambda t=theme_key: window.apply_custom_theme(t))
        btn.pack(side=tk.LEFT, padx=5, pady=5)

    return root

if __name__ == "__main__":
    app = create_custom_theme_example()
    app.mainloop()

Theme Best Practices

Guidelines for effective theming:

  1. Consistent Color Palette: Use a limited, harmonious color scheme

  2. Sufficient Contrast: Ensure text is readable against backgrounds

  3. Semantic Colors: Use colors that convey meaning (red for errors, green for success)

  4. Accessibility: Consider color-blind users and high contrast needs

  5. Brand Alignment: Match your application’s brand colors and style

Available Built-in Themes

ThreePaneWindows includes these built-in themes:

Blue Professional - Primary: Professional blue tones - Use case: Business applications, productivity tools - Characteristics: Clean, trustworthy, professional

Dark Modern - Primary: Dark grays and blacks - Use case: Code editors, creative tools, night mode - Characteristics: Reduced eye strain, modern, sleek

Light Clean - Primary: Light grays and whites - Use case: Document editors, general applications - Characteristics: Bright, clean, minimalist

System - Primary: Follows system theme preferences - Use case: Applications that should match OS appearance - Characteristics: Adaptive, native feel

Theme Configuration

Configure themes in your applications:

# Apply built-in theme
window = EnhancedDockableThreePaneWindow(
    root,
    theme_name="dark"  # or "blue", "light", "system"
)

# Create custom theme
custom_theme = {
    "primary": "#your_color",
    "secondary": "#your_color",
    "background": "#your_color",
    "text": "#your_color",
    "accent": "#your_color"
}

# Apply custom theme
window.apply_custom_theme(custom_theme)

Common Theming Issues and Solutions

Issue: Themes don’t seem to work or look the same

This is usually because user content widgets aren’t using theme colors. The ThreePaneWindows framework (headers, separators, containers) gets themed automatically, but content you add to panes needs manual theming.

Solution: Always apply theme colors to your widgets:

def build_properly_themed_content(frame):
    # Get the current theme
    theme = window.theme_manager.get_current_theme()

    # Apply theme to frame
    frame.configure(bg=theme.colors.panel_content_bg)

    # Apply theme to widgets
    label = tk.Label(frame, text="Themed Label")
    label.configure(
        bg=theme.colors.panel_content_bg,
        fg=theme.colors.primary_text
    )

    button = tk.Button(frame, text="Themed Button")
    button.configure(
        bg=theme.colors.button_bg,
        fg=theme.colors.button_fg,
        activebackground=theme.colors.button_hover
    )

Issue: Blue theme looks the same as light theme

The built-in “blue” and “light” themes have subtle differences. For more dramatic theming, create custom themes:

from threepanewindows.themes import Theme, ColorScheme

# Create dramatic custom theme
dramatic_colors = ColorScheme(
    primary_bg="#000080",      # Navy blue
    secondary_bg="#0000cc",    # Bright blue
    panel_content_bg="#e6f0ff", # Light blue
    primary_text="#ffffff",    # White text
    button_bg="#ff4500",       # Orange buttons
    button_fg="#ffffff"        # White button text
)

custom_theme = Theme(name="Dramatic Blue", colors=dramatic_colors)

# Register and use
window.theme_manager.register_theme(custom_theme)
window.theme_manager.set_theme("dramatic blue")

Issue: Themes work on some platforms but not others

Different operating systems handle widget styling differently:

  • Windows: May require explicit color setting for all widgets

  • macOS: Better automatic theme inheritance

  • Linux: Varies by desktop environment

  • Android (Pydroid): Different default styling

Solution: Always explicitly set theme colors for cross-platform consistency.

Theme Helper Function

Create a helper function to easily apply themes to your widgets:

def apply_theme_to_widget(widget, widget_type="default", theme_manager=None):
    """Apply current theme to a widget."""
    if not theme_manager:
        return

    theme = theme_manager.get_current_theme()

    if widget_type == "label":
        widget.configure(
            bg=theme.colors.panel_content_bg,
            fg=theme.colors.primary_text
        )
    elif widget_type == "button":
        widget.configure(
            bg=theme.colors.button_bg,
            fg=theme.colors.button_fg,
            activebackground=theme.colors.button_hover,
            activeforeground=theme.colors.button_fg,
            relief="flat"
        )
    elif widget_type == "text":
        widget.configure(
            bg=theme.colors.secondary_bg,
            fg=theme.colors.primary_text,
            insertbackground=theme.colors.primary_text,
            selectbackground=theme.colors.accent_bg
        )
    elif widget_type == "frame":
        widget.configure(bg=theme.colors.panel_content_bg)

# Usage
label = tk.Label(frame, text="My Label")
apply_theme_to_widget(label, "label", window.theme_manager)

Best Practices for Theming

  1. Always Theme User Content: Framework components are themed automatically, but your content needs manual theming

  2. Use Theme Colors Consistently: Don’t mix hardcoded colors with theme colors

  3. Test on Multiple Platforms: Themes may look different on Windows, macOS, and Linux

  4. Provide Theme Switching: Allow users to change themes at runtime

  5. Create Dramatic Custom Themes: For better visual feedback during development

  6. Use Helper Functions: Create utilities to apply themes consistently

Next Steps

Explore more customization options: