[Python] 纯文本查看 复制代码
# Decompiled with PyLingual ([url]https://pylingual.io[/url])
# Internal filename: qfluentwidgets\window\fluent_window.py
# Bytecode version: 3.11a7e (3495)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)
from typing import Union
import sys
from PySide6.QtCore import Qt, QSize, QRect
from PySide6.QtGui import QIcon, QPainter, QColor
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QApplication
from ..common.config import qconfig
from ..common.icon import FluentIconBase
from ..common.router import qrouter
from ..common.style_sheet import FluentStyleSheet, isDarkTheme, setTheme, Theme
from ..common.animation import BackgroundAnimationWidget
from ..components.widgets.frameless_window import FramelessWindow
from ..components.navigation import NavigationInterface, NavigationBar, NavigationItemPosition, NavigationBarPushButton, NavigationTreeWidget
from .stacked_widget import StackedWidget
from qframelesswindow import TitleBar, TitleBarBase
class FluentWindowBase(BackgroundAnimationWidget, FramelessWindow):
""" Fluent window base class """
def __init__(self, parent=None):
self._isMicaEnabled = False
self._lightBackgroundColor = QColor(240, 244, 249)
self._darkBackgroundColor = QColor(32, 32, 32)
super().__init__(parent=parent)
self.hBoxLayout = QHBoxLayout(self)
self.stackedWidget = StackedWidget(self)
self.navigationInterface = None
self.hBoxLayout.setSpacing(0)
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
FluentStyleSheet.FLUENT_WINDOW.apply(self.stackedWidget)
self.setMicaEffectEnabled(True)
if sys.platform == 'darwin':
self.setSystemTitleBarButtonVisible(True)
qconfig.themeChangedFinished.connect(self._onThemeChangedFinished)
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str, position=NavigationItemPosition.TOP):
""" add sub interface """
raise NotImplementedError
def switchTo(self, interface: QWidget):
self.stackedWidget.setCurrentWidget(interface, popOut=False)
def _onCurrentInterfaceChanged(self, index: int):
widget = self.stackedWidget.widget(index)
self.navigationInterface.setCurrentItem(widget.objectName())
qrouter.push(self.stackedWidget, widget.objectName())
self._updateStackedBackground()
def _updateStackedBackground(self):
isTransparent = self.stackedWidget.currentWidget().property('isStackedTransparent')
if bool(self.stackedWidget.property('isTransparent')) == isTransparent:
return
self.stackedWidget.setProperty('isTransparent', isTransparent)
self.stackedWidget.setStyle(QApplication.style())
def setCustomBackgroundColor(self, light, dark):
""" set custom background color
Parameters
----------
light, dark: QColor | Qt.GlobalColor | str
background color in light/dark theme mode
"""
self._lightBackgroundColor = QColor(light)
self._darkBackgroundColor = QColor(dark)
self._updateBackgroundColor()
def _normalBackgroundColor(self):
if not self.isMicaEffectEnabled():
return self._darkBackgroundColor if isDarkTheme() else self._lightBackgroundColor
return QColor(0, 0, 0, 0)
def _onThemeChangedFinished(self):
if self.isMicaEffectEnabled():
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
def paintEvent(self, e):
super().paintEvent(e)
painter = QPainter(self)
painter.setPen(Qt.NoPen)
painter.setBrush(self.backgroundColor)
painter.drawRect(self.rect())
def setMicaEffectEnabled(self, isEnabled: bool):
""" set whether the mica effect is enabled, only available on Win11 """
if sys.platform != 'win32' or sys.getwindowsversion().build < 22000:
return None
self._isMicaEnabled = isEnabled
if isEnabled:
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
else:
self.windowEffect.removeBackgroundEffect(self.winId())
self.setBackgroundColor(self._normalBackgroundColor())
def isMicaEffectEnabled(self):
return self._isMicaEnabled
def systemTitleBarRect(self, size: QSize) -> QRect:
""" Returns the system title bar rect, only works for macOS
Parameters
----------
size: QSize
original system title bar rect
"""
return QRect(size.width() - 75, 0 if self.isFullScreen() else 9, 75, size.height())
def setTitleBar(self, titleBar):
super().setTitleBar(titleBar)
if sys.platform == 'darwin' and self.isSystemButtonVisible() and isinstance(titleBar, TitleBarBase):
titleBar.minBtn.hide()
titleBar.maxBtn.hide()
titleBar.closeBtn.hide()
class FluentTitleBar(TitleBar):
""" Fluent title bar"""
def __init__(self, parent):
super().__init__(parent)
self.setFixedHeight(48)
self.hBoxLayout.removeWidget(self.minBtn)
self.hBoxLayout.removeWidget(self.maxBtn)
self.hBoxLayout.removeWidget(self.closeBtn)
self.iconLabel = QLabel(self)
self.iconLabel.setFixedSize(18, 18)
self.hBoxLayout.insertWidget(0, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
self.window().windowIconChanged.connect(self.setIcon)
self.titleLabel = QLabel(self)
self.hBoxLayout.insertWidget(1, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
self.titleLabel.setObjectName('titleLabel')
self.window().windowTitleChanged.connect(self.setTitle)
self.vBoxLayout = QVBoxLayout()
self.buttonLayout = QHBoxLayout()
self.buttonLayout.setSpacing(0)
self.buttonLayout.setContentsMargins(0, 0, 0, 0)
self.buttonLayout.setAlignment(Qt.AlignTop)
self.buttonLayout.addWidget(self.minBtn)
self.buttonLayout.addWidget(self.maxBtn)
self.buttonLayout.addWidget(self.closeBtn)
self.vBoxLayout.addLayout(self.buttonLayout)
self.vBoxLayout.addStretch(1)
self.hBoxLayout.addLayout(self.vBoxLayout, 0)
FluentStyleSheet.FLUENT_WINDOW.apply(self)
def setTitle(self, title):
self.titleLabel.setText(title)
self.titleLabel.adjustSize()
def setIcon(self, icon):
self.iconLabel.setPixmap(QIcon(icon).pixmap(18, 18))
class FluentWindow(FluentWindowBase):
""" Fluent window """
def __init__(self, parent=None):
super().__init__(parent)
self.setTitleBar(FluentTitleBar(self))
self.navigationInterface = NavigationInterface(self, showReturnButton=True)
self.widgetLayout = QHBoxLayout()
self.hBoxLayout.addWidget(self.navigationInterface)
self.hBoxLayout.addLayout(self.widgetLayout)
self.hBoxLayout.setStretchFactor(self.widgetLayout, 1)
self.widgetLayout.addWidget(self.stackedWidget)
self.widgetLayout.setContentsMargins(0, 48, 0, 0)
self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
self.titleBar.raise_()
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str, position=NavigationItemPosition.TOP, parent=None, isTransparent=False) -> NavigationTreeWidget:
""" add sub interface, the object name of `interface` should be set already
before calling this method
Parameters
----------
interface: QWidget
the subinterface to be added
icon: FluentIconBase | QIcon | str
the icon of navigation item
text: str
the text of navigation item
position: NavigationItemPosition
the position of navigation item
parent: QWidget
the parent of navigation item
isTransparent: bool
whether to use transparent background
"""
if not interface.objectName():
raise ValueError("The object name of `interface` can't be empty string.")
if parent and (not parent.objectName()):
raise ValueError("The object name of `parent` can't be empty string.")
interface.setProperty('isStackedTransparent', isTransparent)
self.stackedWidget.addWidget(interface)
routeKey = interface.objectName()
item = self.navigationInterface.addItem(routeKey=routeKey, icon=icon, text=text, onClick=lambda: self.switchTo(interface), position=position, tooltip=text, parentRouteKey=parent.objectName() if parent else None)
if self.stackedWidget.count() == 1:
self.stackedWidget.currentChanged.connect(self._onCurrentInterfaceChanged)
self.navigationInterface.setCurrentItem(routeKey)
qrouter.setDefaultRouteKey(self.stackedWidget, routeKey)
self._updateStackedBackground()
return item
def resizeEvent(self, e):
self.titleBar.move(46, 0)
self.titleBar.resize(self.width() - 46, self.titleBar.height())
class MSFluentTitleBar(FluentTitleBar):
def __init__(self, parent):
super().__init__(parent)
self.hBoxLayout.insertSpacing(0, 20)
self.hBoxLayout.insertSpacing(2, 2)
class MSFluentWindow(FluentWindowBase):
""" Fluent window in Microsoft Store style """
def __init__(self, parent=None):
super().__init__(parent)
self.setTitleBar(MSFluentTitleBar(self))
self.navigationInterface = NavigationBar(self)
self.hBoxLayout.setContentsMargins(0, 48, 0, 0)
self.hBoxLayout.addWidget(self.navigationInterface)
self.hBoxLayout.addWidget(self.stackedWidget, 1)
self.titleBar.raise_()
self.titleBar.setAttribute(Qt.WA_StyledBackground)
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str, selectedIcon=None, position=NavigationItemPosition.TOP, isTransparent=False) -> NavigationBarPushButton:
""" add sub interface, the object name of `interface` should be set already
before calling this method
Parameters
----------
interface: QWidget
the subinterface to be added
icon: FluentIconBase | QIcon | str
the icon of navigation item
text: str
the text of navigation item
selectedIcon: str | QIcon | FluentIconBase
the icon of navigation item in selected state
position: NavigationItemPosition
the position of navigation item
"""
if not interface.objectName():
raise ValueError("The object name of `interface` can't be empty string.")
interface.setProperty('isStackedTransparent', isTransparent)
self.stackedWidget.addWidget(interface)
routeKey = interface.objectName()
item = self.navigationInterface.addItem(routeKey=routeKey, icon=icon, text=text, onClick=lambda: self.switchTo(interface), selectedIcon=selectedIcon, position=position)
if self.stackedWidget.count() == 1:
self.stackedWidget.currentChanged.connect(self._onCurrentInterfaceChanged)
self.navigationInterface.setCurrentItem(routeKey)
qrouter.setDefaultRouteKey(self.stackedWidget, routeKey)
self._updateStackedBackground()
return item
class SplitTitleBar(TitleBar):
def __init__(self, parent):
super().__init__(parent)
self.iconLabel = QLabel(self)
self.iconLabel.setFixedSize(18, 18)
self.hBoxLayout.insertSpacing(0, 12)
self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
self.window().windowIconChanged.connect(self.setIcon)
self.titleLabel = QLabel(self)
self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
self.titleLabel.setObjectName('titleLabel')
self.window().windowTitleChanged.connect(self.setTitle)
FluentStyleSheet.FLUENT_WINDOW.apply(self)
def setTitle(self, title):
self.titleLabel.setText(title)
self.titleLabel.adjustSize()
def setIcon(self, icon):
self.iconLabel.setPixmap(QIcon(icon).pixmap(18, 18))
class SplitFluentWindow(FluentWindow):
""" Fluent window with split style """
def __init__(self, parent=None):
super().__init__(parent)
self.setTitleBar(SplitTitleBar(self))
if sys.platform == 'darwin':
self.titleBar.setFixedHeight(48)
self.widgetLayout.setContentsMargins(0, 0, 0, 0)
self.titleBar.raise_()
self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
class FluentBackgroundTheme:
""" Fluent background theme """
DEFAULT = (QColor(243, 243, 243), QColor(32, 32, 32))
DEFAULT_BLUE = (QColor(240, 244, 249), QColor(25, 33, 42))