精彩的人生

好好工作,好好生活

BlogJava 首页 新随笔 联系 聚合 管理
  147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks
这是本人原创作品,如有转载,请注明出处。

 

前面的那篇文章emf&gef之一example.my.gefpractice讲述的是如何将emfgef结合起来使用。

在实际的项目开发中模型的是根据需求来定的,可以说模型事实上是业务逻辑。声明这一点是为了说明本文研究内容的必要性。

前面的文章中使用的模型定义,包含x,y,w,h(他们确定了编辑器的一个矩形区域,这个矩形区域用来显示模型的图像),除此之外还包含了一个connection对象,每个nodeinputsoutputs

简单的说,前文中的模型是从编辑器的角度来定义模型的。

假如从业务的角度来看,模型之间的关系是什么样的呢?

假如从业务上来看,node之间只有一个next关系,来表明先后顺序。

 

定义模型

 

根据上面的分析,从新定义模型,如下图所示:

emfgef2_1.JPG

第一篇文章中定义的模型,编辑器内容序列化为xml文件格式为:

<Diagram>
<Node >
    
<Connection />
</Node>
</Diagram>

那么本文中的格式为

<Diagram>
<Node name=”node0” next=”node1”/>
<Node name
=”node1”/>
</Diagram>

 

创建工程

与前面的文章一样,利用这个ecore文件创建EMF Project,并根据生成的genmodel文件生成模型代码。

 

事件监听

    也与前面的文章一样,对每个模型创建一个对应的PropertySource文件,在EditPart中将PropertySource安装给模型,并在EditPart中监听模型更改事件,做相应处理。

 

编辑器

 

对模型而言,Connection对象是可有可无的,但是对编辑器而言,没有了Connection对象,如何创建连线对象呢?

所以我们需要写Connection对象,这个对象只在GEF框架下使用,用来描述两个节点间的next关系,不写入xml文件。

 

Connection.java

public class Connection {
    
protected Node source = null
;
    
protected Node target = null
;
    
public Connection() 
{
    }

    
    
public Node getSource() {
        
return
 source;
    }

    
    
public void setSource(Node newSource) {
        source 
=
 newSource;
    }


    
public Node getTarget() {
        
return
 target;
    }


    
public void setTarget(Node newTarget) {
        target 
=
 newTarget;
    }


}

 

有了 Connection对象,并不代表就能正确使用它。

 

首先,在NodeEditPart中定义两个变量以及相应的get方法

 

NodesEditPart.java

……
private
 ArrayList sourceConnections;
    
private
 ArrayList targetConnections;
    ……
public List getModelSourceConnections() 
{
        
if(this.sourceConnections==null
)
            
this.sourceConnections = new
 ArrayList();
        
return
 sourceConnections;
    }

    
public List getModelTargetConnections() {
        
if(this.targetConnections==null
)
            
this.targetConnections = new
 ArrayList();
        
return
 targetConnections;
    }

……

 

接着在ConnectionCreateCommand中,在执行这个命令的时候,给nodenext属性赋值:

public void execute() {
        connection 
= new
 Connection();
        connection.setSource(source);
        connection.setTarget(target);
        sourcePart.getModelTargetConnections().add(connection);
        targetPart.getModelSourceConnections().add(connection);
        
        source.getNext().add(target);
//模型属性改变,会刷新相关的对象

        targetPart.refresh();//模型没有改变,手工要求刷新
}

 

以上仅完成了创建一个Connection,完成了给Nodenext赋值。保存编辑器内容,可以查看一下结果。

 

    假如重新打开刚刚保存的文件,发现问题了吗?连线对象消失了。

       为什么呢?看看NodesEditPartFactory#createEditPart你会有收获的。

 

    EMFxml文件反序列化为了一个数据结构,很明显,这个数据结构中没有Connection对象。GEF将按照这个数据结构提供的模型来初始化编辑器内容,那么当然会丢失连线。

 

    解决方法:创建一个TargetAddConnectionTable,它用来保存未完成的连线。

 

NodesEditPartFactory.java

private EditPart getPartForElement(Object modelElement) {
        
if (modelElement instanceof Diagram) 
{
            
return new
 DiagramEditPart();
        }

        
if (modelElement instanceof Node) {
            NodesEditPart nep 
= new
 NodesEditPart();
            
            
//add target connections

            if(TargetAddConnectionTable.getInstance().contains((Node) modelElement)){
                List l 
=
 TargetAddConnectionTable.getInstance().getValue((Node) modelElement);
                
if(l!=null && l.size()>0)
{
                    
for(int i=0; i<l.size(); i++)
{
                        Connection c 
=
 (Connection) l.get(i);
                        nep.getModelSourceConnections().add(c);
                        TargetAddConnectionTable.getInstance().remove(c);
                    }

                }

            }

            
            
//add source connections
            List l = ((Node)modelElement).getNext();
            
if(l!=null && l.size()>0)
{
                
for(int i=0; i<l.size(); i++)
{
                    Connection c 
= new
 Connection();
                    c.setSource((Node) modelElement);
                    c.setTarget((Node) l.get(i));
                    nep.getModelTargetConnections().add(c);
                    TargetAddConnectionTable.getInstance().add(c, c.getTarget());
                }

            }

            
            
return nep;
        }

        
if (modelElement instanceof Connection) {
            
return new
 ConnectionEditPart();
        }

        
throw new RuntimeException(
                
"Can't create part for model element: "

                
+ ((modelElement != null? modelElement.getClass().getName() : "null"));
    }

 

TargetAddConnectionTable.java

public class TargetAddConnectionTable {
    
private Hashtable hs = null
;
    
private static TargetAddConnectionTable table=null
;
    
    
private TargetAddConnectionTable()
{
            hs
=new
 Hashtable();
    }

    
    
public static TargetAddConnectionTable getInstance(){
        
if(table==null
)
            table 
= new
 TargetAddConnectionTable();
        
return
 table;
    }

    
    
public void add(Connection connection, Node target ){
        hs.put( connection, target );
    }

    
    
public void remove(Connection connection){
        hs.remove(connection);
    }

    
    
public boolean contains(Node target){
        
return
 hs.containsValue(target);
    }

    
    
public List getValue(Node target){
        ArrayList result 
= new
 ArrayList();
        Enumeration em 
=
 hs.keys();
        Connection c 
= null
;
        
while(em.hasMoreElements())
{
            c 
=
 (Connection) em.nextElement();
            
if
(hs.get(c).equals(target))
                result.add(c);
        }

        
return result;
    }


}

 

再试试打开xml文件,应该出现连线了。

 

这里需要说明的是,由于本例比较简单,TargetAddConnectionTable没有出现太大问题。在实际应用中发现TergetAddConnectionTable有不足,也做过了更正。笔者在此不再修改代码。假如读者有兴趣,可以测测问题是什么,问题产生的原因以及如何解决。

 

其他

本例依然采用两个action来打开编辑器。

本例的运行结果与前面的例子是一样的,因为从编辑器的角度来看,没有变化。

 

源码

 

点击下载

 

运行环境

JDK1.4

Eclipse 3.1

GEF

EMF

 


posted on 2005-12-15 13:44 hopeshared 阅读(2696) 评论(0)  编辑  收藏 所属分类: EMF&GEF

只有注册用户登录后才能发表评论。


网站导航: