Files
Feeding_control_system/view/widgets/clamp_widget.py

176 lines
7.4 KiB
Python
Raw Permalink Normal View History

2025-10-31 18:52:31 +08:00
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())