精彩的人生

好好工作,好好生活

BlogJava 首页 新随笔 联系 聚合 管理
  147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

八进制写的关于GEF以及EMF的文章,对我当时的工作帮助很大。

 

我最初看的是他的关于GEF的文章,但是我的工作需要将GEFEMF结合,本文使用的例子就是根据八进制的Bloggefpractice改编而成。

 

 

定义模型

 

自从EMF出现以后,出现了一种新的说法:模型驱动的软件开发(例如Marlin),经过这段时间的研究开发,发现使用GEFEMF确实是这样,一旦模型定义好了,这个项目就基本定型了。

 

Ok,废话留着以后慢慢说,进入正题先。

 

首先,定义模型。在gefpractice这个例子中,模型很简单,只有三类元素:DiagramNodeConnection。他们之间的关系,用EMF的模型文件(ecore)定义出来就是这样的:

1.JPG

在做模型定义的时候,需要注意他们之间的包含关系。打开Properties视图,有一个
2.JPG

Containment属性需要格外注意,因为它将决定该接点是一个属性还是一个子节点。以上图为例,这个属性设置为true,那么xml文件的格式是

<Diagram>

<Node/>

</Diagram>

 

假如是false,那么就是

<Diagram nodes=”//node.0”/>

<Node />

 

