from PySide6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout from PySide6.QtGui import QPixmap,QRegion,QPainter, QColor, QPainterPath from PySide6.QtCore import Qt, QPropertyAnimation, Property, QSize, QRectF import sys class MaskedLabel(QLabel): def __init__(self, parent=None): super().__init__(parent) self.setFixedSize(28, 20) # 遮罩大小 self.setStyleSheet("background-color: transparent; border: none;") def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) parent_widget = self.parent() bg_color = QColor("#f3f3f3") # 默认颜色 if parent_widget: # 从父控件的调色板中提取背景色 bg_color = parent_widget.palette().color(parent_widget.backgroundRole()) # 用父控件背景色绘制遮罩 painter.setBrush(bg_color) painter.setPen(Qt.NoPen) # 步骤3:绘制遮罩路径(逻辑不变) path = QPainterPath() mask_rect = QRectF(0, 0, 28, 20) circle_radius = 10 circle_center_x = 28 circle_center_y = 10 path.addRect(mask_rect) path.addEllipse( circle_center_x - circle_radius, circle_center_y - circle_radius, circle_radius * 2, circle_radius * 2 ) path.setFillRule(Qt.OddEvenFill) painter.drawPath(path) class LinearProductionProgress(QWidget): def __init__(self, parent=None): super().__init__(parent) self._progress = 0 # 进度(0-100) self.setFixedSize(450 + 18, 20) self.setStyleSheet( """ border-radius: 9px; """ ) # 底层背景 self.bg_label = QLabel(self) self.bg_label.setFixedSize(450, 20) self.bg_label.setStyleSheet( """ background-color: #e7e7e7; """ ) self.bg_label.move(18, 0) # 上层进度填充 self.fg_label = QLabel(self) self.fg_label.setStyleSheet( """ background-color: #0052d9; min-width: 18px; """ ) self.fg_label.setFixedHeight(20) self.fg_label.move(0, 0) self.fg_label.raise_() # 百分比标签(宽33px,高19px,右偏9px) self.percent_label = QLabel(self) self.percent_label.setText("0%") self.percent_label.setAlignment(Qt.AlignCenter) self.percent_label.setFixedSize(33, 19) self.percent_label.setStyleSheet( """ color: white; font-size: 12px; font-weight: bold; background-color: transparent; """ ) self.percent_label.move(18, 0) # 百分比标签初始位置 self.percent_label.raise_() # 遮盖左侧区域 self.mask_label = MaskedLabel(self) self.mask_label.move(0, 0) # 进度属性 @Property(int) def progress(self): return self._progress @progress.setter def progress(self, value): if 0 <= value <= 100 and value != self._progress: self._progress = value self.update_foreground() # 线性更新进度显示 def update_foreground(self): # 注意:为了实现前4%的动态效果,需要从 fd_width的4%起开始计算 fg_width = int(450 * (self._progress + 4) / 100) self.fg_label.setFixedWidth(fg_width) # 计算百分比标签位置:进度条右边缘 - 9px(偏移) - 标签宽度(33px) if fg_width > 60: # 当上层进度条宽度大于60px,开始移动 label_x = fg_width - 9 - 33 # 移动百分比标签 self.percent_label.move(label_x, 0) else: # 复原百分比标签 # 移动回初始位置 self.percent_label.move(18, 0) # 设置百分比标签 self.percent_label.setText(f"{self._progress}%") class ProductionProgressWidget(QWidget): def __init__(self): super().__init__() self.setFixedSize(620, 49) # 进度条控件大小 # 左侧文字标签 self.text_label = QLabel("生产进度") self.text_label.setFixedSize(112, 29) self.text_label.setAlignment(Qt.AlignVCenter | Qt.AlignRight) self.text_label.setStyleSheet("font-family: 'Microsoft YaHei';font-size: 18px;") # 右侧进度条 self.linear_progress = LinearProductionProgress() self.main_layout = QHBoxLayout(self) self.main_layout.addWidget(self.text_label) self.main_layout.addWidget(self.linear_progress) self.main_layout.setContentsMargins(0, 0, 0, 0) def testProgress(self, seconds: float): self.animation = QPropertyAnimation(self.linear_progress, b"progress") self.animation.setDuration(seconds * 1000) self.animation.setStartValue(0) self.animation.setEndValue(100) self.animation.start() def setProgress(self, progress: float): """ 设置progress之后, 会根据该值调整进度条 Args: progress: 传入去掉百分号之后的数值, 如80%, 传入80.0 """ self.linear_progress.progress = progress if __name__ == "__main__": app = QApplication(sys.argv) window = ProductionProgressWidget() # window.testProgress(60) # 进度条测试 window.show() sys.exit(app.exec())