如何在QML中创建圆形鼠标区域

时间:2016-07-02 20:09:43

标签: qt user-interface qml qtquick2

我使用带radius: width/2的矩形的基本自定义按钮。现在我在我的按钮上添加MouseArea。但是MouseArea的形状是平方的。这意味着当我在圆形按钮外略微点击时,即在圆形按钮周围的假想方块的角落中,也会触发点击事件。我能以某种方式制作MouseArea轮吗?

  import QtQuick 2.7
  import QtQuick.Window 2.2

  Window {
      visible: true
      width: 640
      height: 480
      title: qsTr("TestApp")

      Rectangle {
          id: background
          anchors.fill: parent
          color: Qt.rgba(0.25, 0.25, 0.25, 1);


          Rectangle {
              id: button
              width: 64
              height: 64
              color: "transparent"
              anchors.centerIn: parent
              radius: 32
              border.width: 4
              border.color: "grey"

              MouseArea {
                  anchors.fill: parent
                  onPressed: button.color = "red";
                  onReleased: button.color = "transparent";
              }
          }

      }
  }

3 个答案:

答案 0 :(得分:15)

PieMenu窃取代码,此处为RoundMouseArea.qml

import QtQuick 2.0

Item {
    id: roundMouseArea

    property alias mouseX: mouseArea.mouseX
    property alias mouseY: mouseArea.mouseY

    property bool containsMouse: {
        var x1 = width / 2;
        var y1 = height / 2;
        var x2 = mouseX;
        var y2 = mouseY;
        var distanceFromCenter = Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
        var radiusSquared = Math.pow(Math.min(width, height) / 2, 2);
        var isWithinOurRadius = distanceFromCenter < radiusSquared;
        return isWithinOurRadius;
    }

    readonly property bool pressed: containsMouse && mouseArea.pressed

    signal clicked

    MouseArea {
        id: mouseArea
        anchors.fill: parent
        hoverEnabled: true
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onClicked: if (roundMouseArea.containsMouse) roundMouseArea.clicked()
    }
}

你可以像这样使用它:

import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    width: 640
    height: 480
    visible: true

    RoundMouseArea {
        id: roundMouseArea
        width: 100
        height: 100
        anchors.centerIn: parent

        onClicked: print("clicked")

        // Show the boundary of the area and whether or not it's hovered.
        Rectangle {
            color: roundMouseArea.pressed ? "red" : (roundMouseArea.containsMouse ? "darkorange" : "transparent")
            border.color: "darkorange"
            radius: width / 2
            anchors.fill: parent
        }
    }
}

round mouse area gif

答案 1 :(得分:6)

另一种选择是在example中描述的C ++ / QML方式。此示例提供了一种使用任何形状的蒙版的方法。它可以根据您的需求进行定制。

按原样发布代码:

<强> maskedmousearea.cpp

MaskedMouseArea::MaskedMouseArea(QQuickItem *parent)
    : QQuickItem(parent),
      m_pressed(false),
      m_alphaThreshold(0.0),
      m_containsMouse(false)
{
    setAcceptHoverEvents(true);
    setAcceptedMouseButtons(Qt::LeftButton);
}

void MaskedMouseArea::setPressed(bool pressed)
{
    if (m_pressed != pressed) {
    m_pressed = pressed;
    emit pressedChanged();
    }
}

void MaskedMouseArea::setContainsMouse(bool containsMouse)
{
    if (m_containsMouse != containsMouse) {
    m_containsMouse = containsMouse;
    emit containsMouseChanged();
    }
}

void MaskedMouseArea::setMaskSource(const QUrl &source)
{
    if (m_maskSource != source) {
    m_maskSource = source;
    m_maskImage = QImage(QQmlFile::urlToLocalFileOrQrc(source));
    emit maskSourceChanged();
    }
}

void MaskedMouseArea::setAlphaThreshold(qreal threshold)
{
    if (m_alphaThreshold != threshold) {
    m_alphaThreshold = threshold;
    emit alphaThresholdChanged();
    }
}

bool MaskedMouseArea::contains(const QPointF &point) const
{
    if (!QQuickItem::contains(point) || m_maskImage.isNull())
    return false;

    QPoint p = point.toPoint();

    if (p.x() < 0 || p.x() >= m_maskImage.width() ||
    p.y() < 0 || p.y() >= m_maskImage.height())
    return false;

    qreal r = qBound<int>(0, m_alphaThreshold * 255, 255);
    return qAlpha(m_maskImage.pixel(p)) > r;
}

void MaskedMouseArea::mousePressEvent(QMouseEvent *event)
{
    setPressed(true);
    m_pressPoint = event->pos();
    emit pressed();
}

void MaskedMouseArea::mouseReleaseEvent(QMouseEvent *event)
{
    setPressed(false);
    emit released();

    const int threshold = qApp->styleHints()->startDragDistance();
    const bool isClick = (threshold >= qAbs(event->x() - m_pressPoint.x()) &&
                      threshold >= qAbs(event->y() - m_pressPoint.y()));

    if (isClick)
    emit clicked();
}

void MaskedMouseArea::mouseUngrabEvent()
{
    setPressed(false);
    emit canceled();
}

void MaskedMouseArea::hoverEnterEvent(QHoverEvent *event)
{
    Q_UNUSED(event);
    setContainsMouse(true);
}

void MaskedMouseArea::hoverLeaveEvent(QHoverEvent *event)
{
    Q_UNUSED(event);
    setContainsMouse(false);
}

QML中的用法:

import Example 1.0
MaskedMouseArea {
    id: moonArea
    anchors.fill: parent
    alphaThreshold: 0.4
    maskSource: moon.source
}

注册自定义项目:

qmlRegisterType<MaskedMouseArea>("Example", 1, 0, "MaskedMouseArea");

答案 2 :(得分:0)

感谢@Mitch。有时,此类mousearea表示离开后它包含鼠标,因此我添加了“ if(!mouseArea.containsMouse)return false;”。到“ containsMouse”属性的开头:

property bool containsMouse: {
    if(!mouseArea.containsMouse)
        return false;

    var x1 = width / 2;
    var y1 = height / 2;
    var x2 = mouseX;
    var y2 = mouseY;
    var distanceFromCenter = Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
    var radiusSquared = Math.pow(Math.min(width, height) / 2, 2);
    var isWithinOurRadius = distanceFromCenter < radiusSquared;
    return isWithinOurRadius;
}