from PySide6.QtWidgets import QWidget, QLabel, QHBoxLayout from PySide6.QtGui import QPixmap, QFont, QTransform from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve, Property import resources.resources_rc from utils.image_paths import ImagePaths class BladeLabel(QLabel): def __init__(self, parent=None): super().__init__(parent) self._rotation = 0.0 self._original_pixmap = None self._original_center_x = 0.0 # 原始图片自身中心点x self._original_center_y = 0.0 # 原始图片自身中心点y self._fixed_center_in_parent_x = 0 # 父容器中的固定中心点x(关键) self._fixed_center_in_parent_y = 0 # 父容器中的固定中心点y(关键) # self.setFixedSize(50, 54) def set_original_pixmap(self, pixmap, fixed_center_x, fixed_center_y): """ :param pixmap: 原始图片 :param fixed_center_x: 父容器中固定的中心点x坐标(绝对位置) :param fixed_center_y: 父容器中固定的中心点y坐标(绝对位置) """ self._original_pixmap = pixmap if pixmap.isNull(): print("错误:搅拌桨图片加载失败!") return # 记录原始图片自身的中心点(用于旋转计算) self._original_center_x = 28 # 图片的中心点为 28,28 self._original_center_y = 28 # 记录在父容器中的固定中心点(旋转时始终对齐这个点) self._fixed_center_in_parent_x = fixed_center_x self._fixed_center_in_parent_y = fixed_center_y # 初始显示图片 self.setPixmap(pixmap) # 初始位置:让原始图片的中心点与固定中心点对齐 self._update_position(pixmap.width(), pixmap.height()) def _update_position(self, current_w, current_h): """根据当前图片尺寸,计算位置使中心点与固定坐标对齐""" # 当前图片的中心点坐标(自身坐标系) current_center_x = current_w / 2 current_center_y = current_h / 2 # 计算左上角坐标:固定中心点 - 当前图片中心点 x = self._fixed_center_in_parent_x - current_center_x y = self._fixed_center_in_parent_y - current_center_y self.move(round(x), round(y)) # 取整避免浮点数位置偏差 self.setFixedSize(current_w, current_h) def get_rotation(self): return self._rotation def set_rotation(self, angle): self._rotation = angle if self._original_pixmap is None: return # 生成旋转后的图片(保持旋转中心为原始图片中心) transform = QTransform() transform.translate(self._original_center_x, self._original_center_y) transform.rotate(angle) transform.translate(-self._original_center_x, -self._original_center_y) rotated_pixmap = self._original_pixmap.transformed(transform, Qt.SmoothTransformation) # 强制对齐固定中心点(关键:无论尺寸如何变化,中心点不变) self._update_position(rotated_pixmap.width(), rotated_pixmap.height()) self.setPixmap(rotated_pixmap) rotation = Property(float, get_rotation, set_rotation) def reset_to_original(self): self._rotation = 0.0 # 重置旋转角度为0° if self._original_pixmap is not None: self.setPixmap(self._original_pixmap) # 恢复原始图片 # 恢复初始位置(基于原始图片尺寸) self._update_position(self._original_pixmap.width(), self._original_pixmap.height()) class MixerWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) # 状态变量:标记搅拌桨是否正在旋转 self.is_mixing = False # 初始状态为未旋转 # 两个搅拌桨的转动的动画引用 self.animations = [] # 保存动画引用 # 初始化布局 layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setFixedSize(225, 102) # 1. 创建“搅拌机”文字标签 self.text_label = QLabel("搅拌机") self.text_label.setFixedSize(100, 23) self.text_label.setFont(QFont("Arial", 14)) # 设置字体大小为16px self.text_label.setAlignment(Qt.AlignCenter) self.text_label.setStyleSheet(f""" background-image: url({ImagePaths.TEXT_TITLE_BG}); background-repeat: no-repeat; background-position: center; color: #0bffff; /* 可根据需求调整文字颜色 */ """) layout.addWidget(self.text_label, alignment=Qt.AlignLeft) # 2. 创建搅拌机设备 self.device_label = QLabel() device_pixmap = QPixmap(ImagePaths.MIXER) self.device_label.setPixmap(device_pixmap) layout.addWidget(self.device_label, alignment=Qt.AlignLeft) # 3. 初始化两个搅拌桨 self._init_blades() def _init_blades(self): blade_pixmap = QPixmap(ImagePaths.MIXER_PADDLE) if blade_pixmap.isNull(): return # 设备背景的尺寸(用于计算固定中心点) device_pixmap = self.device_label.pixmap() if not device_pixmap: return device_w = device_pixmap.width() device_h = device_pixmap.height() # -------------------------- # 左搅拌桨:计算固定中心点 # -------------------------- left_center_x = (device_w // 2) - 26 # 左桨中心点x(示例值,需根据实际调整) left_center_y = device_h // 2 - 5 # 左桨中心点y(示例值,需根据实际调整) self.blade1 = BladeLabel(self.device_label) self.blade1.set_original_pixmap(blade_pixmap, left_center_x, left_center_y) # -------------------------- # 右搅拌桨:计算固定中心点 # -------------------------- right_center_x = (device_w // 2) + 30 # 右桨中心点x(示例值,需根据实际调整) right_center_y = device_h // 2 - 5 # 右桨中心点y(与左桨对齐) self.blade2 = BladeLabel(self.device_label) self.blade2.set_original_pixmap(blade_pixmap, right_center_x, right_center_y) def _start_animation(self, blade: BladeLabel, duration: int, reverse: bool = False): """ Args: blade: 所需旋转的搅拌桨标签 duration 一次搅拌桨旋转所需的时间,值越小,旋转越快 reverse: 是否反转(逆时针转) """ animation = QPropertyAnimation(blade, b"rotation") animation.setStartValue(360 if reverse else 0) animation.setEndValue(0 if reverse else 360) animation.setDuration(duration) animation.setEasingCurve(QEasingCurve.Linear) animation.setLoopCount(-1) self.animations.append(animation) animation.start() # 搅拌桨开始搅拌 def startBladeMix(self, duration=700): if self.is_mixing: # 搅拌桨已经在旋转 return self.animations.clear() # 备注:duration控制搅拌桨旋转的速度,值越小旋转得越快 self._start_animation(self.blade1, duration) self._start_animation(self.blade2, duration) self.is_mixing = True # 更新搅拌桨状态为旋转中 def stopBladeMix(self): if not self.is_mixing: # 搅拌桨已经停止 return for animation in self.animations: animation.stop() if self.blade1: self.blade1.reset_to_original() if self.blade2: self.blade2.reset_to_original() self.is_mixing = False # 更新搅拌桨状态为停止