monkeyqt 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- monkeyqt/__init__.py +154 -0
- monkeyqt/common/enums.py +14 -0
- monkeyqt/components/basic/button.py +191 -0
- monkeyqt/components/basic/checkbox.py +112 -0
- monkeyqt/components/data/__init__.py +0 -0
- monkeyqt/components/data/avatar.py +101 -0
- monkeyqt/components/data/data_table.py +588 -0
- monkeyqt/components/data/image_compare.py +342 -0
- monkeyqt/components/data/image_split.py +486 -0
- monkeyqt/components/data/preview_dialogs.py +588 -0
- monkeyqt/components/data/table.py +66 -0
- monkeyqt/components/feedback/__init__.py +0 -0
- monkeyqt/components/feedback/alert.py +187 -0
- monkeyqt/components/feedback/progress_bar.py +133 -0
- monkeyqt/components/feedback/progress_ring.py +132 -0
- monkeyqt/components/form/auth.py +769 -0
- monkeyqt/components/form/captcha.py +208 -0
- monkeyqt/components/form/combobox.py +115 -0
- monkeyqt/components/form/date_picker.py +443 -0
- monkeyqt/components/form/form.py +61 -0
- monkeyqt/components/form/input.py +129 -0
- monkeyqt/components/form/multicombobox.py +375 -0
- monkeyqt/components/form/slider.py +169 -0
- monkeyqt/components/form/switch.py +83 -0
- monkeyqt/components/form/upload.py +308 -0
- monkeyqt/components/layout/window.py +685 -0
- monkeyqt/components/navigation/breadcrumb.py +95 -0
- monkeyqt/components/navigation/dropdown.py +71 -0
- monkeyqt/components/navigation/pagination.py +189 -0
- monkeyqt/components/navigation/sidebar.py +515 -0
- monkeyqt/components/navigation/tabs.py +97 -0
- monkeyqt/components/navigation/topbar.py +110 -0
- monkeyqt/core/icons.py +210 -0
- monkeyqt/core/theme.py +43 -0
- monkeyqt/core/theme_data.py +5313 -0
- monkeyqt/designer/plugins.py +24 -0
- monkeyqt/themes/__init__.py +92 -0
- monkeyqt/themes/__main__.py +6 -0
- monkeyqt/themes/adapter.py +4112 -0
- monkeyqt/themes/components/__init__.py +33 -0
- monkeyqt/themes/components/alert.py +298 -0
- monkeyqt/themes/components/avatar.py +164 -0
- monkeyqt/themes/components/breadcrumb.py +96 -0
- monkeyqt/themes/components/button.py +308 -0
- monkeyqt/themes/components/captcha.py +92 -0
- monkeyqt/themes/components/card.py +234 -0
- monkeyqt/themes/components/checkbox.py +151 -0
- monkeyqt/themes/components/combobox.py +238 -0
- monkeyqt/themes/components/data_table.py +59 -0
- monkeyqt/themes/components/date_picker.py +104 -0
- monkeyqt/themes/components/dropdown.py +107 -0
- monkeyqt/themes/components/form.py +62 -0
- monkeyqt/themes/components/image_compare.py +117 -0
- monkeyqt/themes/components/image_split.py +104 -0
- monkeyqt/themes/components/input.py +195 -0
- monkeyqt/themes/components/menu.py +138 -0
- monkeyqt/themes/components/message.py +63 -0
- monkeyqt/themes/components/multicombobox.py +228 -0
- monkeyqt/themes/components/pagination.py +190 -0
- monkeyqt/themes/components/progress.py +190 -0
- monkeyqt/themes/components/progress_ring.py +166 -0
- monkeyqt/themes/components/slider.py +209 -0
- monkeyqt/themes/components/switch.py +218 -0
- monkeyqt/themes/components/table.py +110 -0
- monkeyqt/themes/components/tabs.py +228 -0
- monkeyqt/themes/components/theme_selector.py +100 -0
- monkeyqt/themes/components/topbar.py +122 -0
- monkeyqt/themes/components/upload.py +178 -0
- monkeyqt/themes/components/window.py +110 -0
- monkeyqt/themes/engine.py +754 -0
- monkeyqt/themes/gallery.py +747 -0
- monkeyqt/themes/manager.py +428 -0
- monkeyqt/themes/names.py +81 -0
- monkeyqt/themes/style_utils.py +233 -0
- monkeyqt/themes/tokens.py +1557 -0
- monkeyqt-0.1.0.dist-info/METADATA +87 -0
- monkeyqt-0.1.0.dist-info/RECORD +80 -0
- monkeyqt-0.1.0.dist-info/WHEEL +5 -0
- monkeyqt-0.1.0.dist-info/licenses/LICENSE +201 -0
- monkeyqt-0.1.0.dist-info/top_level.txt +1 -0
monkeyqt/__init__.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from .components.basic.button import MkButton
|
|
2
|
+
from .components.basic.checkbox import MkCheckBox
|
|
3
|
+
# Navigation
|
|
4
|
+
from .components.navigation.sidebar import MkMenu
|
|
5
|
+
from .components.navigation.topbar import MkTopbar
|
|
6
|
+
from .components.navigation.breadcrumb import MkBreadcrumb
|
|
7
|
+
from .components.navigation.tabs import MkTabs
|
|
8
|
+
from .components.navigation.pagination import MkPagination
|
|
9
|
+
from .components.navigation.dropdown import MkDropdown
|
|
10
|
+
|
|
11
|
+
# Form
|
|
12
|
+
from .components.form.switch import MkSwitch
|
|
13
|
+
from .components.form.slider import MkSlider
|
|
14
|
+
from .components.form.date_picker import MkDatePicker
|
|
15
|
+
from .components.form.form import MkForm
|
|
16
|
+
from .components.form.input import MkInput
|
|
17
|
+
from .components.form.captcha import MkCaptchaWidget
|
|
18
|
+
from .components.form.auth import MkAuthScreen, MkMessage
|
|
19
|
+
from .components.form.upload import MkUpload
|
|
20
|
+
from .components.form.combobox import MkComboBox
|
|
21
|
+
from .components.form.multicombobox import MkMultiComboBox
|
|
22
|
+
|
|
23
|
+
# Data
|
|
24
|
+
from .components.data.avatar import MkAvatar
|
|
25
|
+
from .components.data.table import MkTable
|
|
26
|
+
from .components.data.data_table import MkDataTable
|
|
27
|
+
from .components.data.image_compare import MkImageCompare
|
|
28
|
+
from .components.data.image_split import MkImageSplit
|
|
29
|
+
|
|
30
|
+
# Feedback
|
|
31
|
+
from .components.feedback.alert import MkAlert
|
|
32
|
+
from .components.feedback.progress_bar import MkProgressBar
|
|
33
|
+
from .components.feedback.progress_ring import MkProgressRing
|
|
34
|
+
|
|
35
|
+
# Layout
|
|
36
|
+
from .components.layout.window import MkTitleBar, MkWindow
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Themes (67 UI Styles)
|
|
40
|
+
from .themes import (
|
|
41
|
+
ThemeEngine,
|
|
42
|
+
apply_monkeyqt_theme,
|
|
43
|
+
use_theme,
|
|
44
|
+
set_theme_chrome,
|
|
45
|
+
clear_theme_chrome,
|
|
46
|
+
clear_theme,
|
|
47
|
+
set_theme_enabled,
|
|
48
|
+
exclude_from_theme,
|
|
49
|
+
include_in_theme,
|
|
50
|
+
MkThemeSelector,
|
|
51
|
+
ThemedButton,
|
|
52
|
+
ThemedCheckBox,
|
|
53
|
+
ThemedInput,
|
|
54
|
+
ThemedSwitch,
|
|
55
|
+
ThemedCard,
|
|
56
|
+
ThemedProgressBar,
|
|
57
|
+
ThemedProgressRing,
|
|
58
|
+
ThemedAlert,
|
|
59
|
+
ThemedComboBox,
|
|
60
|
+
ThemedSlider,
|
|
61
|
+
ThemedTabs,
|
|
62
|
+
ThemedAvatar,
|
|
63
|
+
ThemedPagination,
|
|
64
|
+
ThemedBreadcrumb,
|
|
65
|
+
ThemedDropdown,
|
|
66
|
+
ThemedTable,
|
|
67
|
+
ThemedForm,
|
|
68
|
+
ThemedDatePicker,
|
|
69
|
+
ThemedMultiComboBox,
|
|
70
|
+
ThemedUpload,
|
|
71
|
+
ThemedTopbar,
|
|
72
|
+
ThemedMenu,
|
|
73
|
+
ThemedMessage,
|
|
74
|
+
ThemedCaptchaWidget,
|
|
75
|
+
ThemedDataTable,
|
|
76
|
+
ThemedImageCompare,
|
|
77
|
+
ThemedImageSplit,
|
|
78
|
+
ThemedTitleBar,
|
|
79
|
+
ThemedWindowShell,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
__version__ = "0.1.0"
|
|
83
|
+
|
|
84
|
+
__all__ = [
|
|
85
|
+
"MkButton",
|
|
86
|
+
"MkCheckBox",
|
|
87
|
+
"MkMenu",
|
|
88
|
+
"MkTopbar",
|
|
89
|
+
"MkBreadcrumb",
|
|
90
|
+
"MkTabs",
|
|
91
|
+
"MkPagination",
|
|
92
|
+
"MkDropdown",
|
|
93
|
+
"MkSwitch",
|
|
94
|
+
"MkSlider",
|
|
95
|
+
"MkDatePicker",
|
|
96
|
+
"MkForm",
|
|
97
|
+
"MkInput",
|
|
98
|
+
"MkComboBox",
|
|
99
|
+
"MkMultiComboBox",
|
|
100
|
+
"MkCaptchaWidget",
|
|
101
|
+
"MkAuthScreen",
|
|
102
|
+
"MkMessage",
|
|
103
|
+
"MkUpload",
|
|
104
|
+
"MkAvatar",
|
|
105
|
+
"MkTable",
|
|
106
|
+
"MkDataTable",
|
|
107
|
+
"MkImageCompare",
|
|
108
|
+
"MkImageSplit",
|
|
109
|
+
"MkAlert",
|
|
110
|
+
"MkProgressBar",
|
|
111
|
+
"MkProgressRing",
|
|
112
|
+
"MkTitleBar",
|
|
113
|
+
"MkWindow",
|
|
114
|
+
# Themed components
|
|
115
|
+
"ThemeEngine",
|
|
116
|
+
"apply_monkeyqt_theme",
|
|
117
|
+
"use_theme",
|
|
118
|
+
"set_theme_chrome",
|
|
119
|
+
"clear_theme_chrome",
|
|
120
|
+
"clear_theme",
|
|
121
|
+
"set_theme_enabled",
|
|
122
|
+
"exclude_from_theme",
|
|
123
|
+
"include_in_theme",
|
|
124
|
+
"MkThemeSelector",
|
|
125
|
+
"ThemedButton",
|
|
126
|
+
"ThemedCheckBox",
|
|
127
|
+
"ThemedInput",
|
|
128
|
+
"ThemedSwitch",
|
|
129
|
+
"ThemedCard",
|
|
130
|
+
"ThemedProgressBar",
|
|
131
|
+
"ThemedProgressRing",
|
|
132
|
+
"ThemedAlert",
|
|
133
|
+
"ThemedComboBox",
|
|
134
|
+
"ThemedSlider",
|
|
135
|
+
"ThemedTabs",
|
|
136
|
+
"ThemedAvatar",
|
|
137
|
+
"ThemedPagination",
|
|
138
|
+
"ThemedBreadcrumb",
|
|
139
|
+
"ThemedDropdown",
|
|
140
|
+
"ThemedTable",
|
|
141
|
+
"ThemedForm",
|
|
142
|
+
"ThemedDatePicker",
|
|
143
|
+
"ThemedMultiComboBox",
|
|
144
|
+
"ThemedUpload",
|
|
145
|
+
"ThemedTopbar",
|
|
146
|
+
"ThemedMenu",
|
|
147
|
+
"ThemedMessage",
|
|
148
|
+
"ThemedCaptchaWidget",
|
|
149
|
+
"ThemedDataTable",
|
|
150
|
+
"ThemedImageCompare",
|
|
151
|
+
"ThemedImageSplit",
|
|
152
|
+
"ThemedTitleBar",
|
|
153
|
+
"ThemedWindowShell",
|
|
154
|
+
]
|
monkeyqt/common/enums.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
class MkType(str, Enum):
|
|
4
|
+
DEFAULT = "default"
|
|
5
|
+
PRIMARY = "primary"
|
|
6
|
+
SUCCESS = "success"
|
|
7
|
+
WARNING = "warning"
|
|
8
|
+
DANGER = "danger"
|
|
9
|
+
INFO = "info"
|
|
10
|
+
|
|
11
|
+
class MkSize(str, Enum):
|
|
12
|
+
LARGE = "large"
|
|
13
|
+
DEFAULT = "default"
|
|
14
|
+
SMALL = "small"
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from PySide6.QtWidgets import QPushButton, QWidget
|
|
2
|
+
from PySide6.QtCore import Property, Qt
|
|
3
|
+
from monkeyqt.common.enums import MkType, MkSize
|
|
4
|
+
|
|
5
|
+
class MkButton(QPushButton):
|
|
6
|
+
"""MkButton 组件"""
|
|
7
|
+
|
|
8
|
+
def __init__(self, text="", parent=None, type=MkType.DEFAULT.value, size=MkSize.DEFAULT.value):
|
|
9
|
+
# 兼容 Qt Designer (它实例化时会将 parent 传给第一个参数)
|
|
10
|
+
if isinstance(text, QWidget):
|
|
11
|
+
parent = text
|
|
12
|
+
text = ""
|
|
13
|
+
|
|
14
|
+
super().__init__(text, parent)
|
|
15
|
+
|
|
16
|
+
self._mk_type = type
|
|
17
|
+
self._mk_size = size
|
|
18
|
+
|
|
19
|
+
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
20
|
+
|
|
21
|
+
# 实际开发中,这里应该调用 ThemeManager 加载 QSS
|
|
22
|
+
# 以下是完整的 Element Plus 风格按钮样式
|
|
23
|
+
self.setStyleSheet("""
|
|
24
|
+
/* Default 基础样式 */
|
|
25
|
+
MkButton {
|
|
26
|
+
border-radius: 4px;
|
|
27
|
+
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
border: 1px solid #dcdfe6;
|
|
30
|
+
background-color: #ffffff;
|
|
31
|
+
color: #606266;
|
|
32
|
+
outline: none;
|
|
33
|
+
}
|
|
34
|
+
MkButton:hover {
|
|
35
|
+
color: #409eff;
|
|
36
|
+
border-color: #c6e2ff;
|
|
37
|
+
background-color: #ecf5ff;
|
|
38
|
+
}
|
|
39
|
+
MkButton:pressed {
|
|
40
|
+
color: #3a8ee6;
|
|
41
|
+
border-color: #3a8ee6;
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
MkButton:disabled {
|
|
45
|
+
color: #c0c4cc;
|
|
46
|
+
background-color: #ffffff;
|
|
47
|
+
border-color: #ebeef5;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Primary */
|
|
51
|
+
MkButton[mk_type="primary"] {
|
|
52
|
+
color: #ffffff;
|
|
53
|
+
background-color: #409eff;
|
|
54
|
+
border-color: #409eff;
|
|
55
|
+
}
|
|
56
|
+
MkButton[mk_type="primary"]:hover {
|
|
57
|
+
background-color: #66b1ff;
|
|
58
|
+
border-color: #66b1ff;
|
|
59
|
+
}
|
|
60
|
+
MkButton[mk_type="primary"]:pressed {
|
|
61
|
+
background-color: #3a8ee6;
|
|
62
|
+
border-color: #3a8ee6;
|
|
63
|
+
}
|
|
64
|
+
MkButton[mk_type="primary"]:disabled {
|
|
65
|
+
color: #ffffff;
|
|
66
|
+
background-color: #a0cfff;
|
|
67
|
+
border-color: #a0cfff;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Success */
|
|
71
|
+
MkButton[mk_type="success"] {
|
|
72
|
+
color: #ffffff;
|
|
73
|
+
background-color: #67c23a;
|
|
74
|
+
border-color: #67c23a;
|
|
75
|
+
}
|
|
76
|
+
MkButton[mk_type="success"]:hover {
|
|
77
|
+
background-color: #85ce61;
|
|
78
|
+
border-color: #85ce61;
|
|
79
|
+
}
|
|
80
|
+
MkButton[mk_type="success"]:pressed {
|
|
81
|
+
background-color: #5daf34;
|
|
82
|
+
border-color: #5daf34;
|
|
83
|
+
}
|
|
84
|
+
MkButton[mk_type="success"]:disabled {
|
|
85
|
+
color: #ffffff;
|
|
86
|
+
background-color: #b3e19d;
|
|
87
|
+
border-color: #b3e19d;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Warning */
|
|
91
|
+
MkButton[mk_type="warning"] {
|
|
92
|
+
color: #ffffff;
|
|
93
|
+
background-color: #e6a23c;
|
|
94
|
+
border-color: #e6a23c;
|
|
95
|
+
}
|
|
96
|
+
MkButton[mk_type="warning"]:hover {
|
|
97
|
+
background-color: #ebb563;
|
|
98
|
+
border-color: #ebb563;
|
|
99
|
+
}
|
|
100
|
+
MkButton[mk_type="warning"]:pressed {
|
|
101
|
+
background-color: #cf9236;
|
|
102
|
+
border-color: #cf9236;
|
|
103
|
+
}
|
|
104
|
+
MkButton[mk_type="warning"]:disabled {
|
|
105
|
+
color: #ffffff;
|
|
106
|
+
background-color: #f3d19e;
|
|
107
|
+
border-color: #f3d19e;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Danger */
|
|
111
|
+
MkButton[mk_type="danger"] {
|
|
112
|
+
color: #ffffff;
|
|
113
|
+
background-color: #f56c6c;
|
|
114
|
+
border-color: #f56c6c;
|
|
115
|
+
}
|
|
116
|
+
MkButton[mk_type="danger"]:hover {
|
|
117
|
+
background-color: #f78989;
|
|
118
|
+
border-color: #f78989;
|
|
119
|
+
}
|
|
120
|
+
MkButton[mk_type="danger"]:pressed {
|
|
121
|
+
background-color: #dd6161;
|
|
122
|
+
border-color: #dd6161;
|
|
123
|
+
}
|
|
124
|
+
MkButton[mk_type="danger"]:disabled {
|
|
125
|
+
color: #ffffff;
|
|
126
|
+
background-color: #fab6b6;
|
|
127
|
+
border-color: #fab6b6;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Info */
|
|
131
|
+
MkButton[mk_type="info"] {
|
|
132
|
+
color: #ffffff;
|
|
133
|
+
background-color: #909399;
|
|
134
|
+
border-color: #909399;
|
|
135
|
+
}
|
|
136
|
+
MkButton[mk_type="info"]:hover {
|
|
137
|
+
background-color: #a6a9ad;
|
|
138
|
+
border-color: #a6a9ad;
|
|
139
|
+
}
|
|
140
|
+
MkButton[mk_type="info"]:pressed {
|
|
141
|
+
background-color: #82848a;
|
|
142
|
+
border-color: #82848a;
|
|
143
|
+
}
|
|
144
|
+
MkButton[mk_type="info"]:disabled {
|
|
145
|
+
color: #ffffff;
|
|
146
|
+
background-color: #c8c9cc;
|
|
147
|
+
border-color: #c8c9cc;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* 尺寸 Sizes */
|
|
151
|
+
MkButton[mk_size="large"] {
|
|
152
|
+
padding: 12px 19px;
|
|
153
|
+
font-size: 14px;
|
|
154
|
+
}
|
|
155
|
+
MkButton[mk_size="default"] {
|
|
156
|
+
padding: 8px 15px;
|
|
157
|
+
font-size: 14px;
|
|
158
|
+
}
|
|
159
|
+
MkButton[mk_size="small"] {
|
|
160
|
+
padding: 5px 11px;
|
|
161
|
+
font-size: 12px;
|
|
162
|
+
border-radius: 3px;
|
|
163
|
+
}
|
|
164
|
+
""")
|
|
165
|
+
|
|
166
|
+
# 暴露给 Qt Designer 的右侧属性面板
|
|
167
|
+
@Property(str)
|
|
168
|
+
def mk_type(self):
|
|
169
|
+
return self._mk_type
|
|
170
|
+
|
|
171
|
+
@mk_type.setter
|
|
172
|
+
def mk_type(self, value):
|
|
173
|
+
if self._mk_type == value:
|
|
174
|
+
return
|
|
175
|
+
self._mk_type = value
|
|
176
|
+
self.setProperty("mk_type", value)
|
|
177
|
+
self.style().unpolish(self)
|
|
178
|
+
self.style().polish(self)
|
|
179
|
+
|
|
180
|
+
@Property(str)
|
|
181
|
+
def mk_size(self):
|
|
182
|
+
return self._mk_size
|
|
183
|
+
|
|
184
|
+
@mk_size.setter
|
|
185
|
+
def mk_size(self, value):
|
|
186
|
+
if self._mk_size == value:
|
|
187
|
+
return
|
|
188
|
+
self._mk_size = value
|
|
189
|
+
self.setProperty("mk_size", value)
|
|
190
|
+
self.style().unpolish(self)
|
|
191
|
+
self.style().polish(self)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from PySide6.QtWidgets import QCheckBox, QWidget
|
|
2
|
+
from PySide6.QtCore import Property, Qt
|
|
3
|
+
from monkeyqt.common.enums import MkSize
|
|
4
|
+
|
|
5
|
+
class MkCheckBox(QCheckBox):
|
|
6
|
+
"""
|
|
7
|
+
MkCheckBox 组件
|
|
8
|
+
对标 Element Plus 的 Checkbox,支持自定义尺寸和现代化的选中动画(通过 QSS)。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, text="", parent=None, size=MkSize.DEFAULT.value):
|
|
12
|
+
# 兼容 Qt Designer
|
|
13
|
+
if isinstance(text, QWidget):
|
|
14
|
+
parent = text
|
|
15
|
+
text = ""
|
|
16
|
+
|
|
17
|
+
super().__init__(text, parent)
|
|
18
|
+
|
|
19
|
+
self._mk_size = size
|
|
20
|
+
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
21
|
+
|
|
22
|
+
self._apply_style()
|
|
23
|
+
|
|
24
|
+
def _apply_style(self):
|
|
25
|
+
"""注入 Element Plus 风格的 QSS 样式"""
|
|
26
|
+
self.setStyleSheet("""
|
|
27
|
+
/* 基础样式与文本颜色 */
|
|
28
|
+
MkCheckBox {
|
|
29
|
+
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
|
|
30
|
+
color: #606266;
|
|
31
|
+
spacing: 8px; /* 框与文字的间距 */
|
|
32
|
+
outline: none;
|
|
33
|
+
}
|
|
34
|
+
MkCheckBox:hover {
|
|
35
|
+
color: #409eff;
|
|
36
|
+
}
|
|
37
|
+
MkCheckBox:disabled {
|
|
38
|
+
color: #c0c4cc;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* 自定义勾选框 (Indicator) */
|
|
42
|
+
MkCheckBox::indicator {
|
|
43
|
+
width: 14px;
|
|
44
|
+
height: 14px;
|
|
45
|
+
background-color: #ffffff;
|
|
46
|
+
border: 1px solid #dcdfe6;
|
|
47
|
+
border-radius: 2px;
|
|
48
|
+
transition: border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* 悬浮时的框边框变蓝 */
|
|
52
|
+
MkCheckBox::indicator:hover {
|
|
53
|
+
border-color: #409eff;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* 选中状态 */
|
|
57
|
+
MkCheckBox::indicator:checked {
|
|
58
|
+
background-color: #409eff;
|
|
59
|
+
border-color: #409eff;
|
|
60
|
+
/* Qt 的 QSS 不支持绘制复杂的 SVG,这里我们用一个 unicode 字符模拟对号,或者依赖背景图。
|
|
61
|
+
为保持纯代码,我们先利用自带的选中样式或后续加载本地 svg */
|
|
62
|
+
image: url(none); /* 阻止原生丑陋渲染 */
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* 禁用状态 */
|
|
66
|
+
MkCheckBox::indicator:disabled {
|
|
67
|
+
background-color: #edf2fc;
|
|
68
|
+
border-color: #dcdfe6;
|
|
69
|
+
}
|
|
70
|
+
MkCheckBox::indicator:checked:disabled {
|
|
71
|
+
background-color: #a0cfff;
|
|
72
|
+
border-color: #a0cfff;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* --- 尺寸控制 --- */
|
|
76
|
+
MkCheckBox[mk_size="large"] {
|
|
77
|
+
font-size: 14px;
|
|
78
|
+
height: 40px;
|
|
79
|
+
}
|
|
80
|
+
MkCheckBox[mk_size="large"]::indicator {
|
|
81
|
+
width: 16px;
|
|
82
|
+
height: 16px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
MkCheckBox[mk_size="default"] {
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
height: 32px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
MkCheckBox[mk_size="small"] {
|
|
91
|
+
font-size: 12px;
|
|
92
|
+
height: 24px;
|
|
93
|
+
}
|
|
94
|
+
MkCheckBox[mk_size="small"]::indicator {
|
|
95
|
+
width: 12px;
|
|
96
|
+
height: 12px;
|
|
97
|
+
}
|
|
98
|
+
""")
|
|
99
|
+
|
|
100
|
+
# --- 暴露属性 ---
|
|
101
|
+
@Property(str)
|
|
102
|
+
def mk_size(self):
|
|
103
|
+
return self._mk_size
|
|
104
|
+
|
|
105
|
+
@mk_size.setter
|
|
106
|
+
def mk_size(self, value):
|
|
107
|
+
if self._mk_size == value:
|
|
108
|
+
return
|
|
109
|
+
self._mk_size = value
|
|
110
|
+
self.setProperty("mk_size", value)
|
|
111
|
+
self.style().unpolish(self)
|
|
112
|
+
self.style().polish(self)
|
|
File without changes
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from PySide6.QtWidgets import QLabel, QSizePolicy
|
|
3
|
+
from PySide6.QtCore import Qt, Property, QRect
|
|
4
|
+
from PySide6.QtGui import QPainter, QPainterPath, QColor, QPixmap, QFont
|
|
5
|
+
|
|
6
|
+
class MkAvatar(QLabel):
|
|
7
|
+
"""
|
|
8
|
+
头像组件 (Avatar)
|
|
9
|
+
支持圆形和矩形,支持显示图片或文字。
|
|
10
|
+
"""
|
|
11
|
+
def __init__(self, text="", image_path="", shape="circle", size=40, parent=None):
|
|
12
|
+
super().__init__(parent)
|
|
13
|
+
self._text = text
|
|
14
|
+
self._image_path = image_path
|
|
15
|
+
self._shape = shape # circle, square
|
|
16
|
+
self._avatar_size = size
|
|
17
|
+
|
|
18
|
+
self.setFixedSize(self._avatar_size, self._avatar_size)
|
|
19
|
+
self.setAlignment(Qt.AlignCenter)
|
|
20
|
+
self._setup_style()
|
|
21
|
+
|
|
22
|
+
def _setup_style(self):
|
|
23
|
+
font = self.font()
|
|
24
|
+
font.setPixelSize(int(self._avatar_size * 0.4))
|
|
25
|
+
self.setFont(font)
|
|
26
|
+
|
|
27
|
+
# We handle drawing entirely in paintEvent
|
|
28
|
+
self.setAttribute(Qt.WA_TranslucentBackground)
|
|
29
|
+
|
|
30
|
+
def paintEvent(self, event):
|
|
31
|
+
painter = QPainter(self)
|
|
32
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
|
33
|
+
painter.setRenderHint(QPainter.SmoothPixmapTransform)
|
|
34
|
+
|
|
35
|
+
rect = self.rect()
|
|
36
|
+
path = QPainterPath()
|
|
37
|
+
|
|
38
|
+
if self._shape == "circle":
|
|
39
|
+
path.addEllipse(rect)
|
|
40
|
+
else:
|
|
41
|
+
# Rounded square
|
|
42
|
+
path.addRoundedRect(rect, 4, 4)
|
|
43
|
+
|
|
44
|
+
painter.setClipPath(path)
|
|
45
|
+
|
|
46
|
+
if self._image_path and os.path.exists(self._image_path):
|
|
47
|
+
pixmap = QPixmap(self._image_path)
|
|
48
|
+
# Scale and crop to fill
|
|
49
|
+
scaled = pixmap.scaled(self.size(), Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
|
|
50
|
+
|
|
51
|
+
# Center the pixmap
|
|
52
|
+
x = (self.width() - scaled.width()) // 2
|
|
53
|
+
y = (self.height() - scaled.height()) // 2
|
|
54
|
+
painter.drawPixmap(x, y, scaled)
|
|
55
|
+
else:
|
|
56
|
+
# Draw background
|
|
57
|
+
painter.fillPath(path, QColor("#c0c4cc"))
|
|
58
|
+
|
|
59
|
+
# Draw text
|
|
60
|
+
if self._text:
|
|
61
|
+
painter.setPen(QColor("white"))
|
|
62
|
+
painter.drawText(rect, Qt.AlignCenter, self._text[:2].upper())
|
|
63
|
+
|
|
64
|
+
@Property(str)
|
|
65
|
+
def text(self):
|
|
66
|
+
return self._text
|
|
67
|
+
|
|
68
|
+
@text.setter
|
|
69
|
+
def text(self, value):
|
|
70
|
+
self._text = value
|
|
71
|
+
self.update()
|
|
72
|
+
|
|
73
|
+
@Property(str)
|
|
74
|
+
def image_path(self):
|
|
75
|
+
return self._image_path
|
|
76
|
+
|
|
77
|
+
@image_path.setter
|
|
78
|
+
def image_path(self, value):
|
|
79
|
+
self._image_path = value
|
|
80
|
+
self.update()
|
|
81
|
+
|
|
82
|
+
@Property(str)
|
|
83
|
+
def shape(self):
|
|
84
|
+
return self._shape
|
|
85
|
+
|
|
86
|
+
@shape.setter
|
|
87
|
+
def shape(self, value):
|
|
88
|
+
if value in ["circle", "square"]:
|
|
89
|
+
self._shape = value
|
|
90
|
+
self.update()
|
|
91
|
+
|
|
92
|
+
@Property(int)
|
|
93
|
+
def size(self):
|
|
94
|
+
return self._avatar_size
|
|
95
|
+
|
|
96
|
+
@size.setter
|
|
97
|
+
def size(self, value):
|
|
98
|
+
self._avatar_size = value
|
|
99
|
+
self.setFixedSize(value, value)
|
|
100
|
+
self._setup_style()
|
|
101
|
+
self.update()
|