paint函数无限循环
The paint function reloop infinitely
我已经更新了 diagramscene 示例以绘制窄线的法线。我将这一行添加到 Arrow::paint
函数中:
painter->drawLine(line());
painter->drawLine(line().normalVector()); // this line was added
//...
//scene()->update(); //add this line make this paint function reloop infinitely
没有 update
,正常的行没有显示,如果我移动项目,它可以显示但不正确。使用 update
,一切都正确绘制,但 paint
函数无限循环。我无法解释为什么,请帮助我!
//--编辑:
我添加原点 Arrow::paint
函数的代码:
void Arrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
QWidget *)
{
if (myStartItem->collidesWithItem(myEndItem))
return;
QPen myPen = pen();
myPen.setColor(myColor);
qreal arrowSize = 20;
painter->setPen(myPen);
painter->setBrush(myColor);
QLineF centerLine(myStartItem->pos(), myEndItem->pos());
QPolygonF endPolygon = myEndItem->polygon();
QPointF p1 = endPolygon.first() + myEndItem->pos();
QPointF p2;
QPointF intersectPoint;
QLineF polyLine;
for (int i = 1; i < endPolygon.count(); ++i) {
p2 = endPolygon.at(i) + myEndItem->pos();
polyLine = QLineF(p1, p2);
QLineF::IntersectType intersectType =
polyLine.intersect(centerLine, &intersectPoint);
if (intersectType == QLineF::BoundedIntersection)
break;
p1 = p2;
}
setLine(QLineF(intersectPoint, myStartItem->pos()));
double angle = ::acos(line().dx() / line().length());
if (line().dy() >= 0)
angle = (Pi * 2) - angle;
QPointF arrowP1 = line().p1() + QPointF(sin(angle + Pi / 3) * arrowSize,
cos(angle + Pi / 3) * arrowSize);
QPointF arrowP2 = line().p1() + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
cos(angle + Pi - Pi / 3) * arrowSize);
arrowHead.clear();
arrowHead << line().p1() << arrowP1 << arrowP2;
painter->drawLine(line());
painter->drawPolygon(arrowHead);
if (isSelected()) {
painter->setPen(QPen(myColor, 1, Qt::DashLine));
QLineF myLine = line();
myLine.translate(0, 4.0);
painter->drawLine(myLine);
myLine.translate(0,-8.0);
painter->drawLine(myLine);
}
}
//-- 更新:答案:
QRectF Arrow::boundingRect() const
{
qreal extra = (pen().width() + 20) / 2.0;
QLineF myVLine = line().normalVector();
return QRectF(line().p1(), QSizeF(line().p2().x() - line().p1().x(),
line().p2().y() - line().p1().y()))
.normalized()
.adjusted(-extra, -extra, extra, extra)
.united(QRectF(myVLine.p1(), QSizeF(myVLine.p2().x() - myVLine.p1().x(),
myVLine.p2().y() - myVLine.p1().y())));
}
之所以添加对 update() 的调用会导致 paint() 方法被一遍又一遍地调用,正如 Ari0nhh 在他的评论中所说的那样——具体来说,update() 方法会导致对 paint( ) 进行调度,下一次调用 paint() 调用 update(),等等。当然,该问题的解决方案是不要从 paint() 中调用 update()。
不过,您真正的问题是让您觉得需要首先调用 update() 方法的问题:您添加的行没有正确显示。这样做的原因是您添加的代码是 "cheating" - 具体来说,它试图在 Arrow 对象承诺它只会在内部绘制的区域之外绘制。因此,显示无法正确更新。
Arrow class 如何告诉 Qt 场景它将绘制的位置?通过覆盖 boundingRect() and shape() 虚拟方法。您会注意到 Arrow class 已经覆盖了这两个方法,以说明它在行的一端添加了 arrowHead;为了正确绘制第二条线,您还需要在返回的边界矩形和形状值中包含额外线的范围。
我已经更新了 diagramscene 示例以绘制窄线的法线。我将这一行添加到 Arrow::paint
函数中:
painter->drawLine(line());
painter->drawLine(line().normalVector()); // this line was added
//...
//scene()->update(); //add this line make this paint function reloop infinitely
没有 update
,正常的行没有显示,如果我移动项目,它可以显示但不正确。使用 update
,一切都正确绘制,但 paint
函数无限循环。我无法解释为什么,请帮助我!
//--编辑:
我添加原点 Arrow::paint
函数的代码:
void Arrow::paint(QPainter *painter, const QStyleOptionGraphicsItem *,
QWidget *)
{
if (myStartItem->collidesWithItem(myEndItem))
return;
QPen myPen = pen();
myPen.setColor(myColor);
qreal arrowSize = 20;
painter->setPen(myPen);
painter->setBrush(myColor);
QLineF centerLine(myStartItem->pos(), myEndItem->pos());
QPolygonF endPolygon = myEndItem->polygon();
QPointF p1 = endPolygon.first() + myEndItem->pos();
QPointF p2;
QPointF intersectPoint;
QLineF polyLine;
for (int i = 1; i < endPolygon.count(); ++i) {
p2 = endPolygon.at(i) + myEndItem->pos();
polyLine = QLineF(p1, p2);
QLineF::IntersectType intersectType =
polyLine.intersect(centerLine, &intersectPoint);
if (intersectType == QLineF::BoundedIntersection)
break;
p1 = p2;
}
setLine(QLineF(intersectPoint, myStartItem->pos()));
double angle = ::acos(line().dx() / line().length());
if (line().dy() >= 0)
angle = (Pi * 2) - angle;
QPointF arrowP1 = line().p1() + QPointF(sin(angle + Pi / 3) * arrowSize,
cos(angle + Pi / 3) * arrowSize);
QPointF arrowP2 = line().p1() + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
cos(angle + Pi - Pi / 3) * arrowSize);
arrowHead.clear();
arrowHead << line().p1() << arrowP1 << arrowP2;
painter->drawLine(line());
painter->drawPolygon(arrowHead);
if (isSelected()) {
painter->setPen(QPen(myColor, 1, Qt::DashLine));
QLineF myLine = line();
myLine.translate(0, 4.0);
painter->drawLine(myLine);
myLine.translate(0,-8.0);
painter->drawLine(myLine);
}
}
//-- 更新:答案:
QRectF Arrow::boundingRect() const
{
qreal extra = (pen().width() + 20) / 2.0;
QLineF myVLine = line().normalVector();
return QRectF(line().p1(), QSizeF(line().p2().x() - line().p1().x(),
line().p2().y() - line().p1().y()))
.normalized()
.adjusted(-extra, -extra, extra, extra)
.united(QRectF(myVLine.p1(), QSizeF(myVLine.p2().x() - myVLine.p1().x(),
myVLine.p2().y() - myVLine.p1().y())));
}
之所以添加对 update() 的调用会导致 paint() 方法被一遍又一遍地调用,正如 Ari0nhh 在他的评论中所说的那样——具体来说,update() 方法会导致对 paint( ) 进行调度,下一次调用 paint() 调用 update(),等等。当然,该问题的解决方案是不要从 paint() 中调用 update()。
不过,您真正的问题是让您觉得需要首先调用 update() 方法的问题:您添加的行没有正确显示。这样做的原因是您添加的代码是 "cheating" - 具体来说,它试图在 Arrow 对象承诺它只会在内部绘制的区域之外绘制。因此,显示无法正确更新。
Arrow class 如何告诉 Qt 场景它将绘制的位置?通过覆盖 boundingRect() and shape() 虚拟方法。您会注意到 Arrow class 已经覆盖了这两个方法,以说明它在行的一端添加了 arrowHead;为了正确绘制第二条线,您还需要在返回的边界矩形和形状值中包含额外线的范围。