Skip to content
This repository was archived by the owner on Jun 28, 2025. It is now read-only.

Commit 886b4e8

Browse files
committed
feat(RoundShadow.py): Added window dragging movement.(Bugs occured).
feat(MyIconTextButton.py): Added new custom widget: MyIconTextButton. A simple button widget with an SVG icon and line of text.
1 parent ef10be6 commit 886b4e8

13 files changed

Lines changed: 562 additions & 44 deletions

File tree

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
# -*- coding: utf-8 -*-
2+
from selectors import SelectorKey
3+
from PyQt5.QtWidgets import QPushButton, QLabel, QHBoxLayout
4+
from PyQt5.QtSvg import QSvgWidget
5+
from PyQt5.QtCore import Qt, QSize, QPropertyAnimation, QEasingCurve, QRect
6+
from PyQt5.QtGui import QColor, QPainter, QPen, QBrush, QFont, QFontMetrics
7+
import os
8+
9+
10+
class MyIconTextButton(QPushButton):
11+
"""图标文本按钮
12+
13+
一个左侧显示 SVG 图标、右侧显示文本的按钮,支持悬停效果和点击效果,两端为圆角
14+
"""
15+
16+
def __init__(self, parent=None, svg_path="", text="", height=36, tooltip="",
17+
svg_size=(24, 24),
18+
border_width=1, border_color=QColor(255, 255, 255, 0),
19+
svg_color=QColor(255, 255, 255, 255),
20+
text_color=QColor(0, 0, 0, 255),
21+
font_size=12,
22+
margin=(8, 0, 8, 0),
23+
padding=(4, 0, 4, 0),
24+
command=None):
25+
"""
26+
初始化图标文本按钮
27+
28+
Args:
29+
parent: 父控件
30+
svg_path: SVG 文件路径
31+
text: 按钮文本
32+
height: 按钮高度,默认为 36
33+
tooltip: 鼠标悬停提示文本
34+
svg_size: SVG 图标大小,默认为 (24, 24)
35+
border_width: 边框宽度,默认为 1
36+
border_color: 边框颜色,默认为透明
37+
svg_color: SVG 图标颜色,默认为白色
38+
text_color: 文本颜色,默认为黑色
39+
font_size: 文本字体大小,默认为 12
40+
margin: 按钮内容外边距,格式为 (左, 上, 右, 下),默认为 (8, 0, 8, 0)
41+
padding: 图标与文本之间的间距,格式为 (左, 上, 右, 下),默认为 (4, 0, 4, 0)
42+
command: 按下按钮时执行的函数
43+
44+
"""
45+
super().__init__(parent)
46+
47+
# 保存参数
48+
self.button_height = height
49+
self._text = text
50+
self._font_size = font_size
51+
self._margin = margin
52+
self._padding = padding
53+
self._svg_size = svg_size
54+
55+
# 设置按钮属性
56+
self.setToolTip(tooltip)
57+
self.setCursor(Qt.PointingHandCursor)
58+
59+
# 设置样式
60+
self.setStyleSheet("""
61+
QPushButton {
62+
background-color: transparent;
63+
border: none;
64+
}
65+
QPushButton:hover {
66+
background-color: transparent;
67+
}
68+
QPushButton:pressed {
69+
background-color: transparent;
70+
}
71+
""")
72+
73+
# 创建水平布局
74+
self.layout = QHBoxLayout(self)
75+
self.layout.setContentsMargins(*margin)
76+
self.layout.setSpacing(padding[0] + padding[2]) # 使用左右内边距作为间距
77+
78+
# 创建 SVG 控件
79+
self.svg_widget = QSvgWidget()
80+
self.svg_widget.setFixedSize(*svg_size)
81+
82+
# 加载 SVG 文件
83+
if svg_path:
84+
self.svg_widget.load(svg_path)
85+
86+
# 设置 SVG 颜色
87+
self.setSvgColor(svg_color)
88+
89+
# 创建文本标签
90+
self.text_label = QLabel(text)
91+
self.text_label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
92+
93+
# 根据文本内容选择字体
94+
self.updateFont(text, font_size)
95+
96+
# 设置文本颜色
97+
self.setTextColor(text_color)
98+
99+
# 添加控件到布局
100+
self.layout.addWidget(self.svg_widget)
101+
self.layout.addWidget(self.text_label)
102+
103+
# 设置圆角边框属性
104+
self.border_color = border_color
105+
self.border_width = border_width
106+
self.radius = height // 2 # 圆角半径设为高度的一半,实现两端圆角效果
107+
108+
# 添加状态跟踪
109+
self.is_hovered = False
110+
self.is_pressed = False
111+
112+
# 绑定函数
113+
if command:
114+
self.clicked.connect(command)
115+
116+
# 设置背景颜色(默认透明)
117+
self.bg_color = QColor(255, 255, 255, 0)
118+
self.hover_color = QColor(255, 255, 255, 127)
119+
self.press_color = QColor(255, 255, 255, 127)
120+
121+
# 计算并设置按钮宽度
122+
self.updateButtonSize()
123+
124+
def containsChinese(self, text):
125+
"""检查文本是否包含中文字符
126+
127+
Args:
128+
text: 要检查的文本
129+
130+
Returns:
131+
bool: 如果包含中文字符返回 True,否则返回 False
132+
"""
133+
for char in text:
134+
if '\u4e00' <= char <= '\u9fff':
135+
return True
136+
return False
137+
138+
def updateFont(self, text, font_size):
139+
"""根据文本内容更新字体
140+
141+
Args:
142+
text: 文本内容
143+
font_size: 字体大小
144+
"""
145+
font = QFont()
146+
147+
# 检查文本是否包含中文
148+
if self.containsChinese(text):
149+
# 中文字体路径
150+
chinese_font_path = "Resources/FontChinese.ttc"
151+
if os.path.exists(chinese_font_path):
152+
font.setFamily(chinese_font_path)
153+
else:
154+
# 英文字体路径
155+
english_font_path = "Resources\Fonts\Font.ttf"
156+
if os.path.exists(english_font_path):
157+
font.setFamily(english_font_path)
158+
159+
font.setPointSize(font_size)
160+
self.text_label.setFont(font)
161+
162+
def updateButtonSize(self):
163+
"""根据文本内容、字体和字号计算并更新按钮宽度"""
164+
# 创建字体度量对象
165+
font = self.text_label.font()
166+
font_metrics = QFontMetrics(font)
167+
168+
# 计算文本宽度
169+
text_width = font_metrics.width(self._text)
170+
171+
# 计算总宽度:左边距 + SVG宽度 + 间距 + 文本宽度 + 右边距
172+
total_width = (self._margin[0] + self._svg_size[0] +
173+
(self._padding[0] + self._padding[2]) +
174+
text_width + self._margin[2])
175+
176+
# 设置按钮大小
177+
self.setFixedSize(total_width, self.button_height)
178+
179+
def setSvgColor(self, color):
180+
"""设置 SVG 的颜色(仅当 SVG 支持颜色修改时有效)
181+
182+
Args:
183+
color: QColor 对象或颜色名称字符串
184+
"""
185+
if isinstance(color, str):
186+
color = QColor(color)
187+
188+
# 通过样式表设置 SVG 颜色
189+
self.svg_widget.setStyleSheet(f"background-color: transparent; color: {color.name()};")
190+
191+
def setTextColor(self, color):
192+
"""设置文本颜色
193+
194+
Args:
195+
color: QColor 对象或颜色名称字符串
196+
"""
197+
if isinstance(color, str):
198+
color = QColor(color)
199+
200+
# 设置文本颜色
201+
self.text_label.setStyleSheet(f"color: {color.name()};")
202+
203+
def setText(self, text):
204+
"""设置按钮文本
205+
206+
Args:
207+
text: 文本内容
208+
"""
209+
self._text = text
210+
self.text_label.setText(text)
211+
212+
# 更新字体
213+
self.updateFont(text, self._font_size)
214+
215+
# 更新按钮大小
216+
self.updateButtonSize()
217+
218+
def setSvgPath(self, svg_path):
219+
"""更新 SVG 图标
220+
221+
Args:
222+
svg_path: SVG 文件路径
223+
"""
224+
# 加载 SVG 文件
225+
self.svg_widget.load(svg_path)
226+
227+
def setSvgSize(self, size):
228+
"""设置 SVG 图标的大小
229+
230+
Args:
231+
size: (width, height) 元组
232+
"""
233+
self._svg_size = size
234+
self.svg_widget.setFixedSize(*size)
235+
self.updateButtonSize() # 更新按钮大小
236+
237+
def setFontSize(self, size):
238+
"""设置文本字体大小
239+
240+
Args:
241+
size: 字体大小(点)
242+
"""
243+
self._font_size = size
244+
245+
# 更新字体
246+
self.updateFont(self._text, size)
247+
248+
# 更新按钮大小
249+
self.updateButtonSize()
250+
251+
def setBorderColor(self, color):
252+
"""设置边框颜色
253+
254+
Args:
255+
color: QColor 对象或颜色名称字符串
256+
"""
257+
if isinstance(color, str):
258+
color = QColor(color)
259+
self.border_color = color
260+
self.update() # 触发重绘
261+
262+
def setBorderWidth(self, width):
263+
"""设置边框宽度
264+
265+
Args:
266+
width: 边框宽度(像素)
267+
"""
268+
self.border_width = width
269+
self.update() # 触发重绘
270+
271+
def enterEvent(self, event):
272+
"""鼠标进入事件"""
273+
self.is_hovered = True
274+
self.update() # 触发重绘
275+
super().enterEvent(event)
276+
277+
def leaveEvent(self, event):
278+
"""鼠标离开事件"""
279+
self.is_hovered = False
280+
self.update() # 触发重绘
281+
super().leaveEvent(event)
282+
283+
def mousePressEvent(self, event):
284+
"""鼠标按下事件"""
285+
if event.button() == Qt.LeftButton:
286+
self.is_pressed = True
287+
self.update() # 触发重绘
288+
super().mousePressEvent(event)
289+
290+
def mouseReleaseEvent(self, event):
291+
"""鼠标释放事件"""
292+
if event.button() == Qt.LeftButton:
293+
self.is_pressed = False
294+
self.update() # 触发重绘
295+
super().mouseReleaseEvent(event)
296+
297+
def paintEvent(self, event):
298+
"""重写绘制事件,添加两端圆角矩形边框和背景"""
299+
# 不调用父类的绘制方法,完全自定义绘制
300+
301+
# 创建画笔
302+
painter = QPainter(self)
303+
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
304+
305+
# 根据状态设置背景颜色
306+
if self.is_pressed:
307+
# 按下状态
308+
bg_color = self.press_color
309+
border_color = QColor(self.border_color)
310+
border_color.setAlpha(127)
311+
elif self.is_hovered:
312+
# 悬停状态
313+
bg_color = self.hover_color
314+
border_color = QColor(self.border_color)
315+
border_color.setAlpha(0) # 悬停时边框透明
316+
else:
317+
# 正常状态
318+
bg_color = self.bg_color
319+
border_color = QColor(self.border_color)
320+
321+
# 绘制背景
322+
painter.setBrush(QBrush(bg_color))
323+
324+
# 设置画笔属性
325+
pen = QPen(border_color)
326+
pen.setWidth(self.border_width)
327+
painter.setPen(pen)
328+
329+
# 绘制两端圆角矩形边框和背景
330+
# 圆角半径设为高度的一半,实现两端圆角效果
331+
painter.drawRoundedRect(self.rect().adjusted(
332+
self.border_width // 2,
333+
self.border_width // 2,
334+
-self.border_width // 2,
335+
-self.border_width // 2
336+
), self.radius, self.radius)
337+
338+
def setHoverColor(self, color):
339+
"""设置鼠标悬停时的背景颜色
340+
341+
Args:
342+
color: 颜色值,可以是 QColor 对象或颜色名称字符串
343+
"""
344+
if isinstance(color, str):
345+
color = QColor(color)
346+
self.hover_color = color
347+
348+
def setPressColor(self, color):
349+
"""设置鼠标按下时的背景颜色
350+
351+
Args:
352+
color: 颜色值,可以是 QColor 对象或颜色名称字符串
353+
"""
354+
if isinstance(color, str):
355+
color = QColor(color)
356+
self.press_color = color
357+
358+
def setBackgroundColor(self, color):
359+
"""设置按钮的背景颜色
360+
361+
Args:
362+
color: 颜色值,可以是 QColor 对象或颜色名称字符串
363+
"""
364+
if isinstance(color, str):
365+
color = QColor(color)
366+
self.bg_color = color
367+
self.update() # 触发重绘

0 commit comments

Comments
 (0)