Skip to content

Commit b898e95

Browse files
authored
feat: add NavigationUserCard component (#1085)
1 parent 2212a09 commit b898e95

File tree

9 files changed

+423
-5
lines changed

9 files changed

+423
-5
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# coding:utf-8
2+
import sys
3+
from pathlib import Path
4+
5+
#sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
6+
7+
from PyQt5.QtCore import Qt
8+
from PyQt5.QtGui import QIcon
9+
from PyQt5.QtWidgets import QApplication, QFrame, QHBoxLayout
10+
from qfluentwidgets import (NavigationItemPosition, MessageBox, FluentWindow, SubtitleLabel, setFont)
11+
from qfluentwidgets import FluentIcon as FIF
12+
13+
14+
class Widget(QFrame):
15+
16+
def __init__(self, text: str, parent=None):
17+
super().__init__(parent=parent)
18+
self.label = SubtitleLabel(text, self)
19+
self.hBoxLayout = QHBoxLayout(self)
20+
21+
setFont(self.label, 24)
22+
self.label.setAlignment(Qt.AlignCenter)
23+
self.hBoxLayout.addWidget(self.label, 1, Qt.AlignCenter)
24+
self.setObjectName(text.replace(' ', '-'))
25+
26+
27+
class Window(FluentWindow):
28+
29+
def __init__(self):
30+
super().__init__()
31+
32+
# create sub interface
33+
self.homeInterface = Widget('Home Interface', self)
34+
self.musicInterface = Widget('Music Interface', self)
35+
self.videoInterface = Widget('Video Interface', self)
36+
self.settingInterface = Widget('Setting Interface', self)
37+
38+
self.initNavigation()
39+
self.initWindow()
40+
41+
def initNavigation(self):
42+
# add user card with custom parameters
43+
self.userCard = self.navigationInterface.addUserCard(
44+
routeKey='userCard',
45+
avatar='resource/shoko.png',
46+
title='zhiyiYo',
47+
subtitle='shokokawaii@outlook.com',
48+
onClick=self.showMessageBox,
49+
position=NavigationItemPosition.TOP,
50+
aboveMenuButton=False # place below the expand/collapse button
51+
)
52+
53+
# customize user card (optional)
54+
# self.userCard.setTitleFontSize(15)
55+
# self.userCard.setSubtitleFontSize(11)
56+
# self.userCard.setAnimationDuration(300)
57+
58+
# placement: set aboveMenuButton=True to place card above expand/collapse button
59+
# default: aboveMenuButton=False (card placed below menu button)
60+
61+
# add navigation items
62+
self.addSubInterface(self.homeInterface, FIF.HOME, 'Home')
63+
self.addSubInterface(self.musicInterface, FIF.MUSIC, 'Music library')
64+
65+
self.navigationInterface.addSeparator()
66+
67+
self.addSubInterface(self.videoInterface, FIF.VIDEO, 'Video library')
68+
self.addSubInterface(self.settingInterface, FIF.SETTING, 'Settings', NavigationItemPosition.BOTTOM)
69+
70+
def initWindow(self):
71+
self.resize(900, 700)
72+
self.setWindowIcon(QIcon('resource/logo.png'))
73+
self.setWindowTitle('Navigation User Card')
74+
75+
desktop = QApplication.desktop().availableGeometry()
76+
w, h = desktop.width(), desktop.height()
77+
self.move(w//2 - self.width()//2, h//2 - self.height()//2)
78+
79+
def showMessageBox(self):
80+
w = MessageBox(
81+
'User Card',
82+
'This is a navigation user card that displays avatar, title and subtitle.\n\n'
83+
'Placement:\n'
84+
'• aboveMenuButton=True: Place above expand/collapse button\n'
85+
'• aboveMenuButton=False: Place below menu button (default)',
86+
self
87+
)
88+
w.exec_()
89+
90+
91+
if __name__ == '__main__':
92+
QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
93+
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
94+
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
95+
96+
app = QApplication(sys.argv)
97+
w = Window()
98+
w.show()
99+
app.exec_()
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
Widget > QLabel {
2+
font: 24px 'Segoe UI', 'Microsoft YaHei';
3+
}
4+
5+
Widget {
6+
border: 1px solid rgb(29, 29, 29);
7+
border-right: none;
8+
border-bottom: none;
9+
border-top-left-radius: 10px;
10+
background-color: rgb(39, 39, 39);
11+
}
12+
13+
Window {
14+
background-color: rgb(32, 32, 32);
15+
}
16+
17+
StandardTitleBar {
18+
background-color: rgb(32, 32, 32);
19+
}
20+
21+
StandardTitleBar > QLabel,
22+
Widget > QLabel {
23+
color: white;
24+
}
25+
26+
27+
MinimizeButton {
28+
qproperty-normalColor: white;
29+
qproperty-normalBackgroundColor: transparent;
30+
qproperty-hoverColor: white;
31+
qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
32+
qproperty-pressedColor: white;
33+
qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
34+
}
35+
36+
37+
MaximizeButton {
38+
qproperty-normalColor: white;
39+
qproperty-normalBackgroundColor: transparent;
40+
qproperty-hoverColor: white;
41+
qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
42+
qproperty-pressedColor: white;
43+
qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
44+
}
45+
46+
CloseButton {
47+
qproperty-normalColor: white;
48+
qproperty-normalBackgroundColor: transparent;
49+
}
50+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Widget > QLabel {
2+
font: 24px 'Segoe UI', 'Microsoft YaHei';
3+
}
4+
5+
Widget {
6+
border: 1px solid rgb(229, 229, 229);
7+
border-right: none;
8+
border-bottom: none;
9+
border-top-left-radius: 10px;
10+
background-color: rgb(249, 249, 249);
11+
}
12+
13+
Window {
14+
background-color: rgb(243, 243, 243);
15+
}
16+
7.42 KB
Loading
262 KB
Loading

qfluentwidgets/components/navigation/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .navigation_widget import (NavigationWidget, NavigationPushButton, NavigationSeparator, NavigationToolButton,
22
NavigationTreeWidget, NavigationTreeWidgetBase, NavigationAvatarWidget, NavigationItemHeader)
3+
from .navigation_user_card import NavigationUserCard
34
from .navigation_panel import NavigationPanel, NavigationItemPosition, NavigationDisplayMode
45
from .navigation_interface import NavigationInterface
56
from .navigation_bar import NavigationBarPushButton, NavigationBar

qfluentwidgets/components/navigation/navigation_interface.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
from typing import Union
33

44
from PyQt5.QtCore import Qt, QEvent, pyqtSignal
5-
from PyQt5.QtGui import QResizeEvent, QIcon
5+
from PyQt5.QtGui import QResizeEvent, QIcon, QPixmap
66
from PyQt5.QtWidgets import QWidget
77

88
from .navigation_panel import NavigationPanel, NavigationItemPosition, NavigationWidget, NavigationDisplayMode
99
from .navigation_widget import NavigationTreeWidget
10+
from .navigation_user_card import NavigationUserCard
1011
from ...common.style_sheet import FluentStyleSheet
1112
from ...common.icon import FluentIconBase
1213

@@ -220,6 +221,68 @@ def insertItemHeader(self, index: int, text: str, position=NavigationItemPositio
220221
"""
221222
return self.panel.insertItemHeader(index, text, position)
222223

224+
def addUserCard(self, routeKey: str, avatar: Union[str, QIcon, FluentIconBase] = None,
225+
title: str = '', subtitle: str = '', onClick=None,
226+
position=NavigationItemPosition.TOP, aboveMenuButton: bool = False):
227+
""" add user card to navigation panel
228+
229+
Parameters
230+
----------
231+
routeKey: str
232+
the unique name of user card
233+
234+
avatar: str | QIcon | FluentIconBase
235+
avatar image or icon
236+
237+
title: str
238+
user name or title text
239+
240+
subtitle: str
241+
subtitle text (e.g., email, status)
242+
243+
onClick: callable
244+
the slot connected to card clicked signal
245+
246+
position: NavigationItemPosition
247+
where the card is added
248+
249+
aboveMenuButton: bool
250+
whether to place the card above the menu button (expand/collapse button)
251+
252+
Returns
253+
-------
254+
NavigationUserCard
255+
created user card widget
256+
"""
257+
card = NavigationUserCard(self)
258+
259+
if avatar:
260+
if isinstance(avatar, FluentIconBase):
261+
card.setAvatarIcon(avatar)
262+
else:
263+
card.setAvatar(avatar)
264+
265+
card.setTitle(title)
266+
card.setSubtitle(subtitle)
267+
268+
# calculate insert index if placing above menu button
269+
index = -1
270+
if aboveMenuButton and position == NavigationItemPosition.TOP:
271+
# find menu button index in top layout
272+
layout = self.panel.topLayout
273+
for i in range(layout.count()):
274+
item = layout.itemAt(i)
275+
if item and item.widget() == self.panel.menuButton:
276+
index = i
277+
break
278+
279+
if index >= 0:
280+
self.panel.insertWidget(index, routeKey, card, onClick, position)
281+
else:
282+
self.addWidget(routeKey, card, onClick, position)
283+
284+
return card
285+
223286
def insertSeparator(self, index: int, position=NavigationItemPosition.TOP):
224287
""" add separator
225288

0 commit comments

Comments
 (0)