[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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.