QGraphicsView 框架学习(二),组合与撤销组合

QGraphicsItemGroup 是Qt二维图形框架提供的对图元进行组合操作的类。它提供了了void addToGroup(QGraphicsItem * item) 和 void removeFromGroup(QGraphicsItem *);两个方法。实际使用中可以通过 scene的createItemGroup()方法来创建组合对象,通过destroyItemGroup方法撤销组合。看上去就这么简单,但是事情没这么简单。如果组合对象中的图元都是简单的单体对象,那么情况的确和上面说的一样很简单,如果组合对象中包含组合对象,情况就变的复杂了。

在一个交互式绘图程序中,对任意图形对象的组合与撤销组合都是不可缺少的操作。QGraphicsView框架中,提供了通过鼠标框选对象的功能,如果我们框选一个组合对象,你回发现,组合对象中的子对象也被包括在selectedItems当中,如果我们这个时候需要再次组合对象,就出现问题了,新的组合对象会把被包含的组合对象的子对象再次组合一次,结果就是被组合的组合对象被破坏了,实际上只剩下一个boundingRect了。没办法,找不到解决的方法,好像用它的人很少,我只好用一个笨办法解决了,那就是重写
scene的createItemGroup()方法。在向组合对象添加子对象的时候判断一下对象的父对象是不是一个组合,QGraphicsItem 提供了一个group()方法,说是可以通过它判断对象是否被组合,实际情况是没用。所以只能用 qgraphicsitem_cast方法判断了。代码如下:

GraphicsItemGroup *DrawScene::createGroup(const QList<QGraphicsItem *> &items,bool isAdd)
{
    // Build a list of the first item's ancestors
    QList<QGraphicsItem *> ancestors;
    int n = 0;
    if (!items.isEmpty()) {
        QGraphicsItem *parent = items.at(n++);
        while ((parent = parent->parentItem()))
            ancestors.append(parent);
    }

    // Find the common ancestor for all items
    QGraphicsItem *commonAncestor = 0;
    if (!ancestors.isEmpty()) {
        while (n < items.size()) {
            int commonIndex = -1;
            QGraphicsItem *parent = items.at(n++);
            do {
                int index = ancestors.indexOf(parent, qMax(0, commonIndex));
                if (index != -1) {
                    commonIndex = index;
                    break;
                }
            } while ((parent = parent->parentItem()));

            if (commonIndex == -1) {
                commonAncestor = 0;
                break;
            }

            commonAncestor = ancestors.at(commonIndex);
        }
    }

    // Create a new group at that level
    GraphicsItemGroup *group = new GraphicsItemGroup(commonAncestor);
    if (!commonAncestor && isAdd )
        addItem(group);
    foreach (QGraphicsItem *item, items){
        item->setSelected(false);
        QGraphicsItemGroup *g = dynamic_cast<QGraphicsItemGroup*>(item->parentItem()); //判断父对象是否为组合对象。
        if ( !g )
             group->addToGroup(item);
    }
    return group;
}

撤销组合

void DrawScene::destroyGroup(QGraphicsItemGroup *group)
{
    group->setSelected(false);
    foreach (QGraphicsItem *item, group->childItems()){
        item->setSelected(true);
        group->removeFromGroup(item);
    }
    removeItem(group);
    delete group;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-25 05:35:20

QGraphicsView 框架学习(二),组合与撤销组合的相关文章

Struts2框架学习(二) Action

Struts2框架学习(二) Action Struts2框架中的Action类是一个单独的javabean对象.不像Struts1中还要去继承HttpServlet,耦合度减小了. 1,流程 拦截器拦截请求,创建代理Action对象,执行方法,返回结果,界面跳转. 拦截器解析请求路径,获取Action的名称,到配置文件中查找action的完整类名,利用反射创建对象. 每请求一次,就创建一个对象,所以action是多例的,也是线程安全的. 2,关系 请求的路径和配置文件的对应关系: 配置文件中包

Android Afinal框架学习(二) FinalActivity 一个IOC框架

框架地址:https://github.com/yangfuhai/afinal 对应的源码: net.tsz.afinal.annotation.view.* FinalActivity FinalActivity是一个基础类,结合注解实现了,依赖注入(view的资源id,常用的监听器), 利用set方式注入 完全注解方式就可以进行UI绑定和事件绑定,无需findViewById和set event Listener 这个过程:initInjectedView>findViewById.set

Android 学习笔记之AndBase框架学习(二) 使用封装好的进度框,Toast框,弹出框,确认框...

PS:渐渐明白,在实验室呆三年都不如在企业呆一年... 学习内容: 1.使用AbActivity内部封装的方法实现进度框,Toast框,弹出框,确认框...   AndBase中AbActivity封装好了许多方法提供我们去使用,使得在使用的时候更加的方便,只需要传递相关参数即可..省去了我们自己使用基础的函数进行构造...   就好比进度框,Toast框,弹出框,确认框...这些基本的东西都在AndBase的AbActivity封装好了...我们只需要传递参数调用其中内部的方法就可以完成这些视

laravel框架学习(二)

在了解Laravel框架的基本结构之后,初步认识访问过程中路由的使用方法,以一套基本的学生信息增删改查来迅速学习框架开发. 首先了解几个目录文件作为开发的主要阵地: 1. /app/Http/routes.php 路由文件,一切访问从路由开始 2./app/Http/Controllers 控制器目录,我们写的控制器都放在该目录下 3./app/config Laravel配置文件夹一般修改.env文件 4./.env 经常修改配置的文件,数据库配置就在这里 5./public Laravel框

Hibernate框架学习(二)——api详解

一.Configuration对象 功能:配置加载类,用于加载主配置,orm元数据加载. 1 //1.创建,调用空参构造(还没有读配置文件) 2 Configuration conf=new Configuration(); 3 //2.读取指令配置文件=>空参加载方法,加载src下的hibernate.cfg.xml文件 4 conf.configure(); 5 6 //3.读取指定orm元数据(扩展),如果主配置中已经引入映射配置,不需要手动加载 7 //conf.addResource(

TP框架学习(二)

简单的增删改查 1 1.创建一个index.php文件 2 定义应用App目录名 3 导入窗口入口文件 4 开启调试模式//出现错误会报告出错的详细信息 5 define("APP_DEBUG",true);//上线时要关闭的 6 2.前端后台 7 App内Home复制一份,重命名Admin后台模块 8 如果有手机端可再复制一份Api模块 9 3.修改Admin/Controller/IndexController.class.php文件 10 namespace Admin\Cont

Castle ActiveRecord框架学习(二):快速搭建简单博客网站

一.数据库 1.数据表 Category:类别标签表(字段Type=1为类别,Type=2为标签) Category_Post:类别标签与文章中间表 Post:文章表 Comment:评论表 2.数据库关系图 3.简单说明 Category和Post表为多对多关系 Post和Comment表 为一对多关系 二.实体类 1.Category类: // 指定数据表,Lazy为延迟加载 [ActiveRecord("Category",Lazy=true)] public class Cat

actix rust actor 框架学习 二 ping actor demo 代码

以下是官方文档的学习,了解基本的actix actor 编程模型 项目初始化 cargo 创建 cargo new actor-ping --bin 效果 ├── Cargo.toml └── src    └── main.rs 添加依赖 cargo.toml 配置 [package] name = "actor-ping" version = "0.1.0" authors = ["rongfengliang <[email protected]

bottle框架学习(二)之HTTP请求

HTTP 请求方法 HTTP 协议有很多种请求方法.route默认使用GET方法,只响应GET请求.method参数可以给route()函数指定使用哪种方法.或用get(),post(),put()或delete()等函数来代替route()函数. POST 方法一般用于HTML 表单的提交.下面是一个使用POST 来实现用户登录的例子: [[email protected]]# cat login.py #!/usr/bin/envpython #coding=utf-8 from bottl