Как я могу использовать MouseArea на ShapePath в QML?

В настоящее время я изучаю, как использовать фигуры в QML для рисования более сложных компонентов. Я пытаюсь создать кнопку, которая выглядит так:

Моя пользовательская кнопка

Когда я пытаюсь применить MouseArea к компоненту Shape, MouseArea, похоже, не может улавливать события в Shape. Вот мой код:

import QtQuick 2.13
import QtQuick.Shapes 1.13

Item
{
    Shape
    {
        id: myShape

        ShapePath {
            id: myButton

            strokeWidth:3.114000082015991
            strokeColor: "#000"
            miterLimit:7
            fillColor: "#ccc"
            capStyle:ShapePath.RoundCap
            PathSvg {
                path: "M392.4,205.9a132.34,132.34,0,0,1,31.7,49.2H575.6a289.67,289.67,0,0,0-12.9-49.2Z"
            }
        }
    }

    MouseArea
    {
        id: myMouseArea
        anchors.fill: myShape
        enabled: true
        hoverEnabled: true

        onEntered: myButton.fillColor = "yellow"
        onExited: myButton.fillColor = "green"
    }
}

Итак, мой вопрос: можно ли вообще сделать Shape / ShapePath интерактивным? И если да, то как это сделать?

1 ответ

Аналогичный вопрос был задан здесь, но они просто хотели простой круг. Тем не менее, непринятый ответ описывает замаскированную область мыши, которая может быть вам полезна. Он использует изображение для определения замаскированной области. Первоначально он взят из примера программы Qt.

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");
Другие вопросы по тегам