将CustomFluentWindow改为继承自MSFluentWindow,简化导航接口实现 更新导航项设置方式,使用objectName作为路由键 优化头像widget的添加方式,直接使用QIcon而非NavigationAvatarWidget 移除冗余代码,统一使用MSFluentWindow提供的方法
210 lines
6.7 KiB
Python
210 lines
6.7 KiB
Python
# 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_()
|