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

Calling grabToImage() without qualifying the call with an id causes the call to happen on the wrong item

    XMLWordPrintable

Details

    Description

      In the attached (simplified) application, the goal is to take a screenshot of each individual DelegateContainer instance. In DelegateContainer.qml, qualifying the call to grabToImage() with the id of the root item container works, but an unqualified call does not. I would expect that an unqualified call in that context should result in the root item's function being called, but it doesn't.

      With the following patch:

      diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
      index c3f8d4f..703de19 100644
      --- a/src/quick/items/qquickitemgrabresult.cpp
      +++ b/src/quick/items/qquickitemgrabresult.cpp
      @@ -376,6 +376,7 @@ QSharedPointer<QQuickItemGrabResult> QQuickItem::grabToImage(const QSize &target
        */
       bool QQuickItem::grabToImage(const QJSValue &callback, const QSize &targetSize)
       {
      +    qDebug() << this;
           QQmlEngine *engine = qmlEngine(this);
           if (!engine) {
               qmlWarning(this) << "grabToImage: item has no QML engine";
      

      I get this output when running the application with the incorrect behaviour:

      QML debugging is enabled. Only use this in a safe environment.
      QQuickRow_QML_2(0x19ad7b0, parent=0x1c85aa0, geometry=0,0 190x40)
      QQuickRow_QML_2(0x19ad7b0, parent=0x1c85aa0, geometry=0,0 190x40)
      QQuickRow_QML_2(0x19ad7b0, parent=0x1c85aa0, geometry=0,0 190x40)
      QQuickRow_QML_2(0x19ad7b0, parent=0x1c85aa0, geometry=0,0 190x40)
      qml: OK: test1.png
      qml: OK: test2.png
      qml: OK: test3.png
      qml: OK: test4.png
      

      And this output with the correct behaviour:

      DelegateContainer_QMLTYPE_0(0x1b7e770, parent=0x1a4fe80, geometry=0,0 40x40)
      DelegateContainer_QMLTYPE_0(0x1b80d40, parent=0x1a4fe80, geometry=50,0 40x40)
      DelegateContainer_QMLTYPE_0(0x1b82780, parent=0x1a4fe80, geometry=100,0 40x40)
      DelegateContainer_QMLTYPE_0(0x1b840e0, parent=0x1a4fe80, geometry=150,0 40x40)
      qml: OK: test1.png
      qml: OK: test2.png
      qml: OK: test3.png
      qml: OK: test4.png
      

      The relevant files from the project for convenience:

      main.qml
      import QtQuick 2.7
      import QtQuick.Layouts 1.3
      import QtQuick.Window 2.3
      import QtQuick.Controls 2.0
      
      ApplicationWindow {
          id: window
          width: 800
          height: 640
          visible: true
          title: "repeater-loader-grabToImage"
      
          Component.onCompleted: {
              x = Screen.width / 2 - width / 2
              y = Screen.height / 2 - height / 2
      
              takeScreenshots()
          }
      
          Shortcut {
              sequence: "Ctrl+Q"
              onActivated: Qt.quit()
          }
      
          function takeScreenshots() {
              var repeater = stateRepeater.itemAt(0).nestedRepeater
              for (var j = 0; j < repeater.count; ++j) {
                  repeater.itemAt(j).takeScreenshot()
              }
          }
      
          Repeater {
              id: stateRepeater
              model: 1
      
              Row {
                  id: dprRow
                  spacing: 10
      
                  property alias nestedRepeater: dprRepeater
      
                  Repeater {
                      id: dprRepeater
                      model: 4
      
                      DelegateContainer {
                          id: delegateContainer
                      }
                  }
              }
          }
      }
      
      DelegateContainer.qml
      import QtQuick 2.0
      
      Item {
          id: container
          x: index * (width + 10)
          width: delegate.width
          height: delegate.height
      
          property int dpr: index + 1
      
          function takeScreenshot() {
              // Incorrect - takes screenshot of all items
              grabToImage(function(result) {
              // Correct - only takes screenshot of container
      //        container.grabToImage(function(result) {
                  var fileName = "test" + dpr + ".png"
                  var res = result.saveToFile(fileName)
                  console.log(res ? "OK:" : "### NOK:", fileName)
              })
          }
      
          Loader {
              id: delegate
              sourceComponent: Rectangle {
                  width: 40
                  height: 40
                  color: "blue"
              }
          }
      }
      

      Attachments

        1. qtbug61317.tar.gz
          2 kB
        2. test-correct.png
          test-correct.png
          0.1 kB
        3. test-incorrect.png
          test-incorrect.png
          0.2 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qtqmlteam Qt Qml Team User
            mitch_curtis Mitch Curtis
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes