提交 ed8d28f0 编写于 作者: 之一Yo's avatar 之一Yo

添加设置标签栏阴影的功能

上级 9bf5f2e5
......@@ -34,27 +34,27 @@
<translation>下拉框</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="208"/>
<location filename="../../view/basic_input_interface.py" line="209"/>
<source>A group of RadioButton controls in a button group</source>
<translation>单选按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="219"/>
<location filename="../../view/basic_input_interface.py" line="220"/>
<source>A simple horizontal slider</source>
<translation>水平滑动条</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="270"/>
<location filename="../../view/basic_input_interface.py" line="271"/>
<source>A simple switch button</source>
<translation>开关按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="309"/>
<location filename="../../view/basic_input_interface.py" line="310"/>
<source>Off</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="307"/>
<location filename="../../view/basic_input_interface.py" line="308"/>
<source>On</source>
<translation></translation>
</message>
......@@ -84,32 +84,32 @@
<translation>GItHub 主页</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Star Platinum</source>
<translation>白金之星</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Crazy Diamond</source>
<translation>疯狂钻石</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="199"/>
<location filename="../../view/basic_input_interface.py" line="200"/>
<source>Soft and Wet</source>
<translation>软又湿</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Gold Experience</source>
<translation>黄金体验</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Sticky Fingers</source>
<translation>钢链手指</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="251"/>
<location filename="../../view/basic_input_interface.py" line="252"/>
<source>Choose your stand</source>
<translation>选择你的替身</translation>
</message>
......@@ -144,37 +144,37 @@
<translation>带下拉菜单的工具按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="291"/>
<location filename="../../view/basic_input_interface.py" line="292"/>
<source>Start practicing</source>
<translation>开始练习</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="228"/>
<location filename="../../view/basic_input_interface.py" line="229"/>
<source>A split push button with drop down menu</source>
<translation>带下拉菜单的拆分按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Sing</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Jump</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Rap</source>
<translation>Rap</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Music</source>
<translation>Music</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="244"/>
<location filename="../../view/basic_input_interface.py" line="245"/>
<source>A split tool button with drop down menu</source>
<translation>带下拉菜单的工具按钮</translation>
</message>
......@@ -199,12 +199,12 @@
<translation>带下拉菜单的主题色工具按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="253"/>
<location filename="../../view/basic_input_interface.py" line="254"/>
<source>A primary color split push button with drop down menu</source>
<translation>带下拉菜单的主题色拆分按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="261"/>
<location filename="../../view/basic_input_interface.py" line="262"/>
<source>A primary color split tool button with drop down menu</source>
<translation>带下拉菜单的主题色拆分工具按钮</translation>
</message>
......@@ -229,22 +229,22 @@
<translation>带下拉菜单的透明工具按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="277"/>
<location filename="../../view/basic_input_interface.py" line="278"/>
<source>A simple toggle push button</source>
<translation>状态开关按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="284"/>
<location filename="../../view/basic_input_interface.py" line="285"/>
<source>A simple toggle tool button</source>
<translation>状态开关工具按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="291"/>
<location filename="../../view/basic_input_interface.py" line="292"/>
<source>A transparent toggle push button</source>
<translation>透明的状态开关按钮</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="298"/>
<location filename="../../view/basic_input_interface.py" line="299"/>
<source>A transparent toggle tool button</source>
<translation>透明的状态开关工具按钮</translation>
</message>
......@@ -899,30 +899,35 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>NavigationViewInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="23"/>
<location filename="../../view/navigation_view_interface.py" line="24"/>
<source>A basic pivot</source>
<translation>顶部导航栏</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="29"/>
<location filename="../../view/navigation_view_interface.py" line="30"/>
<source>A segmented control</source>
<translation>分段导航栏</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="36"/>
<source>A tab bar</source>
<translation>标签栏</translation>
</message>
</context>
<context>
<name>PivotInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="54"/>
<location filename="../../view/navigation_view_interface.py" line="63"/>
<source>Song</source>
<translation>歌曲</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="55"/>
<location filename="../../view/navigation_view_interface.py" line="64"/>
<source>Album</source>
<translation>专辑</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="56"/>
<location filename="../../view/navigation_view_interface.py" line="65"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
......@@ -1369,6 +1374,64 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<translation>带工具提示的按钮</translation>
</message>
</context>
<context>
<name>TabInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="116"/>
<source>IsTabMovable</source>
<translation>启用标签拖拽</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="117"/>
<source>IsTabScrollable</source>
<translation>启用标签滚动</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="121"/>
<source>TabCloseButtonDisplayMode</source>
<translation>关闭按钮显示模式</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="143"/>
<source>Always</source>
<translation>始终显示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="144"/>
<source>OnHover</source>
<translation>进入时显示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="145"/>
<source>Never</source>
<translation>从不显示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="148"/>
<source>Song</source>
<translation>歌曲</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="150"/>
<source>Album</source>
<translation>专辑</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="152"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="118"/>
<source>IsTabShadowEnabled</source>
<translation>启用标签阴影</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="119"/>
<source>TabMaximumWidth</source>
<translation>标签最大宽度</translation>
</message>
</context>
<context>
<name>TableFrame</name>
<message>
......@@ -1412,27 +1475,27 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<message>
<location filename="../../view/text_interface.py" line="75"/>
<source>A DoubleSpinBox with a spin button</source>
<translation>带调节按钮的 DoubleSpinBox</translation>
<translation>浮点数旋转框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="82"/>
<source>A DateEdit with a spin button</source>
<translation>带调节按钮的 DateEdit</translation>
<translation>日期编辑框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="89"/>
<source>A TimeEdit with a spin button</source>
<translation>带调节按钮的 TimeEdit</translation>
<translation>时间编辑框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="96"/>
<source>A DateTimeEdit with a spin button</source>
<translation>带调节按钮的 DateTimeEdit</translation>
<translation>日期时间编辑框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="68"/>
<source>A SpinBox with a spin button</source>
<translation>带调节按钮的 SpinBox</translation>
<translation>旋转框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="107"/>
......
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_HK" sourcelanguage="en_US">
<TS version="2.1" language="zh_CN" sourcelanguage="en_US">
<context>
<name>BasicInputInterface</name>
<message>
......@@ -34,27 +34,27 @@
<translation>下拉框</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="208"/>
<location filename="../../view/basic_input_interface.py" line="209"/>
<source>A group of RadioButton controls in a button group</source>
<translation>單選按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="219"/>
<location filename="../../view/basic_input_interface.py" line="220"/>
<source>A simple horizontal slider</source>
<translation>水平滑動條</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="270"/>
<location filename="../../view/basic_input_interface.py" line="271"/>
<source>A simple switch button</source>
<translation>開關按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="309"/>
<location filename="../../view/basic_input_interface.py" line="310"/>
<source>Off</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="307"/>
<location filename="../../view/basic_input_interface.py" line="308"/>
<source>On</source>
<translation></translation>
</message>
......@@ -84,32 +84,32 @@
<translation>GItHub 主頁</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Star Platinum</source>
<translation>白金之星</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Crazy Diamond</source>
<translation>瘋狂鑽石</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="199"/>
<location filename="../../view/basic_input_interface.py" line="200"/>
<source>Soft and Wet</source>
<translation>軟又溼</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Gold Experience</source>
<translation>黃金體驗</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="313"/>
<location filename="../../view/basic_input_interface.py" line="314"/>
<source>Sticky Fingers</source>
<translation>鋼鏈手指</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="251"/>
<location filename="../../view/basic_input_interface.py" line="252"/>
<source>Choose your stand</source>
<translation>選擇你的替身</translation>
</message>
......@@ -144,37 +144,37 @@
<translation>帶下拉菜單的工具按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="291"/>
<location filename="../../view/basic_input_interface.py" line="292"/>
<source>Start practicing</source>
<translation>開始練習</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="228"/>
<location filename="../../view/basic_input_interface.py" line="229"/>
<source>A split push button with drop down menu</source>
<translation>帶下拉菜單的拆分按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Sing</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Jump</source>
<translation></translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Rap</source>
<translation>Rap</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="235"/>
<location filename="../../view/basic_input_interface.py" line="236"/>
<source>Music</source>
<translation>Music</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="244"/>
<location filename="../../view/basic_input_interface.py" line="245"/>
<source>A split tool button with drop down menu</source>
<translation>帶下拉菜單的工具按鈕</translation>
</message>
......@@ -199,12 +199,12 @@
<translation>帶下拉菜單的主題色工具按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="253"/>
<location filename="../../view/basic_input_interface.py" line="254"/>
<source>A primary color split push button with drop down menu</source>
<translation>帶下拉菜單的主題色拆分按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="261"/>
<location filename="../../view/basic_input_interface.py" line="262"/>
<source>A primary color split tool button with drop down menu</source>
<translation>帶下拉菜單的主題色拆分工具按鈕</translation>
</message>
......@@ -229,22 +229,22 @@
<translation>帶下拉菜單的透明工具按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="277"/>
<location filename="../../view/basic_input_interface.py" line="278"/>
<source>A simple toggle push button</source>
<translation>狀態開關按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="284"/>
<location filename="../../view/basic_input_interface.py" line="285"/>
<source>A simple toggle tool button</source>
<translation>狀態開關工具按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="291"/>
<location filename="../../view/basic_input_interface.py" line="292"/>
<source>A transparent toggle push button</source>
<translation>透明的狀態開關按鈕</translation>
</message>
<message>
<location filename="../../view/basic_input_interface.py" line="298"/>
<location filename="../../view/basic_input_interface.py" line="299"/>
<source>A transparent toggle tool button</source>
<translation>透明的狀態開關工具按鈕</translation>
</message>
......@@ -899,30 +899,35 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<context>
<name>NavigationViewInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="23"/>
<location filename="../../view/navigation_view_interface.py" line="24"/>
<source>A basic pivot</source>
<translation>頂部導航欄</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="29"/>
<location filename="../../view/navigation_view_interface.py" line="30"/>
<source>A segmented control</source>
<translation>分段導航欄</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="36"/>
<source>A tab bar</source>
<translation>標籤欄</translation>
</message>
</context>
<context>
<name>PivotInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="54"/>
<location filename="../../view/navigation_view_interface.py" line="63"/>
<source>Song</source>
<translation>歌曲</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="55"/>
<location filename="../../view/navigation_view_interface.py" line="64"/>
<source>Album</source>
<translation>專輯</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="56"/>
<location filename="../../view/navigation_view_interface.py" line="65"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
......@@ -1369,6 +1374,64 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<translation>帶工具提示的按鈕</translation>
</message>
</context>
<context>
<name>TabInterface</name>
<message>
<location filename="../../view/navigation_view_interface.py" line="116"/>
<source>IsTabMovable</source>
<translation>啟用標籤拖拽</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="117"/>
<source>IsTabScrollable</source>
<translation>啟用標籤滾動</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="121"/>
<source>TabCloseButtonDisplayMode</source>
<translation>關閉按鈕顯示模式</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="143"/>
<source>Always</source>
<translation>始終顯示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="144"/>
<source>OnHover</source>
<translation>進入時顯示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="145"/>
<source>Never</source>
<translation>從不顯示</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="148"/>
<source>Song</source>
<translation>歌曲</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="150"/>
<source>Album</source>
<translation>專輯</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="152"/>
<source>Artist</source>
<translation>歌手</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="118"/>
<source>IsTabShadowEnabled</source>
<translation>啟用標籤陰影</translation>
</message>
<message>
<location filename="../../view/navigation_view_interface.py" line="119"/>
<source>TabMaximumWidth</source>
<translation>標籤最大寬度</translation>
</message>
</context>
<context>
<name>TableFrame</name>
<message>
......@@ -1412,27 +1475,27 @@ In that case, I would accept it no matter which side the ball falls on.</source>
<message>
<location filename="../../view/text_interface.py" line="75"/>
<source>A DoubleSpinBox with a spin button</source>
<translation>帶調節按鈕的 DoubleSpinBox</translation>
<translation>浮點數旋轉框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="82"/>
<source>A DateEdit with a spin button</source>
<translation>帶調節按鈕的 DateEdit</translation>
<translation>日期編輯框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="89"/>
<source>A TimeEdit with a spin button</source>
<translation>帶調節按鈕的 TimeEdit</translation>
<translation>時間編輯框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="96"/>
<source>A DateTimeEdit with a spin button</source>
<translation>帶調節按鈕的 DateTimeEdit</translation>
<translation>日期時間編輯框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="68"/>
<source>A SpinBox with a spin button</source>
<translation>帶調節按鈕的 SpinBox</translation>
<translation>旋轉框</translation>
</message>
<message>
<location filename="../../view/text_interface.py" line="107"/>
......
PivotInterface QLabel {
PivotInterface QLabel,
TabInterface QLabel {
padding-left: 10px;
font: 14px 'Segoe UI', 'Microsoft YaHei', 'PingFang SC';
color: white;
}
#controlPanel {
background-color: rgb(43, 43, 43);
border-left: 1px solid rgb(50, 50, 50);
border-top-right-radius: 10px;
}
\ No newline at end of file
PivotInterface QLabel {
PivotInterface QLabel,
TabInterface QLabel {
padding-left: 10px;
font: 14px 'Segoe UI', 'Microsoft YaHei', 'PingFang SC';
color: black;
}
#controlPanel {
background-color: white;
border-left: 1px solid rgb(229, 229, 229);
border-top-right-radius: 10px;
}
\ No newline at end of file
......@@ -118,6 +118,10 @@
<file>images/shoko.png</file>
<file>images/Gyro.jpg</file>
<file>images/SBR.jpg</file>
<file>images/Dvd.png</file>
<file>images/Singer.png</file>
<file>images/MusicNote.png</file>
<file>images/Smiling_with_heart.png</file>
<file>qss/dark/gallery_interface.qss</file>
<file>qss/dark/home_interface.qss</file>
......
......@@ -329,6 +329,14 @@ class HomeInterface(ScrollArea):
routeKey="navigationViewInterface",
index=0
)
navigationView.addSampleCard(
icon=":/gallery/images/controls/TabView.png",
title="TabView",
content=self.tr(
"Presents information from different sources in a tabbed view."),
routeKey="navigationViewInterface",
index=2
)
self.vBoxLayout.addWidget(navigationView)
# scroll samples
......
# coding:utf-8
from PyQt5.QtCore import Qt, QEasingCurve
from PyQt5.QtWidgets import QWidget, QStackedWidget, QVBoxLayout, QLabel
from qfluentwidgets import Pivot, qrouter, SegmentedWidget
from PyQt5.QtWidgets import QWidget, QStackedWidget, QVBoxLayout, QLabel, QHBoxLayout, QFrame, QSizePolicy
from qfluentwidgets import (Pivot, qrouter, SegmentedWidget, TabBar, CheckBox, ComboBox,
TabCloseButtonDisplayMode, BodyLabel, SpinBox)
from .gallery_interface import GalleryInterface
from ..common.translator import Translator
......@@ -32,6 +33,14 @@ class NavigationViewInterface(GalleryInterface):
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/pivot/demo.py'
)
card = self.addExampleCard(
title=self.tr('A tab bar'),
widget=TabInterface(self),
sourcePath='https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/tab_view/demo.py',
stretch=1
)
card.topLayout.setContentsMargins(12, 0, 0, 0)
class PivotInterface(QWidget):
""" Pivot interface """
......@@ -90,3 +99,143 @@ class SegmentedInterface(PivotInterface):
super().__init__(parent)
self.vBoxLayout.removeWidget(self.pivot)
self.vBoxLayout.insertWidget(0, self.pivot)
class TabInterface(QWidget):
""" Tab interface """
def __init__(self, parent=None):
super().__init__(parent=parent)
self.tabCount = 1
self.tabBar = TabBar(self)
self.stackedWidget = QStackedWidget(self)
self.tabView = QWidget(self)
self.controlPanel = QFrame(self)
self.movableCheckBox = CheckBox(self.tr('IsTabMovable'), self)
self.scrollableCheckBox = CheckBox(self.tr('IsTabScrollable'), self)
self.shadowEnabledCheckBox = CheckBox(self.tr('IsTabShadowEnabled'), self)
self.tabMaxWidthLabel = BodyLabel(self.tr('TabMaximumWidth'), self)
self.tabMaxWidthSpinBox = SpinBox(self)
self.closeDisplayModeLabel = BodyLabel(self.tr('TabCloseButtonDisplayMode'), self)
self.closeDisplayModeComboBox = ComboBox(self)
self.hBoxLayout = QHBoxLayout(self)
self.vBoxLayout = QVBoxLayout(self.tabView)
self.panelLayout = QVBoxLayout(self.controlPanel)
self.songInterface = QLabel('Song Interface', self)
self.albumInterface = QLabel('Album Interface', self)
self.artistInterface = QLabel('Artist Interface', self)
# add items to pivot
self.__initWidget()
def __initWidget(self):
self.initLayout()
self.shadowEnabledCheckBox.setChecked(True)
self.tabMaxWidthSpinBox.setRange(60, 400)
self.tabMaxWidthSpinBox.setValue(self.tabBar.tabMaximumWidth())
self.closeDisplayModeComboBox.addItem(self.tr('Always'), userData=TabCloseButtonDisplayMode.ALWAYS)
self.closeDisplayModeComboBox.addItem(self.tr('OnHover'), userData=TabCloseButtonDisplayMode.ON_HOVER)
self.closeDisplayModeComboBox.addItem(self.tr('Never'), userData=TabCloseButtonDisplayMode.NEVER)
self.closeDisplayModeComboBox.currentIndexChanged.connect(self.onDisplayModeChanged)
self.addSubInterface(self.songInterface,
'tabSongInterface', self.tr('Song'), ':/gallery/images/MusicNote.png')
self.addSubInterface(self.albumInterface,
'tabAlbumInterface', self.tr('Album'), ':/gallery/images/Dvd.png')
self.addSubInterface(self.artistInterface,
'tabArtistInterface', self.tr('Artist'), ':/gallery/images/Singer.png')
self.controlPanel.setObjectName('controlPanel')
StyleSheet.NAVIGATION_VIEW_INTERFACE.apply(self)
self.connectSignalToSlot()
qrouter.setDefaultRouteKey(
self.stackedWidget, self.songInterface.objectName())
def connectSignalToSlot(self):
self.movableCheckBox.stateChanged.connect(
lambda: self.tabBar.setMovable(self.movableCheckBox.isChecked()))
self.scrollableCheckBox.stateChanged.connect(
lambda: self.tabBar.setScrollable(self.scrollableCheckBox.isChecked()))
self.shadowEnabledCheckBox.stateChanged.connect(
lambda: self.tabBar.setTabShadowEnabled(self.shadowEnabledCheckBox.isChecked()))
self.tabMaxWidthSpinBox.valueChanged.connect(self.tabBar.setTabMaximumWidth)
self.tabBar.tabAddRequested.connect(self.addTab)
self.tabBar.tabCloseRequested.connect(self.removeTab)
self.stackedWidget.currentChanged.connect(self.onCurrentIndexChanged)
def initLayout(self):
self.tabBar.setTabMaximumWidth(200)
self.setFixedHeight(280)
self.controlPanel.setFixedWidth(220)
self.hBoxLayout.addWidget(self.tabView, 1)
self.hBoxLayout.addWidget(self.controlPanel, 0, Qt.AlignRight)
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
self.vBoxLayout.addWidget(self.tabBar)
self.vBoxLayout.addWidget(self.stackedWidget)
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
self.panelLayout.setSpacing(8)
self.panelLayout.setContentsMargins(14, 16, 14, 14)
self.panelLayout.setAlignment(Qt.AlignTop)
self.panelLayout.addWidget(self.movableCheckBox)
self.panelLayout.addWidget(self.scrollableCheckBox)
self.panelLayout.addWidget(self.shadowEnabledCheckBox)
self.panelLayout.addSpacing(4)
self.panelLayout.addWidget(self.tabMaxWidthLabel)
self.panelLayout.addWidget(self.tabMaxWidthSpinBox)
self.panelLayout.addSpacing(4)
self.panelLayout.addWidget(self.closeDisplayModeLabel)
self.panelLayout.addWidget(self.closeDisplayModeComboBox)
def addSubInterface(self, widget: QLabel, objectName, text, icon):
widget.setObjectName(objectName)
widget.setAlignment(Qt.AlignTop | Qt.AlignLeft)
self.stackedWidget.addWidget(widget)
self.tabBar.addTab(
routeKey=objectName,
text=text,
icon=icon,
onClick=lambda: self.stackedWidget.setCurrentWidget(widget)
)
def onDisplayModeChanged(self, index):
mode = self.closeDisplayModeComboBox.itemData(index)
self.tabBar.setCloseButtonDisplayMode(mode)
def onCurrentIndexChanged(self, index):
widget = self.stackedWidget.widget(index)
if not widget:
return
self.tabBar.setCurrentTab(widget.objectName())
qrouter.push(self.stackedWidget, widget.objectName())
def addTab(self):
text = f'硝子酱一级棒卡哇伊×{self.tabCount}'
self.addSubInterface(QLabel('🥰 ' + text), text, text, ':/gallery/images/Smiling_with_heart.png')
self.tabCount += 1
def removeTab(self, index):
item = self.tabBar.tabItem(index)
widget = self.findChild(QLabel, item.routeKey())
self.stackedWidget.removeWidget(widget)
self.tabBar.removeTab(index)
widget.deleteLater()
\ No newline at end of file
......@@ -2,14 +2,15 @@
import sys
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, pyqtSignal, QEasingCurve, QUrl, QPoint
from PyQt5.QtGui import QIcon, QDesktopServices
from PyQt5.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QApplication, QFrame, QStackedWidget
from PyQt5.QtCore import Qt, QSize, QUrl, QPoint
from PyQt5.QtGui import QIcon, QDesktopServices, QColor
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QApplication, QFrame, QStackedWidget
from qfluentwidgets import (NavigationItemPosition, MessageBox, MSFluentTitleBar, MSFluentWindow,
TabBar, SubtitleLabel, setFont, TabCloseButtonDisplayMode, IconWidget)
TabBar, SubtitleLabel, setFont, TabCloseButtonDisplayMode, IconWidget,
TransparentDropDownToolButton, TransparentToolButton, setTheme, Theme, isDarkTheme)
from qfluentwidgets import FluentIcon as FIF
from qframelesswindow import FramelessWindow, TitleBarBase
from qframelesswindow import AcrylicWindow
class Widget(QFrame):
......@@ -28,11 +29,11 @@ class Widget(QFrame):
class TabInterface(QFrame):
""" Tab interface """
def __init__(self, text: str, icon, parent=None):
def __init__(self, text: str, icon, objectName, parent=None):
super().__init__(parent=parent)
self.iconWidget = IconWidget(icon, self)
self.label = SubtitleLabel(text, self)
self.iconWidget.setFixedSize(100, 100)
self.iconWidget.setFixedSize(120, 120)
self.vBoxLayout = QVBoxLayout(self)
self.vBoxLayout.setAlignment(Qt.AlignCenter)
......@@ -41,6 +42,8 @@ class TabInterface(QFrame):
self.vBoxLayout.addWidget(self.label, 0, Qt.AlignCenter)
setFont(self.label, 24)
self.setObjectName(objectName)
class CustomTitleBar(MSFluentTitleBar):
""" Title bar with icon and title """
......@@ -48,38 +51,61 @@ class CustomTitleBar(MSFluentTitleBar):
def __init__(self, parent):
super().__init__(parent)
# add buttons
self.toolButtonLayout = QHBoxLayout()
color = QColor(206, 206, 206) if isDarkTheme() else QColor(96, 96, 96)
self.searchButton = TransparentToolButton(FIF.SEARCH_MIRROR.icon(color=color), self)
self.forwardButton = TransparentToolButton(FIF.RIGHT_ARROW.icon(color=color), self)
self.backButton = TransparentToolButton(FIF.LEFT_ARROW.icon(color=color), self)
self.forwardButton.setDisabled(True)
self.toolButtonLayout.setContentsMargins(20, 0, 20, 0)
self.toolButtonLayout.setSpacing(15)
self.toolButtonLayout.addWidget(self.searchButton)
self.toolButtonLayout.addWidget(self.backButton)
self.toolButtonLayout.addWidget(self.forwardButton)
self.hBoxLayout.insertLayout(4, self.toolButtonLayout)
# add tab bar
self.tabBar = TabBar(self)
self.tabBar.setMovable(True)
self.tabBar.setTabMaximumWidth(200)
self.tabBar.setTabMaximumWidth(220)
self.tabBar.setTabShadowEnabled(False)
self.tabBar.setTabSelectedBackgroundColor(QColor(255, 255, 255, 125), QColor(255, 255, 255, 50))
# self.tabBar.setScrollable(True)
self.tabBar.setCloseButtonDisplayMode(TabCloseButtonDisplayMode.ON_HOVER)
# self.tabBar.setCloseButtonDisplayMode(TabCloseButtonDisplayMode.ON_HOVER)
self.tabBar.tabCloseRequested.connect(self.tabBar.removeTab)
self.tabBar.currentChanged.connect(lambda i: print(self.tabBar.tabText(i)))
self.hBoxLayout.insertSpacing(4, 20)
self.hBoxLayout.insertWidget(5, self.tabBar, 1)
self.hBoxLayout.setStretch(6, 0)
# add avatar
self.avatar = TransparentDropDownToolButton('resource/shoko.png', self)
self.avatar.setIconSize(QSize(26, 26))
self.avatar.setFixedHeight(30)
self.hBoxLayout.insertWidget(7, self.avatar, 0, Qt.AlignRight)
self.hBoxLayout.insertSpacing(8, 20)
def canDrag(self, pos: QPoint):
if not super().canDrag(pos):
return False
return not self.tabBar.geometry().contains(pos)
pos.setX(pos.x() - self.tabBar.x())
return not self.tabBar.tabRegion().contains(pos)
class Window(MSFluentWindow):
def __init__(self):
self.isMicaEnabled = False
super().__init__()
self.setTitleBar(CustomTitleBar(self))
self.tabBar = self.titleBar.tabBar # type: TabBar
# the index of tab can be changed by dragging, so we need to maintain a map
self.tabMap = {}
# create sub interface
self.homeInterface = QStackedWidget(self, objectName='homeInterface')
self.appInterface = Widget('Application Interface', self)
......@@ -89,6 +115,12 @@ class Window(MSFluentWindow):
self.initNavigation()
self.initWindow()
def _normalBackgroundColor(self):
if not self.isMicaEnabled:
return super()._normalBackgroundColor()
return QColor(0, 0, 0, 0) if isDarkTheme() else QColor(255, 255, 255, 50)
def initNavigation(self):
self.addSubInterface(self.homeInterface, FIF.HOME, '主页', FIF.HOME_FILL)
self.addSubInterface(self.appInterface, FIF.APPLICATION, '应用')
......@@ -109,17 +141,19 @@ class Window(MSFluentWindow):
self.homeInterface.objectName())
# add tab
self.addTab('As long as you love me', icon='resource/Heart.png')
self.addTab('Heart', 'As long as you love me', icon='resource/Heart.png')
self.tabBar.currentChanged.connect(self.onTabChanged)
self.tabBar.tabAddRequested.connect(lambda: self.addTab(
f'硝子酱一级棒卡哇伊×{self.tabBar.count()}', 'resource/Smiling_with_heart.png'))
self.tabBar.tabAddRequested.connect(self.onTabAddRequested)
def initWindow(self):
self.resize(900, 700)
self.resize(1100, 750)
self.setWindowIcon(QIcon(':/qfluentwidgets/images/logo.png'))
self.setWindowTitle('PyQt-Fluent-Widgets')
# NOTE: enable mica effect
self.useMicaEffect()
desktop = QApplication.desktop().availableGeometry()
w, h = desktop.width(), desktop.height()
self.move(w//2 - self.width()//2, h//2 - self.height()//2)
......@@ -137,15 +171,30 @@ class Window(MSFluentWindow):
QDesktopServices.openUrl(QUrl("https://afdian.net/a/zhiyiYo"))
def onTabChanged(self, index: int):
self.homeInterface.setCurrentWidget(self.tabMap[self.tabBar.currentTab()])
objectName = self.tabBar.currentTab().routeKey()
self.homeInterface.setCurrentWidget(self.findChild(TabInterface, objectName))
self.stackedWidget.setCurrentWidget(self.homeInterface)
def addTab(self, text, icon):
tab = self.tabBar.addTab(text, icon)
interface = TabInterface(text, icon, self)
self.tabMap[tab] = interface
self.homeInterface.addWidget(interface)
def onTabAddRequested(self):
text = f'硝子酱一级棒卡哇伊×{self.tabBar.count()}'
self.addTab(text, text, 'resource/Smiling_with_heart.png')
def addTab(self, routeKey, text, icon):
self.tabBar.addTab(routeKey, text, icon)
self.homeInterface.addWidget(TabInterface(text, icon, routeKey, self))
def useMicaEffect(self):
self.isMicaEnabled = True
self.windowEffect.enableBlurBehindWindow(self.winId())
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
self.windowEffect.addWindowAnimation(self.winId())
self.windowEffect.setAcrylicEffect(self.winId())
self.windowEffect.addShadowEffect(self.winId())
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
self.setStyleSheet('MSFluentWindow{background:transparent}')
self.update()
if __name__ == '__main__':
......@@ -154,6 +203,8 @@ if __name__ == '__main__':
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
setTheme(Theme.DARK)
app = QApplication(sys.argv)
w = Window()
w.show()
......
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048" xml:space="preserve">
<path fill="#000" transform="translate(0, 40)" d="M2048 960 q0 26 -19 45 q-19 19 -45 19 l-1765 0 l786 787 q19 19 19 45 q0 26 -19 45 q-19 19 -45 19 q-26 0 -45 -19 l-893 -893 q-11 -11 -16.5 -22 q-5.5 -11 -5.5 -26 q0 -15 5.5 -26 q5.5 -11 16.5 -22 l893 -893 q19 -19 45 -19 q26 0 45 19 q19 19 19 45 q0 26 -19 45 l-786 787 l1765 0 q26 0 45 19 q19 19 19 45 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048" xml:space="preserve">
<path fill="#ffffff" transform="translate(0, 40)" d="M2048 960 q0 26 -19 45 q-19 19 -45 19 l-1765 0 l786 787 q19 19 19 45 q0 26 -19 45 q-19 19 -45 19 q-26 0 -45 -19 l-893 -893 q-11 -11 -16.5 -22 q-5.5 -11 -5.5 -26 q0 -15 5.5 -26 q5.5 -11 16.5 -22 l893 -893 q19 -19 45 -19 q26 0 45 19 q19 19 19 45 q0 26 -19 45 l-786 787 l1765 0 q26 0 45 19 q19 19 19 45 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048" xml:space="preserve">
<path fill="#000" transform="translate(0, 40)" d="M1088 1920 q-26 0 -45 -19 q-19 -19 -19 -45 q0 -26 19 -45 l786 -787 l-1765 0 q-26 0 -45 -19 q-19 -19 -19 -45 q0 -26 19 -45 q19 -19 45 -19 l1765 0 l-786 -787 q-19 -19 -19 -45 q0 -26 19 -45 q19 -19 45 -19 q26 0 45 19 l893 893 q11 11 16.5 22 q5.5 11 5.5 26 q0 15 -5.5 26 q-5.5 11 -16.5 22 l-893 893 q-19 19 -45 19 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048" xml:space="preserve">
<path fill="#ffffff" transform="translate(0, 40)" d="M1088 1920 q-26 0 -45 -19 q-19 -19 -19 -45 q0 -26 19 -45 l786 -787 l-1765 0 q-26 0 -45 -19 q-19 -19 -19 -45 q0 -26 19 -45 q19 -19 45 -19 l1765 0 l-786 -787 q-19 -19 -19 -45 q0 -26 19 -45 q19 -19 45 -19 q26 0 45 19 l893 893 q11 11 16.5 22 q5.5 11 5.5 26 q0 15 -5.5 26 q-5.5 11 -16.5 22 l-893 893 q-19 19 -45 19 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#000000" d="M0 1974.86 q0 -29.72 21.71 -51.43 l604.58 -604.57 q-90.29 -107.43 -138.86 -240.57 q-48.57 -133.15 -48.57 -273.72 q0 -110.86 28.57 -213.72 q28.57 -102.86 81.14 -192 q52.57 -89.15 126.29 -162.86 q73.72 -73.71 162.86 -126.28 q89.14 -52.58 192 -81.15 q102.86 -28.57 213.72 -28.57 q110.86 0 213.71 28.57 q102.86 28.57 192 81.15 q89.14 52.57 162.86 126.28 q73.71 73.71 126.28 162.86 q52.58 89.14 81.14 192 q28.57 102.86 28.57 213.72 q0 110.86 -28.57 213.72 q-28.57 102.86 -81.14 192 q-52.57 89.14 -126.28 162.86 q-73.71 73.71 -162.86 126.28 q-89.14 52.57 -192 81.14 q-102.86 28.57 -213.71 28.57 q-140.57 0 -273.72 -48.57 q-133.14 -48.57 -240.57 -138.86 l-604.57 604.58 q-21.71 21.71 -51.43 21.71 q-29.71 0 -51.42 -21.72 q-21.71 -21.71 -21.71 -51.42 ZM585.14 804.57 q0 136 52 256 q52 120 141.14 209.14 q89.14 89.14 209.15 141.14 q120 52 256 52 q137.14 0 257.14 -51.43 q120 -51.43 209.14 -140.57 q89.14 -89.14 140.57 -209.14 q51.43 -120 51.43 -257.14 q0 -136 -52 -256 q-52 -120 -141.14 -209.14 q-89.14 -89.14 -209.14 -141.14 q-120 -52 -256 -52 q-90.29 0 -174.29 23.42 q-84 23.43 -157.14 66.29 q-73.14 42.86 -133.71 103.43 q-60.58 60.57 -103.43 133.71 q-42.86 73.14 -66.29 157.14 q-23.43 84 -23.43 174.28 Z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve"><path fill="#ffffff" d="M0 1974.86 q0 -29.72 21.71 -51.43 l604.58 -604.57 q-90.29 -107.43 -138.86 -240.57 q-48.57 -133.15 -48.57 -273.72 q0 -110.86 28.57 -213.72 q28.57 -102.86 81.14 -192 q52.57 -89.15 126.29 -162.86 q73.72 -73.71 162.86 -126.28 q89.14 -52.58 192 -81.15 q102.86 -28.57 213.72 -28.57 q110.86 0 213.71 28.57 q102.86 28.57 192 81.15 q89.14 52.57 162.86 126.28 q73.71 73.71 126.28 162.86 q52.58 89.14 81.14 192 q28.57 102.86 28.57 213.72 q0 110.86 -28.57 213.72 q-28.57 102.86 -81.14 192 q-52.57 89.14 -126.28 162.86 q-73.71 73.71 -162.86 126.28 q-89.14 52.57 -192 81.14 q-102.86 28.57 -213.71 28.57 q-140.57 0 -273.72 -48.57 q-133.14 -48.57 -240.57 -138.86 l-604.57 604.58 q-21.71 21.71 -51.43 21.71 q-29.71 0 -51.42 -21.72 q-21.71 -21.71 -21.71 -51.42 ZM585.14 804.57 q0 136 52 256 q52 120 141.14 209.14 q89.14 89.14 209.15 141.14 q120 52 256 52 q137.14 0 257.14 -51.43 q120 -51.43 209.14 -140.57 q89.14 -89.14 140.57 -209.14 q51.43 -120 51.43 -257.14 q0 -136 -52 -256 q-52 -120 -141.14 -209.14 q-89.14 -89.14 -209.14 -141.14 q-120 -52 -256 -52 q-90.29 0 -174.29 23.42 q-84 23.43 -157.14 66.29 q-73.14 42.86 -133.71 103.43 q-60.58 60.57 -103.43 133.71 q-42.86 73.14 -66.29 157.14 q-23.43 84 -23.43 174.28 Z"/></svg>
\ No newline at end of file
......@@ -55,3 +55,7 @@ SplitFluentWindow > StackedWidget {
border-top-left-radius: 0px;
border-top: none;
}
FluentWindowBase {
background-color: transparent;
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ SplitFluentWindow>StackedWidget {
}
FluentWindowBase {
background-color: rgb(243, 243, 243);
background-color: transparent;
}
FluentTitleBar, SplitTitleBar {
......
此差异已折叠。
......@@ -326,6 +326,12 @@
<file>images/icons/IOT_black.svg</file>
<file>images/icons/Airplane_white.svg</file>
<file>images/icons/Airplane_black.svg</file>
<file>images/icons/LeftArrow_white.svg</file>
<file>images/icons/LeftArrow_black.svg</file>
<file>images/icons/RightArrow_white.svg</file>
<file>images/icons/RightArrow_black.svg</file>
<file>images/icons/SearchMirror_white.svg</file>
<file>images/icons/SearchMirror_black.svg</file>
<file>images/acrylic/noise.png</file>
<file>images/folder_list_dialog/Close_white.png</file>
......
......@@ -353,6 +353,7 @@ class FluentIcon(FluentIconBase, Enum):
MEGAPHONE = "Megaphone"
PROJECTOR = "Projector"
EDUCATION = "Education"
LEFT_ARROW = "LeftArrow"
ERASE_TOOL = "EraseTool"
PAGE_RIGHT = "PageRight"
BOOK_SHELF = "BookShelf"
......@@ -372,6 +373,7 @@ class FluentIcon(FluentIconBase, Enum):
FULL_SCREEN = "FullScreen"
MIX_VOLUMES = "MixVolumes"
REMOVE_FROM = "RemoveFrom"
RIGHT_ARROW = "RightArrow"
QUIET_HOURS ="QuietHours"
FINGERPRINT = "Fingerprint"
APPLICATION = "Application"
......@@ -387,6 +389,7 @@ class FluentIcon(FluentIconBase, Enum):
CANCEL_MEDIUM = "CancelMedium"
CHEVRON_RIGHT = "ChevronRight"
CLIPPING_TOOL = "ClippingTool"
SEARCH_MIRROR = "SearchMirror"
SHOPPING_CART = "ShoppingCart"
FONT_INCREASE = "FontIncrease"
BACK_TO_WINDOW = "BackToWindow"
......
......@@ -118,7 +118,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
def path(self, theme=Theme.AUTO):
theme = qconfig.theme if theme == Theme.AUTO else theme
return f"qfluentwidgets/_rc/qss/{theme.value.lower()}/{self.value}.qss"
return f":/qfluentwidgets/qss/{theme.value.lower()}/{self.value}.qss"
def getStyleSheet(file: Union[str, StyleSheetBase], theme=Theme.AUTO):
......
# coding:utf-8
from copy import deepcopy
from enum import Enum
from typing import List, Union
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QRectF, QSize, QPoint, QPropertyAnimation, QEasingCurve
from typing import Dict, List, Union
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty, QRectF, QSize, QPoint, QPropertyAnimation, QEasingCurve, QRect
from PyQt5.QtGui import QPainter, QColor, QIcon, QPainterPath, QLinearGradient, QPen, QBrush, QMouseEvent
from PyQt5.QtWidgets import QWidget, QGraphicsDropShadowEffect, QHBoxLayout, QSizePolicy, QApplication
from ...common.icon import FluentIcon, FluentIconBase, drawIcon
from ...common.style_sheet import isDarkTheme, FluentStyleSheet
from ...common.font import setFont
from ...common.router import qrouter
from .button import TransparentToolButton, PushButton
from .scroll_area import SingleDirectionScrollArea
from .tool_tip import ToolTipFilter
......@@ -71,8 +72,10 @@ class TabItem(PushButton):
super()._postInit()
self.borderRadius = 5
self.isSelected = False
self.isShadowEnabled = True
self.closeButtonDisplayMode = TabCloseButtonDisplayMode.ALWAYS
self._routeKey = None
self.textColor = None
self.lightSelectedBackgroundColor = QColor(249, 249, 249)
self.darkSelectedBackgroundColor = QColor(40, 40, 40)
......@@ -94,8 +97,8 @@ class TabItem(PushButton):
self.closeButton.setIconSize(QSize(10, 10))
self.shadowEffect.setBlurRadius(8)
self.shadowEffect.setOffset(0, 0)
self.shadowEffect.setBlurRadius(5)
self.shadowEffect.setOffset(0, 1)
self.setGraphicsEffect(self.shadowEffect)
self.setSelected(False)
......@@ -108,13 +111,31 @@ class TabItem(PushButton):
self.slideAni.setEasingCurve(QEasingCurve.InOutQuad)
self.slideAni.start()
def setShadowEnabled(self, isEnabled: bool):
""" set whether the shadow is enabled """
if isEnabled == self.isShadowEnabled:
return
self.isShadowEnabled = isEnabled
self.shadowEffect.setColor(QColor(0, 0, 0, 50*self._canShowShadow()))
def _canShowShadow(self):
return self.isSelected and self.isShadowEnabled
def setRouteKey(self, key: str):
self._routeKey = key
def routeKey(self):
return self._routeKey
def setBorderRadius(self, radius: int):
self.borderRadius = radius
self.update()
def setSelected(self, isSelected: bool):
self.isSelected = isSelected
self.shadowEffect.setColor(QColor(0, 0, 0, 50*isSelected))
self.shadowEffect.setColor(QColor(0, 0, 0, 50*self._canShowShadow()))
self.update()
if isSelected:
......@@ -307,10 +328,13 @@ class TabBar(SingleDirectionScrollArea):
def __init__(self, parent=None):
super().__init__(parent=parent, orient=Qt.Horizontal)
self.items = [] # type: List[TabItem]
self.itemMap = {} # type: Dict[str, TabItem]
self._currentIndex = -1
self._isMovable = False
self._isScrollable = False
self._isTabShadowEnabled = True
self._tabMaxWidth = 240
self._tabMinWidth = 64
......@@ -372,20 +396,27 @@ class TabBar(SingleDirectionScrollArea):
def setAddButtonVisible(self, isVisible: bool):
self.addButton.setVisible(isVisible)
def addTab(self, text: str, icon: Union[QIcon, str, FluentIconBase] = None):
def addTab(self, routeKey: str, text: str, icon: Union[QIcon, str, FluentIconBase] = None, onClick=None):
""" add tab
Parameters
----------
routeKey: str
the unique name of tab item
text: str
the text of tab item
text: str
the icon of tab item
onClick: callable
the slot connected to item clicked signal
"""
return self.insertTab(-1, text, icon)
return self.insertTab(-1, routeKey, text, icon, onClick)
def insertTab(self, index: int, text: str, icon: Union[QIcon, str, FluentIconBase] = None):
def insertTab(self, index: int, routeKey: str, text: str, icon: Union[QIcon, str, FluentIconBase] = None,
onClick=None):
""" insert tab
Parameters
......@@ -393,12 +424,21 @@ class TabBar(SingleDirectionScrollArea):
index: int
the insert position of tab item
routeKey: str
the unique name of tab item
text: str
the text of tab item
text: str
the icon of tab item
onClick: callable
the slot connected to item clicked signal
"""
if routeKey in self.itemMap:
raise ValueError(f"The route key `{routeKey}` is duplicated.")
if index == -1:
index = len(self.items)
......@@ -407,22 +447,26 @@ class TabBar(SingleDirectionScrollArea):
self._currentIndex += 1
item = TabItem(text, self.view, icon)
item.setRouteKey(routeKey)
# set the size of tab
w = self.tabMaximumWidth() if self.isScrollable() else self.tabMinimumWidth()
item.setMinimumWidth(w)
item.setMaximumWidth(self.tabMaximumWidth())
item.setShadowEnabled(self.isTabShadowEnabled())
item.setCloseButtonDisplayMode(self.closeButtonDisplayMode)
item.setSelectedBackgroundColor(
self.lightSelectedBackgroundColor, self.darkSelectedBackgroundColor)
item.pressed.connect(self._onItemPressed)
item.closed.connect(lambda: self.tabCloseRequested.emit(
self.items.index(item)))
item.closed.connect(lambda: self.tabCloseRequested.emit(self.items.index(item)))
if onClick:
item.pressed.connect(onClick)
self.itemLayout.insertWidget(index, item, 1)
self.items.insert(index, item)
self.itemMap[routeKey] = item
if len(self.items) == 1:
self.setCurrentIndex(0)
......@@ -449,12 +493,20 @@ class TabBar(SingleDirectionScrollArea):
# remove tab
item = self.items.pop(index)
self.itemMap.pop(item.routeKey())
self.hBoxLayout.removeWidget(item)
qrouter.remove(item.routeKey())
item.deleteLater()
# remove shadow
self.update()
def removeTabByKey(self, routeKey: str):
if routeKey not in self.itemMap:
return
self.removeTab(self.items.index(self.tab(routeKey)))
def setCurrentIndex(self, index: int):
""" set current index """
if index == self._currentIndex:
......@@ -466,6 +518,12 @@ class TabBar(SingleDirectionScrollArea):
self._currentIndex = index
self.items[index].setSelected(True)
def setCurrentTab(self, routeKey: str):
if routeKey not in self.itemMap:
return
self.setCurrentIndex(self.items.index(self.tab(routeKey)))
def currentIndex(self):
return self._currentIndex
......@@ -496,6 +554,13 @@ class TabBar(SingleDirectionScrollArea):
def tabItem(self, index: int):
return self.items[index]
def tab(self, routeKey: str):
return self.itemMap.get(routeKey, None)
def tabRegion(self) -> QRect:
""" return the bounding rect of all tabs """
return self.itemLayout.geometry()
@checkIndex()
def tabRect(self, index: int):
""" return the visual rectangle of the tab at position index """
......@@ -575,6 +640,18 @@ class TabBar(SingleDirectionScrollArea):
for item in self.items:
item.setSelectedBackgroundColor(light, dark)
def setTabShadowEnabled(self, isEnabled: bool):
""" set whether the shadow of tab is enabled """
if isEnabled == self.isTabShadowEnabled():
return
self._isTabShadowEnabled = isEnabled
for item in self.items:
item.setShadowEnabled(isEnabled)
def isTabShadowEnabled(self):
return self._isTabShadowEnabled
def paintEvent(self, e):
painter = QPainter(self.viewport())
painter.setRenderHints(QPainter.Antialiasing)
......@@ -720,3 +797,8 @@ class TabBar(SingleDirectionScrollArea):
self._currentIndex = index
swappedItem.slideTo(x)
movable = pyqtProperty(bool, isMovable, setMovable)
scrollable = pyqtProperty(bool, isScrollable, setScrollable)
tabMaxWidth = pyqtProperty(int, tabMaximumWidth, setTabMaximumWidth)
tabMinWidth = pyqtProperty(int, tabMinimumWidth, setTabMinimumWidth)
tabShadowEnabled = pyqtProperty(bool, isTabShadowEnabled, setTabSelectedBackgroundColor)
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册