【问题标题】:Mouse event handling in rotated QQuickItem旋转 QQuickItem 中的鼠标事件处理
【发布时间】:2018-07-23 17:44:05
【问题描述】:

我有一个简单的 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 在 Map 项目中使用,但该问题在没有 Map 项目的情况下也可重现,因此此处大部分省略了与地图相关的部分。

【问题讨论】:

    标签: qt qml qtquick2


    【解决方案1】:

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

    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.center().x(),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);
    }
    
    ...    
    
    void MarkerItem::setAzimuth(int angle)
    {
        miAzimuth = angle;
        setTransformOriginPoint(anchorPoint());
        setRotation(miAzimuth);
    }
    

    【讨论】:

    • 这确实是一个有效的评论,谢谢,但不幸的是并不能解决问题本身,请参阅我的回答。
    【解决方案2】:

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

    setTransformOriginPoint(anchorPoint()); 
    

    锚点之前设置的位置

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

    如果我将变换原点显式设置为项目的底部中心:

    setTransformOrigin(QQuickItem::Bottom);
    

    它可以正常工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 2018-08-15
      • 1970-01-01
      • 2015-02-06
      • 1970-01-01
      相关资源
      最近更新 更多