旋转QQuickItem中的鼠标事件处理

时间:2018-07-22 13:06:15

标签: qt qml qtquick2

我有一个简单的QQuickPaintedItem,它在给定位置绘制了具有给定扇区大小和方位角的圆形扇区。这是标题:

#pragma once

#include <QtQuick/QQuickPaintedItem>
#include <QColor>
#include <QPainter>


class MarkerItem : public QQuickPaintedItem
{
    Q_OBJECT
    Q_PROPERTY(QColor color READ color WRITE setColor)
    Q_PROPERTY(int azimuth READ azimuth WRITE setAzimuth)
    Q_PROPERTY(int sectorSize READ sectorSize WRITE setSectorSize)
    Q_PROPERTY(QPointF anchorPoint READ anchorPoint WRITE setAnchorPoint NOTIFY anchorChanged)
    Q_PROPERTY(bool selected READ selected WRITE setSelected NOTIFY selectedChanged)


public:
    MarkerItem(QQuickItem *parent = nullptr);

    QColor color() const;
    void setColor(const QColor &color);

    int azimuth() const;
    void setAzimuth(int angle);

    int sectorSize() const;
    void setSectorSize(int span);

    QPointF anchorPoint() const;
    void setAnchorPoint(const QPointF &value);

    bool selected();
    void setSelected(const bool bVal);

public slots:
    void mousePressEvent(QMouseEvent *event) override;

protected:
    void paint(QPainter *painter) override;

private:
    QColor mcColor;
    int miAzimuth;
    int miSectorSize;
    QPointF mcAnchorPoint;
    bool mbSelected;
    const int miSectorRadius = 40;

signals:
    void anchorChanged(QPointF);
    void selectedChanged(bool);
};

和实现:

#include "markeritem.h"
#include <QSGGeometryNode>
#include <QtMath>

MarkerItem::MarkerItem(QQuickItem *parent)
    : QQuickPaintedItem(parent)
{
    setAcceptedMouseButtons(Qt::LeftButton);
    qDebug() << "MarkerItem";
    setWidth(qTan(qDegreesToRadians(30.0f))*40);
    setHeight(40);
    mbSelected = false;
}


void MarkerItem::paint(QPainter *painter)
{
    qDebug() << " > MarkerItem paint, azimuth  " << miAzimuth;
    QPen pen;
    QBrush brush(mcColor);
    if (mbSelected)
    {
        pen.setColor(Qt::magenta);
        pen.setWidth(2);
        brush.setColor(mcColor.lighter(150));
    }
    else
    {
        pen.setColor(Qt::black);
        pen.setWidth(1);
    }

    painter->setPen(pen);
    painter->setBrush(brush);
    painter->setRenderHints(QPainter::Antialiasing, true);
    const QRectF rect = boundingRect();
    setAnchorPoint(QPointF(rect.left()+rect.width()/2.0,rect.bottom()));

    // we define a helper rectangle what we use to draw a pie,
    // as the drawPie() method expect a rect, and the pie will start from the
    // center of that rect
    QRectF cPieRect(anchorPoint().x()-rect.height(), anchorPoint().y()-rect.height(),
                    rect.height()*2,rect.height()*2);
    painter->drawPie(cPieRect,(90-miSectorSize/2)*16, miSectorSize * 16);

    // drawing the bounding rectangle in red for visual debugging
    QPen pen2(Qt::red,1);
    painter->setPen(pen2);
    painter->setBrush(QBrush(Qt::transparent));
    painter->drawRect(rect);

    setTransformOriginPoint(anchorPoint());
    setRotation(miAzimuth);
}


// setters/getters
QPointF MarkerItem::anchorPoint() const
{
    return mcAnchorPoint;
}

void MarkerItem::setAnchorPoint(const QPointF &value)
{
    mcAnchorPoint = value;
    emit anchorChanged(value);
}

void
MarkerItem::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "MarkerItem MousePressEvent" << event;
    setSelected(!mbSelected);
}

bool
MarkerItem::selected()
{
    return mbSelected;
}

void
MarkerItem::setSelected(const bool bVal)
{
    if (bVal == mbSelected)
    {
        return;
    }
    mbSelected = bVal;
    emit selectedChanged(mbSelected);
    update();
}

QColor MarkerItem::color() const
{
    return mcColor;
}

void MarkerItem::setColor(const QColor &acColor)
{
    mcColor = acColor;
}

int MarkerItem::azimuth() const
{
    return miAzimuth;
}

void MarkerItem::setAzimuth(int angle)
{
    miAzimuth = angle;
}

int MarkerItem::sectorSize() const
{
    return miSectorSize;
}

void MarkerItem::setSectorSize(int angle)
{
    miSectorSize = angle;
}

并像这样使用它:

import Marker 1.0 // this is the Markeritem class
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.4



Item
{
    id: root
    visible: true
    width: 1800
    height: 900
    MarkerItem
    {
        id: m0
        x: 900
        y:450
        color: "green"
        azimuth: 0
        sectorSize: 30
    }
    MarkerItem
    {
        id: m1
        x: 900
        y:450
        color: "green"
        azimuth: 120
        sectorSize: 30
    }
}

QQuickPaintedItem定义一个适合绘制圆形部分的边界矩形,并使用QPainter的drawPie()方法绘制所需的形状,然后通过调用setRotate()将项目旋转​​到所需的方位角。我还需要处理鼠标单击事件以选择/取消选择一个项目。我的经验是,当某项的方位角为0(因此它没有旋转)时,边界矩形的鼠标事件被我的处理程序接收,但是当该项被旋转时,我的项却没有收到来自绘制项目的区域,但从边界矩形以外的区域接收一些鼠标事件,该区域似乎是原始区域的反射点,该区域的中心是锚点(如果是圆形扇形,则为尖端,这也是旋转的中心),但是很难定义将事件传递到我的处理程序的区域。  我的假设是通过“ setRotation()”调用,鼠标区域也在旋转。有什么我忽略的东西吗?有什么方法可以处理旋转项目中的鼠标事件?

应该通过MapQuickItem在地图项中使用该项目,但是如果没有地图项,该问题也可以重现,因此此处与地图相关的部分大部分都被省略了。

2 个答案:

答案 0 :(得分:1)

setRotation()旋转该项目,因此它不应处于绘制状态,因为每次绘制该项目时都会调用该方法,例如在鼠标事件之前,因此,setRotation()仅应在{ {1}}

setAzimuth()

答案 1 :(得分:0)

好的,原来是问题出在不正确地设置变换原点上。我将锚点设置为边界矩形的底部中心为:

setTransformOriginPoint(anchorPoint()); 

锚点之前设置的位置

 setAnchorPoint(QPointF(rect.center().x(),rect.bottom()));

如果我将转换原点显式设置为以下项的底部中心:

setTransformOrigin(QQuickItem::Bottom);

它可以正常工作。