Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
k54kdk
PyQt Fluent Widgets
提交
6251d7b4
P
PyQt Fluent Widgets
项目概览
k54kdk
/
PyQt Fluent Widgets
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PyQt Fluent Widgets
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
6251d7b4
编写于
8月 06, 2023
作者:
之一Yo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
添加 `TabBar`
上级
2eb09a7a
变更
12
展开全部
隐藏空白更改
内联
并排
Showing
12 changed file
with
95463 addition
and
94609 deletion
+95463
-94609
examples/tab_view/demo.py
examples/tab_view/demo.py
+232
-0
examples/tab_view/resource/Chicken.png
examples/tab_view/resource/Chicken.png
+0
-0
examples/tab_view/resource/Heart.png
examples/tab_view/resource/Heart.png
+0
-0
examples/tab_view/resource/dark/demo.qss
examples/tab_view/resource/dark/demo.qss
+53
-0
examples/tab_view/resource/light/demo.qss
examples/tab_view/resource/light/demo.qss
+46
-0
qfluentwidgets/_rc/qss/dark/tab_view.qss
qfluentwidgets/_rc/qss/dark/tab_view.qss
+8
-0
qfluentwidgets/_rc/qss/light/tab_view.qss
qfluentwidgets/_rc/qss/light/tab_view.qss
+8
-0
qfluentwidgets/_rc/resource.py
qfluentwidgets/_rc/resource.py
+94638
-94608
qfluentwidgets/_rc/resource.qrc
qfluentwidgets/_rc/resource.qrc
+2
-0
qfluentwidgets/common/style_sheet.py
qfluentwidgets/common/style_sheet.py
+1
-0
qfluentwidgets/components/widgets/__init__.py
qfluentwidgets/components/widgets/__init__.py
+2
-1
qfluentwidgets/components/widgets/tab_view.py
qfluentwidgets/components/widgets/tab_view.py
+473
-0
未找到文件。
examples/tab_view/demo.py
0 → 100644
浏览文件 @
6251d7b4
# coding:utf-8
import
sys
from
PyQt5.QtCore
import
Qt
,
pyqtSignal
,
QEasingCurve
,
QUrl
from
PyQt5.QtGui
import
QIcon
,
QDesktopServices
from
PyQt5.QtWidgets
import
QLabel
,
QHBoxLayout
,
QVBoxLayout
,
QApplication
,
QFrame
,
QWidget
from
qfluentwidgets
import
(
NavigationBar
,
NavigationItemPosition
,
NavigationWidget
,
MessageBox
,
isDarkTheme
,
setTheme
,
Theme
,
setThemeColor
,
SearchLineEdit
,
PopUpAniStackedWidget
,
TabBar
,
TransparentToolButton
)
from
qfluentwidgets
import
FluentIcon
as
FIF
from
qframelesswindow
import
FramelessWindow
,
TitleBar
class
Widget
(
QWidget
):
def
__init__
(
self
,
text
:
str
,
parent
=
None
):
super
().
__init__
(
parent
=
parent
)
self
.
label
=
QLabel
(
text
,
self
)
self
.
label
.
setAlignment
(
Qt
.
AlignCenter
)
self
.
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
hBoxLayout
.
addWidget
(
self
.
label
,
1
,
Qt
.
AlignCenter
)
self
.
setObjectName
(
text
.
replace
(
' '
,
'-'
))
class
StackedWidget
(
QFrame
):
""" Stacked widget """
currentChanged
=
pyqtSignal
(
int
)
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
parent
=
parent
)
self
.
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
view
=
PopUpAniStackedWidget
(
self
)
self
.
hBoxLayout
.
setContentsMargins
(
0
,
0
,
0
,
0
)
self
.
hBoxLayout
.
addWidget
(
self
.
view
)
self
.
view
.
currentChanged
.
connect
(
self
.
currentChanged
)
def
addWidget
(
self
,
widget
):
""" add widget to view """
self
.
view
.
addWidget
(
widget
)
def
widget
(
self
,
index
:
int
):
return
self
.
view
.
widget
(
index
)
def
setCurrentWidget
(
self
,
widget
,
popOut
=
False
):
if
not
popOut
:
self
.
view
.
setCurrentWidget
(
widget
,
duration
=
300
)
else
:
self
.
view
.
setCurrentWidget
(
widget
,
True
,
False
,
200
,
QEasingCurve
.
InQuad
)
def
setCurrentIndex
(
self
,
index
,
popOut
=
False
):
self
.
setCurrentWidget
(
self
.
view
.
widget
(
index
),
popOut
)
class
CustomTitleBar
(
TitleBar
):
""" Title bar with icon and title """
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
)
# add window icon
self
.
iconLabel
=
QLabel
(
self
)
self
.
iconLabel
.
setFixedSize
(
18
,
18
)
self
.
hBoxLayout
.
insertSpacing
(
0
,
20
)
self
.
hBoxLayout
.
insertWidget
(
1
,
self
.
iconLabel
,
0
,
Qt
.
AlignLeft
|
Qt
.
AlignVCenter
)
self
.
window
().
windowIconChanged
.
connect
(
self
.
setIcon
)
# add title label
self
.
titleLabel
=
QLabel
(
self
)
self
.
hBoxLayout
.
insertWidget
(
2
,
self
.
titleLabel
,
0
,
Qt
.
AlignLeft
|
Qt
.
AlignVCenter
)
self
.
hBoxLayout
.
insertSpacing
(
3
,
20
)
self
.
titleLabel
.
setObjectName
(
'titleLabel'
)
self
.
window
().
windowTitleChanged
.
connect
(
self
.
setTitle
)
# add tab bar
self
.
tabBar
=
TabBar
(
self
)
self
.
tabBar
.
addTab
(
'As long as you love me'
,
'resource/Heart.png'
)
self
.
tabBar
.
tabAddRequested
.
connect
(
self
.
addTab
)
self
.
tabBar
.
tabCloseRequested
.
connect
(
self
.
tabBar
.
removeTab
)
self
.
tabBar
.
currentChanged
.
connect
(
lambda
i
:
print
(
self
.
tabBar
.
tabText
(
i
)))
self
.
hBoxLayout
.
insertWidget
(
4
,
self
.
tabBar
,
1
)
self
.
hBoxLayout
.
setStretch
(
5
,
0
)
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
)
def
setTitle
(
self
,
title
):
self
.
titleLabel
.
setText
(
title
)
self
.
titleLabel
.
adjustSize
()
def
setIcon
(
self
,
icon
):
self
.
iconLabel
.
setPixmap
(
QIcon
(
icon
).
pixmap
(
18
,
18
))
def
addTab
(
self
):
self
.
tabBar
.
addTab
(
'你干嘛~'
,
'resource/Chicken.png'
)
class
Window
(
FramelessWindow
):
def
__init__
(
self
):
super
().
__init__
()
self
.
setTitleBar
(
CustomTitleBar
(
self
))
# use dark theme mode
# setTheme(Theme.DARK)
# change the theme color
# setThemeColor('#0078d4')
self
.
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
navigationBar
=
NavigationBar
(
self
)
self
.
stackWidget
=
StackedWidget
(
self
)
# create sub interface
self
.
homeInterface
=
Widget
(
'Home Interface'
,
self
)
self
.
appInterface
=
Widget
(
'Application Interface'
,
self
)
self
.
videoInterface
=
Widget
(
'Video Interface'
,
self
)
self
.
libraryInterface
=
Widget
(
'library Interface'
,
self
)
# initialize layout
self
.
initLayout
()
# add items to navigation interface
self
.
initNavigation
()
self
.
initWindow
()
def
initLayout
(
self
):
self
.
hBoxLayout
.
setSpacing
(
0
)
self
.
hBoxLayout
.
setContentsMargins
(
0
,
48
,
0
,
0
)
self
.
hBoxLayout
.
addWidget
(
self
.
navigationBar
)
self
.
hBoxLayout
.
addWidget
(
self
.
stackWidget
)
self
.
hBoxLayout
.
setStretchFactor
(
self
.
stackWidget
,
1
)
def
initNavigation
(
self
):
self
.
addSubInterface
(
self
.
homeInterface
,
FIF
.
HOME
,
'主页'
,
selectedIcon
=
FIF
.
HOME_FILL
)
self
.
addSubInterface
(
self
.
appInterface
,
FIF
.
APPLICATION
,
'应用'
)
self
.
addSubInterface
(
self
.
videoInterface
,
FIF
.
VIDEO
,
'视频'
)
self
.
addSubInterface
(
self
.
libraryInterface
,
FIF
.
BOOK_SHELF
,
'库'
,
NavigationItemPosition
.
BOTTOM
,
FIF
.
LIBRARY_FILL
)
self
.
navigationBar
.
addItem
(
routeKey
=
'Help'
,
icon
=
FIF
.
HELP
,
text
=
'帮助'
,
onClick
=
self
.
showMessageBox
,
selectable
=
False
,
position
=
NavigationItemPosition
.
BOTTOM
,
)
self
.
stackWidget
.
currentChanged
.
connect
(
self
.
onCurrentInterfaceChanged
)
self
.
navigationBar
.
setCurrentItem
(
self
.
homeInterface
.
objectName
())
def
initWindow
(
self
):
self
.
resize
(
900
,
700
)
self
.
setWindowIcon
(
QIcon
(
':/qfluentwidgets/images/logo.png'
))
self
.
setWindowTitle
(
'PyQt-Fluent-Widgets'
)
self
.
titleBar
.
setAttribute
(
Qt
.
WA_StyledBackground
)
desktop
=
QApplication
.
desktop
().
availableGeometry
()
w
,
h
=
desktop
.
width
(),
desktop
.
height
()
self
.
move
(
w
//
2
-
self
.
width
()
//
2
,
h
//
2
-
self
.
height
()
//
2
)
self
.
setQss
()
def
addSubInterface
(
self
,
interface
,
icon
,
text
:
str
,
position
=
NavigationItemPosition
.
TOP
,
selectedIcon
=
None
):
""" add sub interface """
self
.
stackWidget
.
addWidget
(
interface
)
self
.
navigationBar
.
addItem
(
routeKey
=
interface
.
objectName
(),
icon
=
icon
,
text
=
text
,
onClick
=
lambda
:
self
.
switchTo
(
interface
),
selectedIcon
=
selectedIcon
,
position
=
position
,
)
def
setQss
(
self
):
color
=
'dark'
if
isDarkTheme
()
else
'light'
with
open
(
f
'resource/
{
color
}
/demo.qss'
,
encoding
=
'utf-8'
)
as
f
:
self
.
setStyleSheet
(
f
.
read
())
def
switchTo
(
self
,
widget
):
self
.
stackWidget
.
setCurrentWidget
(
widget
)
def
onCurrentInterfaceChanged
(
self
,
index
):
widget
=
self
.
stackWidget
.
widget
(
index
)
self
.
navigationBar
.
setCurrentItem
(
widget
.
objectName
())
def
showMessageBox
(
self
):
w
=
MessageBox
(
'支持作者🥰'
,
'个人开发不易,如果这个项目帮助到了您,可以考虑请作者喝一瓶快乐水🥤。您的支持就是作者开发和维护项目的动力🚀'
,
self
)
w
.
yesButton
.
setText
(
'来啦老弟'
)
w
.
cancelButton
.
setText
(
'下次一定'
)
if
w
.
exec
():
QDesktopServices
.
openUrl
(
QUrl
(
"https://afdian.net/a/zhiyiYo"
))
if
__name__
==
'__main__'
:
QApplication
.
setHighDpiScaleFactorRoundingPolicy
(
Qt
.
HighDpiScaleFactorRoundingPolicy
.
PassThrough
)
QApplication
.
setAttribute
(
Qt
.
AA_EnableHighDpiScaling
)
QApplication
.
setAttribute
(
Qt
.
AA_UseHighDpiPixmaps
)
app
=
QApplication
(
sys
.
argv
)
w
=
Window
()
w
.
show
()
app
.
exec_
()
examples/tab_view/resource/Chicken.png
0 → 100644
浏览文件 @
6251d7b4
141.4 KB
examples/tab_view/resource/Heart.png
0 → 100644
浏览文件 @
6251d7b4
131.2 KB
examples/tab_view/resource/dark/demo.qss
0 → 100644
浏览文件 @
6251d7b4
Widget > QLabel {
font: 24px 'Segoe UI', 'Microsoft YaHei';
}
StackedWidget {
border: 1px solid rgb(29, 29, 29);
border-right: none;
border-bottom: none;
border-top-left-radius: 10px;
background-color: rgb(39, 39, 39);
}
Window {
background-color: rgb(32, 32, 32);
}
Widget > QLabel {
color: white;
}
CustomTitleBar {
background-color: transparent;
}
CustomTitleBar>QLabel#titleLabel {
background: transparent;
font: 13px 'Segoe UI';
padding: 0 10px;
color: white;
}
MinimizeButton {
qproperty-normalColor: white;
qproperty-normalBackgroundColor: transparent;
qproperty-hoverColor: white;
qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
qproperty-pressedColor: white;
qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
}
MaximizeButton {
qproperty-normalColor: white;
qproperty-normalBackgroundColor: transparent;
qproperty-hoverColor: white;
qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
qproperty-pressedColor: white;
qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
}
CloseButton {
qproperty-normalColor: white;
qproperty-normalBackgroundColor: transparent;
}
\ No newline at end of file
examples/tab_view/resource/light/demo.qss
0 → 100644
浏览文件 @
6251d7b4
Widget > QLabel {
font: 24px 'Segoe UI', 'Microsoft YaHei';
}
StackedWidget {
border: 1px solid rgb(229, 229, 229);
border-right: none;
border-bottom: none;
border-top-left-radius: 10px;
background-color: rgb(249, 249, 249);
}
Window {
background-color: rgb(243, 243, 243);
}
CustomTitleBar>QLabel#titleLabel {
color: black;
background: transparent;
font: 13px 'Segoe UI';
padding: 0 10px
}
MinimizeButton {
qproperty-normalColor: black;
qproperty-normalBackgroundColor: transparent;
qproperty-hoverColor: black;
qproperty-hoverBackgroundColor: rgba(0, 0, 0, 26);
qproperty-pressedColor: black;
qproperty-pressedBackgroundColor: rgba(0, 0, 0, 51)
}
MaximizeButton {
qproperty-normalColor: black;
qproperty-normalBackgroundColor: transparent;
qproperty-hoverColor: black;
qproperty-hoverBackgroundColor: rgba(0, 0, 0, 26);
qproperty-pressedColor: black;
qproperty-pressedBackgroundColor: rgba(0, 0, 0, 51)
}
CloseButton {
qproperty-normalColor: black;
qproperty-normalBackgroundColor: transparent;
}
\ No newline at end of file
qfluentwidgets/_rc/qss/dark/tab_view.qss
0 → 100644
浏览文件 @
6251d7b4
TabBar {
border: none;
background-color: transparent;
}
#view {
background-color: transparent;
}
\ No newline at end of file
qfluentwidgets/_rc/qss/light/tab_view.qss
0 → 100644
浏览文件 @
6251d7b4
TabBar {
border: none;
background-color: transparent;
}
#view {
background-color: transparent;
}
\ No newline at end of file
qfluentwidgets/_rc/resource.py
浏览文件 @
6251d7b4
此差异已折叠。
点击以展开。
qfluentwidgets/_rc/resource.qrc
浏览文件 @
6251d7b4
...
@@ -385,6 +385,7 @@
...
@@ -385,6 +385,7 @@
<file>qss/dark/fluent_window.qss</file>
<file>qss/dark/fluent_window.qss</file>
<file>qss/dark/teaching_tip.qss</file>
<file>qss/dark/teaching_tip.qss</file>
<file>qss/dark/info_badge.qss</file>
<file>qss/dark/info_badge.qss</file>
<file>qss/dark/tab_view.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/dialog.qss</file>
<file>qss/light/dialog.qss</file>
...
@@ -414,6 +415,7 @@
...
@@ -414,6 +415,7 @@
<file>qss/light/fluent_window.qss</file>
<file>qss/light/fluent_window.qss</file>
<file>qss/light/teaching_tip.qss</file>
<file>qss/light/teaching_tip.qss</file>
<file>qss/light/info_badge.qss</file>
<file>qss/light/info_badge.qss</file>
<file>qss/light/tab_view.qss</file>
<file>i18n/qfluentwidgets.zh_CN.qm</file>
<file>i18n/qfluentwidgets.zh_CN.qm</file>
<file>i18n/qfluentwidgets.zh_HK.qm</file>
<file>i18n/qfluentwidgets.zh_HK.qm</file>
...
...
qfluentwidgets/common/style_sheet.py
浏览文件 @
6251d7b4
...
@@ -93,6 +93,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
...
@@ -93,6 +93,7 @@ class FluentStyleSheet(StyleSheetBase, Enum):
SLIDER
=
"slider"
SLIDER
=
"slider"
INFO_BAR
=
"info_bar"
INFO_BAR
=
"info_bar"
SPIN_BOX
=
"spin_box"
SPIN_BOX
=
"spin_box"
TAB_VIEW
=
"tab_view"
TOOL_TIP
=
"tool_tip"
TOOL_TIP
=
"tool_tip"
CHECK_BOX
=
"check_box"
CHECK_BOX
=
"check_box"
COMBO_BOX
=
"combo_box"
COMBO_BOX
=
"combo_box"
...
...
qfluentwidgets/components/widgets/__init__.py
浏览文件 @
6251d7b4
...
@@ -33,4 +33,5 @@ from .progress_bar import IndeterminateProgressBar, ProgressBar
...
@@ -33,4 +33,5 @@ from .progress_bar import IndeterminateProgressBar, ProgressBar
from
.progress_ring
import
ProgressRing
,
IndeterminateProgressRing
from
.progress_ring
import
ProgressRing
,
IndeterminateProgressRing
from
.scroll_bar
import
ScrollBar
,
SmoothScrollBar
,
SmoothScrollDelegate
from
.scroll_bar
import
ScrollBar
,
SmoothScrollBar
,
SmoothScrollDelegate
from
.teaching_tip
import
TeachingTip
,
TeachingTipTailPosition
,
TeachingTipView
,
PopupTeachingTip
from
.teaching_tip
import
TeachingTip
,
TeachingTipTailPosition
,
TeachingTipView
,
PopupTeachingTip
from
.flyout
import
FlyoutView
,
FlyoutViewBase
,
Flyout
,
FlyoutAnimationType
,
FlyoutAnimationManager
from
.flyout
import
FlyoutView
,
FlyoutViewBase
,
Flyout
,
FlyoutAnimationType
,
FlyoutAnimationManager
\ No newline at end of file
from
.tab_view
import
TabBar
,
TabItem
\ No newline at end of file
qfluentwidgets/components/widgets/tab_view.py
0 → 100644
浏览文件 @
6251d7b4
# 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
from
PyQt5.QtGui
import
QPixmap
,
QPainter
,
QColor
,
QIcon
,
QPainterPath
,
QLinearGradient
,
QPen
,
QBrush
from
PyQt5.QtWidgets
import
QWidget
,
QGraphicsDropShadowEffect
,
QHBoxLayout
,
QSizePolicy
from
...common.icon
import
FluentIcon
,
FluentIconBase
,
drawIcon
from
...common.style_sheet
import
isDarkTheme
,
FluentStyleSheet
from
...common.font
import
setFont
from
.button
import
TransparentToolButton
,
PushButton
from
.scroll_area
import
SingleDirectionScrollArea
class
TabCloseButtonDisplayMode
(
Enum
):
""" Tab close button display mode """
ALWAYS
=
0
ON_HOVER
=
1
NEVER
=
2
def
checkIndex
(
*
default
):
""" decorator for index checking
Parameters
----------
*default:
the default value returned when an index overflow
"""
def
outer
(
func
):
def
inner
(
tabBar
,
index
:
int
,
*
args
,
**
kwargs
):
if
0
<=
index
<
len
(
tabBar
.
items
):
return
func
(
tabBar
,
index
,
*
args
,
**
kwargs
)
value
=
deepcopy
(
default
)
if
len
(
value
)
==
0
:
return
None
elif
len
(
value
)
==
1
:
return
value
[
0
]
return
value
return
inner
return
outer
class
TabItem
(
PushButton
):
""" Tab item """
closed
=
pyqtSignal
()
def
_postInit
(
self
):
super
().
_postInit
()
self
.
borderRadius
=
6
self
.
isSelected
=
False
self
.
textColor
=
None
self
.
closeButtonDisplayMode
=
TabCloseButtonDisplayMode
.
ALWAYS
self
.
closeButton
=
TransparentToolButton
(
FluentIcon
.
CLOSE
,
self
)
self
.
shadowEffect
=
QGraphicsDropShadowEffect
(
self
)
self
.
__initWidget
()
def
__initWidget
(
self
):
setFont
(
self
,
12
)
self
.
setFixedSize
(
240
,
36
)
self
.
closeButton
.
setFixedSize
(
32
,
24
)
self
.
closeButton
.
setIconSize
(
QSize
(
10
,
10
))
self
.
shadowEffect
.
setBlurRadius
(
12
)
self
.
shadowEffect
.
setOffset
(
0
,
0
)
self
.
setGraphicsEffect
(
self
.
shadowEffect
)
self
.
setSelected
(
False
)
self
.
closeButton
.
clicked
.
connect
(
self
.
closed
)
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
.
update
()
if
self
.
closeButtonDisplayMode
==
TabCloseButtonDisplayMode
.
ON_HOVER
:
self
.
closeButton
.
setVisible
(
isSelected
)
def
setCloseButtonDisplayMode
(
self
,
mode
:
TabCloseButtonDisplayMode
):
""" set close button display mode """
if
mode
==
self
.
closeButtonDisplayMode
:
return
self
.
closeButtonDisplayMode
=
mode
if
mode
==
TabCloseButtonDisplayMode
.
NEVER
:
self
.
closeButton
.
hide
()
elif
mode
==
TabCloseButtonDisplayMode
.
ALWAYS
:
self
.
closeButton
.
show
()
else
:
self
.
closeButton
.
setVisible
(
self
.
isHover
or
self
.
isSelected
)
def
setTextColor
(
self
,
color
:
QColor
):
self
.
textColor
=
color
self
.
update
()
def
resizeEvent
(
self
,
e
):
self
.
closeButton
.
move
(
self
.
width
()
-
6
-
self
.
closeButton
.
width
(),
int
(
self
.
height
()
/
2
-
self
.
closeButton
.
height
()
/
2
))
def
enterEvent
(
self
,
e
):
super
().
enterEvent
(
e
)
if
self
.
closeButtonDisplayMode
==
TabCloseButtonDisplayMode
.
ON_HOVER
:
self
.
closeButton
.
show
()
def
leaveEvent
(
self
,
e
):
super
().
leaveEvent
(
e
)
if
self
.
closeButtonDisplayMode
==
TabCloseButtonDisplayMode
.
ON_HOVER
and
not
self
.
isSelected
:
self
.
closeButton
.
hide
()
def
paintEvent
(
self
,
e
):
painter
=
QPainter
(
self
)
painter
.
setRenderHints
(
QPainter
.
Antialiasing
)
if
self
.
isSelected
:
self
.
_drawSelectedBackground
(
painter
)
else
:
self
.
_drawNotSelectedBackground
(
painter
)
# draw icon
if
not
self
.
isSelected
:
painter
.
setOpacity
(
0.79
if
isDarkTheme
()
else
0.61
)
drawIcon
(
self
.
_icon
,
painter
,
QRectF
(
10
,
10
,
16
,
16
))
# draw text
self
.
_drawText
(
painter
)
def
_drawSelectedBackground
(
self
,
painter
:
QPainter
):
w
,
h
=
self
.
width
(),
self
.
height
()
r
=
self
.
borderRadius
d
=
2
*
r
isDark
=
isDarkTheme
()
# draw top border
path
=
QPainterPath
()
path
.
arcMoveTo
(
1
,
h
-
d
-
1
,
d
,
d
,
225
)
path
.
arcTo
(
1
,
h
-
d
-
1
,
d
,
d
,
225
,
-
45
)
path
.
lineTo
(
1
,
r
)
path
.
arcTo
(
1
,
1
,
d
,
d
,
-
180
,
-
90
)
path
.
lineTo
(
w
-
r
,
1
)
path
.
arcTo
(
w
-
d
-
1
,
1
,
d
,
d
,
90
,
-
90
)
path
.
lineTo
(
w
-
1
,
h
-
r
)
path
.
arcTo
(
w
-
d
-
1
,
h
-
d
-
1
,
d
,
d
,
0
,
-
45
)
topBorderColor
=
QColor
(
0
,
0
,
0
,
20
)
if
isDark
:
if
self
.
isPressed
:
topBorderColor
=
QColor
(
255
,
255
,
255
,
18
)
elif
self
.
isHover
:
topBorderColor
=
QColor
(
255
,
255
,
255
,
13
)
else
:
topBorderColor
=
QColor
(
0
,
0
,
0
,
16
)
painter
.
strokePath
(
path
,
topBorderColor
)
# draw bottom border
path
=
QPainterPath
()
path
.
arcMoveTo
(
1
,
h
-
d
-
1
,
d
,
d
,
225
)
path
.
arcTo
(
1
,
h
-
d
-
1
,
d
,
d
,
225
,
45
)
path
.
lineTo
(
w
-
r
-
1
,
h
-
1
)
path
.
arcTo
(
w
-
d
-
1
,
h
-
d
-
1
,
d
,
d
,
270
,
45
)
bottomBorderColor
=
topBorderColor
if
not
isDark
:
bottomBorderColor
=
QColor
(
0
,
0
,
0
,
63
)
painter
.
strokePath
(
path
,
bottomBorderColor
)
# draw background
painter
.
setPen
(
Qt
.
NoPen
)
rect
=
self
.
rect
().
adjusted
(
1
,
1
,
-
1
,
-
1
)
if
isDark
:
color
=
QColor
(
40
,
40
,
40
)
else
:
color
=
QColor
(
246
,
246
,
246
)
painter
.
setBrush
(
color
)
painter
.
drawRoundedRect
(
rect
,
r
,
r
)
def
_drawNotSelectedBackground
(
self
,
painter
:
QPainter
):
if
not
(
self
.
isPressed
or
self
.
isHover
):
return
isDark
=
isDarkTheme
()
if
self
.
isPressed
:
color
=
QColor
(
255
,
255
,
255
,
12
)
if
isDark
else
QColor
(
0
,
0
,
0
,
7
)
else
:
color
=
QColor
(
255
,
255
,
255
,
15
)
if
isDark
else
QColor
(
0
,
0
,
0
,
10
)
painter
.
setBrush
(
color
)
painter
.
setPen
(
Qt
.
NoPen
)
painter
.
drawRoundedRect
(
self
.
rect
().
adjusted
(
1
,
1
,
-
1
,
-
1
),
self
.
borderRadius
,
self
.
borderRadius
)
def
_drawText
(
self
,
painter
:
QPainter
):
tw
=
self
.
fontMetrics
().
width
(
self
.
text
())
if
self
.
icon
().
isNull
():
dw
=
55
if
self
.
closeButton
.
isVisible
()
else
18
rect
=
QRectF
(
18
,
0
,
self
.
width
()
-
dw
,
self
.
height
())
else
:
dw
=
40
if
self
.
closeButton
.
isVisible
()
else
12
rect
=
QRectF
(
35
,
0
,
self
.
width
()
-
dw
,
self
.
height
())
pen
=
QPen
()
color
=
Qt
.
white
if
isDarkTheme
()
else
Qt
.
black
color
=
self
.
textColor
or
color
if
tw
>
rect
.
width
():
gradient
=
QLinearGradient
(
0
,
0
,
rect
.
width
(),
0
)
gradient
.
setColorAt
(
0
,
color
)
gradient
.
setColorAt
(
0.95
,
color
)
gradient
.
setColorAt
(
1
,
Qt
.
transparent
)
pen
.
setBrush
(
QBrush
(
gradient
))
else
:
pen
.
setColor
(
color
)
painter
.
setPen
(
pen
)
painter
.
setFont
(
self
.
font
())
painter
.
drawText
(
rect
,
Qt
.
AlignVCenter
|
Qt
.
AlignLeft
,
self
.
text
())
class
TabBar
(
SingleDirectionScrollArea
):
""" Tab bar """
currentChanged
=
pyqtSignal
(
int
)
tabBarClicked
=
pyqtSignal
(
int
)
tabCloseRequested
=
pyqtSignal
(
int
)
tabAddRequested
=
pyqtSignal
()
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
parent
=
parent
,
orient
=
Qt
.
Horizontal
)
self
.
items
=
[]
# type: List[TabItem]
self
.
_currentIndex
=
-
1
self
.
closeButtonDisplayMode
=
TabCloseButtonDisplayMode
.
ALWAYS
self
.
view
=
QWidget
(
self
)
self
.
hBoxLayout
=
QHBoxLayout
(
self
.
view
)
self
.
itemLayout
=
QHBoxLayout
()
self
.
widgetLayout
=
QHBoxLayout
()
self
.
addButton
=
TransparentToolButton
(
FluentIcon
.
ADD
,
self
)
self
.
__initWidget
()
def
__initWidget
(
self
):
self
.
setFixedHeight
(
46
)
self
.
setWidget
(
self
.
view
)
self
.
setWidgetResizable
(
True
)
self
.
setHorizontalScrollBarPolicy
(
Qt
.
ScrollBarAlwaysOff
)
self
.
addButton
.
setFixedSize
(
32
,
24
)
self
.
addButton
.
setIconSize
(
QSize
(
12
,
12
))
self
.
addButton
.
clicked
.
connect
(
self
.
tabAddRequested
)
self
.
view
.
setObjectName
(
'view'
)
FluentStyleSheet
.
TAB_VIEW
.
apply
(
self
)
FluentStyleSheet
.
TAB_VIEW
.
apply
(
self
.
view
)
self
.
hBoxLayout
.
setAlignment
(
Qt
.
AlignVCenter
|
Qt
.
AlignLeft
)
self
.
itemLayout
.
setAlignment
(
Qt
.
AlignLeft
|
Qt
.
AlignVCenter
)
self
.
widgetLayout
.
setAlignment
(
Qt
.
AlignLeft
|
Qt
.
AlignVCenter
)
self
.
itemLayout
.
setContentsMargins
(
5
,
5
,
5
,
5
)
self
.
widgetLayout
.
setContentsMargins
(
0
,
0
,
0
,
0
)
self
.
hBoxLayout
.
setContentsMargins
(
0
,
0
,
0
,
0
)
self
.
hBoxLayout
.
setSpacing
(
0
)
self
.
itemLayout
.
setSpacing
(
0
)
self
.
hBoxLayout
.
addLayout
(
self
.
itemLayout
)
self
.
hBoxLayout
.
addSpacing
(
3
)
self
.
widgetLayout
.
addWidget
(
self
.
addButton
,
0
,
Qt
.
AlignLeft
)
self
.
hBoxLayout
.
addLayout
(
self
.
widgetLayout
)
self
.
hBoxLayout
.
addStretch
(
1
)
def
setAddButtonVisible
(
self
,
isVisible
:
bool
):
self
.
addButton
.
setVisible
(
isVisible
)
def
addTab
(
self
,
text
:
str
,
icon
:
Union
[
QIcon
,
str
,
FluentIconBase
]
=
None
):
""" add tab
Parameters
----------
text: str
the text of tab item
text: str
the icon of tab item
"""
self
.
insertTab
(
-
1
,
text
,
icon
)
def
insertTab
(
self
,
index
:
int
,
text
:
str
,
icon
:
Union
[
QIcon
,
str
,
FluentIconBase
]
=
None
):
""" insert tab
Parameters
----------
index: int
the insert position of tab item
text: str
the text of tab item
text: str
the icon of tab item
"""
if
index
==
-
1
:
index
=
len
(
self
.
items
)
# adjust current index
if
index
<=
self
.
currentIndex
()
and
self
.
currentIndex
()
>=
0
:
self
.
_currentIndex
+=
1
item
=
TabItem
(
text
,
self
.
view
,
icon
)
item
.
setCloseButtonDisplayMode
(
self
.
closeButtonDisplayMode
)
item
.
clicked
.
connect
(
self
.
_onItemClicked
)
item
.
closed
.
connect
(
lambda
:
self
.
tabCloseRequested
.
emit
(
self
.
items
.
index
(
item
)))
self
.
itemLayout
.
insertWidget
(
index
,
item
,
1
)
self
.
items
.
insert
(
index
,
item
)
if
len
(
self
.
items
)
==
1
:
self
.
setCurrentIndex
(
0
)
def
removeTab
(
self
,
index
:
int
):
if
not
0
<=
index
<
len
(
self
.
items
):
return
# adjust current index
if
index
<
self
.
currentIndex
():
self
.
_currentIndex
-=
1
elif
index
==
self
.
currentIndex
():
if
self
.
currentIndex
()
>
0
:
self
.
setCurrentIndex
(
self
.
currentIndex
()
-
1
)
elif
len
(
self
.
items
)
==
0
:
self
.
_currentIndex
=
-
1
else
:
self
.
setCurrentIndex
(
1
)
self
.
_currentIndex
=
0
item
=
self
.
items
.
pop
(
index
)
self
.
hBoxLayout
.
removeWidget
(
item
)
item
.
deleteLater
()
def
setCurrentIndex
(
self
,
index
:
int
):
""" set current index """
if
index
==
self
.
_currentIndex
:
return
if
self
.
currentIndex
()
>=
0
:
self
.
items
[
self
.
currentIndex
()].
setSelected
(
False
)
self
.
_currentIndex
=
index
self
.
items
[
index
].
setSelected
(
True
)
def
currentIndex
(
self
):
return
self
.
_currentIndex
def
_onItemClicked
(
self
):
for
item
in
self
.
items
:
item
.
setSelected
(
item
is
self
.
sender
())
index
=
self
.
items
.
index
(
self
.
sender
())
self
.
tabBarClicked
.
emit
(
index
)
if
index
!=
self
.
currentIndex
():
self
.
setCurrentIndex
(
index
)
self
.
currentChanged
.
emit
(
index
)
def
setCloseButtonDisplayMode
(
self
,
mode
:
TabCloseButtonDisplayMode
):
""" set close button display mode """
if
mode
==
self
.
closeButtonDisplayMode
:
return
self
.
closeButtonDisplayMode
=
mode
for
item
in
self
.
items
:
item
.
setCloseButtonDisplayMode
(
mode
)
@
checkIndex
()
def
tabItem
(
self
,
index
:
int
):
return
self
.
items
[
index
]
@
checkIndex
(
''
)
def
tabText
(
self
,
index
:
int
):
return
self
.
tabItem
(
index
).
text
()
@
checkIndex
()
def
tabIcon
(
self
,
index
:
int
):
return
self
.
tabItem
(
index
).
icon
()
@
checkIndex
(
''
)
def
tabToolTip
(
self
,
index
:
int
):
return
self
.
tabItem
(
index
).
toolTip
()
def
setTabsClosable
(
self
,
isClosable
:
bool
):
if
isClosable
:
self
.
setCloseButtonDisplayMode
(
TabCloseButtonDisplayMode
.
ALWAYS
)
else
:
self
.
setCloseButtonDisplayMode
(
TabCloseButtonDisplayMode
.
NEVER
)
def
tabsClosable
(
self
):
return
self
.
closeButtonDisplayMode
!=
TabCloseButtonDisplayMode
.
NEVER
@
checkIndex
()
def
setTabIcon
(
self
,
index
:
int
,
icon
:
Union
[
QIcon
,
FluentIconBase
,
str
]):
""" set tab icon """
self
.
tabItem
(
index
).
setIcon
(
icon
)
@
checkIndex
()
def
setTabText
(
self
,
index
:
int
,
text
:
str
):
""" set tab text """
self
.
tabItem
(
index
).
setText
(
text
)
@
checkIndex
()
def
setTabVisible
(
self
,
index
:
int
,
isVisible
:
bool
):
self
.
tabItem
(
index
).
setVisible
(
isVisible
)
if
isVisible
and
self
.
currentIndex
()
<
0
:
self
.
setCurrentIndex
(
0
)
elif
not
isVisible
:
if
self
.
currentIndex
()
>
0
:
self
.
setCurrentIndex
(
self
.
currentIndex
()
-
1
)
elif
len
(
self
.
items
)
==
1
:
self
.
_currentIndex
=
-
1
else
:
self
.
setCurrentIndex
(
1
)
self
.
_currentIndex
=
0
def
paintEvent
(
self
,
e
):
painter
=
QPainter
(
self
.
viewport
())
painter
.
setRenderHints
(
QPainter
.
Antialiasing
)
# draw separators
if
isDarkTheme
():
color
=
QColor
(
255
,
255
,
255
,
21
)
else
:
color
=
QColor
(
0
,
0
,
0
,
15
)
painter
.
setPen
(
color
)
for
i
,
item
in
enumerate
(
self
.
items
):
canDraw
=
not
(
item
.
isHover
or
item
.
isSelected
)
if
i
<
len
(
self
.
items
)
-
1
:
nextItem
=
self
.
items
[
i
+
1
]
if
nextItem
.
isHover
or
nextItem
.
isSelected
:
canDraw
=
False
if
canDraw
:
x
=
item
.
geometry
().
right
()
y
=
self
.
height
()
/
2
-
8
painter
.
drawLine
(
x
,
y
,
x
,
y
+
16
)
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录