PyQt6 System Monitor
Real-time system monitoring with CPU, RAM, GPU, and VRAM usage graphs.
Module: pyqt_reactive.widgets.system_monitor
Overview
SystemMonitorWidget provides real-time system monitoring for PyQt6 applications. It displays graphs for CPU, RAM, GPU, and VRAM usage, migrated from the Textual TUI version with full feature parity.
The widget uses a two-layer architecture:
SystemMonitorCore (framework-agnostic): Handles metric collection
PersistentSystemMonitor (background thread): Non-blocking metrics collection
SystemMonitorWidget (PyQt6): Renders graphs and UI
This separation allows the monitoring core to be reused in both Textual TUI and PyQt6 applications.
Architecture
Component Layers
┌─────────────────────────────────────────────────────────┐
│ SystemMonitorWidget (PyQt6) │
│ ┌──────────────────────────────────────────────┐ │
│ │ SystemMonitorCore (Framework-Agnostic) │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ PersistentSystemMonitor (Thread) │ │ │
│ │ │ - CPU metrics │ │ │
│ │ │ - RAM metrics │ │ │
│ │ │ - GPU/VRAM metrics (if available) │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ UI: │
│ - Real-time graphs (PyQtGraph) │
│ - Current value labels │
│ - Action buttons (ButtonPanel) │
│ - Layout toggle (stacked vs side-by-side) │
└─────────────────────────────────────────────────────────┘
Lazy PyQtGraph Import
PyQtGraph imports cupy at module level, which takes 8+ seconds and blocks GUI startup. SystemMonitorWidget uses lazy loading:
# Import is delayed until graph creation
PYQTGRAPH_AVAILABLE = None # None = not checked
pg = None # Will be set when pyqtgraph is imported
def create_pyqtgraph_section(self):
"""Create graphs - loads pyqtgraph lazily."""
global PYQTGRAPH_AVAILABLE, pg
if PYQTGRAPH_AVAILABLE is None:
try:
import pyqtgraph as pg # Lazy import
PYQTGRAPH_AVAILABLE = True
except ImportError:
PYQTGRAPH_AVAILABLE = False
if PYQTGRAPH_AVAILABLE:
# Create graphs using pg module
self.cpu_plot = pg.PlotWidget()
# ...
Usage
Basic Usage
from pyqt_reactive.widgets.system_monitor import SystemMonitorWidget
from pyqt_reactive.theming import ColorScheme
# Create widget
color_scheme = ColorScheme()
monitor = SystemMonitorWidget(
color_scheme=color_scheme,
config=None, # Optional: use default config
)
# Add to layout
layout.addWidget(monitor)
Signals
metrics_updated (pyqtSignal)
Emitted when new metrics are collected:
monitor.metrics_updated.connect(self.on_metrics_updated)
def on_metrics_updated(self, metrics):
cpu = metrics.get('cpu_percent')
ram = metrics.get('ram_percent')
# ...
show_global_config (pyqtSignal)
Request to show global configuration.
show_log_viewer (pyqtSignal)
Request to show log viewer window.
show_custom_functions (pyqtSignal)
Request to show custom functions manager.
show_test_plate_generator (pyqtSignal)
Request to show synthetic plate generator.
Layout Modes
SystemMonitor supports two layout modes:
Stacked Layout (default):
┌─────────────────────────────────┐
│ CPU: 45% │
│ ┌─────────────────────────┐ │
│ │ CPU Graph │ │
│ └─────────────────────────┘ │
│ │
│ RAM: 62% │
│ ┌─────────────────────────┐ │
│ │ RAM Graph │ │
│ └─────────────────────────┘ │
│ │
│ GPU: 78% VRAM: 85% │
│ ┌─────────────────────────┐ │
│ │ GPU/VRAM Graph │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
Side-by-Side Layout:
┌─────────────────┬─────────────────┐
│ CPU: 45% │ RAM: 62% │
│ ┌───────────┐ │ ┌───────────┐ │
│ │ CPU │ │ │ RAM │ │
│ │ Graph │ │ │ Graph │ │
│ └───────────┘ │ └───────────┘ │
├─────────────────┼─────────────────┤
│ GPU: 78% │ VRAM: 85% │
│ ┌───────────┐ │ ┌───────────┐ │
│ │ GPU/VRAM │ │ │ │ │
│ │ Graph │ │ │ │ │
│ └───────────┘ │ └───────────┘ │
└─────────────────┴─────────────────┘
Toggle between layouts:
monitor.toggle_layout() # Switch between stacked and side-by-side
Configuration
Update Interval
Metrics collection interval (in seconds):
# Default: 2 seconds
monitor = SystemMonitorWidget(update_interval_seconds=2.0)
# Faster updates (1 second)
monitor = SystemMonitorWidget(update_interval_seconds=1.0)
History Length
Number of data points to keep in history:
# Default: 300 points (5 minutes at 1-second interval)
monitor = SystemMonitorWidget(history_length=300)
# Longer history (600 points = 10 minutes)
monitor = SystemMonitorWidget(history_length=600)
Graph Styling
Graph colors and styles can be customized:
# Default colors (from ColorScheme)
CPU_COLOR = (255, 100, 100) # Red
RAM_COLOR = (100, 255, 100) # Green
GPU_COLOR = (100, 100, 255) # Blue
VRAM_COLOR = (255, 255, 100) # Yellow
GPU Detection
SystemMonitor automatically detects available GPUs:
# If GPU is available:
if monitor.gpu_count > 0:
# GPU and VRAM graphs will be shown
gpu_metrics = monitor.current_metrics.get('gpu_percent')
vram_metrics = monitor.current_metrics.get('vram_percent')
# If no GPU:
if monitor.gpu_count == 0:
# Only CPU and RAM graphs shown
# GPU/VRAM section hidden
Performance Considerations
PyQtGraph OpenGL Acceleration
On systems with OpenGL 3.3+, PyQtGraph uses OpenGL for rendering:
# Auto-detected and used if available
# No configuration needed
Fallback to QPainter
If OpenGL is not available, PyQtGraph falls back to QPainter (CPU rendering):
# Automatic fallback - no code changes needed
Thread-Safe Metrics
PersistentSystemMonitor runs in a background thread and uses thread-safe data structures:
# Metrics are collected in background thread
# Updates are posted to main thread via signals
monitor.metrics_updated.emit(metrics)
Integration with ServiceRegistry
SystemMonitor integrates with ServiceRegistry for widget access:
from pyqt_reactive.services import ServiceRegistry
from pyqt_reactive.widgets.system_monitor import SystemMonitorWidget
# Create and register
monitor = SystemMonitorWidget()
# Auto-registers via AutoRegisterServiceMixin (if subclassed)
# Access anywhere
from pyqt_reactive.services import ServiceRegistry
monitor = ServiceRegistry.get(SystemMonitorWidget)
Migration from Textual TUI
Feature Parity
The PyQt6 version maintains feature parity with the Textual TUI version:
✅ CPU monitoring with graph
✅ RAM monitoring with graph
✅ GPU monitoring (if available)
✅ VRAM monitoring (if available)
✅ Configurable update interval
✅ Configurable history length
✅ Multiple layout modes
✅ Action buttons
Differences
|---------|—————|--------| | Rendering | Terminal text | PyQtGraph widgets | | Interactivity | Keyboard-driven | Mouse-clickable | | Update Mechanism | Timer callback | Background thread | | Layout | Fixed | Resizable (QSplitter) |
See Also
System Monitor Core - Framework-agnostic monitoring core
Persistent System Monitor - Background thread monitor
Button Panel Component - Button panel component
GUI Performance Patterns - Performance optimization patterns