🐟🐟🐟 通过自定义QPushButton实现进度条按钮功能
实现方法
- 基本思路
要想实现在QPushButton中带有进度条的功能,毫无疑问是需要对QPushButton进行自定义操作的。其次就是对其中的paintEvent的方法进行覆写。这个带进度条的按钮总共可以分为三个部分来进行绘制,一是进度条区域、二是文本区域、三是图标区域。三者间的关系是进度条区域为最下层(先绘制),文本和图标区域在进度条区域的上面。其中进度条实现的原理,此次demo将通过定时器来改变进度条的宽度模拟进度条效果。后续可以根据实际场景通过信号传输等方式来实现实际功能。
- 参数初始化
首先是一些参数的初始化,其中num,percent是用于进度条进度的控制。painter_size用于设置图标和文本的字体大小,pos_x,pos_y用于设置进度条绘制的起点来改变按钮和进度条之间的间距
class ProgressButton(QPushButton):
"""
用于HomeWin self.btn_FT ,self.btn_PT
"""
demoSignal = Signal()
def __init__(self, *args, **kwargs):
super(ProgressButton, self).__init__(*args, **kwargs)
self.num = 0 # 进度条初始进度
self.painter_size = 15 # 图标和字体的大小
self.percent = 10 # 进度条前进进度
self.text = "" # 进度条文本
self.text_width = 0 # 进度条文本实际宽度
self.pos_x = 5 # 进度条x轴
self.pos_y = 9 # 进度条y轴
self.timer = QTimer() # 创建定时器
- 覆写paintEvent事件
参数初始化后就开始对paintEvent事件进行覆写,其中绘制的顺序为(进度条->文本->图标),在图标绘制中需要注意的事,因为文本的绘制是采用Qt.AlignCenter进行居中的绘制的,所以在进行图标位置的x轴起点定位时需要通过fontMetrics().horizontalAdvance(str)的方法来确定文本的宽度,以此来定位图标绘制的位置防止图标和文本重叠
def paintEvent(self, event):
super().paintEvent(event)
if self.num == 0:
self.text = "1000个文件正在传输"
self.timer.start(1000)
painter = QPainter(self)
brush = QBrush(QColor(71, 102, 45, 255), Qt.SolidPattern)
painter.setBrush(brush)
# 绘制进度条
rect_progress = QRect(self.pos_x, self.pos_y,
self.num, self.height() - self.pos_y * 2) # 进度条区域
painter.setPen(Qt.NoPen)
painter.drawRect(rect_progress)
# 绘制文字
rect_text = QRect(self.pos_x, self.pos_y, self.width() - self.pos_x * 2,
self.height() - self.pos_y * 2) # 文本区域
painter.setPen(QColor(167, 216, 169))
painter.setFont(QFont("SourceHanSansSC-Regular, SourceHanSansSC",
self.painter_size))
painter.drawText(rect_text, Qt.AlignCenter, self.text)
# 绘制图标
fm = painter.fontMetrics()
self.text_width = fm.horizontalAdvance(self.text)
rect_icon = QRect(self.width() // 2 - self.text_width // 2 - self.painter_size,
self.height() // 2 - self.painter_size // 2,
self.painter_size, self.painter_size) # 图标区域
painter.drawImage(rect_icon, "icon.png")
效果展示
完整代码
from PySide2.QtCore import QRect, Qt, Signal, QTimer
from PySide2.QtGui import QPainter, QBrush, QColor, QFont
from PySide2.QtWidgets import *
class ProgressButton(QPushButton):
"""
用于HomeWin self.btn_FT ,self.btn_PT
"""
demoSignal = Signal()
def __init__(self, *args, **kwargs):
super(ProgressButton, self).__init__(*args, **kwargs)
self.num = 0
self.painter_size = 15
self.percent = 10
self.text = "" # 进度条文本
self.text_width = 0 # 进度条文本实际宽度
self.pos_x = 5 # 进度条x轴
self.pos_y = 9 # 进度条y轴
self.timer = QTimer() # 创建定时器
self.timer.timeout.connect(self.emitDemoSignal)
self.demoSignal.connect(self.updateProgressBar)
def paintEvent(self, event):
super().paintEvent(event)
if self.num == 0:
self.text = "1000个文件正在传输"
self.timer.start(1000)
painter = QPainter(self)
brush = QBrush(QColor(71, 102, 45, 255), Qt.SolidPattern)
painter.setBrush(brush)
# 绘制进度条
rect_progress = QRect(self.pos_x, self.pos_y,
self.num, self.height() - self.pos_y * 2) # 进度条区域
painter.setPen(Qt.NoPen)
painter.drawRect(rect_progress)
# 绘制文字
rect_text = QRect(self.pos_x, self.pos_y, self.width() - self.pos_x * 2,
self.height() - self.pos_y * 2) # 文本区域
painter.setPen(QColor(167, 216, 169))
painter.setFont(QFont("SourceHanSansSC-Regular, SourceHanSansSC",
self.painter_size))
painter.drawText(rect_text, Qt.AlignCenter, self.text)
# 绘制图标
fm = painter.fontMetrics()
self.text_width = fm.horizontalAdvance(self.text)
rect_icon = QRect(self.width() // 2 - self.text_width // 2 - self.painter_size,
self.height() // 2 - self.painter_size // 2,
self.painter_size, self.painter_size) # 图标区域
painter.drawImage(rect_icon, "icon.png")
# 触发demoSignal
def emitDemoSignal(self):
self.demoSignal.emit()
# 更新进度条
def updateProgressBar(self):
self.percent = (self.width() - self.pos_x * 2) / 20
total = self.width() - self.pos_x * 2
if self.num < total:
if self.num + self.percent >= total:
self.num = total
self.text = "完成上传"
self.timer.stop()
else:
self.num += self.percent
self.update()
# 更新字体以及图标大小
def setPainterSize(self, size: int):
self.painter_size = size
self.update()
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("demo")
self.resize(800, 800)
self.setup_ui()
def setup_ui(self):
self.red_btn = ProgressButton(self)
self.red_btn.resize(400, 80)
self.red_btn.setPainterSize(20)
self.red_btn.setStyleSheet("""
border-color: transparents;
""")
self.red_btn.clicked.connect(self.restartProgress)
def restartProgress(self):
self.red_btn.num = 0
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())