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

The PreventStealing of mouseArea does not work properly in Flickable's(ListView) child item.

    XMLWordPrintable

Details

    • d92f1dfe05 (qt/qtdeclarative/dev) d92f1dfe05 (qt/tqtc-qtdeclarative/dev) 07e40cf567 (qt/qtdeclarative/6.3) 07e40cf567 (qt/tqtc-qtdeclarative/6.3) 1fe90c8d2e (qt/tqtc-qtdeclarative/5.15) 07e40cf567 (qt/tqtc-qtdeclarative/6.3.1)

    Description

      first_ok.webm second_ng.webm The PreventStealing of mouseArea does not work properly in Flickable's(ListView) child item.

      If you look at the test application, the configuration is as follows.

      • ListView
      • Custom ScrollBar
        The test application is using ScrollBar for ListView. The ScrollBar has been customized and added handles for quick scrolling.
        We set the preventStealing property to true on the handle of the ScrollBar.

      The screenshot of running the application is as follows.

      Test Application codes

      import QtQuick 2.15
      import QtQuick.Window 2.15
      import QtQuick.Controls 2.12
      
      Window {
          id: root
          width: 640
          height: 480
          visible: true
          title: qsTr("testApplication")
      
          property int dynamicModel: 100
      
          Rectangle {
              anchors.fill: parent
              Component {
                  id: contactDelegate
                  Rectangle {
      
                      border.color: "#81e889"
                      width: 640; height: 100
                      Column {
                          anchors.centerIn: parent
                          Text { text: '<b>Name:</b> ' + index }
                          Text { text: '<b>Number:</b> ' + index }
                      }
                  }
              }
      
              ListView {
                  id: list1
                  model: root.dynamicModel
                  delegate: contactDelegate
                  highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
                  focus: true
                  width: 640
                  height: 480
                  ScrollBar.vertical: ScrollBar {
                      id: control
                      size: 0.3
                      position: 0.2
                      active: true
                      orientation: Qt.Vertical
      
                      contentItem: Rectangle {
                          id: handleBar
                          implicitWidth: 6
                          implicitHeight: 100
                          radius: width / 2
                          color: control.pressed ? "#81e889" : "#c2f4c6"
      
                          Rectangle {
                              id: handle
                              height: 64
                              width: 64
                              anchors.right: handleBar.left
                              anchors.top: handleBar.top
                              visible: true
                              radius: height / 2
                              color: handleControl.pressed ? "#17a81a" : "#21be2b"
      
                              Text {
                                  anchors.centerIn: parent
                                  text: "Drag me"
                              }
      
                              MouseArea {
                                  id: handleControl
                                  anchors.fill: parent
      
      //////////////////////////////////////////////////////////////////
      // set preventStealing to true
      //////////////////////////////////////////////////////////////////
      
                                  preventStealing: true
                                  drag {
                                      target: control.contentItem
                                      minimumY: 0
                                      maximumY: control.height - handle.parent.height
                                      axis: Drag.YAxis
                                  }
      
                                  onPositionChanged: {
                                      if (pressed) {
                                          control.parent.contentY = control.contentItem.y
                                                  / control.height * control.parent.contentHeight
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          }
      }
      

      Steps to reproduce the issue

      1. Run test application
      2. Flicking ListView
      3. Click and Drag handle when ListView is moving (It's OK!) <---- first_ok.webm
      4. Flicking ListView again after ListView is stopping
      5. Do step 3 again. (It's a bug) <---- second_ng.webm

      • Clicking and dragging the handle does not work. In this situation, the ListView is receiving click and dragging events.
      • Expected results : We expect the handle to be clicked and the scrollbar to move through dragging.
      • After the movement of the ListView is completely stopped, you can click or drag the handle. But We want it to work(click and drag) when it moves.

      The Issue analysis

      1. The reason why it doesn't work properly on the second try
        The event is stolen because receiverKeepsGrab is returned as false in the filterMouseEvent function. keepMouseGrab is returned as false. See below the link.
        https://code.woboq.org/qt6/qtdeclarative/src/quick/items/qquickflickable.cpp.html#2582
      2. Why is keepMouseGrab set to false?
        keepMouseGrab is set to false in the mouseReleaseEvent function.
        https://code.woboq.org/qt5/qtdeclarative/src/quick/items/qquickmousearea.cpp.html#823
      3. Why it works normally on the first try
        In the first attempt, the mouseReleaseEvent function has not yet been executed. So, keepMouseGrab is set by setPreventStealing
        https://code.woboq.org/qt5/qtdeclarative/src/quick/items/qquickmousearea.cpp.html#572

      Our approach is as follows

      Fixed KeepMouseGrab not to be set to false when preventStealing is set.

      void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
      {
          Q_D(QQuickMouseArea);
          d->stealMouse = false;
          d->overThreshold = false;
          if (!d->enabled && !d->pressed) {
              QQuickItem::mouseReleaseEvent(event);
          } else {
              d->saveEvent(event);
              setPressed(event->button(), false, event->source());
              if (!d->pressed) {
                  // no other buttons are pressed
      #if QT_CONFIG(quick_draganddrop)
                  if (d->drag)
                      d->drag->setActive(false);
      #endif
                  // If we don't accept hover, we need to reset containsMouse.
                  if (!acceptHoverEvents())
                      setHovered(false);
                  QQuickWindow *w = window();
                  if (w && w->mouseGrabberItem() == this)
                      ungrabMouse();
      
      // this codes !!!!
                  if (!preventStealing())
                      setKeepMouseGrab(false);
              }
          }
          d->doubleClick = false;
      }
      

      original codes : https://code.woboq.org/qt5/qtdeclarative/src/quick/items/qquickmousearea.cpp.html#823

      Please review our approach and hope it gets added upstream.

      Attachments

        1. first_ok.webm
          458 kB
        2. nowindow.qml
          2 kB
        3. Screenshot from 2022-05-17 14-58-23.png
          Screenshot from 2022-05-17 14-58-23.png
          26 kB
        4. second_ng.webm
          527 kB
        5. tree.png
          tree.png
          54 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            srutledg Shawn Rutledge
            jonghokim Jongho Kim
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes