A fluent design widgets library based on PyQt5 providing modern Windows 11-style UI components
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Setting cards, configuration management, and option panels for building preference interfaces with validation and persistence. These components provide a modern approach to application settings with fluent design integration.
Pre-built setting cards for common configuration options with automatic validation and fluent design styling.
class SettingCard(QWidget):
def __init__(self, icon: Union[FluentIconBase, QIcon, str], title: str, content: str = None, parent=None): ...
def setTitle(self, title: str): ...
def setContent(self, content: str): ...
def setValue(self, value): ...
def value(self): ...
class SwitchSettingCard(SettingCard):
def __init__(self, icon: Union[FluentIconBase, QIcon, str], title: str, content: str = None,
configItem: ConfigItem = None, parent=None): ...
def setChecked(self, checked: bool): ...
def isChecked(self) -> bool: ...
checkedChanged = pyqtSignal(bool)
class ComboBoxSettingCard(SettingCard):
def __init__(self, configItem: ConfigItem, icon: Union[FluentIconBase, QIcon, str],
title: str, content: str = None, texts: List[str] = None, parent=None): ...
def setCurrentIndex(self, index: int): ...
def setCurrentText(self, text: str): ...
def currentIndex(self) -> int: ...
def currentText(self) -> str: ...
class RangeSettingCard(SettingCard):
def __init__(self, configItem: ConfigItem, icon: Union[FluentIconBase, QIcon, str],
title: str, content: str = None, parent=None): ...
def setRange(self, min: int, max: int): ...
def setValue(self, value: int): ...
def value(self) -> int: ...Usage Example:
from qfluentwidgets import (SwitchSettingCard, ComboBoxSettingCard, RangeSettingCard,
FluentIcon as FIF, ConfigItem, qconfig)
# Switch setting
auto_save_card = SwitchSettingCard(
FIF.SAVE,
"Auto Save",
"Automatically save documents every 5 minutes"
)
auto_save_card.setChecked(True)
auto_save_card.checkedChanged.connect(self.on_auto_save_changed)
# Combo box setting
theme_card = ComboBoxSettingCard(
qconfig.theme, # Config item
FIF.BRUSH,
"Theme",
"Choose the application theme",
texts=["Light", "Dark", "Auto"]
)
theme_card.setCurrentText("Auto")
# Range setting
volume_card = RangeSettingCard(
qconfig.volume,
FIF.VOLUME,
"Volume",
"Adjust the application volume"
)
volume_card.setRange(0, 100)
volume_card.setValue(75)Specialized setting cards for complex configuration options.
class PushSettingCard(SettingCard):
def __init__(self, text: str, icon: Union[FluentIconBase, QIcon, str],
title: str, content: str = None, parent=None): ...
def setButtonText(self, text: str): ...
def buttonText(self) -> str: ...
clicked = pyqtSignal()
class ColorSettingCard(SettingCard):
def __init__(self, configItem: ConfigItem, icon: Union[FluentIconBase, QIcon, str],
title: str, content: str = None, enableAlpha: bool = False, parent=None): ...
def setColor(self, color: QColor): ...
def color(self) -> QColor: ...
colorChanged = pyqtSignal(QColor)
class HyperlinkCard(SettingCard):
def __init__(self, url: str, text: str, icon: Union[FluentIconBase, QIcon, str],
title: str, content: str = None, parent=None): ...
def setUrl(self, url: str): ...
def setText(self, text: str): ...
class ExpandSettingCard(SettingCard):
def __init__(self, icon: Union[FluentIconBase, QIcon, str], title: str, content: str = None, parent=None): ...
def addWidget(self, widget: QWidget): ...
def setExpanded(self, expanded: bool): ...
def isExpanded(self) -> bool: ...
expandedChanged = pyqtSignal(bool)Usage Example:
from qfluentwidgets import (PushSettingCard, ColorSettingCard, HyperlinkCard,
ExpandSettingCard, FluentIcon as FIF)
# Button setting card
export_card = PushSettingCard(
"Export Settings",
FIF.SHARE,
"Export Configuration",
"Export your settings to a file"
)
export_card.clicked.connect(self.export_settings)
# Color setting card
accent_card = ColorSettingCard(
qconfig.themeColor,
FIF.PALETTE,
"Accent Color",
"Choose your preferred accent color",
enableAlpha=False
)
accent_card.colorChanged.connect(self.on_accent_color_changed)
# Hyperlink card
docs_card = HyperlinkCard(
"https://docs.example.com",
"View Documentation",
FIF.DOCUMENT,
"Help & Support",
"Access online documentation and tutorials"
)
# Expandable setting card
advanced_card = ExpandSettingCard(
FIF.DEVELOPER_TOOLS,
"Advanced Settings",
"Configure advanced options"
)
# Add widgets to expandable card
debug_switch = SwitchSettingCard(FIF.BUG, "Debug Mode", "Enable debug logging")
cache_button = PushSettingCard("Clear Cache", FIF.DELETE, "Cache", "Clear application cache")
advanced_card.addWidget(debug_switch)
advanced_card.addWidget(cache_button)Containers for organizing related setting cards with proper spacing and grouping.
class SettingCardGroup(QWidget):
def __init__(self, title: str, parent=None): ...
def addSettingCard(self, card: SettingCard): ...
def addSettingCards(self, cards: List[SettingCard]): ...
def setTitle(self, title: str): ...
def title(self) -> str: ...Usage Example:
from qfluentwidgets import SettingCardGroup
# Create setting groups
appearance_group = SettingCardGroup("Appearance", self)
appearance_group.addSettingCard(theme_card)
appearance_group.addSettingCard(accent_card)
behavior_group = SettingCardGroup("Behavior", self)
behavior_group.addSettingCard(auto_save_card)
behavior_group.addSettingCard(volume_card)
advanced_group = SettingCardGroup("Advanced", self)
advanced_group.addSettingCard(advanced_card)
advanced_group.addSettingCard(export_card)
# Layout groups in settings interface
settings_layout = QVBoxLayout()
settings_layout.addWidget(appearance_group)
settings_layout.addWidget(behavior_group)
settings_layout.addWidget(advanced_group)Robust configuration management with validation, serialization, and automatic persistence.
class QConfig(QObject):
def __init__(self): ...
def get(self, item: ConfigItem): ...
def set(self, item: ConfigItem, value, save: bool = True): ...
def save(self): ...
def load(self, file: str = None): ...
configChanged = pyqtSignal(ConfigItem, object)
class ConfigItem:
def __init__(self, group: str, name: str, default, validator: ConfigValidator = None,
serializer: ConfigSerializer = None, restart: bool = False): ...
def value(self): ...
def setValue(self, value): ...
class RangeConfigItem(ConfigItem):
def __init__(self, group: str, name: str, default: Union[int, float],
range: Tuple[Union[int, float], Union[int, float]], validator: ConfigValidator = None): ...
class OptionsConfigItem(ConfigItem):
def __init__(self, group: str, name: str, default, options: List, validator: ConfigValidator = None): ...
class ColorConfigItem(ConfigItem):
def __init__(self, group: str, name: str, default: QColor, validator: ConfigValidator = None): ...Usage Example:
from qfluentwidgets import QConfig, ConfigItem, RangeConfigItem, OptionsConfigItem, ColorConfigItem
# Create global config instance
qconfig = QConfig()
# Define configuration items
class Config:
# Basic config items
auto_save = ConfigItem("General", "AutoSave", True)
language = OptionsConfigItem("General", "Language", "English", ["English", "Spanish", "French"])
# Range config
volume = RangeConfigItem("Audio", "Volume", 75, (0, 100))
# Color config
theme_color = ColorConfigItem("Theme", "AccentColor", QColor(0, 120, 212))
# Register with global config
for item in [Config.auto_save, Config.language, Config.volume, Config.theme_color]:
qconfig.addConfigItem(item)
# Load configuration
qconfig.load("config.json")
# Use configuration values
if qconfig.get(Config.auto_save):
self.enable_auto_save()
# React to changes
qconfig.configChanged.connect(self.on_config_changed)
def on_config_changed(self, item, value):
if item == Config.theme_color:
self.update_theme_color(value)Input validation for configuration values with custom validation logic.
class ConfigValidator:
def validate(self, value) -> bool: ...
def correct(self, value): ...
class RangeValidator(ConfigValidator):
def __init__(self, min_value: Union[int, float], max_value: Union[int, float]): ...
class OptionsValidator(ConfigValidator):
def __init__(self, options: List): ...
class BoolValidator(ConfigValidator): ...
class FolderValidator(ConfigValidator): ...
class FolderListValidator(ConfigValidator): ...
class ColorValidator(ConfigValidator): ...Usage Example:
from qfluentwidgets import RangeValidator, OptionsValidator, ColorValidator
# Custom validator
class EmailValidator(ConfigValidator):
def validate(self, value):
return "@" in str(value) and "." in str(value).split("@")[-1]
def correct(self, value):
if not self.validate(value):
return "user@example.com"
return value
# Configuration with validation
email_config = ConfigItem(
"User",
"Email",
"user@example.com",
validator=EmailValidator()
)
# Range validation
volume_config = RangeConfigItem(
"Audio",
"Volume",
50,
(0, 100),
validator=RangeValidator(0, 100)
)
# Options validation
theme_config = OptionsConfigItem(
"Appearance",
"Theme",
"Auto",
["Light", "Dark", "Auto"],
validator=OptionsValidator(["Light", "Dark", "Auto"])
)Custom serialization for complex configuration data types.
class ConfigSerializer:
def serialize(self, value) -> str: ...
def deserialize(self, value: str): ...
class EnumSerializer(ConfigSerializer):
def __init__(self, enum_class): ...
class ColorSerializer(ConfigSerializer): ...Usage Example:
from qfluentwidgets import EnumSerializer, ColorSerializer
from enum import Enum
# Enum serialization
class Priority(Enum):
LOW = 1
MEDIUM = 2
HIGH = 3
priority_config = ConfigItem(
"Tasks",
"DefaultPriority",
Priority.MEDIUM,
serializer=EnumSerializer(Priority)
)
# Color serialization
color_config = ConfigItem(
"Theme",
"AccentColor",
QColor(0, 120, 212),
serializer=ColorSerializer()
)
# Custom serializer
class ListSerializer(ConfigSerializer):
def serialize(self, value):
return ",".join(str(v) for v in value)
def deserialize(self, value):
return [item.strip() for item in value.split(",") if item.strip()]
favorites_config = ConfigItem(
"User",
"FavoriteFolders",
["/home/user/Documents", "/home/user/Pictures"],
serializer=ListSerializer()
)from qfluentwidgets import *
class SettingsInterface(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi()
self.connectSignals()
def setupUi(self):
# Main layout
layout = QVBoxLayout(self)
# Title
title = LargeTitleLabel("Settings")
layout.addWidget(title)
# Scroll area for settings
scroll = SmoothScrollArea(self)
scroll_widget = QWidget()
scroll_layout = QVBoxLayout(scroll_widget)
# General settings group
general_group = SettingCardGroup("General")
self.auto_save_card = SwitchSettingCard(
FIF.SAVE, "Auto Save", "Automatically save changes"
)
self.language_card = ComboBoxSettingCard(
None, FIF.LOCALE, "Language", "Select interface language",
texts=["English", "Spanish", "French", "German"]
)
general_group.addSettingCards([self.auto_save_card, self.language_card])
# Appearance settings group
appearance_group = SettingCardGroup("Appearance")
self.theme_card = ComboBoxSettingCard(
None, FIF.BRUSH, "Theme", "Choose application theme",
texts=["Light", "Dark", "Auto"]
)
self.accent_card = ColorSettingCard(
None, FIF.PALETTE, "Accent Color", "Personalize your accent color"
)
appearance_group.addSettingCards([self.theme_card, self.accent_card])
# Advanced settings group
advanced_group = SettingCardGroup("Advanced")
self.debug_card = SwitchSettingCard(
FIF.DEVELOPER_TOOLS, "Debug Mode", "Enable debugging features"
)
self.export_card = PushSettingCard(
"Export", FIF.SHARE, "Export Settings", "Save settings to file"
)
advanced_group.addSettingCards([self.debug_card, self.export_card])
# Add groups to layout
scroll_layout.addWidget(general_group)
scroll_layout.addWidget(appearance_group)
scroll_layout.addWidget(advanced_group)
scroll_layout.addStretch()
scroll.setWidget(scroll_widget)
layout.addWidget(scroll)
def connectSignals(self):
self.auto_save_card.checkedChanged.connect(self.on_auto_save_changed)
self.language_card.currentTextChanged.connect(self.on_language_changed)
self.theme_card.currentTextChanged.connect(self.on_theme_changed)
self.accent_card.colorChanged.connect(self.on_accent_changed)
self.export_card.clicked.connect(self.export_settings)
def on_auto_save_changed(self, checked):
qconfig.set(Config.auto_save, checked)
def on_language_changed(self, language):
qconfig.set(Config.language, language)
def on_theme_changed(self, theme):
theme_enum = Theme.LIGHT if theme == "Light" else Theme.DARK if theme == "Dark" else Theme.AUTO
setTheme(theme_enum)
def on_accent_changed(self, color):
setThemeColor(color)
def export_settings(self):
file_path, _ = QFileDialog.getSaveFileName(self, "Export Settings", "", "JSON files (*.json)")
if file_path:
qconfig.save(file_path)Install with Tessl CLI
npx tessl i tessl/pypi-pyqt-fluent-widgets