Complete Guide to Acrylic Effects in Qt
We're thrilled to introduce our comprehensive Acrylic Effect system for Qt applications - a complete solution for bringing professional-grade transparency effects to your PyQt and PySide GUIs.
What is Acrylic? Acrylic is a Fluent Design System material that creates a translucent texture using background blur and noise. It's the beautiful frosted glass effect you see throughout Windows 11 and modern applications.
Why Acrylic Effects Matter
Modern UI Standard: Acrylic effects have become the gold standard for modern application design, offering:
- Visual depth and hierarchy
- Context awareness through background blur
- Premium, polished appearance
- Enhanced user experience
Architecture Overview
The Acrylic Effect system is built on a robust, multi-layered architecture:
┌─────────────────────────────────┐
│ AcrylicEffect │ ← User-facing API
├─────────────────────────────────┤
│ AcrylicBrush │ ← Rendering Engine
├─────────────────────────────────┤
│ GaussianBlurUtils │ ← Blur Processing
├─────────────────────────────────┤
│ DominantColor │ ← Color Analysis
├─────────────────────────────────┤
│ AcrylicTextureLabel │ ← Noise Generation
└─────────────────────────────────┘
Core Components Deep Dive
1. GaussianBlurUtils - The Blur Engine
Performance Note: The blur system uses SciPy's gaussian_filter for high-quality blurring. For large images, consider using the blurPicSize parameter to scale down before processing.
# High-quality blur with optimization
blurred_pixmap = GaussianBlurUtils.gaussianBlur(
image="background.jpg",
blurRadius=18, # Control blur intensity
brightFactor=0.85, # Prevent over-brightening
blurPicSize=(400, 400) # Performance optimization
)
# Support for multiple image sources
sources = [
"image.jpg", # File path
QPixmap(":/images/bg.png"), # Qt resource
QImage(100, 100, QImage.Format_RGB32) # Dynamic image
]
2. DominantColor - Intelligent Color Analysis
Pro Tip: Use dominant color extraction to automatically create harmonious tint colors that match your background content.
# Extract dominant color palette
dominant_color = DominantColor.getDominantColor(
"background.jpg",
defaultColor=(24, 24, 24) # Fallback color
)
# Advanced color analysis
palette = color_thief.get_palette(quality=9)
filtered_palette = [rgb for rgb in palette if colorfulness(rgb) > threshold]
3. AcrylicBrush - The Rendering Workhorse
# Complete acrylic brush setup
brush = AcrylicBrush(
device=widget,
blurRadius=15,
tintColor=QColor(242, 242, 242, 150), # Base tint
luminosityColor=QColor(255, 255, 255, 10), # Light layer
noiseOpacity=0.03 # Texture detail
)
# Multi-monitor screen capture
brush.grabFromScreen(rect) # Automatically detects correct screen
Complete Implementation Guide
Basic Setup
Quick Start: The simplest way to apply acrylic effects to any widget with just 3 lines of code.
from Custom_Widgets.AcrylicEffect import AcrylicEffect
from qtpy.QtWidgets import QWidget
from qtpy.QtGui import QColor
class SimpleAcrylicWidget(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 400, 300)
# 1. Create acrylic effect
self.acrylic = AcrylicEffect(
widget=self,
blurRadius=20,
tintColor=QColor(150, 150, 200, 120)
)
# 2. Apply to widget
self.acrylic.applyToWidget()
# 3. Capture background
self.acrylic.grabFromScreen()
Advanced Configuration
# Professional-grade setup
acrylic = AcrylicEffect(
widget=widget,
blurRadius=25, # Strong blur for emphasis
tintColor=QColor(45, 45, 65, 180), # Dark blue tint
luminosityColor=QColor(255, 255, 255, 8), # Subtle luminosity
noiseOpacity=0.04 # Visible texture
)
# Dynamic property updates
acrylic.setBlurRadius(30) # Adjust blur in real-time
acrylic.setTintColor(QColor(200, 150, 150, 100)) # Change tint color
# Custom clipping for shaped effects
path = QPainterPath()
path.addRoundedRect(QRectF(10, 10, 200, 100), 15, 15)
acrylic.setClipPath(path)
Real-World Examples
Example 1: Acrylic Sidebar Navigation
Perfect For: Application sidebars, settings panels, and navigation drawers where you want content to show through subtly.
class AcrylicSidebar(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedWidth(280)
self.setup_ui()
self.setup_acrylic()
def setup_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(15, 40, 15, 20)
layout.setSpacing(8)
# Header
header = QLabel("Navigation")
header.setStyleSheet("""
color: white;
font-size: 18px;
font-weight: bold;
padding: 10px;
""")
layout.addWidget(header)
layout.addWidget(QFrame(frameShape=QFrame.HLine))
# Navigation items
nav_items = ["Dashboard", "Projects", "Team", "Calendar", "Settings"]
for item in nav_items:
btn = QPushButton(item)
btn.setFixedHeight(40)
btn.setStyleSheet("""
QPushButton {
background: rgba(255,255,255,20);
border: none;
border-radius: 5px;
color: white;
text-align: left;
padding: 0 15px;
font-size: 14px;
}
QPushButton:hover {
background: rgba(255,255,255,40);
}
""")
layout.addWidget(btn)
layout.addStretch()
def setup_acrylic(self):
self.acrylic_effect = AcrylicEffect(
widget=self,
blurRadius=25,
tintColor=QColor(40, 40, 60, 200), # Dark blue tint
luminosityColor=QColor(255, 255, 255, 12),
noiseOpacity=0.03
)
self.acrylic_effect.applyToWidget()
def showEvent(self, event):
super().showEvent(event)
# Delay background capture to ensure proper positioning
QTimer.singleShot(50, self.acrylic_effect.grabFromScreen)
Example 2: Smart Dashboard Cards
Intelligent Design: These cards automatically extract dominant colors from their backgrounds to create harmonious tint colors.
class SmartAcrylicCard(QWidget):
def __init__(self, title, background_image=None):
super().__init__()
self.title = title
self.background_image = background_image
self.setFixedSize(250, 180)
self.setup_ui()
self.setup_smart_acrylic()
def setup_smart_acrylic(self):
if self.background_image:
# Intelligent color extraction
dominant_rgb = AcrylicEffect.getDominantColor(self.background_image)
r, g, b = dominant_rgb
# Create complementary tint
tint_color = QColor(r, g, b, 80)
# Adjust luminosity based on brightness
brightness = (r * 0.299 + g * 0.587 + b * 0.114)
luminosity = QColor(255, 255, 255, 8) if brightness < 128 else QColor(0, 0, 0, 8)
else:
# Default aesthetic
tint_color = QColor(100, 120, 180, 120)
luminosity = QColor(255, 255, 255, 10)
self.acrylic = AcrylicEffect(
widget=self,
blurRadius=20,
tintColor=tint_color,
luminosityColor=luminosity,
noiseOpacity=0.04
)
self.acrylic.applyToWidget()
# Set background source
if self.background_image:
self.acrylic.setImage(self.background_image)
else:
QTimer.singleShot(100, self.acrylic.grabFromScreen)
Example 3: Floating Action Panel
Performance Consideration: For floating panels that move, consider caching the blurred background or using static images to avoid frequent re-captures.
class FloatingAcrylicPanel(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedSize(300, 200)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setup_ui()
self.setup_acrylic()
def setup_acrylic(self):
self.acrylic_effect = AcrylicEffect(
widget=self,
blurRadius=30, # Strong blur for floating effect
tintColor=QColor(255, 255, 255, 180), # Light tint
luminosityColor=QColor(255, 255, 255, 15),
noiseOpacity=0.02
)
self.acrylic_effect.applyToWidget()
def moveEvent(self, event):
super().moveEvent(event)
# Update background when moved
QTimer.singleShot(50, self.acrylic_effect.grabFromScreen)
Integration with Other Components
With Hamburger Menu System
class AcrylicHamburgerMenu(QCustomHamburgerMenu):
def __init__(self, parent=None):
super().__init__(parent)
self.enable_acrylic_effect()
def enable_acrylic_effect(self):
# Enable built-in acrylic support
self._acrylicEnabled = True
self._acrylicBlurRadius = 20
self._acrylicTintColor = QColor(45, 45, 45, 220)
self._acrylicLuminosityColor = QColor(255, 255, 255, 8)
self._acrylicNoiseOpacity = 0.03
# The QHamburgerMenuOverlay will automatically handle acrylic rendering
With Custom Main Window
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_acrylic_regions()
def setup_acrylic_regions(self):
# Apply acrylic to specific regions
regions = [
(self.sidebar, 25, QColor(40, 40, 60, 180)),
(self.toolbar, 15, QColor(255, 255, 255, 150)),
(self.status_panel, 20, QColor(30, 30, 30, 200))
]
self.acrylic_effects = []
for widget, blur_radius, tint_color in regions:
effect = AcrylicEffect(
widget=widget,
blurRadius=blur_radius,
tintColor=tint_color
)
effect.applyToWidget()
self.acrylic_effects.append(effect)
# Capture backgrounds after window is shown
QTimer.singleShot(100, self.capture_all_backgrounds)
def capture_all_backgrounds(self):
for effect in self.acrylic_effects:
effect.grabFromScreen()
Performance Optimization Strategies
Critical: Acrylic effects can be computationally expensive. Follow these optimization guidelines for best performance.
1. Smart Blur Configuration
# ✅ Recommended settings
optimal_settings = AcrylicEffect(
widget=widget,
blurRadius=15, # Good balance of quality/performance
blurPicSize=(400, 400) # Scale large backgrounds
)
# ❌ Avoid these in performance-critical scenarios
expensive_settings = AcrylicEffect(
widget=widget,
blurRadius=40, # Very expensive
blurPicSize=None # No optimization
)
2. Efficient Update Patterns
class OptimizedAcrylicWidget(QWidget):
def __init__(self):
super().__init__()
self.last_background_capture = 0
self.capture_interval = 500 # ms
def request_background_update(self):
current_time = QDateTime.currentMSecsSinceEpoch()
if current_time - self.last_background_capture > self.capture_interval:
self.acrylic_effect.grabFromScreen()
self.last_background_capture = current_time
3. Caching Strategies
# Cache blurred backgrounds for static content
class CachedAcrylicEffect(AcrylicEffect):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.background_cache = {}
def grabFromScreen(self, rect=None):
cache_key = f"{rect}" if rect else "full"
if cache_key not in self.background_cache:
super().grabFromScreen(rect)
self.background_cache[cache_key] = self.acrylicBrush.image
else:
self.acrylicBrush.image = self.background_cache[cache_key]
self.widget.update()
Troubleshooting Guide
Common Issues and Solutions
Problem: Acrylic effect not appearing Solution:
- Call
applyToWidget()after widget construction - Ensure widget is visible and has valid size
- Verify
grabFromScreen()is called after widget is shown - Check that widget has
WA_TranslucentBackgroundattribute
Problem: Poor performance Solution:
- Reduce
blurRadius(15-25 recommended) - Use
blurPicSizeto scale large images - Avoid applying to very large widgets
- Cache backgrounds for static content
# Debugging helper
def debug_acrylic_setup(widget, effect):
print(f"Widget visible: {widget.isVisible()}")
print(f"Widget size: {widget.size()}")
print(f"Effect applied: {hasattr(widget, 'acrylic_effect')}")
print(f"Background valid: {not effect.acrylicBrush.image.isNull()}")
Multi-Monitor Support
The system automatically handles multi-monitor setups:
# No special configuration needed - it just works!
effect.grabFromScreen() # Automatically detects correct screen
# Manual screen selection (advanced)
screen = QApplication.screenAt(global_pos)
if screen:
pixmap = screen.grabWindow(0, x, y, width, height)
effect.setImage(pixmap)
Browser Compatibility Matrix
| Platform | PyQt5 | PyQt6 | PySide2 | PySide6 |
|---|---|---|---|---|
| Full Support | ✅ | ✅ | ✅ | ✅ |
| Multi-Monitor | ✅ | ✅ | ✅ | ✅ |
| Performance | Excellent | Excellent | Excellent | Excellent |
Installation and Setup
# Install the complete widget library
pip install QT-PyQt-PySide-Custom-Widgets
# Or install from source for latest features
pip install git+https://github.com/SpinnCompany/QT-PyQt-PySide-Custom-Widgets.git
Dependencies
The Acrylic Effect system requires:
Required:
- PyQt5/PyQt6/PySide2/PySide6
- Pillow (PIL)
- color-thief-py
Optional (for enhanced performance):
- numpy
- scipy
Conclusion
The new Acrylic Effect system represents a significant leap forward in Qt UI capabilities. By bringing Windows 11 Fluent Design aesthetics to Python applications, we're empowering developers to create professional, modern interfaces that rival native applications.
Ready to Transform Your UI? Start with the basic examples and gradually incorporate more advanced features as you become comfortable with the system. The result will be applications that look and feel truly premium.
Resources and Next Steps
- GitHub Repository - Full source code and issues
- Documentation - Detailed API references
- Examples Gallery - Ready-to-run demo applications
- Community Discord - Get help and share creations
We can't wait to see what you create with the new Acrylic Effect system! Share your projects and experiences with our community. 🎨
