Button Panel Component
Reusable button panel with declarative configuration.
Module: pyqt_reactive.widgets.shared.button_panel
Overview
ButtonPanel provides a reusable button panel component that can be used by any widget without requiring inheritance. It uses a declarative BUTTON_CONFIGS format for specifying buttons.
This component was extracted from AbstractManagerWidget to allow widgets to use the same button panel pattern without inheriting from the full manager class.
Architecture
ButtonPanel uses a simple declarative configuration:
BUTTON_CONFIGS = [
("Refresh", "refresh", "Refresh the display"),
("Toggle", "toggle_layout", "Toggle between layouts"),
("Export", "export", "Export data"),
]
Each button configuration is a tuple of: - label: Button text (e.g., “Refresh”) - action_id: Identifier passed to callback (e.g., “refresh”) - tooltip: Tooltip text (e.g., “Refresh the display”)
Usage
Basic Usage
from pyqt_reactive.widgets.shared.button_panel import ButtonPanel
from pyqt_reactive.theming import StyleSheetGenerator
# Define button configurations
BUTTON_CONFIGS = [
("Refresh", "refresh", "Refresh the display"),
("Toggle", "toggle_layout", "Toggle between layouts"),
("Export", "export", "Export data"),
]
# Create button panel
panel = ButtonPanel(
button_configs=BUTTON_CONFIGS,
on_action=self.handle_button_action,
style_generator=self.style_generator,
)
# Add panel to layout
layout.addWidget(panel)
Action Handler
The on_action callback receives the action_id from the clicked button:
def handle_button_action(self, action_id: str):
"""Handle button actions."""
if action_id == "refresh":
self.refresh_display()
elif action_id == "toggle_layout":
self.toggle_layout()
elif action_id == "export":
self.export_data()
Grid Layout
By default, buttons are laid out in a single horizontal row. You can specify a grid layout:
panel = ButtonPanel(
button_configs=self.BUTTON_CONFIGS,
on_action=self.handle_button_action,
grid_columns=2, # 2 columns
)
This creates a grid with the specified number of columns:
grid_columns |
Layout |
|---|---|
0 |
Single horizontal row |
1 |
Single vertical column |
2 |
2x2 grid |
3 |
3x2 grid |
4 |
4x2 grid |
Integration with SystemMonitor
SystemMonitor uses ButtonPanel for its action buttons:
class SystemMonitorWidget(QWidget):
"""System Monitor Widget."""
# Declarative button configuration
BUTTON_CONFIGS = [
("Global Config", "global_config", "Open global configuration editor"),
("Log Viewer", "log_viewer", "Open log viewer window"),
("Custom Functions", "custom_functions", "Manage custom functions"),
("Test Plate", "test_plate", "Generate synthetic test plate"),
]
BUTTON_GRID_COLUMNS = 0 # Single row
def __init__(self, color_scheme=None, config=None, parent=None):
super().__init__(parent)
# Create button panel
self.button_panel = ButtonPanel(
button_configs=self.BUTTON_CONFIGS,
style_generator=self.style_generator,
grid_columns=self.BUTTON_GRID_COLUMNS,
)
# Connect actions
self.button_panel.action_triggered.connect(self.handle_button_action)
def handle_button_action(self, action_id: str):
"""Handle button panel actions."""
if action_id == "global_config":
self.show_global_config.emit()
elif action_id == "log_viewer":
self.show_log_viewer.emit()
# ... etc
Styling
ButtonPanel integrates with StyleSheetGenerator for consistent styling:
from pyqt_reactive.theming import StyleSheetGenerator, ColorScheme
color_scheme = ColorScheme()
style_generator = StyleSheetGenerator(color_scheme)
panel = ButtonPanel(
button_configs=self.BUTTON_CONFIGS,
on_action=self.handle_button_action,
style_generator=style_generator, # Apply styles
)
Signals
action_triggered (pyqtSignal)
Emitted when a button is clicked. Provides the action_id:
panel.action_triggered.connect(lambda action_id: print(f"Action: {action_id}"))
Migration from AbstractManagerWidget
Before (AbstractManagerWidget):
class MyWidget(AbstractManagerWidget):
"""Widget with button panel."""
BUTTON_CONFIGS = [
("Refresh", "refresh", "Refresh the display"),
]
def __init__(self):
super().__init__()
# Button panel created automatically by AbstractManagerWidget
After (ButtonPanel):
class MyWidget(QWidget):
"""Widget with button panel."""
def __init__(self):
super().__init__()
# Create button panel manually
self.button_panel = ButtonPanel(
button_configs=[
("Refresh", "refresh", "Refresh the display"),
],
on_action=self.handle_button_action,
)
def handle_button_action(self, action_id: str):
if action_id == "refresh":
self.refresh()
Benefits
No inheritance required: Use with any widget class
Declarative configuration: Define buttons in a list
Flexible layout: Single row or grid layout
Consistent styling: Integrates with StyleSheetGenerator
Action-based: Simple callback interface with action IDs
See Also
AbstractManagerWidget Architecture - Abstract manager widget (original button panel location)
responsive_layout_widgets - Responsive layout components
PyQt6 System Monitor - System monitor usage example