Skip to main content

用 QFluentWidgets 美化 PySide6 介面

PyQt-Fluent-Widgets / QFluentWidgets 是一套 Fluent Design 風格的 Qt 元件庫。官方文件預設範例多半寫 PyQt5,但同一套 API 也有 PySide6 專用套件:PySide6-Fluent-Widgets。import 名稱一律是 qfluentwidgets

結論:可以,而且很適合拿來「美化」PySide6——多數情況只要把 QPushButton 換成 PushButton,再呼叫 setTheme(),外觀就會明顯現代化。


版本對照(很重要)

你用的 Qt binding要安裝的套件
PyQt5PyQt-Fluent-Widgets
PyQt6PyQt6-Fluent-Widgets
PySide2PySide2-Fluent-Widgets
PySide6PySide6-Fluent-Widgets

注意:

  • 不要同時安裝 上述多個套件,它們的 Python package 名稱都是 qfluentwidgets,會互相覆寫。
  • 不要混用 PySide 與 PyQt(例如程式用 PySide6,卻裝了 PyQt 版 Fluent),容易直接崩潰。
  • 文件站:pyqt-fluent-widgets.readthedocs.io;安裝說明亦可參考 qfluentwidgets.com/pages/install

授權為 GPLv3(開源版)。商業閉源產品需自行評估授權,或考慮官方 Pro 方案。


安裝(PySide6)

# 建議獨立虛擬環境
pip install PySide6

# lite:一般元件足夠
pip install PySide6-Fluent-Widgets -i https://pypi.org/simple/

# full:含 AcrylicLabel 等材質效果
pip install "PySide6-Fluent-Widgets[full]" -i https://pypi.org/simple/

用 uv:

uv add PySide6 "PySide6-Fluent-Widgets"

若出現 ImportError: cannot import name 'XXX' from 'qfluentwidgets',多半是版本過舊,改用官方 PyPI 來源重裝最新版。

較新的 PySide6 在 Windows 11 上偶有 QStyle 衝突導致樣式異常;官方建議可暫時鎖在例如 6.7.2 再回報問題。


核心用法:換元件名即可

QFluentWidgets 很多元件是「帶 Fluent 樣式的 Qt 控件」。API 與原生控件相近,學習成本低:

原生 QtQFluentWidgets
QPushButtonPushButton / PrimaryPushButton
QLabelBodyLabel / TitleLabel / SubtitleLabel
QLineEditLineEdit / SearchLineEdit
QCheckBoxCheckBox
QComboBoxComboBox
QSliderSlider
QProgressBarProgressBar / ProgressRing

另外還有原生沒有、但桌面 App 很常用的:InfoBarFlyoutMessageBoxNavigationInterfaceFluentWindowSettingCard 等。


最小美化範例

import sys

from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from qfluentwidgets import (
BodyLabel,
PushButton,
SwitchButton,
Theme,
setTheme,
)


class MyWindow(QWidget):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("My First Fluent App")
self.resize(400, 220)

self.label = BodyLabel("歡迎使用 PySide6-Fluent-Widgets", self)
self.button = PushButton("點擊我", self)
self.switch = SwitchButton(self)

self.button.clicked.connect(self.on_button_clicked)
self.switch.checkedChanged.connect(self.on_switch_toggled)

layout = QVBoxLayout(self)
layout.setSpacing(20)
layout.setContentsMargins(30, 30, 30, 30)
layout.addWidget(self.label)
layout.addWidget(self.button)
layout.addWidget(self.switch)
layout.addStretch(1)

def on_button_clicked(self) -> None:
self.label.setText("按鈕被點擊了!")

def on_switch_toggled(self, is_checked: bool) -> None:
self.label.setText(f"開關狀態:{'開啟' if is_checked else '關閉'}")


if __name__ == "__main__":
app = QApplication(sys.argv)
setTheme(Theme.DARK) # LIGHT / DARK / AUTO
window = MyWindow()
window.show()
sys.exit(app.exec())

你會看到圓角按鈕、懸停效果與切換動畫——不用自己寫一長串 QSS


主題與主題色

亮/暗模式

from qfluentwidgets import Theme, setTheme

setTheme(Theme.LIGHT) # 淺色
setTheme(Theme.DARK) # 深色
setTheme(Theme.AUTO) # 跟隨系統(偵測不到則用淺色)

主題變更時,qconfig 會發出 themeChanged 訊號。細節見官方 Theme

主題色

from qfluentwidgets import setThemeColor

