Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-84890

Skip drawing if dirty items have not been processed

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 5.15.0
    • Widgets: GraphicsView
    • 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;
       
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            bibr Andreas Aardal Hanssen
            cwgthornton Chris Thornton
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes