【问题标题】:How to change cursor shape in qml when MouseArea is covered with another MouseArea当 MouseArea 被另一个 MouseArea 覆盖时如何更改 qml 中的光标形状
【发布时间】:2015-01-07 13:55:36
【问题描述】:

有两个具有两种不同职责的 MouseArea,一个(green)部分位于另一个(red)之上。我想在 red MA 悬停时更改光标的形状(即使它在 green MA 下面),我想要 green MA对新闻做出反应,仅此而已。

两个 MA 可能位于不同的文件中,因此我不想在它们之间建立显式依赖关系,例如每当 red 中的 containsMouse 发生变化时在 green 中设置正确的 cursorShape。有没有办法防止 green MouseArea 处理光标形状?

import QtQuick 2.4
import QtQuick.Window 2.2

Window {
    visible: true
    width: 200
    height: 200

    Rectangle { anchors.fill: parent; color: "yellow"; }

    MouseArea {
        width: 150
        height: 150
        hoverEnabled: true
        cursorShape: Qt.OpenHandCursor
        Rectangle { anchors.fill: parent; color: "red"; }
        onPositionChanged: console.log("position", mouse.x, mouse.y)
        onContainsMouseChanged: console.log("containsMouse", containsMouse)
    }
    MouseArea {
        x: 50
        y: 50
        width: 150
        height: 150
        hoverEnabled: false
        Rectangle { anchors.fill: parent; color: "green"; }
        onPressed: console.log("Ahoj!")
    }
}

