173 lines
7.4 KiB
Python
173 lines
7.4 KiB
Python
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.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):
|
||
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()
|