[Solved] GraphicsView: Fixed line width regardless of transformations?
-
I need to draw a line that is always exactly n pixels wide, regardless of any transformations applied.
Cosmetic pens are not supported in GraphicsView (as can be seen in the comments to "QTBUG-5294":https://bugreports.qt-project.org/browse/QTBUG-5294 )
How else to do this? I could calculate the necessary width once I get the transformation in the paint() method, but that would mean changing the boundingRect. Not something I'd like to do while painting.
-
This is how I do it now:
- I calculate my effective non-cosmetic pen from the given pen plus the scene transform
@ const qreal effectiveSourcePenWidth = qMax(sourcePen.widthF(),static_cast<qreal>(1.0));
if ( ! sourcePen.isCosmetic()) { QPen finalPen = sourcePen; finalPen.setWidthF(effectiveSourcePenWidth); return sourcePen; } QPointF scenePos = mapToScene(QPointF()); const qreal halfPenWidth = effectiveSourcePenWidth / 2.0; QPointF edgeRight = mapFromScene(scenePos.x() + halfPenWidth,scenePos.y()); QPen finalPen = sourcePen; finalPen.setCosmetic(false); finalPen.setWidthF(qAbs(edgeRight.x())); return finalPen;@
- Based on that pen, I calculate my boundingRect
@ if (m_eOrientation == Qt::Vertical)
{
m_CachedBoundingRect.setLeft(-effectiveHalfWidth);
m_CachedBoundingRect.setRight(effectiveHalfWidth);
m_CachedBoundingRect.setTop(-1000000.0);
m_CachedBoundingRect.setBottom(1000000.0);
}
else
{
m_CachedBoundingRect.setTop(-effectiveHalfWidth);
m_CachedBoundingRect.setBottom(effectiveHalfWidth);
m_CachedBoundingRect.setLeft(-1000000.0);
m_CachedBoundingRect.setRight(1000000.0);
}m_CachedBoundingRectSceneTransform = sceneTransform(); m_bCachedBoundingRectValid = true;@
- I remember the sceneTransform I used, because whenever it changes, I need to recalculate pen and boundingRect. Now this is the tricky part, because I simply can't know about all cases where the sceneTransform changes. One thing I can recognize is if the transform of my own item changes:
@ if (change == QGraphicsItem::ItemTransformHasChanged)
{
invalidateBoundingRectIfTransformChanged();
}@- Otherwise I assume that any change to the sceneTransform must be followed by a paint(), so within paint() I do
@ invalidateBoundingRectIfTransformChanged();
updateBoundingRectAndPen();
@
Of course, this might trigger another paint. But after that, the sceneTransform should be stable.