[GEF]实现模板功能

简介: 最近遇到一个需求是要在GEF应用里实现“模板”的功能,也就是像word那样在新建一个文件的时候,用户可以选择一个模板,然后以这个模板为基础进行编辑,而不用每次都从头开始。同时,用户要能够创建新模板和对模板进行编辑,在模板里可以指定一些对模型的限制,例如树的最大高度、子节点数目的限制,等等。

最近遇到一个需求是要在GEF应用里实现“模板”的功能,也就是像word那样在新建一个文件的时候,用户可以选择一个模板,然后以这个模板为基础进行编辑,而不用每次都从头开始。同时,用户要能够创建新模板和对模板进行编辑,在模板里可以指定一些对模型的限制,例如树的最大高度、子节点数目的限制,等等。

最简单的模板可以就是一个实例,以它为模板时创建的新实例就是这个实例的副本。这种情况下,模板编辑器就是实例编辑器。问题主要有两个,一是无法通过模板实现上述对实例的限制,二是除了扩展名以外,用户难以通过编辑器外观区分是在编辑模板还是编辑实例(本文中实例指原有的那个模型)。

更一般的模板可以这样设计:首先,模板模型和实例模型是很相似的,只是在实例模型的基础上,每个模板类多了一些用来限制实例的属性,因此,模板模型中的每个类应该是实例模型中对应类的子类,这样就解决了限制实例的问题。其次,对模板的编辑不能使用现有的Editor,而应该是对现有Editor的扩展,目的是区分两种编辑器的外观。

等一下,按照这个设计在实现上会有一些问题,在根据某个模板编辑实例的时候,必须知道模板信息,这样才能判断比如新增子节点操作是否可用。但是如果你某天打开一个实例时模板早已被删除了呢?我们实际需要的是,一旦实例被创建,它就与模板脱离关系,即使模板被修改和删除。因此,我认为模板和实例必须共享完全相同的模型,这样实例中就有完整的限制信息,并且还有一个额外的好处,它们的读取方法是完全一致的,可以节约不少工作量。

现在来看看实现。为了更加灵活,我们把模板单独作为一个新的Plugin,这样一是便于分开代码,二是很方便添加或移除模板功能(只要删掉模板Plugin就能移除模板功能)。因此,在模板Plugin里要额外指定对原来Plugin的依赖(在Plugin编辑器的dependencies属性页里),而原来Plugin里要确保Export了模板Plugin需要的所有包(在runtime属性页里)。

在这个Plugin里,创建一个继承实例Editor的新Editor(名为TemplateEditor)。怎样让这个Editor里显示的界面与实例Editor有所区别呢?最简单的一个方法是设置viewer的背景颜色,也就是覆盖configureGraphicalViewer()方法,加上下面这句:

None.gif getGraphicalViewer().getControl().setBackground( new  Color( null 250 250 200 )); 

如此一来,这个Editor的背景就是淡黄色了。但我还想进一步改造它,让每个节点的显示都与实例编辑器中不同。因为节点的figure是在editpart里创建的,所以就必须使用与原来不同的editpart,而editpart是通过partfactory创建的,所以要让viewer使用与原来不同的partfactory:

None.gif getGraphicalViewer().setEditPartFactory( new  TemplatePartFactory()); 

当然,我们还要通过继承原来的那些editpart得到一套新的editpart,在TemplatePartFactory的createEditPart()方法里返回它们。在新的editpart的createFigure()方法里,返回你希望的图形。

template1.gif

模板编辑(左图)和实例编辑(右图)

图形的问题解决了,还剩下另一个问题,应该只在编辑模板的时候在properties view里显示那些限制属性,而在编辑实例时不显示(这些属性在起作用,但不应该能被编辑)。按照GEF提供的例子,一般是在model类里定义用来控制哪些属性显示在properties view的IPropertyDescriptor数组,我们现在的情况是两个Plugin使用同一个model,这样就造成了矛盾。解决的办法是改为在editpart里定义IPropertyDescriptor数组。GEF的editpart通过getAdapter()方法返回实现IPropertySource接口的对象:

ExpandedBlockStart.gif public  Object getAdapter(Class key)  {
ExpandedSubBlockStart.gif    
if (IPropertySource.class == key) {
InBlock.gif        
if (getModel() instanceof IPropertySource)
InBlock.gif            
return getModel();
InBlock.gif        
if (getModel() instanceof IAdaptable)
InBlock.gif            
return ((IAdaptable)getModel()).getAdapter(key);
ExpandedSubBlockEnd.gif    }

InBlock.gif    
if (AccessibleEditPart.class == key)
InBlock.gif        
return getAccessibleEditPart();
InBlock.gif    
return null;
ExpandedBlockEnd.gif}

None.gif

可以看到当model类实现了IPropertySource时,就会返回model类。我们要覆盖这个方法,让它返回editpart本身,同时让editpart实现IPropertySource并把原来放在model类里的那些代码移动到editpart里。最好在原来的editpart里就做出修改,这样模板部分只要简单的继承下来并修改getPropertyDescriptors()等几个相关方法即可:

ExpandedBlockStart.gif public  Object getAdapter(Class key)  {
ExpandedSubBlockStart.gif    
if (IPropertySource.class == key) {
InBlock.gif        
return this;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
return super.getAdapter(key);
ExpandedBlockEnd.gif}

None.gif

template2.gif

模板模型的属性视图(左图)和实例模型的属性视图(右图)

要记住,为了让这些限制属性在实例编辑中起作用,必须修改原来的代码,增加这些额外的判断。之后,再在原来的CreationWizard里增加一个选择模板的page,模板功能就算实现了。按照这个思路,不需要额外写很多代码。

本文转自博客园八进制的博客,原文链接:[GEF]实现模板功能,如需转载请自行联系原博主。

相关文章
|
2月前
|
C++
CLion创建C/C++文件时添加模板代码
CLion创建C/C++文件时添加模板代码
CLion创建C/C++文件时添加模板代码
|
2月前
|
Python 容器
pyqt5-布局管理入门-信号和槽关联-菜单与工具栏-打包资源文件
pyqt5-布局管理入门-信号和槽关联-菜单与工具栏-打包资源文件
32 0
|
数据处理 C#
基于C#的ArcEngine二次开发39:GP工具的使用--界面、参数及示例代码
基于C#的ArcEngine二次开发39:GP工具的使用--界面、参数及示例代码
基于C#的ArcEngine二次开发39:GP工具的使用--界面、参数及示例代码
|
前端开发
【Ant Design Pro】使用ant design pro做为你的开发模板(七)如何动态加载菜单列表
【Ant Design Pro】使用ant design pro做为你的开发模板(七)如何动态加载菜单列表
719 0
【Ant Design Pro】使用ant design pro做为你的开发模板(七)如何动态加载菜单列表
|
Unix Linux Windows
Qwt开发笔记(一):Qwt简介、下载以及基础demo工程模板
QWT开发笔记系列整理集合,这是目前使用最为广泛的Qt图表类(Qt的QWidget代码方向只有QtCharts,Qwt,QCustomPlot),使用多年,系统性的整理,本系列旨在系统解说并逐步更新其各种Demo示例。
Qwt开发笔记(一):Qwt简介、下载以及基础demo工程模板
|
开发框架 图形学
Unity Hub 自定义一个创建新项目模板(Template)
Unity Hub 自定义一个创建新项目模板(Template)
424 1
Unity Hub 自定义一个创建新项目模板(Template)
|
小程序 API 数据安全/隐私保护
小程序模板及插件开发应用
本节对小程序模板和插件开发以及会涉及到的场景做了介绍。
小程序模板及插件开发应用
|
前端开发 容器
GEF入门实例_总结_06_为编辑器添加内容
一、前言 本文承接上一节:GEF入门实例_总结_05_显示一个空白编辑器 在上一节我们为我们的插件添加了一个空白的编辑器,这一节我们将为此编辑器添加内容。   二、GEF的MVC模式 在此只简单总结一下,后面会详细介绍。
1415 0
xal
|
Web App开发 JSON 前端开发
VSCode插件开发全攻略(八)代码片段、设置、自定义欢迎页
更多文章请戳[VSCode插件开发全攻略系列目录导航](https://www.atatech.org/articles/121864)。 # 代码片段 代码片段,也叫`snippets`,相信大家都不陌生,就是输入一个很简单的单词然后一回车带出来很多代码。平时大家也可以直接在vscode中创建属于自己的`snippets`: ![_W354xH542_](http://imag
xal
2496 0
|
BI 测试技术 数据库
Ireport报表插件使用之二——table组件(Ireport5.6.0版本)
Ireport如何使用table组件,其中list,子表,交叉表也是这种用法