176 lines
7.4 KiB
Python
176 lines
7.4 KiB
Python
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()) |