【发布时间】: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 项目的情况下也可重现,因此此处大部分省略了与地图相关的部分。
【问题讨论】: