Details
-
Bug
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
5.15.0
-
None
Description
The drawing code sets `paintedViewBoundingRects` to an item's bounding rectangle when the item is drawn. The processing of dirty items rely on `paintedViewBoundingRects` to determine their old positions. However, it is possible for the drawing code to be called after an item is moved and before the dirty item is processed. When this happens, the old position is not properly repainted, leading to the appearance of more items than expected. Skipping the drawing in such situation should be okay, as it'll be repainted immediately after the dirty items is processed.
Sample Program that shows this behaviour
#include <QApplication> #include <QChartView> #include <QGraphicsRectItem> #include <QGraphicsScene> #include <QGraphicsView> #include <QLineSeries> #include <QMdiArea> #include <QMdiSubWindow> #include <thread> // Steps to reproduce: // 1. Start the app. // 2. Drag to select a rectangle in the larger subwindow. // 3. Switch to another window (not this app). // 4. Drag again to select another rectangle in the larger subwindow. // // Expected Behavior: The old rectangle disappears. // // Actual Behavior: The old rectangle is still there. int main(int argc, char **argv) { QApplication app(argc, argv); QMdiArea *parent = new QMdiArea(); QGraphicsScene *scene = new QGraphicsScene(); QGraphicsView *view = new QGraphicsView(scene); QGraphicsRectItem *item = new QGraphicsRectItem(); QtCharts::QChartView *chart = new QtCharts::QChartView(); scene->addItem(new QGraphicsRectItem(0, 0, 900, 900)); scene->addItem(item); view->setDragMode(QGraphicsView::RubberBandDrag); QObject::connect(parent, &QMdiArea::subWindowActivated, chart, [chart] { using namespace std::chrono_literals; std::this_thread::sleep_for(400ms); chart->chart()->removeAllSeries(); chart->chart()->addSeries(new QtCharts::QLineSeries()); }); QObject::connect(view, &QGraphicsView::rubberBandChanged, [view, item](QRect rect) { if (!rect.isNull()) item->setRect({view->mapToScene(rect.topLeft()), view->mapToScene(rect.bottomRight())}); }); parent->addSubWindow(view); parent->addSubWindow(chart); parent->show(); return app.exec(); }
A possible fix:
--- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -4735,6 +4735,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * { Q_ASSERT(item); + if (processDirtyItemsEmitted) + return; + if (!item->d_ptr->visible) return;