即使稍后在场景中移动和旋转箭头,此解决方案也有效:
箭头.h
#ifndef ARROW_H
#define ARROW_H
#include <QGraphicsLineItem>
#include <QObject>
#include <QtCore/qmath.h>
class Arrow : public QGraphicsLineItem, public QObject
{
public:
Arrow(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem* parent = 0);
virtual ~Arrow();
QPointF objectEndPoint1();
QPointF objectEndPoint2();
void setObjectEndPoint1(qreal x1, qreal y1);
void setObjectEndPoint2(qreal x2, qreal y2);
protected:
void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
void timerEvent(QTimerEvent* event);
private:
inline qreal pi() { return (qAtan(1.0)*4.0); }
inline qreal radians(qreal degrees) { return (degrees*pi()/180.0); }
void createArrow(qreal penWidth);
QPainterPath arrowPath;
QPainterPath strokePath;
QPainterPath fillPath;
int timerID_Anim;
int animFrame;
qreal animLength;
QVector<qreal> dashPattern;
};
#endif
箭头.cpp
#include "arrow.h"
#include <QPen>
#include <QPainter>
#include <QTimerEvent>
Arrow::Arrow(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem* parent) : QGraphicsLineItem(0, 0, x2, y2, parent)
{
setFlag(QGraphicsItem::ItemIsSelectable, true);
setObjectEndPoint1(x1, y1);
setObjectEndPoint2(x2, y2);
qreal dashLength = 3;
qreal dashSpace = 3;
animLength = dashLength + dashSpace;
dashPattern << dashLength << dashSpace;
createArrow(1.0);
animFrame = 0;
timerID_Anim = startTimer(100);
}
Arrow::~Arrow()
{
}
void Arrow::timerEvent(QTimerEvent* event)
{
if(event->timerId() == timerID_Anim)
{
animFrame++;
if(animFrame >= animLength) animFrame = 0;
}
update(); //This forces a repaint, even if the mouse isn't moving
}
void Arrow::createArrow(qreal penWidth)
{
QPen arrowPen = pen();
arrowPen.setWidthF(penWidth);
arrowPen.setDashPattern(dashPattern);
setPen(arrowPen);
QPointF p1 = line().p1();
QPointF p2 = line().p2();
qreal angle = line().angle();
qreal arrowHeadAngle = 32.0;
qreal length = line().length();
qreal arrowHeadLength = length/10.0;
QLineF arrowLine1(p1, p2);
QLineF arrowLine2(p1, p2);
arrowLine1.setAngle(angle + arrowHeadAngle);
arrowLine2.setAngle(angle - arrowHeadAngle);
arrowLine1.setLength(arrowHeadLength);
arrowLine2.setLength(arrowHeadLength);
QPainterPath linePath;
linePath.moveTo(p1);
linePath.lineTo(p2);
QPainterPath arrowheadPath;
arrowheadPath.moveTo(arrowLine1.p2());
arrowheadPath.lineTo(p1);
arrowheadPath.lineTo(arrowLine2.p2());
arrowheadPath.lineTo(p1);
arrowheadPath.lineTo(arrowLine1.p2());
arrowPath = QPainterPath();
arrowPath.addPath(linePath);
arrowPath.addPath(arrowheadPath);
}
void Arrow::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
{
QPen paintPen = pen();
QPainterPathStroker stroker;
stroker.setWidth(paintPen.widthF());
stroker.setCapStyle(Qt::FlatCap);
stroker.setJoinStyle(Qt::MiterJoin);
strokePath = stroker.createStroke(arrowPath);
strokePath = strokePath.simplified();
stroker.setDashOffset(animFrame);
stroker.setDashPattern(dashPattern);
fillPath = stroker.createStroke(strokePath);
paintPen.setDashOffset(animFrame);
painter->fillPath(fillPath, QBrush(QColor(255,0,0)));
painter->fillPath(strokePath, QBrush(QColor(0,255,0)));
}
QPointF Arrow::objectEndPoint1()
{
return scenePos();
}
QPointF Arrow::objectEndPoint2()
{
QLineF lyne = line();
qreal rot = radians(rotation());
qreal cosRot = qCos(rot);
qreal sinRot = qSin(rot);
qreal x2 = lyne.x2();
qreal y2 = lyne.y2();
qreal rotEnd2X = x2*cosRot - y2*sinRot;
qreal rotEnd2Y = x2*sinRot + y2*cosRot;
return (scenePos() + QPointF(rotEnd2X, rotEnd2Y));
}
void Arrow::setObjectEndPoint1(qreal x1, qreal y1)
{
QPointF endPt2 = objectEndPoint2();
qreal x2 = endPt2.x();
qreal y2 = endPt2.y();
qreal dx = x2 - x1;
qreal dy = y2 - y1;
setRotation(0);
setLine(0, 0, dx, dy);
setPos(x1, y1);
}
void Arrow::setObjectEndPoint2(qreal x2, qreal y2)
{
QPointF endPt1 = scenePos();
qreal x1 = endPt1.x();
qreal y1 = endPt1.y();
qreal dx = x2 - x1;
qreal dy = y2 - y1;
setRotation(0);
setLine(0, 0, dx, dy);
setPos(x1, y1);
}