【问题讨论】:

    标签: qt qml qt5 qtquick2 mouse-cursor


    【解决方案1】:

    MouseArea 属性或任何其他现成的解决方案都无法做到这一点。 MouseArea 总是设置一些光标形状——如果没有指定 cursorShape 属性而不是使用默认值 (Qt.ArrowCursor) 您当然可以使用mapToItem()/mapFromItem() 来解决此问题(如 Mitch 建议的那样)。但也有其他可能性:

    您可以将覆盖鼠标区域的visible临时更改为false
    或者,如果两个MouseArea 都是兄弟姐妹,您可以对z 属性进行操作以获得适合您需要的对象的特定层次结构。

    【讨论】:

      【解决方案2】:

      我认为这不可能,至少在 QML 中是不可能的。绿色鼠标区域没有将 hoverEnabled 设置为 true,因此您不会收到任何位置更改。

      解决此问题的更好方法是使用更大的MouseArea 填充您感兴趣的最大区域,并使用mapToItem() / mapFromItem() 将全局鼠标位置转换为局部坐标以进行比较每个鼠标区域:

      import QtQuick 2.4
      import QtQuick.Window 2.2
      
      Window {
          id: window
          visible: true
          width: 200
          height: 200
      
          Rectangle {
              anchors.fill: parent
              color: "yellow"
          }
      
          MouseArea {
              id: globalMouseArea
              anchors.fill: parent
              hoverEnabled: true
          }
      
          MouseArea {
              id: redMouseArea
              width: 150
              height: 150
              cursorShape: containsMouse ? Qt.OpenHandCursor : Qt.ArrowCursor
              enabled: false
      
              readonly property bool containsMouse: {
                  var relativePos = mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY);
                  return contains(Qt.point(relativePos.x, relativePos.y));
              }
      
              Rectangle {
                  anchors.fill: parent
                  color: "red"
              }
          }
          Rectangle {
              id: greenMouseArea
              x: 50
              y: 50
              width: 150
              height: 150
              color: containsMouse ? "brown" : "green"
      
              readonly property bool containsMouse: {
                  var relativePos = mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY);
                  return contains(Qt.point(relativePos.x, relativePos.y));
              }
      
              Connections {
                  target: globalMouseArea
                  onPressed: if (greenMouseArea.containsMouse) greenMouseArea.pressed()
              }
      
              signal pressed
              onPressed: console.log("Ahoj!")
          }
      }
      

      如您所见,绿色鼠标区域不再是鼠标区域。似乎堆叠顺序高于另一个鼠标区域的鼠标区域会阻止较低鼠标区域的位置更改,即使较高的鼠标区域没有将hoverEnabled 设置为 true。

      另外,请注意,如果不是QTBUG-41452,它会稍微简洁一些。即,您可以缩短 containsMouse 表达式:

      readonly property bool containsMouse: contains(mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY))
      

      如果您担心这里的代码重复,那么您可以改用函数:

      import QtQuick 2.4
      import QtQuick.Window 2.2
      
      Window {
          id: window
          visible: true
          width: 200
          height: 200
      
          Rectangle {
              anchors.fill: parent
              color: "yellow"
          }
      
          MouseArea {
              id: globalMouseArea
              anchors.fill: parent
              hoverEnabled: true
          }
      
          function containsMouse(item) {
              var relativePos = globalMouseArea.mapToItem(item, globalMouseArea.mouseX, globalMouseArea.mouseY);
              return item.contains(Qt.point(relativePos.x, relativePos.y));
          }
      
          MouseArea {
              id: redMouseArea
              width: 150
              height: 150
              cursorShape: window.containsMouse(redMouseArea) ? Qt.OpenHandCursor : Qt.ArrowCursor
              enabled: false
      
              Rectangle {
                  anchors.fill: parent
                  color: "red"
              }
          }
          Rectangle {
              id: greenMouseArea
              x: 50
              y: 50
              width: 150
              height: 150
              color: containsMouse ? "brown" : "green"
      
              readonly property bool containsMouse: window.containsMouse(greenMouseArea)
      
              Connections {
                  target: globalMouseArea
                  onPressed: if (greenMouseArea.containsMouse) greenMouseArea.pressed()
              }
      
              signal pressed
              onPressed: console.log("Ahoj!")
          }
      }
      

      我为绿色鼠标区域使用了一个属性,否则它会调用containsMouse() 两次,这很浪费。

      【讨论】:

      • 这行得通,但也迫使用户再次实现类似 MouseArea 的组件。项目堆叠信息也会丢失,因为没有保证另一个类似于绿色的 MA 不会覆盖它,并且在这种情况下它应该得到新闻事件。
      【解决方案3】:

      您可以创建自己的 CusorShapeArea,如下所示。它将帮助您更轻松地控制光标形状。

      首先创建C++类CursorShapeArea:

      cursorshapearea.h
      
      #ifndef CURSORSHAPEAREA_H
      #define CURSORSHAPEAREA_H
      
      #include <QDeclarativeItem>
      
      class QsltCursorShapeArea : public QDeclarativeItem
      {
        Q_OBJECT
      
        Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
      
      public:
      
        explicit QsltCursorShapeArea(QDeclarativeItem *parent = 0);
      
        Qt::CursorShape cursorShape() const;
        Q_INVOKABLE void setCursorShape(Qt::CursorShape cursorShape);
      
      private:
        int m_currentShape;
      
      signals:
        void cursorShapeChanged();
      };
      
      #endif // CURSORSHAPEAREA_H
      

      cursorshapearea.cpp

      #include "cursorshapearea.h"
      
      QsltCursorShapeArea::QsltCursorShapeArea(QDeclarativeItem *parent) :
        QDeclarativeItem(parent),
        m_currentShape(-1)
      {
      }
      
      Qt::CursorShape QsltCursorShapeArea::cursorShape() const
      {
        return cursor().shape();
      }
      
      void QsltCursorShapeArea::setCursorShape(Qt::CursorShape cursorShape)
      {
        if (m_currentShape == (int) cursorShape)
          return;
      
        setCursor(cursorShape);
        emit cursorShapeChanged();
      
        m_currentShape = cursorShape;
      }
      

      然后注册这个qml类型:

      #include <QtDeclarative>
      #include "cursorshapearea.h"
      
      int main(int argc, char **argv)
      {
      ...
        qmlRegisterType<CursorShapeArea>("MyTools", 1, 0, "CursorShapeArea");
      ...
      }
      

      然后在 QML 中使用它,在你的问题中:

      import QtQuick 1.1
      import CursorShapeArea 0.1
      
      Window {
      visible: true
      width: 200
      height: 200
      
      Rectangle { anchors.fill: parent; color: "yellow"; }
      
      MouseArea {
          id: redArea
          width: 150
          height: 150
          hoverEnabled: true
          //cursorShape: Qt.OpenHandCursor
          Rectangle { anchors.fill: parent; color: "red"; }
          onPositionChanged: console.log("position", mouse.x, mouse.y)
          onContainsMouseChanged: console.log("containsMouse", containsMouse)
      }
      MouseArea {
          x: 50
          y: 50
          width: 150
          height: 150
          hoverEnabled: false
          Rectangle { anchors.fill: parent; color: "green"; }
          onPressed: console.log("Ahoj!")
      } 
      CursorShapeArea {
          anchors.fill: redArea
          cursorShape: Qt.OpenHandCursor
      }
      }
      

      【讨论】:

        【解决方案4】:

        您可以将绿色鼠标区域中的cursorShape设置为undefined,这样可以防止它改变光标。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多