组合的QGraphicsItem未检测到子项上的单击

Composed QGraphicsItem not detecting clicks on sub-items

本文关键字:单击 检测 QGraphicsItem 组合      更新时间:2023-10-16

我正在尝试对QGraphicsRectItem进行一个简单的扩展,它允许我调整矩形的大小并用鼠标四处移动。我在角上用椭圆拱建模手柄,我想启用它进行拖动,我将其实现为QGraphicsEllipseItems:

class QGraphicsBoxWithHandlesItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
typedef enum {
None,
BottomLeft,
TopRight
} ActiveAnchor;
private:
QGraphicsEllipseItem m_anchorBottomLeft;
QGraphicsEllipseItem m_anchorTopRight;
float m_anchorRadius;
ActiveAnchor m_activeAnchor;
public:
QGraphicsBoxWithHandlesItem(QRectF r, float handlesRadius = 20.0, QGraphicsItem *parent = nullptr);
void setAnchorRadius(float radius);
float getAnchorRadius();
QPainterPath shape() const;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent * event);
void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
};

我希望能够检测矩形和句柄项目上的点击(这是必要的,因为如果矩形太小,句柄是唯一容易点击的区域(,所以我想扩展QGraphicsRectItem::shape(),将子项目的路径添加到返回的QPainterPath中(调整坐标,使其相对于父项目(:

QPainterPath QGraphicsBoxWithHandlesItem::shape() const
{
auto curShape = QGraphicsRectItem::shape();
curShape.addPath( mapFromItem(&m_anchorBottomLeft, m_anchorBottomLeft.shape()) );
curShape.addPath( mapFromItem(&m_anchorTopRight, m_anchorTopRight.shape()) );
return curShape;
}

然而,我得到的是,现在句柄区域内的单击被完全忽略,只处理矩形中心区域的单击。

当项目具有非平凡的形状时,扩展其可点击区域的正确方法是什么?

更新:我试图在句柄上设置ItemIsSelectable标志,现在,如果我单击它,我会看到它被选中。然而,我仍然没有在父级中得到任何mousePressEvent。我做错了什么?

编辑:

这是构造函数的实现:

QGraphicsBoxWithHandlesItem::QGraphicsBoxWithHandlesItem( QRectF r, float handlesRadius, QGraphicsItem * parent) :
QGraphicsRectItem(parent),
m_anchorRadius(handlesRadius),
m_activeAnchor(None)
{
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
setRect(r);
m_anchorBottomLeft.setRect(-m_anchorRadius, -m_anchorRadius, m_anchorRadius*2, m_anchorRadius*2);
m_anchorBottomLeft.setPos(rect().bottomLeft());
m_anchorBottomLeft.setSpanAngle(90 * 16); // angle is in 16ths of degree
m_anchorBottomLeft.setParentItem(this);
m_anchorTopRight.setRect(-m_anchorRadius, -m_anchorRadius, m_anchorRadius*2, m_anchorRadius*2);
m_anchorTopRight.setPos(rect().topRight());
m_anchorTopRight.setStartAngle(180 * 16); // angle is in 16ths of degree
m_anchorTopRight.setSpanAngle(90 * 16); // angle is in 16ths of degree
m_anchorTopRight.setParentItem(this);
}

您的QGraphicsEllipseItem位于基本项之上,因此鼠标事件永远不会出现。

您要做的是使用sceneEventFilter,但由于QGraphicsEllipseItem是主项的子项,它们永远不会移动,因此它们不应该有父项,但您应该将它们直接添加到场景中。

完整的功能在以下代码中实现:

*.h

#ifndef QGRAPHICSBOXWITHHANDLESITEM_H
#define QGRAPHICSBOXWITHHANDLESITEM_H
#include <QGraphicsRectItem>
#include <QObject>
class QGraphicsBoxWithHandlesItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT
enum ActiveAnchor{
None,
BottomLeft,
TopRight
};
public:
QGraphicsBoxWithHandlesItem(QRectF r, float handlesRadius = 20.0, QGraphicsItem *parent = nullptr);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event);
private:
QGraphicsEllipseItem m_anchorBottomLeft;
QGraphicsEllipseItem m_anchorTopRight;
float m_anchorRadius;
ActiveAnchor m_activeAnchor;
};
#endif // QGRAPHICSBOXWITHHANDLESITEM_H

*.cpp

#include "qgraphicsboxwithhandlesitem.h"
#include <QEvent>
#include <QGraphicsScene>
#include <QDebug>
QGraphicsBoxWithHandlesItem::QGraphicsBoxWithHandlesItem( QRectF r, float handlesRadius, QGraphicsItem * parent) :
QGraphicsRectItem(parent),
m_anchorRadius(handlesRadius),
m_activeAnchor(None)
{
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
setRect(r);
m_anchorBottomLeft.setRect(-m_anchorRadius, -m_anchorRadius, m_anchorRadius*2, m_anchorRadius*2);
m_anchorBottomLeft.setPos(rect().bottomLeft());
m_anchorBottomLeft.setSpanAngle(90 * 16); // angle is in 16ths of degree
//m_anchorBottomLeft.setParentItem(this);
m_anchorBottomLeft.setFlag(QGraphicsItem::ItemIsMovable);
m_anchorBottomLeft.setFlag(QGraphicsItem::ItemIsSelectable);
m_anchorTopRight.setRect(-m_anchorRadius, -m_anchorRadius, m_anchorRadius*2, m_anchorRadius*2);
m_anchorTopRight.setPos(rect().topRight());
m_anchorTopRight.setStartAngle(180 * 16); // angle is in 16ths of degree
m_anchorTopRight.setSpanAngle(90 * 16); // angle is in 16ths of degree
//m_anchorTopRight.setParentItem(this);
m_anchorTopRight.setFlag(QGraphicsItem::ItemIsMovable);
m_anchorTopRight.setFlag(QGraphicsItem::ItemIsSelectable);
}
QVariant QGraphicsBoxWithHandlesItem::itemChange(GraphicsItemChange change, const QVariant & value){
if(change == QGraphicsItem::ItemSceneHasChanged){
if(scene()){
scene()->addItem(&m_anchorBottomLeft);
scene()->addItem(&m_anchorTopRight);
m_anchorBottomLeft.installSceneEventFilter(this);
m_anchorTopRight.installSceneEventFilter(this);
}
}
else if (change == QGraphicsItem::ItemPositionHasChanged) {
m_anchorBottomLeft.setPos(mapToScene(rect().bottomLeft()));
m_anchorTopRight.setPos(mapToScene(rect().topRight()));
}
return QGraphicsRectItem::itemChange(change, value);
}
bool QGraphicsBoxWithHandlesItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
if(watched == &m_anchorTopRight){
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:{
//mousePressEvent
qDebug()<<"mousePressEvent m_anchorTopRight";
break;
}
case QEvent::GraphicsSceneMouseMove:{
// mouseMoveEvent
QRectF r = rect();
auto p = m_anchorTopRight.mapToScene(m_anchorTopRight.rect().center());
r.setTopRight(mapFromScene(p));
setRect(r);
qDebug()<<"mouseMoveEvent m_anchorTopRight";
break;
}
case QEvent::GraphicsSceneMouseRelease :{
//mouseReleaseEvent
qDebug()<<"mouseReleaseEvent m_anchorTopRight";
break;
}
}
}
if(watched == &m_anchorBottomLeft){
switch (event->type()) {
case QEvent::GraphicsSceneMousePress:{
//mousePressEvent
qDebug()<<"mousePressEvent m_anchorBottomLeft";
break;
}
case QEvent::GraphicsSceneMouseMove:{
// mouseMoveEvent
QRectF r = rect();
auto p = m_anchorBottomLeft.mapToScene(m_anchorBottomLeft.rect().center());
r.setBottomLeft(mapFromScene(p));
setRect(r);
qDebug()<<"mouseMoveEvent m_anchorBottomLeft";
break;
}
case QEvent::GraphicsSceneMouseRelease :{
//mouseReleaseEvent
qDebug()<<"mouseReleaseEvent m_anchorBottomLeft";
break;
}
}
}
return  QGraphicsRectItem::sceneEventFilter(watched, event);
}