[](https://pypi.org/project/flextabs/)
[](https://www.python.org/)
[](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": "[](https://pypi.org/project/flextabs/)\n[](https://www.python.org/)\n[](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"
}