如何在弃用setHandlesChildEvents时传递QGraphicsItemGroup鼠标事件给子元素
QGraphicsItemGroup鼠标事件传递给子项的解决方案(替代已弃用的setHandlesChildEvents)
你的代码没生效主要有几个问题:直接用sendEvent传递原始事件会导致状态异常、强制转换子项不安全、重写sceneEvent时直接返回true阻断了父类默认处理逻辑。下面给你两种可行的实现方式:
方法一:重写具体鼠标事件,定向转发给子项
这种方式针对特定事件(比如双击)进行处理,先让符合条件的子项接收事件:
class MoveItemBase : public QObject, public QGraphicsItemGroup { Q_OBJECT Q_INTERFACES(QGraphicsItem) public: explicit MoveItemBase(QGraphicsItem *parent = nullptr) : QGraphicsItemGroup(parent) {} protected: void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override { // 遍历子项,找到事件位置上的可交互子项 for (QGraphicsItem *child : childItems()) { if (!child->isEnabled() || !child->acceptsHoverEvents()) continue; QPointF childPos = mapToChild(event->pos()); if (child->contains(childPos)) { // 复制事件并转换坐标到子项坐标系 QGraphicsSceneMouseEvent childEvent(*event); childEvent.setPos(childPos); // 让子项处理事件 child->mouseDoubleClickEvent(&childEvent); // 如果子项标记事件已处理,就终止传递 if (childEvent.isAccepted()) { event->setAccepted(true); return; } } } // 没有子项处理时,执行父类默认逻辑 QGraphicsItemGroup::mouseDoubleClickEvent(event); } };
方法二:给子项安装事件过滤器,灵活控制事件
如果需要监听多种事件或者更精细的控制,可以用事件过滤器:
class MoveItemBase : public QObject, public QGraphicsItemGroup { Q_OBJECT Q_INTERFACES(QGraphicsItem) public: explicit MoveItemBase(QGraphicsItem *parent = nullptr) : QGraphicsItemGroup(parent) {} void addItem(QGraphicsItem *item) override { QGraphicsItemGroup::addItem(item); // 给继承QObject的子项安装过滤器(非QObject子类无法使用) if (QObject *childObj = qobject_cast<QObject*>(item)) { childObj->installEventFilter(this); } } protected: bool eventFilter(QObject *watched, QEvent *event) override { if (event->type() == QEvent::GraphicsSceneMouseDoubleClick) { // 这里可以插入你的自定义逻辑,比如日志、状态更新 // 返回false让子项继续处理事件,返回true则拦截 return false; } return QGraphicsItemGroup::eventFilter(watched, event); } };
核心注意事项
- 必须转换事件坐标:父item的事件坐标是自身坐标系,要转成子项的局部坐标才能让子项正确识别事件位置;
- 安全类型转换:用
qobject_cast替代static_cast,转换后做空指针检查,避免崩溃; - 保留父类默认逻辑:不要随意阻断事件的默认处理流程,除非你明确不需要。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

