现在开始学习GEF,我觉得学习GEF是非常有挑战性和从满乐趣的,我希望能够把平时的学习进程记录下来,既可以帮助入门者,也做为自己的笔记,能够加深自己对GEF的理解.
现在网上有许多GEF的教程,有些非常优秀,比如dudu的GEF教程,非常适合入门,八进制的教程,讲解了许多高级知识点,但是我还是觉得有很多他们的教程中没有或是说得不详细,我的目的不是取代他们的教程,而是一个补充:P
因为大部分教程都是以连接为重点,而我希望做一些和连接无关的GEF例子.
比如这个例子就是用了draw2d自带的ToolbarLayout来为column布局.
代码下载
1.model
作为开始,model非常简单,uml图如下:
为了让model的变化能够通知给editpart,我让所有model继承了AbstractModel类:
AbstractModel.java
public
class
AbstractModel
{
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public void firePropertyChange(String propName, Object oldValue,
Object newValue) {
listeners.firePropertyChange(propName, oldValue, newValue);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
}
具体的model代码就不贴在这里了.可以查看下载plugin中的源代码.
2.EditPart:
写好model的代码后,开始写每个model对应的EditPart,这里分别是ContentEditPart和ColumnEditPart:
因为ContentEditPart作为最高层容器,我们是在它的上面添加Column,所以它负责为Column布局,给它设置ToolbarLayout.
首先给所有editPart写一个超类,让它自动注册为model的listener:
AbstractModel.java
public
class
AbstractModel
{
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener){
listeners.addPropertyChangeListener(listener);
}
public void firePropertyChange(String propName, Object oldValue, Object newValue){
listeners.firePropertyChange(propName, oldValue, newValue);
}
public void removePropertyChangeListener(PropertyChangeListener listener){
listeners.removePropertyChangeListener(listener);
}
}
然后开始写每个EditPart:
下面是ContentEditPart中的createFigure()方法:
ContentEditPart.java
@Override
protected
IFigure createFigure()
{
Layer layer = new FreeformLayer();
ToolbarLayout layout = new ToolbarLayout();
layout.setVertical(false);
layout.setSpacing(5);
layout.setStretchMinorAxis(true);
layer.setLayoutManager(layout);
layer.setBorder(new MarginBorder(5));
return layer;
}
Column的EditPart的createFigure就简单得多,只是一个Label,如下所示:
ColumnEditPart.java
@Override
protected
IFigure createFigure()
{
Column column = (Column) getModel();
Label label = new Label();
label.setText(column.getName());
label.setBorder(new CompoundBorder(new LineBorder(),
new MarginBorder(3)));
label.setBackgroundColor(ColorConstants.green);
label.setOpaque(true);
label.setSize(40, 60);
return label;
}
3.PartFactory:
PartFactory就象其名字一样,很简单的Factory对象,用来连接EditPart和Model,只有一个方法,createEditPart()如下:
PartFactory.java
public
EditPart createEditPart(EditPart context, Object model)
{
if (model instanceof Content){
EditPart part = new ContentEditPart();
part.setModel(model);
return part;
}else if (model instanceof Column){
EditPart part = new ColumnEditPart();
part.setModel(model);
return part;
}
throw new RuntimeException();
}
4.Command:
然后就是开始写Command了.
这个例子只是简单的把Column加入到编辑器中,所以只有一个CreateCommand:
CreateCommand.java
@Override
public
void
execute()
{
content.addChild(column);
}
4.1command执行后,model将发生变化,那么editPart如何得到通知并将变化转交给figure呢?
在这里editPart中加入以下两个方法.(EditPart是实现了PropertyChangeListener接口)
ContentEditPart.java
@Override
protected
List getModelChildren()
{
return ((Content) getModel()).getChildren();
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
public
void
propertyChange(PropertyChangeEvent evt)
{
if (evt.getPropertyName().equals(Content.P_CHILDREN))
refreshChildren();
}
5.Policy:
tool接收到request,然后发给对应的EditPart,EditPart会遍历所有安装过的Policy,找到能够处理request的Policy,然后构造Command,并在适当时刻执行Command.
因为这个例子中的最高层Container我们使用的是ToolbarLayout,所以我这里没有象以往一样安装XYLayout可以使用的XYLayoutEditPolicy,而是选择了继承OrderedLayoutEditPolicy .为什么呢?
因为Layout是来安排每个child的位置,而XYLayout是用坐标进行绝对定位,所以不仅model需要拥有对应的坐标属性,而且相应的policy在创建Command时需要得到相应的坐标信息.这个例子里面我们使用的是ToolbarLayout,它不是以坐标来定位的,所以我们不需要用XYLayoutEditPolicy.
GEF中自带的LayoutPolicy结构如下:
这样可以很清晰得看出来GEF为不同的Layout已经设计过不同的policy,Draw2D中主要有以坐标定位的XYLayout和按位置定位的ToolbarLayout和FlowLayout.(后两者的区别主要是FlowLayout可以转行).暂时我是用的ToolbarLayout最简单的方式,所以选择了继承OrderedLayoutEditPolicy.
因为只要实现创建Column,所以我只覆写了OrderedLayoutEditPolicy里的getCreateCommand方法,如下:
CustomOrderedLayoutEditPolicy.java
@Override
protected
Command getCreateCommand(CreateRequest request)
{
CreateCommand command = new CreateCommand();
Column column = (Column) request.getNewObject();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
command.setContent((Content) getHost().getModel());
command.setColumn(column);
return command;
}
5.1安装policy
写好policy后就是安装它到editPart上了,回到ContentEditPart,覆写createEditPolicies方法:
ContentEditPart.java
@Override
protected
void
createEditPolicies()
{
installEditPolicy(EditPolicy.LAYOUT_ROLE, new CustomOrderedLayoutEditPolicy());
}
6.Editor:
主要是getPaletteRoot方法:
Editor.java
@Override
protected
PaletteRoot getPaletteRoot()
{
PaletteRoot root = new PaletteRoot();
PaletteGroup toolGroup = new PaletteGroup("tools");
ToolEntry tool = new SelectionToolEntry();
toolGroup.add(tool);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
tool = new MarqueeToolEntry();
toolGroup.add(tool);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
PaletteDrawer drawer = new PaletteDrawer("draw");
ImageDescriptor descriptor = ImageDescriptor
.getMissingImageDescriptor();
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
CreationToolEntry creationEntry = new CreationToolEntry(
"draw column", "create column", new SimpleFactory(
Column.class), descriptor, descriptor);
drawer.add(creationEntry);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
root.add(toolGroup);
root.add(drawer);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
return root;
}
参考资源:
eclipse cvs上的draw2d examples
gef源代码
dudu的教程
八进制的教程
现在网上有许多GEF的教程,有些非常优秀,比如dudu的GEF教程,非常适合入门,八进制的教程,讲解了许多高级知识点,但是我还是觉得有很多他们的教程中没有或是说得不详细,我的目的不是取代他们的教程,而是一个补充:P
因为大部分教程都是以连接为重点,而我希望做一些和连接无关的GEF例子.
比如这个例子就是用了draw2d自带的ToolbarLayout来为column布局.
代码下载
![](https://p-blog.csdn.net/images/p_blog_csdn_net/starshus/geftest2overview.gif)
1.model
作为开始,model非常简单,uml图如下:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/starshus/geftest2_uml.gif)
为了让model的变化能够通知给editpart,我让所有model继承了AbstractModel类:
AbstractModel.java
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
具体的model代码就不贴在这里了.可以查看下载plugin中的源代码.
2.EditPart:
写好model的代码后,开始写每个model对应的EditPart,这里分别是ContentEditPart和ColumnEditPart:
因为ContentEditPart作为最高层容器,我们是在它的上面添加Column,所以它负责为Column布局,给它设置ToolbarLayout.
首先给所有editPart写一个超类,让它自动注册为model的listener:
AbstractModel.java
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
然后开始写每个EditPart:
下面是ContentEditPart中的createFigure()方法:
ContentEditPart.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
ColumnEditPart.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
PartFactory就象其名字一样,很简单的Factory对象,用来连接EditPart和Model,只有一个方法,createEditPart()如下:
PartFactory.java
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
然后就是开始写Command了.
这个例子只是简单的把Column加入到编辑器中,所以只有一个CreateCommand:
CreateCommand.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
4.1command执行后,model将发生变化,那么editPart如何得到通知并将变化转交给figure呢?
在这里editPart中加入以下两个方法.(EditPart是实现了PropertyChangeListener接口)
ContentEditPart.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
5.Policy:
tool接收到request,然后发给对应的EditPart,EditPart会遍历所有安装过的Policy,找到能够处理request的Policy,然后构造Command,并在适当时刻执行Command.
因为这个例子中的最高层Container我们使用的是ToolbarLayout,所以我这里没有象以往一样安装XYLayout可以使用的XYLayoutEditPolicy,而是选择了继承OrderedLayoutEditPolicy .为什么呢?
因为Layout是来安排每个child的位置,而XYLayout是用坐标进行绝对定位,所以不仅model需要拥有对应的坐标属性,而且相应的policy在创建Command时需要得到相应的坐标信息.这个例子里面我们使用的是ToolbarLayout,它不是以坐标来定位的,所以我们不需要用XYLayoutEditPolicy.
GEF中自带的LayoutPolicy结构如下:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/starshus/layoutpolicy.gif)
这样可以很清晰得看出来GEF为不同的Layout已经设计过不同的policy,Draw2D中主要有以坐标定位的XYLayout和按位置定位的ToolbarLayout和FlowLayout.(后两者的区别主要是FlowLayout可以转行).暂时我是用的ToolbarLayout最简单的方式,所以选择了继承OrderedLayoutEditPolicy.
因为只要实现创建Column,所以我只覆写了OrderedLayoutEditPolicy里的getCreateCommand方法,如下:
CustomOrderedLayoutEditPolicy.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
写好policy后就是安装它到editPart上了,回到ContentEditPart,覆写createEditPolicies方法:
ContentEditPart.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
主要是getPaletteRoot方法:
Editor.java
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
参考资源:
eclipse cvs上的draw2d examples
gef源代码
dudu的教程
八进制的教程