flextabs


Nameflextabs JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://github.com/MS-32154/flextabs
SummaryA flexible and extensible tab manager widget for tkinter applications built on top of ttk.Notebook
upload_time2025-08-06 19:25:32
maintainerNone
docs_urlNone
authorMS-32154
requires_python>=3.8
licenseNone
keywords tkinter ttk notebook tabs gui widget interface
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![PyPI version](https://img.shields.io/pypi/v/flextabs.svg)](https://pypi.org/project/flextabs/)
[![Python](https://img.shields.io/badge/python-3.7%2B-blue.svg)](https://www.python.org/)
[![License](https://img.shields.io/github/license/MS-32154/flextabs.svg)](LICENSE)

# FlexTabs

A powerful and flexible tab management library for Python tkinter applications that extends `ttk.Notebook` with advanced features like dynamic tab opening/closing, multiple opener styles, keyboard shortcuts, icon support, and state retention.

## Table of Contents

- [Features](#features)
  - [Core Features](#core-features)
  - [Advanced Features](#advanced-features)
- [Installation](#installation)
- [Running the Demo](#running-the-demo)
- [Quick Start](#quick-start)
- [Core Components](#core-components)
  - [TabConfig](#tabconfig)
  - [TabContent](#tabcontent)
  - [TabManager](#tabmanager)
- [Opener Types](#opener-types)
  - [Sidebar Opener](#sidebar-opener)
  - [Toolbar Opener](#toolbar-opener)
  - [Menu Opener](#menu-opener)
- [Close Modes](#close-modes)
- [Keyboard Shortcuts](#keyboard-shortcuts)
  - [Built-in Shortcuts](#built-in-shortcuts)
  - [Custom Shortcuts](#custom-shortcuts)
- [Event Callbacks](#event-callbacks)
- [Runtime Management](#runtime-management)
  - [Tab Operations](#tab-operations)
  - [Dynamic Configuration](#dynamic-configuration)
  - [Icon Management](#icon-management)
- [Notifications](#notifications)
- [Advanced Examples](#advanced-examples)
    - [Custom Tab with Complex UI](#custom-tab-with-complex-uI)
    - [Multi-Window Application](#multi-window-application)
    - [Notebook Styling](#notebook-styling)
- [Error Handling](#error-handling)
- [Performance Tips](#performance-tips)
- [Best Practices](#best-practices)
- [Examples](#examples)
    - [Complete Application Example](#complete-application-example)
    - [Dynamic Tab Management](#dynamic-tab-management)
- [Styling and Customization](#styling-and-customization)
    - [Custom Tooltip Styling](#custom-tooltip-styling)
    - [TTK Styling and Compatibility](#ttk-styling-and-compatibility)
    - [Migrating from ttk.Notebook](#migrating-from-ttk.Notebook)
- [Requirements](#requirements)
- [API Reference](#api-reference)
- [License](#license)
- [Contributing](#contributing)
- [Support](#support)
- [Roadmap](#roadmap)

## Features

### Core Features

- **Dynamic Tab Management**: Open and close tabs programmatically with state retention
- **Multiple Opener Styles**: Toolbar, Sidebar, and Menu-based tab openers
- **Flexible Close Modes**: Control how and when tabs can be closed
- **Icon Support**: Full icon support for both tab openers and notebook tabs (images + emoji/text fallbacks)
- **Keyboard Shortcuts**: Built-in navigation shortcuts plus custom tab shortcuts
- **State Management**: Automatic tab state tracking and restoration
- **Event System**: Comprehensive callbacks for tab lifecycle events
- **Toast Notifications**: Built-in notification system for user feedback
- **Runtime Configuration**: Change settings and add/remove tabs at runtime

### Advanced Features

- **Smart Refresh**: Efficient UI updates that preserve layout and state
- **Multiple Close Confirmation Types**: None, Yes/No, Warning, or Info dialogs
- **Unclosable Tabs**: Mark tabs as permanent with visual indicators
- **Icon Caching**: Automatic icon loading and caching for performance
- **Tooltip Support**: Rich tooltips for tab openers
- **Error Handling**: Robust error handling with user-friendly notifications

## Installation

```bash
pip install flextabs
```

Or clone the repository:

```bash
git clone https://github.com/MS-32154/flextabs.git
cd flextabs
pip install -e .
```

**Dependencies:**

- Python 3.8+
- tkinter (usually included with Python)
- Pillow (PIL) for image icon support

## Running the Demo

```
python3 -m flextabs
```

## Quick Start

```python
import tkinter as tk
from tkinter import ttk
from flextabs import TabManager, TabConfig, TabContent

# Create your tab content classes
class HomeTabContent(TabContent):
    def setup_content(self):
        ttk.Label(self.frame, text="Welcome to the Home tab!").pack(pady=20)

class SettingsTabContent(TabContent):
    def setup_content(self):
        ttk.Label(self.frame, text="Settings Configuration").pack(pady=20)
        # Add a close button
        self.manager().add_close_button(self.frame, self.tab_id).pack(pady=10)

# Create the main window
root = tk.Tk()
root.title("FlexTabs Demo")
root.geometry("800x600")

# Define tab configurations
tab_configs = [
    TabConfig(
        id="home",
        title="Home",
        content_class=HomeTabContent,
        icon="🏠",  # Emoji icon
        tooltip="Go to home page",
        closable=False  # This tab cannot be closed
    ),
    TabConfig(
        id="settings",
        title="Settings",
        content_class=SettingsTabContent,
        icon="⚙️",
        tooltip="Application settings",
        keyboard_shortcut="<Control-s>"
    )
]

# Create the tab manager
tab_manager = TabManager(
    parent=root,
    tab_configs=tab_configs,
    opener_type="sidebar",  # or "toolbar", "menu"
    opener_config={
        "position": "left",
        "width": 150,
        "title": "Navigation"
    }
)
tab_manager.pack(fill=tk.BOTH, expand=True)

# Open the home tab by default
tab_manager.open_tab("home")

root.mainloop()
```

## Core Components

### TabConfig

Defines the configuration for each tab:

```python
TabConfig(
    id="unique_id",              # Required: Unique identifier
    title="Tab Title",           # Required: Display title
    content_class=YourContent,   # Required: TabContent subclass
    icon="🏠",                   # Optional: Icon (emoji, text, or file path)
    tooltip="Helpful text",      # Optional: Tooltip text
    closable=True,               # Optional: Whether tab can be closed
    keyboard_shortcut="<Control-t>",  # Optional: Keyboard shortcut
    data={"key": "value"}        # Optional: Custom data dictionary
)
```

#### Icon Support

FlexTabs supports multiple icon types:

```python
# Emoji/text icons (≤4 characters)
icon="🏠"
icon="⚙️"
icon="📊"

# File paths to images (PNG, JPEG, etc.)
icon="/path/to/icon.png"
icon="resources/settings.ico"

# Context-specific icons
icon={
    "opener": "🏠",              # Icon for tab opener
    "tab": "/path/to/home.png",  # Icon for notebook tab
    "default": "📄"              # Fallback
}
```

### TabContent

Base class for all tab content. Inherit from this to create your tabs:

```python
class MyTabContent(TabContent):
    def setup_content(self):
        """Required: Set up your tab's UI here"""
        ttk.Label(self.frame, text="My content").pack()

    def on_tab_focus(self):
        """Optional: Called when tab becomes active"""
        print(f"Tab {self.tab_id} focused")

    def on_tab_blur(self):
        """Optional: Called when tab loses focus"""
        print(f"Tab {self.tab_id} blurred")

    def on_tab_close(self) -> bool:
        """Optional: Called before closing. Return False to prevent."""
        return True  # Allow closing

    def cleanup(self):
        """Optional: Clean up resources"""
        super().cleanup()
```

### TabManager

The main component that orchestrates everything:

```python
TabManager(
    parent=root,                    # Parent widget
    tab_configs=[...],              # List of TabConfig objects
    opener_type="sidebar",          # "toolbar", "sidebar", or "menu"
    opener_config={},               # Opener-specific configuration
    close_button_style="right_click",  # "right_click", "double_click", "both"
    close_confirmation=False,       # Enable close confirmations
    close_confirmation_type="none", # "none", "yesno", "warning", "info"
    close_mode="active_only",       # "active_only", "any_visible", "both"
    enable_keyboard_shortcuts=True, # Enable built-in shortcuts
    show_notebook_icons=True,       # Show icons in notebook tabs
    notebook_icon_size=(16, 16),    # Icon size for notebook tabs
    **kwargs                        # Additional ttk.Frame options
)
```

## Opener Types

### Sidebar Opener

Creates a sidebar with navigation buttons:

```python
opener_config = {
    "position": "left",      # "left" or "right"
    "width": 150,           # Sidebar width
    "title": "Navigation",  # Optional title
    "style": {},           # ttk.Frame styling
    "button_style": {},    # Button styling
    "show_icons": True,    # Show icons on buttons
    "icon_size": (16, 16), # Icon size
    "icon_position": "left" # "left", "right", "top", "bottom"
}
```

### Toolbar Opener

Creates a horizontal or vertical toolbar:

```python
opener_config = {
    "position": "top",        # "top", "bottom", "left", "right"
    "layout": "horizontal",   # "horizontal" or "vertical"
    "style": {},             # ttk.Frame styling
    "button_style": {},      # Button styling
    "show_icons": True,      # Show icons on buttons
    "icon_size": (16, 16),   # Icon size
    "icon_position": "left"  # Icon position relative to text
}
```

### Menu Opener

Creates a menu in the application's menu bar:

```python
opener_config = {
    "menu_title": "Tabs",    # Menu title in menu bar
    "show_icons": True,      # Show icons in menu items
    # Note: Icons are limited to emoji/text for menus
}
```

## Close Modes

Control how tabs can be closed:

- **`active_only`**: Only the currently active tab can be closed
- **`any_visible`**: Any visible tab can be closed by clicking
- **`both`**: Active tab closes normally, others require Ctrl+click

## Keyboard Shortcuts

### Built-in Shortcuts

- `Ctrl+W`: Close current tab
- `Ctrl+Tab`: Next tab
- `Ctrl+Shift+Tab`: Previous tab
- `Ctrl+1` through `Ctrl+9`: Select tab by index

### Custom Shortcuts

Add shortcuts to individual tabs:

```python
TabConfig(
    id="settings",
    title="Settings",
    content_class=SettingsContent,
    keyboard_shortcut="<Control-comma>"  # Ctrl+,
)
```

## Event Callbacks

Set up callbacks to respond to tab events:

```python
def on_tab_opened(tab_id):
    print(f"Tab {tab_id} opened")

def on_tab_closed(tab_id):
    print(f"Tab {tab_id} closed")

def on_tab_switched(new_tab_id, old_tab_id):
    print(f"Switched from {old_tab_id} to {new_tab_id}")

def on_tab_error(tab_id, error):
    print(f"Error in tab {tab_id}: {error}")

tab_manager.on_tab_opened = on_tab_opened
tab_manager.on_tab_closed = on_tab_closed
tab_manager.on_tab_switched = on_tab_switched
tab_manager.on_tab_error = on_tab_error
```

## Runtime Management

### Tab Operations

```python
# Open/close tabs
tab_manager.open_tab("settings")
tab_manager.close_tab("settings")

# Check tab status
is_open = tab_manager.is_tab_open("settings")
current_tab = tab_manager.get_current_tab()
open_tabs = tab_manager.get_open_tabs()

# Select tabs
tab_manager.select_tab("home")

# Close all tabs
closed_count = tab_manager.close_all_tabs()

# Get tab content instance
content = tab_manager.get_tab_content("settings")
```

### Dynamic Configuration

```python
# Add new tab at runtime
new_tab = TabConfig(
    id="reports",
    title="Reports",
    content_class=ReportsContent
)
tab_manager.add_tab_config(new_tab)

# Remove tab
tab_manager.remove_tab_config("reports")

# Change close mode
tab_manager.set_close_mode("any_visible")
```

### Icon Management

```python
# Refresh all icons (useful after changing icon files)
tab_manager.refresh_tab_icons()

# Update icon settings
tab_manager.set_notebook_icon_settings(
    show_icons=True,
    icon_size=(20, 20),
    fallback_icon_key="default"
)

tab_manager.set_opener_icon_settings(
    show_icons=True,
    icon_size=(18, 18),
    icon_position="top"
)

# Add custom fallback icons
tab_manager.add_fallback_icon("custom", "🔧")
available_icons = tab_manager.get_available_fallback_icons()
```

## Notifications

Show toast notifications to users:

```python
# Basic notification
tab_manager.show_notification("Tab opened successfully")

# Styled notifications
tab_manager.show_notification(
    "Settings saved!",
    toast_type="success",  # "info", "warning", "error", "success"
    duration=3000  # milliseconds
)
```

## Advanced Examples

### Custom Tab with Complex UI

```python
class DataAnalysisTab(TabContent):
    def setup_content(self):
        # Create a complex interface
        main_frame = ttk.Frame(self.frame)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # Toolbar
        toolbar = ttk.Frame(main_frame)
        toolbar.pack(fill=tk.X, pady=(0, 10))

        ttk.Button(toolbar, text="Load Data").pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(toolbar, text="Export").pack(side=tk.LEFT, padx=(0, 5))

        # Content area with notebook
        content_nb = ttk.Notebook(main_frame)
        content_nb.pack(fill=tk.BOTH, expand=True)

        # Data tab
        data_frame = ttk.Frame(content_nb)
        content_nb.add(data_frame, text="Raw Data")

        # Charts tab
        chart_frame = ttk.Frame(content_nb)
        content_nb.add(chart_frame, text="Charts")

    def on_tab_focus(self):
        # Refresh data when tab becomes active
        self.refresh_data()

    def on_tab_close(self):
        # Ask user to save unsaved changes
        if self.has_unsaved_changes():
            from tkinter import messagebox
            result = messagebox.askyesnocancel(
                "Unsaved Changes",
                "Save changes before closing?",
                parent=self.frame
            )
            if result is None:  # Cancel
                return False
            elif result:  # Yes
                self.save_changes()
        return True

    def refresh_data(self):
        # Implementation here
        pass

    def has_unsaved_changes(self):
        # Check for unsaved changes
        return False

    def save_changes(self):
        # Save changes
        pass
```

### Multi-Window Application

```python
class MultiWindowApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Multi-Window App")

        # Create main tab manager
        self.main_tabs = TabManager(
            parent=self.root,
            tab_configs=self.get_main_tab_configs(),
            opener_type="toolbar",
            opener_config={"position": "top"}
        )
        self.main_tabs.pack(fill=tk.BOTH, expand=True)

        # Set up callbacks
        self.main_tabs.on_tab_opened = self.on_main_tab_opened

    def get_main_tab_configs(self):
        return [
            TabConfig("home", "Home", HomeTab, icon="🏠", closable=False),
            TabConfig("projects", "Projects", ProjectsTab, icon="📁"),
            TabConfig("settings", "Settings", SettingsTab, icon="⚙️")
        ]

    def on_main_tab_opened(self, tab_id):
        if tab_id == "projects":
            # When projects tab opens, populate with recent projects
            content = self.main_tabs.get_tab_content(tab_id)
            if content:
                content.load_recent_projects()

    def run(self):
        self.main_tabs.open_tab("home")
        self.root.mainloop()
```

### Notebook Styling

FlexTabs uses `ttk.Notebook` internally, so all standard ttk styling applies:

```python
import tkinter.ttk as ttk

# Create custom notebook style
style = ttk.Style()
style.configure("Custom.TNotebook",
               background="lightgray",
               tabmargins=[0, 5, 0, 0])
style.configure("Custom.TNotebook.Tab",
               padding=[20, 10],
               background="white")

tab_manager = TabManager(
    parent,
    tab_configs=tabs,
    notebook_config={
        "style": "Custom.TNotebook",  # Apply custom ttk style
        "padding": 5
    }
)
```

You can also access the underlying `ttk.Notebook` directly:

```python
# Access the internal ttk.Notebook for advanced customization
internal_notebook = tab_manager.notebook
internal_notebook.configure(width=500, height=300)
```

## Error Handling

FlexTabs includes comprehensive error handling:

```python
# Errors are automatically caught and can be handled via callback
def handle_tab_error(tab_id, error):
    print(f"Error in tab {tab_id}: {error}")
    # Log to file, show user message, etc.

tab_manager.on_tab_error = handle_tab_error
```

## Performance Tips

1. **Icon Preloading**: Icons are automatically preloaded and cached
2. **Smart Refresh**: UI updates use smart refresh to avoid recreating widgets unnecessarily
3. **Lazy Loading**: Tabs are only created when first opened
4. **Memory Management**: Proper cleanup prevents memory leaks

## Best Practices

1. **Tab IDs**: Use descriptive, unique IDs for all tabs
2. **Resource Cleanup**: Always implement `cleanup()` in TabContent subclasses that use resources
3. **Error Handling**: Implement robust error handling in your TabContent classes
4. **Icon Sizes**: Use consistent icon sizes for better visual appearance
5. **Keyboard Shortcuts**: Use standard shortcuts when possible (Ctrl+S for settings, etc.)

## Examples

### Complete Application Example

```python
import tkinter as tk
from tkinter import ttk, messagebox
from flextabs import TabManager, TabConfig, TabContent

class HomeTab(TabContent):
    def setup_content(self):
        ttk.Label(self.frame, text="Welcome to the Home Tab!",
                 font=("TkDefaultFont", 16)).pack(pady=20)

        ttk.Button(self.frame, text="Open Settings",
                  command=lambda: self.get_manager().open_tab("settings")).pack(pady=5)

class SettingsTab(TabContent):
    def setup_content(self):
        ttk.Label(self.frame, text="Settings",
                 font=("TkDefaultFont", 14, "bold")).pack(pady=10)

        # Some settings widgets
        ttk.Checkbutton(self.frame, text="Enable notifications").pack(pady=2)
        ttk.Checkbutton(self.frame, text="Auto-save").pack(pady=2)

        # Add close button
        close_btn = self.get_manager().add_close_button(self.frame, self.tab_id)
        close_btn.pack(pady=10)

class DataTab(TabContent):
    def setup_content(self):
        self.data_modified = False

        ttk.Label(self.frame, text="Data Editor").pack(pady=10)

        self.text_area = tk.Text(self.frame, height=10, width=50)
        self.text_area.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)
        self.text_area.bind('<KeyPress>', self.on_data_change)

    def on_data_change(self, event):
        self.data_modified = True

    def on_tab_close(self) -> bool:
        if self.data_modified:
            result = messagebox.askyesnocancel(
                "Unsaved Changes",
                "You have unsaved changes. Save before closing?",
                parent=self.frame
            )
            if result is None:  # Cancel
                return False
            elif result:  # Yes - save
                # Simulate saving
                self.get_manager().show_notification("Data saved!", "success")
        return True

def main():
    root = tk.Tk()
    root.title("FlexTabs Demo Application")
    root.geometry("900x600")

    # Define tabs
    tabs = [
        TabConfig("home", "Home", HomeTab,
                 tooltip="Application home page",
                 keyboard_shortcut="<Control-h>"),
        TabConfig("settings", "Settings", SettingsTab,
                 tooltip="Application settings",
                 closable=False),  # Can't be closed
        TabConfig("data", "Data Editor", DataTab,
                 tooltip="Edit your data here",
                 keyboard_shortcut="<Control-d>"),
    ]

    # Create tab manager with sidebar
    tab_manager = TabManager(
        root,
        tab_configs=tabs,
        opener_type="sidebar",
        opener_config={
            "position": "left",
            "width": 180,
            "title": "Navigation",
            "style": {"bg": "#f8f9fa"}
        },
        close_confirmation=True,
        close_confirmation_type="yesno",
        enable_keyboard_shortcuts=True
    )

    # Set up event handlers
    def on_tab_opened(tab_id):
        tab_manager.show_notification(f"Opened {tabs[0].title}", "info")

    tab_manager.on_tab_opened = on_tab_opened
    tab_manager.pack(fill=tk.BOTH, expand=True)

    # Open home tab by default
    tab_manager.open_tab("home")

    root.mainloop()

if __name__ == "__main__":
    main()
```

### Dynamic Tab Management

```python
import tkinter as tk
from flextabs import TabManager, TabConfig, TabContent

class DynamicContent(TabContent):
    def setup_content(self):
        data = self.config.data
        tk.Label(self.frame, text=f"Dynamic tab: {data.get('content', 'No content')}").pack()

def create_dynamic_tab(tab_manager, counter):
    """Create a new tab dynamically"""
    tab_id = f"dynamic_{counter}"
    config = TabConfig(
        id=tab_id,
        title=f"Dynamic {counter}",
        content_class=DynamicContent,
        data={"content": f"This is dynamic tab #{counter}"}
    )

    tab_manager.add_tab_config(config)
    tab_manager.open_tab(tab_id)

# Usage in your application
root = tk.Tk()
tab_manager = TabManager(root, tab_configs=[], opener_type="toolbar")

# Add button to create new tabs
counter = 1
def add_tab():
    global counter
    create_dynamic_tab(tab_manager, counter)
    counter += 1

tk.Button(root, text="Add Tab", command=add_tab).pack()
tab_manager.pack(fill=tk.BOTH, expand=True)
```

## Styling and Customization

### Custom Tooltip Styling

The library includes built-in tooltips that can be customized by modifying the `TooltipWidget` class or by styling the underlying tkinter widgets.

### Toast Notifications

Built-in toast notification system with four types:

- `info` (blue) - General information
- `warning` (yellow) - Warnings
- `error` (red) - Error messages
- `success` (green) - Success messages

### TTK Styling and Compatibility

FlexTabs preserves full compatibility with `ttk.Notebook` styling and behavior:

```python
import tkinter.ttk as ttk

# All standard ttk.Notebook features work
style = ttk.Style()
style.configure("Custom.TNotebook", background="lightgray")
style.configure("Custom.TNotebook.Tab", padding=[20, 10])

# FlexTabs respects ttk themes
style.theme_use('clam')  # or 'alt', 'default', 'classic'

tab_manager = TabManager(
    parent,
    tab_configs=tabs,
    notebook_config={"style": "Custom.TNotebook"}
)

# Access underlying ttk.Notebook for direct manipulation
notebook = tab_manager.notebook
print(f"Current tab: {notebook.select()}")
print(f"All tabs: {notebook.tabs()}")
```

### Migrating from ttk.Notebook

If you have existing `ttk.Notebook` code, migration is straightforward:

**Before (ttk.Notebook):**

```python
notebook = ttk.Notebook(parent)
frame = ttk.Frame(notebook)
notebook.add(frame, text="My Tab")
# Content goes directly in frame
```

**After (FlexTabs):**

```python
class MyTab(TabContent):
    def setup_content(self):
        # Content goes in self.frame
        pass

config = TabConfig("my_tab", "My Tab", MyTab)
tab_manager = TabManager(parent, [config], opener_type="toolbar")
```

## Requirements

- Python 3.8+
- tkinter (usually included with Python)
- Pillow (PIL) for image icon support

## API Reference

For the complete API reference got to [FlexTabs API Documentation](https://ms-32154.github.io/flextabs/) or see the source code.

### Enums

- `TabPosition`: TOP, BOTTOM, LEFT, RIGHT
- `CloseMode`: ACTIVE_ONLY, ANY_VISIBLE, BOTH
- `CloseConfirmationType`: NONE, YESNO, WARNING, INFO

### Classes

- `TabConfig`: Tab configuration dataclass
- `TabContent`: Base class for tab content
- `TabOpener`: Base class for tab openers
- `TabManager`: Main tab management widget
- `IconManager`: Icon loading and caching
- `TooltipWidget`: Tooltip implementation
- `ToastNotification`: Notification system

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

## Support

If you encounter any issues or have questions, please:

1. Check the [examples](#examples) section
2. Search existing [GitHub Issues](https://github.com/MS-32154/flextabs/issues)
3. Create a new issue with:
   - Python version
   - Operating system
   - Minimal code example reproducing the issue
   - Full error traceback (if applicable)

## Roadmap

- [x] Icon support for tabs and buttons
- [ ] Drag and drop tab reordering
- [ ] Tab groups and separators
- [ ] Persistent tab state between sessions
- [ ] Theme system
- [ ] Animation effects
- [ ] Tab overflow handling

---

**FlexTabs** – Extending `ttk.Notebook` for powerful and flexible tab management in Tkinter.

© 2025 MS-32154. All rights reserved.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/MS-32154/flextabs",
    "name": "flextabs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "tkinter, ttk, Notebook, tabs, gui, widget, interface",
    "author": "MS-32154",
    "author_email": "MS-32154 <msttoffg@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/8e/fd/d3e0c08d41c1f2d7ef1cd9da0921c63eb67b40cd9cce03d054286d3a143d/flextabs-0.2.0.tar.gz",
    "platform": null,
    "description": "[![PyPI version](https://img.shields.io/pypi/v/flextabs.svg)](https://pypi.org/project/flextabs/)\n[![Python](https://img.shields.io/badge/python-3.7%2B-blue.svg)](https://www.python.org/)\n[![License](https://img.shields.io/github/license/MS-32154/flextabs.svg)](LICENSE)\n\n# FlexTabs\n\nA powerful and flexible tab management library for Python tkinter applications that extends `ttk.Notebook` with advanced features like dynamic tab opening/closing, multiple opener styles, keyboard shortcuts, icon support, and state retention.\n\n## Table of Contents\n\n- [Features](#features)\n  - [Core Features](#core-features)\n  - [Advanced Features](#advanced-features)\n- [Installation](#installation)\n- [Running the Demo](#running-the-demo)\n- [Quick Start](#quick-start)\n- [Core Components](#core-components)\n  - [TabConfig](#tabconfig)\n  - [TabContent](#tabcontent)\n  - [TabManager](#tabmanager)\n- [Opener Types](#opener-types)\n  - [Sidebar Opener](#sidebar-opener)\n  - [Toolbar Opener](#toolbar-opener)\n  - [Menu Opener](#menu-opener)\n- [Close Modes](#close-modes)\n- [Keyboard Shortcuts](#keyboard-shortcuts)\n  - [Built-in Shortcuts](#built-in-shortcuts)\n  - [Custom Shortcuts](#custom-shortcuts)\n- [Event Callbacks](#event-callbacks)\n- [Runtime Management](#runtime-management)\n  - [Tab Operations](#tab-operations)\n  - [Dynamic Configuration](#dynamic-configuration)\n  - [Icon Management](#icon-management)\n- [Notifications](#notifications)\n- [Advanced Examples](#advanced-examples)\n    - [Custom Tab with Complex UI](#custom-tab-with-complex-uI)\n    - [Multi-Window Application](#multi-window-application)\n    - [Notebook Styling](#notebook-styling)\n- [Error Handling](#error-handling)\n- [Performance Tips](#performance-tips)\n- [Best Practices](#best-practices)\n- [Examples](#examples)\n    - [Complete Application Example](#complete-application-example)\n    - [Dynamic Tab Management](#dynamic-tab-management)\n- [Styling and Customization](#styling-and-customization)\n    - [Custom Tooltip Styling](#custom-tooltip-styling)\n    - [TTK Styling and Compatibility](#ttk-styling-and-compatibility)\n    - [Migrating from ttk.Notebook](#migrating-from-ttk.Notebook)\n- [Requirements](#requirements)\n- [API Reference](#api-reference)\n- [License](#license)\n- [Contributing](#contributing)\n- [Support](#support)\n- [Roadmap](#roadmap)\n\n## Features\n\n### Core Features\n\n- **Dynamic Tab Management**: Open and close tabs programmatically with state retention\n- **Multiple Opener Styles**: Toolbar, Sidebar, and Menu-based tab openers\n- **Flexible Close Modes**: Control how and when tabs can be closed\n- **Icon Support**: Full icon support for both tab openers and notebook tabs (images + emoji/text fallbacks)\n- **Keyboard Shortcuts**: Built-in navigation shortcuts plus custom tab shortcuts\n- **State Management**: Automatic tab state tracking and restoration\n- **Event System**: Comprehensive callbacks for tab lifecycle events\n- **Toast Notifications**: Built-in notification system for user feedback\n- **Runtime Configuration**: Change settings and add/remove tabs at runtime\n\n### Advanced Features\n\n- **Smart Refresh**: Efficient UI updates that preserve layout and state\n- **Multiple Close Confirmation Types**: None, Yes/No, Warning, or Info dialogs\n- **Unclosable Tabs**: Mark tabs as permanent with visual indicators\n- **Icon Caching**: Automatic icon loading and caching for performance\n- **Tooltip Support**: Rich tooltips for tab openers\n- **Error Handling**: Robust error handling with user-friendly notifications\n\n## Installation\n\n```bash\npip install flextabs\n```\n\nOr clone the repository:\n\n```bash\ngit clone https://github.com/MS-32154/flextabs.git\ncd flextabs\npip install -e .\n```\n\n**Dependencies:**\n\n- Python 3.8+\n- tkinter (usually included with Python)\n- Pillow (PIL) for image icon support\n\n## Running the Demo\n\n```\npython3 -m flextabs\n```\n\n## Quick Start\n\n```python\nimport tkinter as tk\nfrom tkinter import ttk\nfrom flextabs import TabManager, TabConfig, TabContent\n\n# Create your tab content classes\nclass HomeTabContent(TabContent):\n    def setup_content(self):\n        ttk.Label(self.frame, text=\"Welcome to the Home tab!\").pack(pady=20)\n\nclass SettingsTabContent(TabContent):\n    def setup_content(self):\n        ttk.Label(self.frame, text=\"Settings Configuration\").pack(pady=20)\n        # Add a close button\n        self.manager().add_close_button(self.frame, self.tab_id).pack(pady=10)\n\n# Create the main window\nroot = tk.Tk()\nroot.title(\"FlexTabs Demo\")\nroot.geometry(\"800x600\")\n\n# Define tab configurations\ntab_configs = [\n    TabConfig(\n        id=\"home\",\n        title=\"Home\",\n        content_class=HomeTabContent,\n        icon=\"\ud83c\udfe0\",  # Emoji icon\n        tooltip=\"Go to home page\",\n        closable=False  # This tab cannot be closed\n    ),\n    TabConfig(\n        id=\"settings\",\n        title=\"Settings\",\n        content_class=SettingsTabContent,\n        icon=\"\u2699\ufe0f\",\n        tooltip=\"Application settings\",\n        keyboard_shortcut=\"<Control-s>\"\n    )\n]\n\n# Create the tab manager\ntab_manager = TabManager(\n    parent=root,\n    tab_configs=tab_configs,\n    opener_type=\"sidebar\",  # or \"toolbar\", \"menu\"\n    opener_config={\n        \"position\": \"left\",\n        \"width\": 150,\n        \"title\": \"Navigation\"\n    }\n)\ntab_manager.pack(fill=tk.BOTH, expand=True)\n\n# Open the home tab by default\ntab_manager.open_tab(\"home\")\n\nroot.mainloop()\n```\n\n## Core Components\n\n### TabConfig\n\nDefines the configuration for each tab:\n\n```python\nTabConfig(\n    id=\"unique_id\",              # Required: Unique identifier\n    title=\"Tab Title\",           # Required: Display title\n    content_class=YourContent,   # Required: TabContent subclass\n    icon=\"\ud83c\udfe0\",                   # Optional: Icon (emoji, text, or file path)\n    tooltip=\"Helpful text\",      # Optional: Tooltip text\n    closable=True,               # Optional: Whether tab can be closed\n    keyboard_shortcut=\"<Control-t>\",  # Optional: Keyboard shortcut\n    data={\"key\": \"value\"}        # Optional: Custom data dictionary\n)\n```\n\n#### Icon Support\n\nFlexTabs supports multiple icon types:\n\n```python\n# Emoji/text icons (\u22644 characters)\nicon=\"\ud83c\udfe0\"\nicon=\"\u2699\ufe0f\"\nicon=\"\ud83d\udcca\"\n\n# File paths to images (PNG, JPEG, etc.)\nicon=\"/path/to/icon.png\"\nicon=\"resources/settings.ico\"\n\n# Context-specific icons\nicon={\n    \"opener\": \"\ud83c\udfe0\",              # Icon for tab opener\n    \"tab\": \"/path/to/home.png\",  # Icon for notebook tab\n    \"default\": \"\ud83d\udcc4\"              # Fallback\n}\n```\n\n### TabContent\n\nBase class for all tab content. Inherit from this to create your tabs:\n\n```python\nclass MyTabContent(TabContent):\n    def setup_content(self):\n        \"\"\"Required: Set up your tab's UI here\"\"\"\n        ttk.Label(self.frame, text=\"My content\").pack()\n\n    def on_tab_focus(self):\n        \"\"\"Optional: Called when tab becomes active\"\"\"\n        print(f\"Tab {self.tab_id} focused\")\n\n    def on_tab_blur(self):\n        \"\"\"Optional: Called when tab loses focus\"\"\"\n        print(f\"Tab {self.tab_id} blurred\")\n\n    def on_tab_close(self) -> bool:\n        \"\"\"Optional: Called before closing. Return False to prevent.\"\"\"\n        return True  # Allow closing\n\n    def cleanup(self):\n        \"\"\"Optional: Clean up resources\"\"\"\n        super().cleanup()\n```\n\n### TabManager\n\nThe main component that orchestrates everything:\n\n```python\nTabManager(\n    parent=root,                    # Parent widget\n    tab_configs=[...],              # List of TabConfig objects\n    opener_type=\"sidebar\",          # \"toolbar\", \"sidebar\", or \"menu\"\n    opener_config={},               # Opener-specific configuration\n    close_button_style=\"right_click\",  # \"right_click\", \"double_click\", \"both\"\n    close_confirmation=False,       # Enable close confirmations\n    close_confirmation_type=\"none\", # \"none\", \"yesno\", \"warning\", \"info\"\n    close_mode=\"active_only\",       # \"active_only\", \"any_visible\", \"both\"\n    enable_keyboard_shortcuts=True, # Enable built-in shortcuts\n    show_notebook_icons=True,       # Show icons in notebook tabs\n    notebook_icon_size=(16, 16),    # Icon size for notebook tabs\n    **kwargs                        # Additional ttk.Frame options\n)\n```\n\n## Opener Types\n\n### Sidebar Opener\n\nCreates a sidebar with navigation buttons:\n\n```python\nopener_config = {\n    \"position\": \"left\",      # \"left\" or \"right\"\n    \"width\": 150,           # Sidebar width\n    \"title\": \"Navigation\",  # Optional title\n    \"style\": {},           # ttk.Frame styling\n    \"button_style\": {},    # Button styling\n    \"show_icons\": True,    # Show icons on buttons\n    \"icon_size\": (16, 16), # Icon size\n    \"icon_position\": \"left\" # \"left\", \"right\", \"top\", \"bottom\"\n}\n```\n\n### Toolbar Opener\n\nCreates a horizontal or vertical toolbar:\n\n```python\nopener_config = {\n    \"position\": \"top\",        # \"top\", \"bottom\", \"left\", \"right\"\n    \"layout\": \"horizontal\",   # \"horizontal\" or \"vertical\"\n    \"style\": {},             # ttk.Frame styling\n    \"button_style\": {},      # Button styling\n    \"show_icons\": True,      # Show icons on buttons\n    \"icon_size\": (16, 16),   # Icon size\n    \"icon_position\": \"left\"  # Icon position relative to text\n}\n```\n\n### Menu Opener\n\nCreates a menu in the application's menu bar:\n\n```python\nopener_config = {\n    \"menu_title\": \"Tabs\",    # Menu title in menu bar\n    \"show_icons\": True,      # Show icons in menu items\n    # Note: Icons are limited to emoji/text for menus\n}\n```\n\n## Close Modes\n\nControl how tabs can be closed:\n\n- **`active_only`**: Only the currently active tab can be closed\n- **`any_visible`**: Any visible tab can be closed by clicking\n- **`both`**: Active tab closes normally, others require Ctrl+click\n\n## Keyboard Shortcuts\n\n### Built-in Shortcuts\n\n- `Ctrl+W`: Close current tab\n- `Ctrl+Tab`: Next tab\n- `Ctrl+Shift+Tab`: Previous tab\n- `Ctrl+1` through `Ctrl+9`: Select tab by index\n\n### Custom Shortcuts\n\nAdd shortcuts to individual tabs:\n\n```python\nTabConfig(\n    id=\"settings\",\n    title=\"Settings\",\n    content_class=SettingsContent,\n    keyboard_shortcut=\"<Control-comma>\"  # Ctrl+,\n)\n```\n\n## Event Callbacks\n\nSet up callbacks to respond to tab events:\n\n```python\ndef on_tab_opened(tab_id):\n    print(f\"Tab {tab_id} opened\")\n\ndef on_tab_closed(tab_id):\n    print(f\"Tab {tab_id} closed\")\n\ndef on_tab_switched(new_tab_id, old_tab_id):\n    print(f\"Switched from {old_tab_id} to {new_tab_id}\")\n\ndef on_tab_error(tab_id, error):\n    print(f\"Error in tab {tab_id}: {error}\")\n\ntab_manager.on_tab_opened = on_tab_opened\ntab_manager.on_tab_closed = on_tab_closed\ntab_manager.on_tab_switched = on_tab_switched\ntab_manager.on_tab_error = on_tab_error\n```\n\n## Runtime Management\n\n### Tab Operations\n\n```python\n# Open/close tabs\ntab_manager.open_tab(\"settings\")\ntab_manager.close_tab(\"settings\")\n\n# Check tab status\nis_open = tab_manager.is_tab_open(\"settings\")\ncurrent_tab = tab_manager.get_current_tab()\nopen_tabs = tab_manager.get_open_tabs()\n\n# Select tabs\ntab_manager.select_tab(\"home\")\n\n# Close all tabs\nclosed_count = tab_manager.close_all_tabs()\n\n# Get tab content instance\ncontent = tab_manager.get_tab_content(\"settings\")\n```\n\n### Dynamic Configuration\n\n```python\n# Add new tab at runtime\nnew_tab = TabConfig(\n    id=\"reports\",\n    title=\"Reports\",\n    content_class=ReportsContent\n)\ntab_manager.add_tab_config(new_tab)\n\n# Remove tab\ntab_manager.remove_tab_config(\"reports\")\n\n# Change close mode\ntab_manager.set_close_mode(\"any_visible\")\n```\n\n### Icon Management\n\n```python\n# Refresh all icons (useful after changing icon files)\ntab_manager.refresh_tab_icons()\n\n# Update icon settings\ntab_manager.set_notebook_icon_settings(\n    show_icons=True,\n    icon_size=(20, 20),\n    fallback_icon_key=\"default\"\n)\n\ntab_manager.set_opener_icon_settings(\n    show_icons=True,\n    icon_size=(18, 18),\n    icon_position=\"top\"\n)\n\n# Add custom fallback icons\ntab_manager.add_fallback_icon(\"custom\", \"\ud83d\udd27\")\navailable_icons = tab_manager.get_available_fallback_icons()\n```\n\n## Notifications\n\nShow toast notifications to users:\n\n```python\n# Basic notification\ntab_manager.show_notification(\"Tab opened successfully\")\n\n# Styled notifications\ntab_manager.show_notification(\n    \"Settings saved!\",\n    toast_type=\"success\",  # \"info\", \"warning\", \"error\", \"success\"\n    duration=3000  # milliseconds\n)\n```\n\n## Advanced Examples\n\n### Custom Tab with Complex UI\n\n```python\nclass DataAnalysisTab(TabContent):\n    def setup_content(self):\n        # Create a complex interface\n        main_frame = ttk.Frame(self.frame)\n        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)\n\n        # Toolbar\n        toolbar = ttk.Frame(main_frame)\n        toolbar.pack(fill=tk.X, pady=(0, 10))\n\n        ttk.Button(toolbar, text=\"Load Data\").pack(side=tk.LEFT, padx=(0, 5))\n        ttk.Button(toolbar, text=\"Export\").pack(side=tk.LEFT, padx=(0, 5))\n\n        # Content area with notebook\n        content_nb = ttk.Notebook(main_frame)\n        content_nb.pack(fill=tk.BOTH, expand=True)\n\n        # Data tab\n        data_frame = ttk.Frame(content_nb)\n        content_nb.add(data_frame, text=\"Raw Data\")\n\n        # Charts tab\n        chart_frame = ttk.Frame(content_nb)\n        content_nb.add(chart_frame, text=\"Charts\")\n\n    def on_tab_focus(self):\n        # Refresh data when tab becomes active\n        self.refresh_data()\n\n    def on_tab_close(self):\n        # Ask user to save unsaved changes\n        if self.has_unsaved_changes():\n            from tkinter import messagebox\n            result = messagebox.askyesnocancel(\n                \"Unsaved Changes\",\n                \"Save changes before closing?\",\n                parent=self.frame\n            )\n            if result is None:  # Cancel\n                return False\n            elif result:  # Yes\n                self.save_changes()\n        return True\n\n    def refresh_data(self):\n        # Implementation here\n        pass\n\n    def has_unsaved_changes(self):\n        # Check for unsaved changes\n        return False\n\n    def save_changes(self):\n        # Save changes\n        pass\n```\n\n### Multi-Window Application\n\n```python\nclass MultiWindowApp:\n    def __init__(self):\n        self.root = tk.Tk()\n        self.root.title(\"Multi-Window App\")\n\n        # Create main tab manager\n        self.main_tabs = TabManager(\n            parent=self.root,\n            tab_configs=self.get_main_tab_configs(),\n            opener_type=\"toolbar\",\n            opener_config={\"position\": \"top\"}\n        )\n        self.main_tabs.pack(fill=tk.BOTH, expand=True)\n\n        # Set up callbacks\n        self.main_tabs.on_tab_opened = self.on_main_tab_opened\n\n    def get_main_tab_configs(self):\n        return [\n            TabConfig(\"home\", \"Home\", HomeTab, icon=\"\ud83c\udfe0\", closable=False),\n            TabConfig(\"projects\", \"Projects\", ProjectsTab, icon=\"\ud83d\udcc1\"),\n            TabConfig(\"settings\", \"Settings\", SettingsTab, icon=\"\u2699\ufe0f\")\n        ]\n\n    def on_main_tab_opened(self, tab_id):\n        if tab_id == \"projects\":\n            # When projects tab opens, populate with recent projects\n            content = self.main_tabs.get_tab_content(tab_id)\n            if content:\n                content.load_recent_projects()\n\n    def run(self):\n        self.main_tabs.open_tab(\"home\")\n        self.root.mainloop()\n```\n\n### Notebook Styling\n\nFlexTabs uses `ttk.Notebook` internally, so all standard ttk styling applies:\n\n```python\nimport tkinter.ttk as ttk\n\n# Create custom notebook style\nstyle = ttk.Style()\nstyle.configure(\"Custom.TNotebook\",\n               background=\"lightgray\",\n               tabmargins=[0, 5, 0, 0])\nstyle.configure(\"Custom.TNotebook.Tab\",\n               padding=[20, 10],\n               background=\"white\")\n\ntab_manager = TabManager(\n    parent,\n    tab_configs=tabs,\n    notebook_config={\n        \"style\": \"Custom.TNotebook\",  # Apply custom ttk style\n        \"padding\": 5\n    }\n)\n```\n\nYou can also access the underlying `ttk.Notebook` directly:\n\n```python\n# Access the internal ttk.Notebook for advanced customization\ninternal_notebook = tab_manager.notebook\ninternal_notebook.configure(width=500, height=300)\n```\n\n## Error Handling\n\nFlexTabs includes comprehensive error handling:\n\n```python\n# Errors are automatically caught and can be handled via callback\ndef handle_tab_error(tab_id, error):\n    print(f\"Error in tab {tab_id}: {error}\")\n    # Log to file, show user message, etc.\n\ntab_manager.on_tab_error = handle_tab_error\n```\n\n## Performance Tips\n\n1. **Icon Preloading**: Icons are automatically preloaded and cached\n2. **Smart Refresh**: UI updates use smart refresh to avoid recreating widgets unnecessarily\n3. **Lazy Loading**: Tabs are only created when first opened\n4. **Memory Management**: Proper cleanup prevents memory leaks\n\n## Best Practices\n\n1. **Tab IDs**: Use descriptive, unique IDs for all tabs\n2. **Resource Cleanup**: Always implement `cleanup()` in TabContent subclasses that use resources\n3. **Error Handling**: Implement robust error handling in your TabContent classes\n4. **Icon Sizes**: Use consistent icon sizes for better visual appearance\n5. **Keyboard Shortcuts**: Use standard shortcuts when possible (Ctrl+S for settings, etc.)\n\n## Examples\n\n### Complete Application Example\n\n```python\nimport tkinter as tk\nfrom tkinter import ttk, messagebox\nfrom flextabs import TabManager, TabConfig, TabContent\n\nclass HomeTab(TabContent):\n    def setup_content(self):\n        ttk.Label(self.frame, text=\"Welcome to the Home Tab!\",\n                 font=(\"TkDefaultFont\", 16)).pack(pady=20)\n\n        ttk.Button(self.frame, text=\"Open Settings\",\n                  command=lambda: self.get_manager().open_tab(\"settings\")).pack(pady=5)\n\nclass SettingsTab(TabContent):\n    def setup_content(self):\n        ttk.Label(self.frame, text=\"Settings\",\n                 font=(\"TkDefaultFont\", 14, \"bold\")).pack(pady=10)\n\n        # Some settings widgets\n        ttk.Checkbutton(self.frame, text=\"Enable notifications\").pack(pady=2)\n        ttk.Checkbutton(self.frame, text=\"Auto-save\").pack(pady=2)\n\n        # Add close button\n        close_btn = self.get_manager().add_close_button(self.frame, self.tab_id)\n        close_btn.pack(pady=10)\n\nclass DataTab(TabContent):\n    def setup_content(self):\n        self.data_modified = False\n\n        ttk.Label(self.frame, text=\"Data Editor\").pack(pady=10)\n\n        self.text_area = tk.Text(self.frame, height=10, width=50)\n        self.text_area.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)\n        self.text_area.bind('<KeyPress>', self.on_data_change)\n\n    def on_data_change(self, event):\n        self.data_modified = True\n\n    def on_tab_close(self) -> bool:\n        if self.data_modified:\n            result = messagebox.askyesnocancel(\n                \"Unsaved Changes\",\n                \"You have unsaved changes. Save before closing?\",\n                parent=self.frame\n            )\n            if result is None:  # Cancel\n                return False\n            elif result:  # Yes - save\n                # Simulate saving\n                self.get_manager().show_notification(\"Data saved!\", \"success\")\n        return True\n\ndef main():\n    root = tk.Tk()\n    root.title(\"FlexTabs Demo Application\")\n    root.geometry(\"900x600\")\n\n    # Define tabs\n    tabs = [\n        TabConfig(\"home\", \"Home\", HomeTab,\n                 tooltip=\"Application home page\",\n                 keyboard_shortcut=\"<Control-h>\"),\n        TabConfig(\"settings\", \"Settings\", SettingsTab,\n                 tooltip=\"Application settings\",\n                 closable=False),  # Can't be closed\n        TabConfig(\"data\", \"Data Editor\", DataTab,\n                 tooltip=\"Edit your data here\",\n                 keyboard_shortcut=\"<Control-d>\"),\n    ]\n\n    # Create tab manager with sidebar\n    tab_manager = TabManager(\n        root,\n        tab_configs=tabs,\n        opener_type=\"sidebar\",\n        opener_config={\n            \"position\": \"left\",\n            \"width\": 180,\n            \"title\": \"Navigation\",\n            \"style\": {\"bg\": \"#f8f9fa\"}\n        },\n        close_confirmation=True,\n        close_confirmation_type=\"yesno\",\n        enable_keyboard_shortcuts=True\n    )\n\n    # Set up event handlers\n    def on_tab_opened(tab_id):\n        tab_manager.show_notification(f\"Opened {tabs[0].title}\", \"info\")\n\n    tab_manager.on_tab_opened = on_tab_opened\n    tab_manager.pack(fill=tk.BOTH, expand=True)\n\n    # Open home tab by default\n    tab_manager.open_tab(\"home\")\n\n    root.mainloop()\n\nif __name__ == \"__main__\":\n    main()\n```\n\n### Dynamic Tab Management\n\n```python\nimport tkinter as tk\nfrom flextabs import TabManager, TabConfig, TabContent\n\nclass DynamicContent(TabContent):\n    def setup_content(self):\n        data = self.config.data\n        tk.Label(self.frame, text=f\"Dynamic tab: {data.get('content', 'No content')}\").pack()\n\ndef create_dynamic_tab(tab_manager, counter):\n    \"\"\"Create a new tab dynamically\"\"\"\n    tab_id = f\"dynamic_{counter}\"\n    config = TabConfig(\n        id=tab_id,\n        title=f\"Dynamic {counter}\",\n        content_class=DynamicContent,\n        data={\"content\": f\"This is dynamic tab #{counter}\"}\n    )\n\n    tab_manager.add_tab_config(config)\n    tab_manager.open_tab(tab_id)\n\n# Usage in your application\nroot = tk.Tk()\ntab_manager = TabManager(root, tab_configs=[], opener_type=\"toolbar\")\n\n# Add button to create new tabs\ncounter = 1\ndef add_tab():\n    global counter\n    create_dynamic_tab(tab_manager, counter)\n    counter += 1\n\ntk.Button(root, text=\"Add Tab\", command=add_tab).pack()\ntab_manager.pack(fill=tk.BOTH, expand=True)\n```\n\n## Styling and Customization\n\n### Custom Tooltip Styling\n\nThe library includes built-in tooltips that can be customized by modifying the `TooltipWidget` class or by styling the underlying tkinter widgets.\n\n### Toast Notifications\n\nBuilt-in toast notification system with four types:\n\n- `info` (blue) - General information\n- `warning` (yellow) - Warnings\n- `error` (red) - Error messages\n- `success` (green) - Success messages\n\n### TTK Styling and Compatibility\n\nFlexTabs preserves full compatibility with `ttk.Notebook` styling and behavior:\n\n```python\nimport tkinter.ttk as ttk\n\n# All standard ttk.Notebook features work\nstyle = ttk.Style()\nstyle.configure(\"Custom.TNotebook\", background=\"lightgray\")\nstyle.configure(\"Custom.TNotebook.Tab\", padding=[20, 10])\n\n# FlexTabs respects ttk themes\nstyle.theme_use('clam')  # or 'alt', 'default', 'classic'\n\ntab_manager = TabManager(\n    parent,\n    tab_configs=tabs,\n    notebook_config={\"style\": \"Custom.TNotebook\"}\n)\n\n# Access underlying ttk.Notebook for direct manipulation\nnotebook = tab_manager.notebook\nprint(f\"Current tab: {notebook.select()}\")\nprint(f\"All tabs: {notebook.tabs()}\")\n```\n\n### Migrating from ttk.Notebook\n\nIf you have existing `ttk.Notebook` code, migration is straightforward:\n\n**Before (ttk.Notebook):**\n\n```python\nnotebook = ttk.Notebook(parent)\nframe = ttk.Frame(notebook)\nnotebook.add(frame, text=\"My Tab\")\n# Content goes directly in frame\n```\n\n**After (FlexTabs):**\n\n```python\nclass MyTab(TabContent):\n    def setup_content(self):\n        # Content goes in self.frame\n        pass\n\nconfig = TabConfig(\"my_tab\", \"My Tab\", MyTab)\ntab_manager = TabManager(parent, [config], opener_type=\"toolbar\")\n```\n\n## Requirements\n\n- Python 3.8+\n- tkinter (usually included with Python)\n- Pillow (PIL) for image icon support\n\n## API Reference\n\nFor the complete API reference got to [FlexTabs API Documentation](https://ms-32154.github.io/flextabs/) or see the source code.\n\n### Enums\n\n- `TabPosition`: TOP, BOTTOM, LEFT, RIGHT\n- `CloseMode`: ACTIVE_ONLY, ANY_VISIBLE, BOTH\n- `CloseConfirmationType`: NONE, YESNO, WARNING, INFO\n\n### Classes\n\n- `TabConfig`: Tab configuration dataclass\n- `TabContent`: Base class for tab content\n- `TabOpener`: Base class for tab openers\n- `TabManager`: Main tab management widget\n- `IconManager`: Icon loading and caching\n- `TooltipWidget`: Tooltip implementation\n- `ToastNotification`: Notification system\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## Support\n\nIf you encounter any issues or have questions, please:\n\n1. Check the [examples](#examples) section\n2. Search existing [GitHub Issues](https://github.com/MS-32154/flextabs/issues)\n3. Create a new issue with:\n   - Python version\n   - Operating system\n   - Minimal code example reproducing the issue\n   - Full error traceback (if applicable)\n\n## Roadmap\n\n- [x] Icon support for tabs and buttons\n- [ ] Drag and drop tab reordering\n- [ ] Tab groups and separators\n- [ ] Persistent tab state between sessions\n- [ ] Theme system\n- [ ] Animation effects\n- [ ] Tab overflow handling\n\n---\n\n**FlexTabs** \u2013 Extending `ttk.Notebook` for powerful and flexible tab management in Tkinter.\n\n\u00a9 2025 MS-32154. All rights reserved.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A flexible and extensible tab manager widget for tkinter applications built on top of ttk.Notebook",
    "version": "0.2.0",
    "project_urls": {
        "Bug Reports": "https://github.com/MS-32154/flextabs/issues",
        "Homepage": "https://github.com/MS-32154/flextabs",
        "Source": "https://github.com/MS-32154/flextabs"
    },
    "split_keywords": [
        "tkinter",
        " ttk",
        " notebook",
        " tabs",
        " gui",
        " widget",
        " interface"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2c54ea6c4370b4ecf6a7329fe75706e46cd33c0968c447f13a5db2a9042467e4",
                "md5": "0a11c82c29e0aca6c4463ca3b8229fd6",
                "sha256": "af727c536c3b4cca5ce068bb3924410143d79b4a8c20756736470e2cad89f2e8"
            },
            "downloads": -1,
            "filename": "flextabs-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0a11c82c29e0aca6c4463ca3b8229fd6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 35623,
            "upload_time": "2025-08-06T19:25:31",
            "upload_time_iso_8601": "2025-08-06T19:25:31.779349Z",
            "url": "https://files.pythonhosted.org/packages/2c/54/ea6c4370b4ecf6a7329fe75706e46cd33c0968c447f13a5db2a9042467e4/flextabs-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8efdd3e0c08d41c1f2d7ef1cd9da0921c63eb67b40cd9cce03d054286d3a143d",
                "md5": "74b58f6c28849522450a2934ed858db2",
                "sha256": "017ac2d078bb7e5e5403f812d701b2991b7373453f1c6b5402944435ad0bcdf5"
            },
            "downloads": -1,
            "filename": "flextabs-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "74b58f6c28849522450a2934ed858db2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 39019,
            "upload_time": "2025-08-06T19:25:32",
            "upload_time_iso_8601": "2025-08-06T19:25:32.692467Z",
            "url": "https://files.pythonhosted.org/packages/8e/fd/d3e0c08d41c1f2d7ef1cd9da0921c63eb67b40cd9cce03d054286d3a143d/flextabs-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-06 19:25:32",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "MS-32154",
    "github_project": "flextabs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "flextabs"
}
        
Elapsed time: 1.26636s