Files
leonpan-pc/app/view/widgets/custom_fluent_window.py
Leonmmcoset ebf784146e refactor(view): 重构主窗口和自定义Fluent窗口实现
将CustomFluentWindow改为继承自MSFluentWindow,简化导航接口实现
更新导航项设置方式,使用objectName作为路由键
优化头像widget的添加方式,直接使用QIcon而非NavigationAvatarWidget
移除冗余代码,统一使用MSFluentWindow提供的方法
2025-11-01 20:39:53 +08:00

210 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding:utf-8
import sys
from typing import Union
from PyQt6.QtCore import QRect, QSize, Qt
from PyQt6.QtGui import QColor, QIcon, QPainter, QPixmap
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QLabel, QVBoxLayout, QWidget
from qfluentwidgets import MSFluentWindow, NavigationItemPosition, setTheme, Theme
from qfluentwidgets.common.config import qconfig
from qfluentwidgets.common.icon import FluentIconBase
from qfluentwidgets.common.router import qrouter
from qfluentwidgets.common.style_sheet import (
FluentStyleSheet,
isDarkTheme,
)
from qfluentwidgets.components.navigation import (
NavigationTreeWidget
)
from qfluentwidgets.components.widgets.frameless_window import FramelessWindow
from app.view.widgets.stacked_widget import StackedWidget
class CustomFluentWindow(MSFluentWindow):
"""自定义的Fluent窗口基于MSFluentWindow实现"""
def __init__(self, parent=None):
super().__init__(parent)
# 背景相关设置
self._isMicaEnabled = False
self._lightBackgroundColor = QColor(240, 244, 249)
self._darkBackgroundColor = QColor(32, 32, 32)
self._backgroundPixmap = None # 存储背景图片
self._backgroundOpacity = 1.0 # 背景图片不透明度
# 启用mica效果
self.setMicaEffectEnabled(True)
# 连接主题变化信号
qconfig.themeChangedFinished.connect(self._onThemeChangedFinished)
def addSubInterface(
self,
interface: QWidget,
icon: Union[FluentIconBase, QIcon, str],
text: str,
selectedIcon: Union[FluentIconBase, QIcon, str] = None,
position=NavigationItemPosition.TOP,
parent=None,
isTransparent=False,
) -> NavigationTreeWidget:
"""添加子界面
Parameters
----------
interface: QWidget
要添加的子界面
icon: FluentIconBase | QIcon | str
导航项的图标
selectedIcon: FluentIconBase | QIcon | str
选中状态下的图标
text: str
导航项的文本
position: NavigationItemPosition
导航项的位置
parent: QWidget
导航项的父项
isTransparent: bool
是否使用透明背景
"""
if not interface.objectName():
raise ValueError("The object name of `interface` can't be empty string.")
interface.setProperty("isStackedTransparent", isTransparent)
# 使用MSFluentWindow的addSubInterface方法
if selectedIcon:
item = super().addSubInterface(interface, icon, text, selectedIcon, position)
else:
item = super().addSubInterface(interface, icon, text, position=position)
return item
def removeInterface(self, interface, isDelete=False):
"""移除子界面
Parameters
----------
interface: QWidget
要移除的子界面
isDelete: bool
是否删除子界面
"""
# 从stackedWidget中移除
self.stackedWidget.removeWidget(interface)
interface.hide()
# 从导航中移除
self.navigationInterface.removeWidget(interface.objectName())
if isDelete:
interface.deleteLater()
def setCustomBackgroundColor(self, light, dark):
"""设置自定义背景颜色
Parameters
----------
light, dark: QColor | Qt.GlobalColor | str
亮/暗主题模式下的背景颜色
"""
self._lightBackgroundColor = QColor(light)
self._darkBackgroundColor = QColor(dark)
self._updateBackgroundColor()
def setBackgroundImage(self, imagePath: str, opacity: float = 1.0):
"""设置背景图片
Parameters
----------
imagePath: str
背景图片路径
opacity: float
背景图片不透明度范围0.0-1.0
"""
# 如果启用了Mica效果先禁用
if self._isMicaEnabled:
self.setMicaEffectEnabled(False)
self._backgroundPixmap = QPixmap(imagePath)
if self._backgroundPixmap.isNull():
print(f"无法加载背景图片: {imagePath}")
return
self._backgroundOpacity = max(0.0, min(1.0, opacity)) # 确保在0-1范围内
self.update() # 触发重绘
def removeBackgroundImage(self):
"""移除背景图片"""
self._backgroundPixmap = None
self.update()
def _normalBackgroundColor(self):
if not self._isMicaEnabled:
return (
self._darkBackgroundColor
if isDarkTheme()
else self._lightBackgroundColor
)
return QColor(0, 0, 0, 0)
def _onThemeChangedFinished(self):
if self._isMicaEnabled:
# MSFluentWindow已经处理了Mica效果这里只需要确保背景颜色正确
self.setBackgroundColor(self._normalBackgroundColor())
def paintEvent(self, e):
# 先调用父类的绘制方法
super().paintEvent(e)
# 如果有背景图片,绘制背景图片
if self._backgroundPixmap and not self._backgroundPixmap.isNull():
painter = QPainter(self)
# 设置不透明度
painter.setOpacity(self._backgroundOpacity)
# 缩放图片以适应窗口大小
scaled_pixmap = self._backgroundPixmap.scaled(
self.size(), Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.SmoothTransformation
)
painter.drawPixmap(0, 0, scaled_pixmap)
def setMicaEffectEnabled(self, isEnabled: bool):
"""设置是否启用mica效果仅在Win11上可用"""
if sys.platform != "win32" or sys.getwindowsversion().build < 22000:
self._isMicaEnabled = False
return
self._isMicaEnabled = isEnabled
if isEnabled:
# 启用Mica效果时移除背景图片
self.removeBackgroundImage()
# MSFluentWindow自带Mica效果支持
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
else:
self.windowEffect.removeBackgroundEffect(self.winId())
self.setBackgroundColor(self._normalBackgroundColor())
def isMicaEffectEnabled(self):
"""获取是否启用了mica效果"""
return self._isMicaEnabled
def resizeEvent(self, e):
super().resizeEvent(e)
# 确保标题栏正确显示
if hasattr(self, 'titleBar'):
self.titleBar.raise_()