让QGraphicsItemGroup中的item处理自己的事件

简介: 简述QGraphicsItem 分组比较简单,但在分组之后 group 中的 QGraphicsItem 无法捕获自己的相关事件(例如:鼠标事件、键盘事件),实际接受消息对象为 QGraphicsItemGroup。那么,如何处理呢?简述处理方式处理方式处理方式有两种:方式一,也是最简单的一种: void QGraphics

简述

QGraphicsItem 分组比较简单,但在分组之后 group 中的 QGraphicsItem 无法捕获自己的相关事件(例如:鼠标事件、键盘事件),实际接受消息对象为 QGraphicsItemGroup。那么,如何处理呢?

处理方式

处理方式有两种:

  • 方式一,也是最简单的一种:

void QGraphicsItem::setHandlesChildEvents(bool enabled)

如果 enabled 为 true,QGraphicsItemGroup 将处理其所有子 item 的所有事件(即,其任何子 item 的所有事件都发送到此 item),例如:鼠标点击子 item 的事件不会被子 item 自身处理;否则,如果 enabled 为 false,QGraphicsItemGroup 将只处理自己的事件,不会阻止子 item 的事件,并让子 item 处理自己的事件。

根据官方文档描述,该函数参数的默认值为 false。经过实验,重写鼠标事件、键盘事件之后,会发现依然会阻止子 item 的事件,究竟为何?难道是文档有误?

当然不会,打开 QGraphicsItemGroup 的源码,可以发现:

QGraphicsItemGroup::QGraphicsItemGroup(QGraphicsItem *parent)
    : QGraphicsItem(*new QGraphicsItemGroupPrivate, parent)
{
    setHandlesChildEvents(true);
}

在 QGraphicsItemGroup 的构造函数中就这一行代码,也正是我们要找的答案!

所以,要让 QGraphicsItemGroup 中的 item 处理自己的事件,还需要在构造 group 后,再手动调用:

QGraphicsItemGroup::setHandlesChildEvents(false);

这一行代码即可。

  • 方式二,

bool QGraphicsItem::sceneEvent(QEvent *event)

该虚函数接收到此 item 的事件。重新实现这个函数,在事件被分派到专门的事件处理程序之前拦截事件 contextMenuEvent()、focusInEvent()、focusOutEvent()、hoverEnterEvent()、hoverMoveEvent()、hoverLeaveEvent()、keyPressEvent()、keyReleaseEvent()、mousePressEvent()、mouseReleaseEvent()、mouseMoveEvent()、和 mouseDoubleClickEvent()。

如果事件被识别和处理,则返回 true;否则(例如,如果事件类型未被识别),则返回 false。

event 是拦截的事件。

这样看来,sceneEvent() 接收一个 item 的所有事件,非常类似于 QWidget::event()。

既然如此,重写此函数也可以让 QGraphicsItemGroup 中的 item 处理自己的事件。

#include <QGraphicsEllipseItem>
#include <QEvent>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <qDebug>

class CustomItem : public QGraphicsEllipseItem
{
public:
    CustomItem(QGraphicsItem *parent = 0) {
        setFlag(QGraphicsItem::ItemIsFocusable);
    }
protected:
    // 按键按下事件
    void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE {
        Q_UNUSED(event);
        qDebug() << "keyPressEvent";
    }
    // 按键释放事件
    void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE {
        Q_UNUSED(event);
        qDebug() << "keyReleaseEvent";
    }
    // 鼠标按下事件
    void mousePressEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE {
        Q_UNUSED(event);
        qDebug() << "mousePressEvent";
    }
    // 鼠标按下事件
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE {
        Q_UNUSED(event);
        qDebug() << "mouseMoveEvent";
    }
    // 鼠标释放事件
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_DECL_OVERRIDE {
        Q_UNUSED(event);
        qDebug() << "mouseReleaseEvent";
    }
    // 处理上述事件
    bool sceneEvent(QEvent *event) Q_DECL_OVERRIDE {
        switch (event->type()) {
        case QEvent::GraphicsSceneMousePress:
            mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
            break;
        case QEvent::GraphicsSceneMouseRelease:
            mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
            break;
        case QEvent::GraphicsSceneMouseMove:
            mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
            break;
        case QEvent::KeyPress:
            keyPressEvent(static_cast<QKeyEvent *>(event));
            break;
        case QEvent::KeyRelease:
            keyReleaseEvent(static_cast<QKeyEvent *>(event));
            break;
        default:
            break;
        }
        event->accept();
        return true;
    }
};

显然,大多数情况下,正确的姿势应该选择方式一,因为对我们来说更简单,方式二则需要为每一个自定义 item 都去实现 sceneEvent()。

目录
相关文章
|
4天前
|
JavaScript 前端开发
点击事件中的this|click事件与change事件|v-model
点击事件中的this|click事件与change事件|v-model
13 0
|
5月前
|
前端开发
layui select 绑定onchange事件失效
layui select 绑定onchange事件失效问题处理
|
7天前
oninput事件和onchange事件的区别?
oninput事件和onchange事件的区别?
|
5月前
el-input-number阻止外层button的冒泡
el-input-number阻止外层button的冒泡
47 0
|
5月前
element中el-input组件事件
element中el-input组件事件
el-date-picker change事件不触发
el-date-picker change事件不触发
562 0
|
JavaScript
解决input 有多少个radio绑定change事件,手动触发就会执行多少次问题
如题,相信大家都会遇到这个问题,那么为什么会触发多次呢?其实当你用jquery绑定onchange事件的时候你就无形中给每个radio绑定了事件,所以才会出现执行多少次的问题了,那么如何解决呢,其实这个问题就是最好的解决方法了,你想阿,一组radio当然只会选中一个,但是没有 选中的radio也会执...
1143 0
关于div的outline-offset属性和focus事件的接收
关于div的outline-offset属性和focus事件的接收
114 0
关于div的outline-offset属性和focus事件的接收
|
JavaScript 前端开发 API
tap 和click 事件区别
clike事件和 Zepto.js 中tap的区别  首先介绍下Zepto: 最初是作为移动端开发的库,但是却可以作为JQuery轻量级的替代品,因为API和JQuery相似,而文件更小。 介绍下tap和click的区别: 两者都会在点击时触发,但是在web手机端,clikc会有200-300ms的延时,所以要用tap代替click作为点击事件,singleTap和doubleTap分别作为单次点击和双击,但是使用tap会带来点透事件(事件穿透)。
2067 0