C++ 组合QGraphicsItem未检测到子项上的单击
我正在尝试对C++ 组合QGraphicsItem未检测到子项上的单击,c++,qt,qt5,qgraphicsscene,qgraphicsitem,C++,Qt,Qt5,Qgraphicsscene,Qgraphicsitem,我正在尝试对qgraphicsrecitem进行一个简单的扩展,它允许我调整矩形的大小并用鼠标移动它。我在要启用拖动功能的拐角处用椭圆拱对控制柄进行建模,实现为QGraphicsEllipseItems: class QGraphicsBoxWithHandlesItem : public QObject, public QGraphicsRectItem { Q_OBJECT typedef enum { None, BottomLeft,
qgraphicsrecitem
进行一个简单的扩展,它允许我调整矩形的大小并用鼠标移动它。我在要启用拖动功能的拐角处用椭圆拱对控制柄进行建模,实现为QGraphicsEllipseItem
s:
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
中(调整坐标以使其相对于父项):
然而,我得到的是,现在手柄区域内的点击被完全忽略,只处理矩形中心区域的点击
当项目具有非平凡形状时,扩展其可点击区域的正确方法是什么
更新:我试图在句柄上设置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);
}
您的QGraphicsSellipseitem位于基本项之上,因此鼠标事件永远不会出现在您的面前 您需要做的是使用sceneEventFilter,但由于QGraphicsSellipseitem是主项的子项,它们永远不会移动,因此它们不应该有父项,但您应该将它们直接添加到场景中 完整功能在以下代码中实现: *.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
#如果使用无手柄的QGraphicsBox项目
#定义QGRAPHICSBOXWITHHANDLESITEM_H
#包括
#包括
类QGraphicsBoxWithHandlesItem:公共QObject,公共QGraphicsRecItem
{
Q_对象
枚举活动锚{
没有一个
左下角,
右上角
};
公众:
QGraphicsBoxWithHandlesItem(QRectF r,float handlesRadius=20.0,QGraphicsSitem*父项=nullptr);
受保护的:
QVariant项目变更(图形站点变更、常量QVariant和值);
bool sceneEventFilter(QGraphicsItem*监视,QEvent*事件);
私人:
QGraphicsSellipseitem m_anchorBottomLeft;
QGraphics Sellipseitem m_anchorTopRight;
浮动m_anchorRadius;
主动锚m_主动锚;
};
#endif//qgraphicsboxwithhandles项目
*.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);
}
#包括“qgraphicsboxwithhandlesitem.h”
#包括
#包括
#包括
QGraphicsBoxWithHandlesItem::QGraphicsBoxWithHandlesItem(QRectF r、浮点handlesRadius、QGraphicsSiteM*父项):
QGraphicsRectItem(父级),
m_anchorRadius(handlesRadius),
m_activeAnchor(无)
{
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.设置角度(90*16);//角度为16度
//m_anchorBottomLeft.setParentItem(此项);
setFlag(QGraphicsItem::ItemIsMovable);
m_anchorBottomLeft.setFlag(QGraphicsItem::itemisselect);
m_anchorTopRight.setRect(-m_anchorRadius,-m_anchorRadius,m_anchorRadius*2,m_anchorRadius*2);
m_anchotopright.setPos(rect().topRight());
m_anchorTopRight.设置起始角度(180*16);//角度为16度
m_anchorTopRight.设置角度(90*16);//角度为16度
//m_AnchortoRight.setParentItem(此项);
m_anchorTopRight.setFlag(QGraphicsItem::ItemIsMovable);
m_anchorTopRight.setFlag(QGraphicsItem::itemisselect);
}
QVariant QGraphicsBoxWithHandlesItem::itemChange(GraphicsSitemChange更改,常量QVariant和值){
if(change==QGraphicsItem::ItemSceneHasChanged){
如果(场景()){
场景()->附加项(&m_anchorBottomLeft);
场景()->附加项(&m_AnchortoRight);
m_anchorBottomLeft.installSceneEventFilter(此);
m_anchorTopRight.installSceneEventFilter(此);
}
}
else if(change==QGraphicsItem::ItemPositionHasChanged){
m_anchorBottomLeft.setPos(映射到场景(rect().bottomLeft());
m_anchotopright.setPos(映射到场景(rect().topRight());
}
返回qgraphicsrecitem::itemChange(change,value);
}
bool QGraphicsBoxWithHandlesItem::sceneEventFilter(QGraphicsSitem*监视,QEvent*事件)
{
如果(观看==&m_AnchortoRight){
开关(事件->类型(){
案例QEvent::GraphicsCenemousePress:{
//鼠标垫
qDebug()你是如何将m_anchorBottomLeft和m_AnchorToRight添加到场景中的?好问题。我不确定。它们是rootRect
项的子项,我将其添加到场景中。我假设这些子项是与父项一起添加的,但我不确定情况是否如此。当我们需要解决此问题时,我们使用@ypnos谢谢,我会定义我真的想看看它!(我希望我昨天找到了它。)我仍然想知道我的代码中发生了什么,但是,如果只是想知道在我再次需要它时如何做:)谢谢,我试过了代码,它似乎起了作用(我仍然需要用我在原始代码中的一些东西来修改它,但这确实满足了我的需要)。
#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);
}