setThemeColor("#0065d5") # 也可傳 QColor / Qt.GlobalColor / 色名如 "red"

自訂頁面 QSS 跟隨主題

若自訂視窗也要跟亮暗切換,可繼承 StyleSheetBase,把 light/dark 兩套 qss 分開放:

from enum import Enum

from qfluentwidgets import StyleSheetBase, Theme, qconfig


class StyleSheet(StyleSheetBase, Enum):
MAIN_WINDOW = "main_window"

def path(self, theme: Theme = Theme.AUTO) -> str:
theme = qconfig.theme if theme == Theme.AUTO else theme
return f"app/resource/qss/{theme.value.lower()}/{self.value}.qss"


# StyleSheet.MAIN_WINDOW.apply(self)

小幅覆寫單一控件樣式可用 setCustomStyleSheet(widget, light_qss, dark_qss)


FluentWindow:側邊導航多頁 App

多數工具型桌面 App 需要「左側導航 + 右側內容」。FluentWindow 已幫你組好骨架,用 addSubInterface() 掛頁面即可。

import sys

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget
from qfluentwidgets import (
BodyLabel,
FluentIcon,
FluentWindow,
NavigationItemPosition,
Theme,
setTheme,
)


class HomePage(QWidget):
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent=parent)
self.setObjectName("home")
layout = QVBoxLayout(self)
layout.setAlignment(Qt.AlignCenter)
layout.addWidget(BodyLabel("這是首頁", self))


class SettingsPage(QWidget):
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent=parent)
self.setObjectName("settings")
layout = QVBoxLayout(self)
layout.setAlignment(Qt.AlignCenter)
layout.addWidget(BodyLabel("這是設定頁", self))


class MainWindow(FluentWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("多頁面應用")
self.resize(900, 700)

self.home_page = HomePage(self)
self.settings_page = SettingsPage(self)

self.addSubInterface(self.home_page, FluentIcon.HOME, "首頁")
self.addSubInterface(
self.settings_page,
FluentIcon.SETTING,
"設定",
position=NavigationItemPosition.BOTTOM,
)


if __name__ == "__main__":
app = QApplication(sys.argv)
setTheme(Theme.AUTO)
window = MainWindow()
window.show()
sys.exit(app.exec())

導航結構細節(NavigationInterfacerouteKey、顯示模式 EXPAND / COMPACT / MENU / MINIMAL)見官方 Navigation


常見美化場景速查

需求建議元件/做法
主要 CTA 按鈕PrimaryPushButton
一般操作按鈕PushButton / ToolButton
成功/錯誤提示InfoBar.success() / InfoBar.error()
設定頁SettingCard + SettingCardGroup
搜尋框SearchLineEdit
開關SwitchButton
無邊框視窗套件內建 frameless 相關元件(搭配 FluentWindow)
圖示FluentIcon(內建大量 SVG 風格圖示)

Gallery 分類(官方文件 Gallery):Basic input、Dialogs、Menus、Flow Layout、Navigation、Status & info、Material。

跑官方範例(需 clone 對應分支原始碼):

# PySide6 分支:https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/PySide6
cd examples/gallery
python demo.py

從「醜的原生視窗」遷移的實務步驟

  1. 確認只裝 PySide6 + PySide6-Fluent-Widgets
  2. 全域 setTheme(Theme.AUTO)Theme.DARK
  3. 把頁面上的原生控件改成 qfluentwidgets 同名/對應控件。
  4. 主殼改成 FluentWindow,子頁用 addSubInterface
  5. 回饋訊息改用 InfoBar / MessageBox,少用系統 QMessageBox(除非刻意要原生)。
  6. 需要品牌色時再 setThemeColor(...)

多數按鈕、輸入框、標籤「只改 class 名稱」就能吃到樣式;真正要讀文件的通常是 FluentWindowInfoBarPivotNavigationInterface 這類組裝型元件。


常見問題

樣式沒生效?
確認 import 的是 qfluentwidgets.PushButton,不是 PySide6.QtWidgets.QPushButton

和另一個 Fluent 套件衝突?
卸掉其他 *-Fluent-Widgets,只留 PySide6 版後重裝。

想用 Qt Designer?
官方文件有 Designer(Promote widget / Client 外掛)。做法是在 .ui 裡放基底控件,再 promote 成 qfluentwidgets 類別。

設定頁怎麼做?
見官方 Settingsqconfig + 各種 SettingCard


參考資料