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

Unexpected visibleChanged signals on QQuickItem destruction

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P1: Critical
    • 6.5.0, 5.15
    • 5.15.7
    • Quick: Other
    • None
    • All
    • d1b9a4cac (dev)

    Description

      Unexpected visibleChanged and parentChanged signals on destruction of item based on QQuickItem.

      When the item was invisible before deleting, this item and its children items emit visibleChanged signals inside ~QQuickItem  (related to the item )

      Which is not expected and can lead to unexpected behavior (see https://bugreports.qt.io/browse/QTBUG-107850), also it can trigger unnecessary flickering or actions on the scene and impact performance (if some logic is connected to that signals).

      Isolated example:

      class ItemForTesting: public QQuickItem {
          Q_OBJECT
      public:
          explicit ItemForTesting(QQuickItem *parent = nullptr);
          ~ItemForTesting() override = default;
          void doSomthing();
      };
      
      ItemForTesting::ItemForTesting(QQuickItem *parent)
          : QQuickItem(parent)
      {}
      void ItemForTesting::doSomthing()
      {
          // do something
      }
      //// Test case
      {
      ....
          QPointer<ItemForTesting> mainItem = new ItemForTesting(m_rootItem);
          mainItem->setVisible(false); // in this case visibleChanged will be emitted for item and for child items
          mainItem->connect(mainItem.data(), &QQuickItem::parentChanged, mainItem.data(), [=]() {
              qCritical() << "ParentChanged for mainItem. Check pointer" << QQmlData::wasDeleted(mainItem.data()) << mainItem.isNull();        
          });
          mainItem->connect(mainItem.data(), &QQuickItem::visibleChanged, mainItem.data(), [=]() {
              qCritical() << "visibleChanged for mainItem to" << mainItem->isVisible() << "Check pointer" << QQmlData::wasDeleted(mainItem.data()) << mainItem.isNull();
              mainItem->doSomething();
         });    
      
          QQuickItem *childItem = new QQuickItem(mainItem);
          childItem->connect(childItem, &QQuickItem::visibleChanged, childItem, [=]() {
              qCritical() << "visibleChanged for childItem to" << childItem->isVisible();
              // do something
          });
      
          QSignalSpy spyDestroy(mainItem, &QObject::destroyed);
          mainItem->deleteLater();
          spyDestroy.wait();
          EXPECT_EQ(spyDestroy.count(), 1);
      }
      

       Attached example qtbug107850_extended.ziphas 3 options: 

      1. to change visible for mainItem created in QML 
      2. to call deleting of mainItem created in QML  -> in case if mainItem had visible = false (default case in this example) before the deletion it crashes.
      3. to call Cpp crash case (like mentioned in ticket https://bugreports.qt.io/browse/QTBUG-107850 description)

      pressing on 2 -> crash

      pressing on 3 -> crash

      pressing on 1, then 2 -> no crash

      Attachments

        Issue Links

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

          Activity

            People

              qt.team.quick.subscriptions Qt Quick and Widgets Team
              mjnikoff Ivan Maiornykov
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes