找回密码
 立即注册
收起左侧

QGraphicsScene删除选中的item以后,为什么就不能添加新的item了

8
回复
9916
查看
[复制链接]
累计签到:10 天
连续签到:1 天
来源: 2015-11-28 17:22:17 显示全部楼层 |阅读模式
1Qter豆
写了一个槽函数,如下:
void MyView::deleteItem()
{
    foreach (QGraphicsItem *item, scene->selectedItems()) {
        item = (MyItem*)item;
        scene->removeItem(item);
        delete item;
    }   
}
目的是当按del键的时候删除选中的item,现在能够删除item,但是删除以后,我在scene上添加新的item就会失败,感觉
非常奇怪,请问谁遇到过这种情况,可以怎么解决?

回复

使用道具 举报

累计签到:894 天
连续签到:1 天
2015-11-28 18:36:11 显示全部楼层
把添加的代码贴出来。
回复

使用道具 举报

累计签到:10 天
连续签到:1 天
2015-11-28 20:32:53 显示全部楼层
添加是在view里面的鼠标事件里面,当鼠标移动的时候,根据用户选择的图形创建item,然后把item添加到scene里面,scene是view的成员变量,所以重写了view的鼠标事件,
                 if (shape->getShape() != MyShape::Graffiti)
                 {
                        MyItem* item = new MyItem(QGraphicsView::mapToScene(rect).boundingRect());
                        item->setShape(*this->getShape());
                        if (this->getShape()->getShape() == MyShape:ine)
                        {
                                item->getShape().setBrushColor(Qt::white);
                        }
                        scene->addItem(item);
                }
回复

使用道具 举报

累计签到:10 天
连续签到:1 天
2015-11-28 21:04:22 显示全部楼层
Syylc120317 发表于 2015-11-28 18:36
把添加的代码贴出来。

有一种情况就是当把所有的item都删除以后就不能加了,还剩一个的时候能加
回复

使用道具 举报

累计签到:10 天
连续签到:1 天
2015-11-28 21:25:59 显示全部楼层
Syylc120317 发表于 2015-11-28 18:36
把添加的代码贴出来。

所以我现在用hack的方法解决了这个问题,每次用户按delete键删除选中的item的时候,我就在槽函数末尾加一个item,而这个item的大小是0,位置固定在原点,这样用户看不到绘图软件中有这个item,但是删除之后就可以继续添加新的item了,也就是说可以画图了。但是我不知道这是为什么。改后如下:
void MyView::deleteItem()
{
        foreach (QGraphicsItem *item, scene->selectedItems()) {
                item = (MyItem*)item;
                scene->removeItem(item);
                delete item;
        }       
        QRect rect(0, 0, 0, 0);//原点,大小为0,用户看不见
        MyItem* item = new MyItem(QGraphicsView::mapToScene(rect).boundingRect());
        item->getShape().setShape(MyShape::Ellipse);//这里无所谓了,随便画一个形状
        scene->addItem(item);
}
还有一个问题,就是我的程序的结构问题,一直感觉程序写的有点混乱,自定义类继承了view和item,
不知道是不是应该继承scene更好,因为是画图程序,可以画很多形状,我把形状写成一个类,但是也没有使用继承,用了一个枚举变量表示形状的类型,结果随笔画的时候要单独处理,感觉是不是继承更好,还是把形状本身的信息放到item里面,重写鼠标事件的时候,重写了item,也重写了view的一部分,为了保证view和item能够通信,我把形状做了桥梁,感觉也不好,还有应该在哪个类里面最终把所有类型的对象整合起来,也没有考虑好,是在mainwindow里面一起考虑view,scene,item吗,我目前是把scene作为成员变量放在view里面,item直接加到scene里面,然后再mainwindow里面把view整合进去,感觉很怪,虽然程序能跑,大部分问题都解决了。希望有经验的程序员指导一下,写一个完整的应用的时候,应该怎么考虑重构代码,让代码更整洁,看起来结构更合理,修改起来更方便,谢谢。





点评

写得好详细!!!  发表于 2015-11-28 21:47
回复

使用道具 举报

累计签到:894 天
连续签到:1 天
2015-11-28 21:26:09 显示全部楼层
wwj_ff 发表于 2015-11-28 21:04
有一种情况就是当把所有的item都删除以后就不能加了,还剩一个的时候能加 ...

调试一下,感觉是添加的语句就没执行,或者shape为NUL.
回复

使用道具 举报

累计签到:894 天
连续签到:1 天
2015-11-28 21:46:43 显示全部楼层
wwj_ff 发表于 2015-11-28 21:25
所以我现在用hack的方法解决了这个问题,每次用户按delete键删除选中的item的时候,我就在槽函数末尾加一 ...

你的这种解决方法是好的。但是我觉得应该解决根本问题,看看到底是哪儿出错了。你调试试试,看deleteItem执行完之后发生了什么。

我的建议是继承Item,为每个形状创建Item类。对于鼠标事件,可以使用事件过滤器(eventFilter,installEventFilter()),就不用继承view或者scene了。还有一个建议是消息的传递多采用信号和槽函数。mainWindow有一个centralWidget,你可以继承widget,写一个中心组件。把view和scene放里面。然后把这个中心组件设置为mainwindow的中心组件(setCentralWidget)。

view是视图,相当于照相机。可以拉近,旋转,平移,等等操作。
scene是黑板,你可以在上面作画。
item就是你在黑板上画的图形。
而最后呈现出来的是通过照相机看到的。
所以说不适合把在view上控制item的添加或者删除。(这也不和常理,试想,我能通过相机删除黑板上写的吗?)。

希望我说的能帮到你。

PS:看你认真写了这么多,我要为你点个赞。
回复

使用道具 举报

累计签到:10 天
连续签到:1 天
2015-11-28 22:23:51 显示全部楼层
Syylc120317 发表于 2015-11-28 21:46
你的这种解决方法是好的。但是我觉得应该解决根本问题,看看到底是哪儿出错了。你调试试试,看deleteItem ...

嗯,你的这个思路是清晰多了,我一直是把view直接当中央窗体的。你把scene比喻成黑板,我想在黑板上画图形,步骤是这样,先选择某一个形状,也就是new一个什么类型的item对象,然后鼠标事件应该是针对scene了?把鼠标当作粉笔,在黑板上摆动粉笔,然后画出形状。
现在还有一个问题想请教你,对于矩形,一般四边形,椭圆,五边形,六边形,直线等这些形状,我都是通过两个点的坐标决定的,也就是鼠标按下和放开的两个点,说白了就是这些图形的外接矩形,然后我画出来的图形都是很特殊的,比如五边形,我是选起点和终点这样一个矩形的顶边,左边,右边三边的中点和底边的两个三等分点画出来的,有点相似图形的感觉,放缩的时候,我也是按照放缩后的外接矩形重新计算这5个坐标,如果我要画任意形状的多边形,比如各种样子的五边形,有什么好方法吗?我试了一下windows自带的画图就是我这样做的。

点评

你缺一个绘图工具类DrawTool,可以参考MFC的drawcli。  发表于 2015-11-28 23:17
回复

使用道具 举报

累计签到:894 天
连续签到:1 天
2015-11-29 07:58:46 显示全部楼层
wwj_ff 发表于 2015-11-28 22:23
嗯,你的这个思路是清晰多了,我一直是把view直接当中央窗体的。你把scene比喻成黑板,我想在黑板上画图 ...

事件过滤器是有两个参数,一个是事件的发出者,一个是事件的类型。针对你目前的应用来说,发出者应该是centralWidget,而事件的类型是鼠标事件。你可以看一下eventFilter()函数。

item的缩放可以通过两种方式完成,一个是调用item的函数,setScale。
另外一种方式是缩放view,相当于相机的拉近与推远。
第二种方式需要设置变换的原点,也就是以哪个点为缩放中心。

建议使用第二种方式。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了