Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[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.


Log in to reply