diff --git a/view/main_window.py b/view/main_window.py index 127be50..705c577 100644 --- a/view/main_window.py +++ b/view/main_window.py @@ -197,6 +197,8 @@ class MainWindow(QWidget): # 以下为模拟: # 假设两秒种之后,移动到了搅拌机下 (这里需要根据实际情况修改) QTimer.singleShot(2000, self.conveyor_system_widget.moveHopperBelowMixer) + # 移动到搅拌楼下,搅拌桨就开始旋转 + QTimer.singleShot(2100, self.mixer_widget.startBladeMix) # 料斗左移完成,恢复料斗右移按钮 QTimer.singleShot(2100, lambda: self.conveyor_system_widget.right_btn.setEnabled(True)) @@ -205,8 +207,12 @@ class MainWindow(QWidget): # 演示效果 self.conveyor_system_widget.moveHopperToTransition() # 移动到过渡的位置 self.hopper_widget.upper_clamp_widget.set_angle(0) # 上料斗向右移动到目的地时,夹爪的角度一定是0 - # 按钮状态:点击料斗右移按钮后,禁用料斗左移按钮 - self.conveyor_system_widget.left_btn.setEnabled(False) + # 按钮状态:点击料斗右移按钮后,禁用料斗左移按钮 + self.conveyor_system_widget.left_btn.setEnabled(False) + + # 开始右移,搅拌桨就停止转动 + self.mixer_widget.stopBladeMix() + # 以下为模拟: # 假设两秒后,传送带中 料斗向右移动完成 (这里需要根据实际情况修改) QTimer.singleShot(1900, self.conveyor_system_widget.hideHopper) # 料斗向右移动完成,隐藏料斗 diff --git a/view/widgets/mixer_widget.py b/view/widgets/mixer_widget.py index bea9c29..921a17b 100644 --- a/view/widgets/mixer_widget.py +++ b/view/widgets/mixer_widget.py @@ -1,13 +1,87 @@ from PySide6.QtWidgets import QWidget, QLabel, QHBoxLayout -from PySide6.QtGui import QPixmap, QFont -from PySide6.QtCore import Qt +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.animations = [] # 保存动画引用 # 初始化布局 layout = QHBoxLayout(self) @@ -28,35 +102,71 @@ class MixerWidget(QWidget): """) layout.addWidget(self.text_label, alignment=Qt.AlignLeft) - # 2. 创建搅拌机设备及搅拌桨图标 + # 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.blade1 = QLabel(self.device_label) # 从左往右第一个搅拌桨 - blade1_pixmap = QPixmap(ImagePaths.MIXER_PADDLE) - self.blade1.setPixmap(blade1_pixmap) - self.blade1.move( - (device_pixmap.width() - blade1_pixmap.width()) // 2 - 26, - (device_pixmap.height() - blade1_pixmap.height()) // 2 - 4 - ) + # 3. 初始化两个搅拌桨 + self._init_blades() + + def _init_blades(self): + blade_pixmap = QPixmap(ImagePaths.MIXER_PADDLE) + if blade_pixmap.isNull(): + return - self.blade2 = QLabel(self.device_label) - blade2_pixmap = QPixmap(ImagePaths.MIXER_PADDLE) # 从左往右第二个搅拌桨 - self.blade2.setPixmap(blade2_pixmap) - self.blade2.move( - (device_pixmap.width() - blade2_pixmap.width()) // 2 + 31, - (device_pixmap.height() - blade2_pixmap.height()) // 2 - 4 - ) + # 设备背景的尺寸(用于计算固定中心点) + 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) -# 测试代码 -if __name__ == "__main__": - import sys - from PySide6.QtWidgets import QApplication, QMainWindow + 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() - app = QApplication(sys.argv) - mixer_widget = MixerWidget() - mixer_widget.show() - sys.exit(app.exec()) \ No newline at end of file + # 搅拌桨开始搅拌 + def startBladeMix(self, duration=700): + self.animations.clear() + # 备注:duration控制搅拌桨旋转的速度,值越小旋转得越快 + self._start_animation(self.blade1, duration) + self._start_animation(self.blade2, duration) + + def stopBladeMix(self): + for animation in self.animations: + animation.stop() + + if self.blade1: + self.blade1.reset_to_original() + if self.blade2: + self.blade2.reset_to_original()