from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout, QSizePolicy from PySide6.QtGui import QPixmap from PySide6.QtCore import Qt, QPropertyAnimation, Property import os import resources.resources_rc from utils.image_paths import ImagePaths # 拱形进度条 class OverlapArcProgress(QWidget): def __init__(self, bg_img_path, fg_img_path, parent=None): super().__init__(parent) self._progress = 0 # 进度(0-100) self.setStyleSheet("background: transparent; border: none;") # 加载并统一图片尺寸 self.bg_pixmap = QPixmap(bg_img_path) self.fg_pixmap = QPixmap(fg_img_path) if self.bg_pixmap.isNull(): print(f"错误:拱进度条背景图 {bg_img_path} 加载失败") if self.fg_pixmap.isNull(): print(f"错误:拱进度条前景图 {fg_img_path} 加载失败") if self.bg_pixmap.size() != self.fg_pixmap.size(): self.fg_pixmap = self.fg_pixmap.scaled( self.bg_pixmap.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) # 控件尺寸与图片一致(避免缩放失真) self.setFixedSize(self.bg_pixmap.size()) self.total_height = self.bg_pixmap.height() # 缓存总高度(背景/前景高度一致) # 背景标签(下层,完整显示背景) self.bg_label = QLabel(self) self.bg_label.setPixmap(self.bg_pixmap) self.bg_label.setScaledContents(False) # 禁用缩放 # 前景标签(上层,初始加载完整前景图,通过高度控制显示区域) self.fg_label = QLabel(self) self.fg_label.setPixmap(self.fg_pixmap) # 直接加载完整前景图 self.fg_label.setScaledContents(False) # 禁用缩放(避免图片拉伸) self.fg_label.setAlignment(Qt.AlignBottom) # 图片在标签内底部对齐 self.fg_label.raise_() # 确保在背景上层 # 初始状态:高度为0,位置在底部(不显示任何内容) self.fg_label.setGeometry(0, self.total_height, self.bg_pixmap.width(), 0) # ---------- 进度显示标签 ---------- # self.progress_label = QLabel(self) # self.progress_label.setGeometry(217, 17, 121, 34) # self.progress_label.setStyleSheet(""" # background-color: #444750; # color: #A2EF4D; # font-size: 20px; # font-weight: bold; # """) # # 文本在标签内部居中显示 # self.progress_label.setAlignment(Qt.AlignCenter) # self.progress_label.raise_() # 确保在前景上层(最上层) # self.progress_label.setText("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): """通过调整前景标签的高度和Y坐标, 实现从底部向上填充的进度条""" # 同步更新进度标签文本 # self.progress_label.setText(f"{self._progress}%") # print(f"{self._progress}%") progress_ratio = self._progress / 100.0 k = 8 # 调整此系数:k越大,“快慢差异”越明显(推荐范围 3~10) # 公式:height_ratio = x + k*(x³/3 - x²/2 + x/6) height_ratio = progress_ratio + k * ( (progress_ratio ** 3) / 3 - (progress_ratio ** 2) / 2 + progress_ratio / 6 ) height_ratio = max(0.0, min(1.0, height_ratio)) # 限制范围0-1 # 计算目标高度(随进度变化) target_height = int(self.total_height * height_ratio) # fg_label标签Y坐标 = 总高度 - 目标高度(实现底部对齐,向上延伸) target_y = self.total_height - target_height # 标签宽度与背景一致,高度为目标高度 self.fg_label.setGeometry( 0, # X坐标(与背景左对齐) target_y, # Y坐标(底部对齐) self.bg_pixmap.width(), # 宽度(与背景一致) target_height # 高度(随进度变化) ) class ArcProgressWidget(QWidget): def __init__(self): super().__init__() # 加载ArcProgressWidget背景图 # 添加了 拱3.png 作为背景图 bg_img = ImagePaths.ARCH3 # 需要修改为实际的图片的路径 # self.setStyleSheet(f"background-image: url({bg_img}); background-repeat: no-repeat; background-position: center;") self.bg_pixmap = QPixmap(bg_img) # self.setStyleSheet("background-color: red;") # # 设置控件widget大小与背景图一致 # self.bg_pixmap.size() 为 555x227 # self.setFixedSize(self.bg_pixmap.size()) # self.setFixedSize(555, 254) self.setFixedSize(555, 259) self.setSizePolicy( QSizePolicy.Fixed, # 水平方向固定 QSizePolicy.Fixed # 垂直方向固定 ) # 创建垂直主布局 main_layout = QVBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) # 去除边距 main_layout.setSpacing(0) # 去除控件间距 # 1. 添加标题标签(保持居中) self.arc_title_label = QLabel("振捣模具车", self) self.arc_title_label.setFixedSize(555, 29) self.arc_title_label.setAlignment(Qt.AlignCenter) self.arc_title_label.setStyleSheet(f""" color: #0bffff; font-size: 18px; background-image: url({ImagePaths.TEXT_TITLE_BG}); background-repeat: no-repeat; background-position: center; margin: 4px auto; """) main_layout.addWidget(self.arc_title_label, alignment=Qt.AlignCenter) # 2. 创建普通QWidget作为容器(大小与背景图一致) container = QWidget(self) container.setFixedSize(self.bg_pixmap.size()) # 容器大小=背景图大小 # 容器内设置背景图 background_label = QLabel(container) background_label.setPixmap(self.bg_pixmap) background_label.setScaledContents(True) background_label.setFixedSize(container.size()) background_label.lower() # 背景置底,避免遮挡其他控件 # 3. 在容器内添加所有标签和拱形进度条(用setGeometry定位) # 创建拱形进度条控件 arc_bg_img = ImagePaths.ARCH2 # 替换为实际路径 arc_fg_img = ImagePaths.ARCH1 # 替换为实际路径 self.arc_progress = OverlapArcProgress(arc_bg_img, arc_fg_img, container) # 显示环号的标签 self.ring_number_label = QLabel("环号: 1", container) self.ring_number_label.setGeometry(98, 118, 116, 29) # 保持原坐标 self.ring_number_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.ring_number_label.setAlignment(Qt.AlignCenter) # 显示重量的标签 self.weight_label = QLabel("2000kg", container) self.weight_label.setGeometry(217, 118, 118, 29) # 保持原坐标 self.weight_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.weight_label.setAlignment(Qt.AlignCenter) # 显示管片型号的标签 self.segment_model_label = QLabel("中埋: R12", container) self.segment_model_label.setGeometry(98, 150, 116, 29) self.segment_model_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.segment_model_label.setAlignment(Qt.AlignCenter) # 显示频率的标签 self.frequency_label = QLabel("210Hz", container) self.frequency_label.setGeometry(217, 150, 118, 29) self.frequency_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.frequency_label.setAlignment(Qt.AlignCenter) # 显示管片编号的标签 self.segment_number_label = QLabel("SHRB1-3", container) self.segment_number_label.setGeometry(338, 150, 116, 29) self.segment_number_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.segment_number_label.setAlignment(Qt.AlignCenter) # 显示管片尺寸的标签 self.segment_size_label = QLabel("6900*1500", container) self.segment_size_label.setGeometry(98, 182, 116, 29) self.segment_size_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.segment_size_label.setAlignment(Qt.AlignCenter) # 显示状态的标签 self.state_label = QLabel("振动中", container) self.state_label.setGeometry(217, 182, 118, 29) self.state_label.setStyleSheet(""" background-color: #143a6e; color: #16ffff; font-size: 18px; """) self.state_label.setAlignment(Qt.AlignCenter) # 4. 将拱形进度条容器添加到主布局 main_layout.addWidget(container, alignment=Qt.AlignCenter) # 进度条测试 def testProgress(self, seconds: float): # 启动动画从0%到100% (模拟进度加载) self.animation = QPropertyAnimation(self.arc_progress, b"progress") self.animation.setDuration(seconds * 1000) self.animation.setStartValue(0) self.animation.setEndValue(100) self.animation.start() # 进度条设置 def setProgress(self, progress:int): """ 设置progress之后, 会根据该值调整进度条 Args: progress: 传入去掉百分号之后的数值, 如80%, 传入80 """ try: if isinstance(progress, str): progress = progress.strip().replace("%", "") progress_int = int(float(progress)) progress_int = max(0, min(100, progress_int)) self.arc_progress.progress = progress_int except (ValueError, TypeError): pass # 传入的生产进度类型错误,维持原进度 # 重量设置 (单位kg) def setWeight(self, weight:float): self.weight_label.setText(f"{weight}kg") # 频率设置(单位Hz) def setFrequency(self, frequency:float): self.frequency_label.setText(f"{frequency}Hz") # 状态设置 (...中) def setState(self, stateStr:str): self.state_label.setText(stateStr) # 管片类型设置 (B1、B2、中埋: R12 等) def setSegmentModel(self, segmentModelStr:str): self.segment_model_label.setText(segmentModelStr) # 管片编号设置 def setSegmentNumber(self, segmentNumberStr:str): self.segment_number_label.setText(segmentNumberStr) # 环号设置 def setRingNumber(self, ringNumber:int): self.ring_number_label.setText(f"环号: {ringNumber}") # 管片尺寸(规格)设置 (比如:6900*1500) def setSegmentSize(self, SizeSpecification:str): self.segment_size_label.setText(SizeSpecification) if __name__ == "__main__": import sys app = QApplication(sys.argv) window = ArcProgressWidget() window.testProgress(120) # window.setState("测试中") window.show() sys.exit(app.exec())