【问题标题】:How to create a round mouse area in QML如何在 QML 中创建圆形鼠标区域
【发布时间】:2016-07-02 20:09:43
【问题描述】:

我有一个基本的自定义按钮,使用带有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";
              }
          }

      }
  }

【问题讨论】:

  • 如果将clip: true 设置为button 会起作用吗?只是现在无法测试
  • @folibis:很遗憾没有。我已将clip: true 添加到我的按钮中,但问题仍然没有改变。谢谢。

标签: qt user-interface qml qtquick2


【解决方案1】:

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
        }
    }
}

【讨论】:

【解决方案2】:

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

按原样发布代码:

ma​​skedmousearea.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&lt;MaskedMouseArea&gt;("Example", 1, 0, "MaskedMouseArea");

【讨论】:

    【解决方案3】:

    感谢@Mitch。有时这样的鼠标区域在离开后说它包含鼠标,所以我添加了“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;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-19
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      • 1970-01-01
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多