QGraphicsLineItem::paint() artifacts

2019-07-15 13:25发布

问题:

I have my own class which inherits from QGraphicsLineItem and overrides the paint() method to draw a thick line with an arrow head:

void MyGraphicsItem::paint( QPainter* aPainter,
                            const QStyleOptionGraphicsItem* aOption,
                            QWidget* aWidget /*= nullptr*/ )
{
    Q_UNUSED( aOption );
    Q_UNUSED( aWidget );

    QLineF cLine = line();

    aPainter->setPen( QPen( Qt::black, 6, Qt::SolidLine ) );
    aPainter->drawLine( cLine );

    qreal lineAngle = cLine.angle();

    const qreal radius = 2.0;
    QLineF head1 = cLine;
    head1.setAngle(lineAngle+32);
    head1.setLength( 12 );
    QLineF head2 = cLine;
    head2.setAngle(lineAngle-32);
    head2.setLength( 12 );

    aPainter->drawLine( head1 );
    aPainter->drawLine( head2 );

    aPainter->setPen( QPen( Qt::yellow, 2, Qt::SolidLine ) );

    aPainter->drawLine( cLine );

    aPainter->drawLine( head1 );
    aPainter->drawLine( head2 );
}

This seems to cause rendering artifacts when I draw the item around the scene. From what I can tell its because I've set a thickness on the QPen which makes me believe that I must somehow be drawing outside of the items rectangle?

What is causing my rendering issue and how can I solve it?

Notice the background not being redrawn in the image - this happens to any other objects in the scene that the arrow is dragged over too.

Edit: I think this is actually my problem:

Subclassing QGraphicsView and setting drawBackground

Edit again: Seems drawing the background is the problem, but using full view port updates kills performance so I came up with this which seems to keep the CPU usage at 3% rather than pegging out one core to 100% usage.

// This code lives in the QGraphicsScene constructor, doesn't have to be there though since QGraphicsScene::setBackgroundBrush is public.
int gridSizeX = 25;
int gridSizeY = 20;
QImage singleGrid( gridSizeX, gridSizeY, QImage::Format_RGB32 );
singleGrid.fill( Qt::white );
{
    QPainter painter( &singleGrid );

    // Lighter background
    painter.setPen( QPen( QColor( 240, 240, 240 ) ));

    qreal midx = gridSizeX / 2;
    qreal midy = gridSizeY / 2;
    painter.drawLine( 0, midy, gridSizeX, midy );
    painter.drawLine( midx, 0, midx, gridSizeY );

    // Darker foregound
    painter.setPen( QPen( QColor( 180, 180, 180 ) ));
    painter.drawRect( 0, 0, gridSizeX, gridSizeY );

    painter.end();
}
QBrush brushBackground( singleGrid );
setBackgroundBrush( brushBackground );

The scene then repeats this brush everywhere resulting in the same grid background effect, it even works as expected when zoomed/scaled. :).

回答1:

When you override the paint() function you also need to override QGraphicsItem::boundingRect() in your class to define the outer bounds of your customized graphics item. If you draw outside the bounds you will end up with rendering artifacts. Right now you depend on the QGraphicsLineItem's implementation of boundingRect(), which of course has no knowledge of your implementation of the paint() function. See http://doc.qt.digia.com/main-snapshot/qgraphicsitem.html#boundingRect for details.