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

简述

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()。

时间: 2025-01-27 03:49:06

让QGraphicsItemGroup中的item处理自己的事件的相关文章

android 往dialog中加入listview,并实现listview中item的点击事件

LinearLayout linearLayoutMain = new LinearLayout(this);//自定义一个布局文件 linearLayoutMain.setLayoutParams(new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); ListView listView = new ListView(this);//this为获取当前的上下文 listView.setFadingEdg

如何更改其它程序ListView控件中某个Item的内容

一:程序说明 这次我将介绍如何更改其他程序ListView控件中某个Item的内容,关于类似的拙文我已经写了两篇,这是第三篇,本篇和第一篇<如何向其他程序的 ListView 控件发送 LVM_GETITEMTEXT 消息>类似,区别在于: 发送的消息不同:前者是读取pszText的内容--发送LVM_GETITEMTEXT:这次是设置pszText,应该发送LVM_SETITEMTEXT: 字符串缓冲区的作用不同:前者pItem用来接收ITEMTEXT,我们可以通过ReadProcessMe

spinner-在arrayadapter中获取item的值

问题描述 在arrayadapter中获取item的值 我想从spinner中获取选择项目的值.我使用的是array adapter. <string-array name="my_list"> <item value="">---Select the value from the List---</item> <item value="value1">data1</item> <

listview-点击 ListView 中的 item,然后改变行的背景颜色

问题描述 点击 ListView 中的 item,然后改变行的背景颜色 我想使用BaseAdapter 在ListView中显示item.我在BaseAdapter使用下面的代码: @Override public View getView(final int position, View convertView, ViewGroup parent) { //... convertView.setOnTouchListener(new OnTouchListener() { @Override

appwidget中加了listview,怎么让点击listview中的item后跳转到app主页面

问题描述 appwidget中加了listview,怎么让点击listview中的item后跳转到app主页面 android 中的appwidget中加了listview,怎么让点击listview中的item后跳转到app主页面(MainActivity.class) 解决方案 listview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?>

Android中屏幕显示listview中的item数量

问题描述 Android中屏幕显示listview中的item数量 求大神告知,我如何获取当前屏幕显示出的listview的item数量呢?每个屏幕大小不一,能显示出的数量也是不一样的,有没有方法能够计算的?? 解决方案 刚才那个方法太笨,还可以调用ListView的setOnScrollListener方法,里头复写了一个onScroll方法,方法中的第二个参数就是当前ListView中可见的item数量.下例子中是visibleItemCount: listView.setOnScrollL

点击recyclerview中的item使点击的item中的图片改变要用什么方法?

问题描述 点击recyclerview中的item使点击的item中的图片改变要用什么方法? 2C 求大神指点一下呀..点击recyclerview中的item使点击的item中的图片改变要用什么方法呢?最好有个小demo.. 解决方案 AndroidListView点击Item的时候 改变文字颜色和背景色

横向滑动-Android中用首字母排序的listview中的item的滑动监听与listview的上下滑动冲突

问题描述 Android中用首字母排序的listview中的item的滑动监听与listview的上下滑动冲突 大神帮看看,我现在listview的item中我写了一个OnTouchListener,但是发现横向滑动的时候老是会触发listview的上下滑动事件,导致横向滑动很难滑出来,但是滑出来第一次后,后面就很容易划出来了!大神帮忙看看!!!感谢! 让人很是苦恼,这个该怎么处理呢?查过资料说改返回值为false,改了都滑不出来! /** * 侧滑显示删除按钮 */ private View.

android-点击listview中的item跳转并获取item中的内容出现的问题

问题描述 点击listview中的item跳转并获取item中的内容出现的问题 一用settext()里面写上title就出错了 打印出来的title desc确实传递到另一个activity了 解决方案 文本数据传递到第二个Activity后,这句话报了空针,那就说明textView为null.你debug一下,看看是否是这个控件没有被实例化;或者你实例化错了控件(同样的id,导入的别的Activity下的) 解决方案二: 明确告诉你空指针了,你调试看看是哪个对象,然后检查是不是key写错了