Files
Feeding_control_system/view/widgets/clamp_widget.py
2025-10-31 18:52:35 +08:00

176 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PySide6.QtWidgets import QWidget, QApplication
from PySide6.QtGui import QPainter, QPen, QBrush, QColor, QTransform
from PySide6.QtCore import Qt, QPropertyAnimation, Property, QPointF
import sys
# 料斗夹爪部分,包括夹爪开合动画
class ClampWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._angle = 0.0 # 开合角度0-70度单个夹具旋转角度为angle/2
self.setFixedSize(176, 127) # 绘图区域大小 240x150
# self.rot_center = QPointF(120, 30) # 旋转中心
# 重要,调整这里,设置夹爪绘制位置
self.rot_center = QPointF(88, 14) # 调整!!! 在主界面中位置需要调整这里
self.red_width = 37 # 红框宽度
self.red_height = 81 # 红框高度
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# ---- 左红框及蓝色部分 ----
# 左红框原始顶点(严格对称,以旋转中心为轴)
left_red_vertices = [
QPointF(self.rot_center.x() - self.red_width, self.rot_center.y()), # 顶部左
QPointF(self.rot_center.x(), self.rot_center.y()), # 顶部右(旋转中心)
QPointF(self.rot_center.x(), self.rot_center.y() + self.red_height), # 底部右
QPointF(self.rot_center.x() - self.red_width, self.rot_center.y() + self.red_height) # 底部左
]
# 左红框旋转变换顺时针转angle/2度
painter.save()
transform = QTransform()
transform.translate(self.rot_center.x(), self.rot_center.y())
transform.rotate(self._angle / 2)
transform.translate(-self.rot_center.x(), -self.rot_center.y())
transformed_left_red = [transform.map(p) for p in left_red_vertices]
# 绘制左红框辅助线
# painter.setPen(QPen(QColor(255, 0, 0), 1, Qt.DashLine))
# painter.setBrush(Qt.NoBrush)
# painter.drawPolygon(transformed_left_red)
painter.restore()
# 绘制左蓝色部分 86, 180, 239
# painter.setPen(QPen(QColor(0, 120, 255), 2))
# painter.setBrush(QBrush(QColor(0, 170, 255, 180)))
painter.setPen(QPen(QColor(66, 152, 215, 190), 2))
painter.setBrush(QBrush(QColor(86, 180, 239)))
# 蓝色顶点顶部中间17px直线 + 红框内边界
top_mid = QPointF(
transformed_left_red[0].x() + self.red_width/2 - 10,
transformed_left_red[0].y()
)
top_end = QPointF(top_mid.x() + 17, top_mid.y())
bottom_left = transformed_left_red[3]
# ============================== 特殊计算 bottom_right1 和 bottom_right2 ======
# 定义端点
A = transformed_left_red[1] # 左红框顶部右顶点
B = transformed_left_red[2] # 左红框底部右顶点
t = 0.7 # 70%位置
# 线性插值计算bottom_left2
bottom_right2_x = A.x() + t * (B.x() - A.x())
bottom_right2_y = A.y() + t * (B.y() - A.y())
bottom_right1 = QPointF(bottom_right2_x - 5, bottom_right2_y - 8) # 基于bottom_right2 计算坐标
bottom_right2 = QPointF(bottom_right2_x, bottom_right2_y)
# ===========================================================================
bottom_right3 = QPointF(transformed_left_red[2].x(), transformed_left_red[2].y())
left_blue_vertices = [
top_mid,
top_end,
bottom_right1,
bottom_right2,
bottom_right3,
bottom_left,
top_mid
]
painter.drawPolygon(left_blue_vertices)
# ---- 右红框及蓝色部分 ----
# 右红框原始顶点(与左红框完全对称)
right_red_vertices = [
QPointF(self.rot_center.x(), self.rot_center.y()), # 顶部左(旋转中心)
QPointF(self.rot_center.x() + self.red_width, self.rot_center.y()), # 顶部右
QPointF(self.rot_center.x() + self.red_width, self.rot_center.y() + self.red_height), # 底部右
QPointF(self.rot_center.x(), self.rot_center.y() + self.red_height) # 底部左
]
# 右红框旋转变换逆时针转angle/2度
painter.save()
transform = QTransform()
transform.translate(self.rot_center.x(), self.rot_center.y())
transform.rotate(-self._angle / 2)
transform.translate(-self.rot_center.x(), -self.rot_center.y())
transformed_right_red = [transform.map(p) for p in right_red_vertices]
# 绘制右红框辅助线
# painter.setPen(QPen(QColor(255, 0, 0), 1, Qt.DashLine))
# painter.setBrush(Qt.NoBrush)
# painter.drawPolygon(transformed_right_red)
painter.restore()
# 绘制右蓝色部分 83, 175, 234 66, 152, 215
painter.setPen(QPen(QColor(66, 152, 215, 190), 2))
painter.setBrush(QBrush(QColor(86, 180, 239)))
# painter.setPen(QPen(QColor(0, 120, 255), 2))
# painter.setBrush(QBrush(QColor(0, 170, 255, 180)))
# 蓝色顶点顶部中间17px直线 + 红框内边界
top_mid = QPointF(
transformed_right_red[1].x() - self.red_width/2 + 10,
transformed_right_red[1].y()
)
top_end = QPointF(top_mid.x() - 17, top_mid.y())
# ============================== 特殊计算 bottom_left1 和 bottom_left2 =======
# 定义端点
A = transformed_right_red[0] # 右红框顶部左顶点
B = transformed_right_red[3] # 右红框底部左顶点
t = 0.7 # 70%位置
# 线性插值计算bottom_left2
bottom_left2_x = A.x() + t * (B.x() - A.x())
bottom_left2_y = A.y() + t * (B.y() - A.y())
bottom_left1 = QPointF(bottom_left2_x + 5, bottom_left2_y - 8) # 基于bottom_left2 计算坐标
bottom_left2 = QPointF(bottom_left2_x, bottom_left2_y)
# ===========================================================================
bottom_left3 = transformed_right_red[3]
bottom_right = transformed_right_red[2]
right_blue_vertices = [
top_mid,
top_end,
bottom_left1,
bottom_left2,
bottom_left3,
bottom_right,
top_mid
]
painter.drawPolygon(right_blue_vertices)
# ---- 角度属性(用于动画)----
def get_angle(self):
return self._angle
def set_angle(self, angle):
# 动画夹爪打开,限制范围为 0 到 70度
# 注意为了动画显示效果就算超过70度也只按70度计算
self._angle = max(0.0, min(70.0, angle))
self.update()
angle = Property(float, get_angle, set_angle)
# 测试动画
def testAnimation(self, target_angle, duration=6):
self.animation = QPropertyAnimation(self, b"angle")
self.animation.setDuration(duration * 1000) # duration单位为秒
self.animation.setStartValue(self._angle)
self.animation.setEndValue(target_angle)
self.animation.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = ClampWidget()
widget.show()
# widget.testAnimation(70)
close_anim = QPropertyAnimation(widget, b"angle")
close_anim.setDuration(6000)
close_anim.setStartValue(0)
close_anim.setEndValue(60)
close_anim.start()
# widget.set_angle(30)
sys.exit(app.exec())