当MouseArea被另一个MouseArea覆盖时,如何在qml中更改光标形状

时间:2015-01-07 13:55:37

标签: qt cursor qml qt5 qtquick2

有两个MouseAreas有两个不同的职责,一个(绿色)部分位于另一个(红色)之上。我想在 red MA悬停时改变光标的形状(即使它在绿色 MA下)并且我希望绿色 MA到对压力做出反应而没有别的。

两个MA可能位于不同的文件中,所以我不想在它们之间建立明确的依赖关系,就像在 red 中的containsMouse更改时在绿色中设置正确的cursorShape一样。有没有办法阻止绿色 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!")
    }
}

4 个答案:

答案 0 :(得分:3)

MouseArea属性或任何其他现成解决方案无法执行此操作。 MouseArea始终设置一些游标形状 - 如果未指定cursorShape属性,则使用默认值(Qt.ArrowCursor) 您当然可以使用mapToItem() / mapFromItem()来解决此问题(正如Mitch建议的那样)。但也有其他可能性:

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

答案 1 :(得分: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(),这很浪费。

答案 2 :(得分:1)

您可以像下面一样创建自己的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
}
}

答案 3 :(得分:0)

您可以在绿色鼠标区域将cursorShape设置为undefined,以防止其更改光标。