由于有这个问题,在定义Node的时候就一定要注意sourceConnectionstargetConnections的这个属性,一个是true,另一个是false。(自己想想,为什么呢?^-^

 

当然模型的定义并不是只有这种方式,只要你将逻辑表述对了,这个模型就没有问题。

 

创建工程

 

用这个模型创建一个EMF Project。操作过程是New -> Project -> EMF Project -> 工程名称是eclipse.my.gefpractice -> 选择Ecore Model -> 选择定义好的nodeemf.ecoreload -> 其他的按照默认选择。这样,你的工作区就创建了这个工程。

这个新建的工程有个model文件夹,里面有nodeemf.ecorenodeemf.genmodel两个文件。用当前默认的编辑器打开nodeemf.genmodel文件,更改根节点(Nodeemf)的子节点(nodeemf)的属性(从属性视图中改)
3.JPG

接着,右键选择上图中的根节点,选择Generate Model Code。这样,模型的代码就全部生成了。

 

事件监听

 

一般,完全使用GEF的情况下,模型的监听是通过模型实现PropertySource来实现的。详细的请参看八进制的相关文章。但是本文中使用EMF来定义模型,那么原则上就不修改生成的代码。那么,这里利用Adapter来给模型“安装”属性。

 

这里给出一段示例代码

public class NodePropertySource extends AbstractPropertySource {
    
    
private static final String ID_X = "X";
    
private static final String ID_Y = "Y";
    
private static final String ID_NAME = "Name";
    
private static final String ID_VISIBLE = "Visible";
    
    
public NodePropertySource(Object model) {
        
super(model);
    }

    
    
private Node getNode() {
        
return (Node) getModel();
    }

    
    
public void createPropertyDescriptors(List descriptors) {
        descriptors.add(
new TextPropertyDescriptor(ID_X, ID_X));
        descriptors.add(
new TextPropertyDescriptor(ID_Y, ID_Y));
        descriptors.add(
new TextPropertyDescriptor(ID_NAME, ID_NAME));
        descriptors.add(
new TextPropertyDescriptor(ID_VISIBLE, ID_VISIBLE));
    }

    
    
public Object getPropertyValue(Object id) {
        
if(id == ID_X) {
            
return Integer.toString(getNode().getX());
        }

        
if(id == ID_Y) {
            
return Integer.toString(getNode().getY());
        }

        
if(id == ID_NAME) {
            
return getNode().getName();
        }

        
if(id == ID_VISIBLE) {
            
return Boolean.toString(getNode().isVisible());
        }

        
return null;
    }

    
    
public void setPropertyValue(Object id, Object value) {
        
if (id == ID_X) {
            getNode().setX(Integer.parseInt(value.toString()));
        }
 else if (id == ID_Y) {
            getNode().setY(Integer.parseInt(value.toString()));
        }
 else if (id == ID_NAME) {
            getNode().setName(value.toString());
        }
 else if(id == ID_VISIBLE) {
            getNode().setVisible(Boolean.getBoolean(value.toString()));
        }

    }

    
}


在这个模型对应的EditPart中安装这个PropertySource
public Object getAdapter(Class key) {
        
if (IPropertySource.class == key)
            
return new NodePropertySource(getModel());
        
return super.getAdapter(key);
    }


由于用
EMF定义的model本身就实现了notifier,故在本例中采用了EMF的事件监听机制。(采用GEF的事件监听机制也是可行的)
public void notifyChanged(Notification notification) {
        
int type = notification.getEventType();
        
int featureId = notification.getFeatureID(ModelPackage.class);
        
switch(type) {
        
case Notification.SET:
            
switch(featureId) {
            
case ModelPackage.NODE__X:
            
case ModelPackage.NODE__Y:
            
case ModelPackage.NODE__NAME:
            
case ModelPackage.NODE__VISIBLE:
                refreshVisuals();
                
break;
            }

        
case Notification.ADD:
        
case Notification.REMOVE:
            
switch(featureId) {
            
case ModelPackage.NODE__INPUTS:
                refreshSourceConnections();
                
break;
            
case ModelPackage.NODE__OUTPUTS:
                refreshTargetConnections();
                
break;
            }

        }

    }


编辑器

 

编辑器的其他重要组成部分,如Commandpolicy根原来的基本上没区别,这里就不再叙述了。

 

其他

 

本例中不能从左边的Explorer视图中打开这个编辑器,而是用了Open ActionNew Action。原因是本插件项目打包后可以加载到Rcp项目中。

 

本例的运行结果
4.JPG

除了上图中的问题外,还有一些小bug,呵呵,我比较懒,基本不用它,所以就没有改(Eclipse的懒加载法则)。这是我的一个面试考题,做这个例子,共用了1.5天。

 

 

源码

 

点击下载

 

环境

 

JDK1.4

Eclipse 3.1

GEF

EMF

posted on 2005-11-27 12:43 hopeshared 阅读(2400) 评论(7)  编辑  收藏 所属分类: EMF&GEF

Feedback

# re: emf&gef之一example.my.gefpractice 2005-11-29 17:20 wangzhiwei
你是北航软院哪一级的?  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2005-12-31 22:55 pandawang
http://www.eclipseworld.org/bbs/read.php?tid=785&fpage=1
刚刚看倒这个  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2006-01-02 12:21 hopeshared
那个也是我发的  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2007-01-05 16:25 alf
are you ?  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2007-01-05 16:29 alf
hehe!
时隔一年啊.....
才看到......
感谢
你在那个公司啊?
Boss 给你开多少啊....
只是问问//看看是否有前途啊...Eclipse
  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2007-05-15 09:56 jack.yuan
由于有这个问题,在定义Node的时候就一定要注意sourceConnections和targetConnections的这个属性,一个是true,另一个是false。

我没有想明白,请明示,谢谢!  回复  更多评论
  

# re: emf&gef之一example.my.gefpractice 2013-06-19 17:39 疯狂De年糕
@jack.yuan
虽然已经过去N年了,但是还是希望能给后来可能看到的人以回答。也许不理解之前看到博主的这句话的确会有些困惑
containment这个属性表示了两个EClass的强关联关系
sourceConnections和targetConnections如果将这个属性同时设置为true,那么很遗憾,由于emf的验证机制,一个Connection对象只能存在在这两个集合之一
如果同时设置为false,那么在写入xml作持久化时会报错,因为connection对象无法被识别为任何一个对象的子节点被保存
解决方法之一即一个设为true,一个设为false。另一种方式参考八进制的方式,两个都设置为false,但是需要多一个connections集合,diagram除与nodes结合关联外还与这个connections集合关联,当然这里的containment属性为true  回复  更多评论
  


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


网站导航: