`
liugang594
  • 浏览: 985551 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

GEF理解系列八

    博客分类:
  • GEF
阅读更多
这一节,我们继续来看一下连接线。

一、带箭头的连接线

带箭头本身其实通常来说都不是模型需要的,只是为了看起来方便而已。呵呵。这里我们就做这样的假设。所以要实现一个带箭头的连接线,只要让连线figure加一个箭头就可以了。
之前我们建了一个抽象的连接模型,但是一直只有一个子类。这里它终于又要派上用场了。
我们再建一个连接线模型:ArrowConnectionModel,让它也继承AbstractConnectionModel。这就够了,模型就建好了。然后我们再建一个ArrowConnectionEditPart,继承AbstractConnectionModelEditPart,这就是ArrowConnectionModel的EditPart类。
为了让连接带箭头,我们就不能再用缺省的连接线了,所以我们重写ArrowConnectionEditPart的createFigure()方法如下:
 protected IFigure createFigure() {
       PolylineConnection connection = super.createFigure() ;
       PolygonDecoration decoration = new PolygonDecoration();
       connection.setTargetDecoration(decoration);
       return connection;
 }
因为我们是要装饰target端,所以选择setTargetDecoration方法,也可以装饰source端。这都无所谓。
最后在EditPartFactory里追加这一对模型与控件器:
if(model instanceof ArrowConnectionModel){
   ArrowConnectionEditPart editPart = new ArrowConnectionEditPart();
   editPart.setModel(model);
   return editPart;
}
这样我们整个带箭头的连接线模型就建好了。最后为了能创建这个模型,我们需要在调色板上追加创建工具。还是修改Editor的getPaletteRoot()方法,追加一个:
....
   ConnectionCreationToolEntry arrowConnection = new ConnectionCreationToolEntry(
    "plain", "this is arrow connection", new SimpleFactory(
      ArrowConnectionModel.class), Activator
      .getImageDescriptor("icons/arrowLine.gif"), Activator
      .getImageDescriptor("icons/arrowLine.gif"));
  
  selectionGroup.add(arrowConnection);
....
运行结果 :

arrowLine

图一

二、增加连接线的路由点

现在,我们所有的连线都是直来直去的,不会打弯。这样的一个坏处就是,线会在图上画过。所以为了能更改连接线的路径,我们需要让连接线支持路由点。首先先不考虑其他的,我们单纯创建一个带路由点的线。

背景知识

要想让线支持路由,我们就需要为PolylineConnection设置新的ConnectionRouter对象,因为缺省的是ConnectionRouter.NULL;我们可以找一个ConnectionRouter的子类。这里我们设置为:BendpointConnectionRouter。

所以下面要怎么支持路由点,就由这个BendpointConnectionRouter说了算了。我们看一下BendpointConnectionRouter的源码,看看它是怎么取得和设置路由点的:

首先在方法:setConstraint(Connection connection, Object constraint)的实现里,以connection为键值,将所有这个connection的constraint放到一个Map里去了。

然后看方法:route(Connection conn);这就是用来具体设置路由点的。可以看到它先以connection为键,从Map里取出所有的constraint,然后把这个constraint强制为一个List,最后从List里的取出的对象再强制为一个BendPoint对象。

从上面,我们基础可以猜测,在以BendpointConnectionRouter为连接路由的情况下,我们应该怎么设置路由点了。如下:

  List list = new ArrayList();
  list.add(new AbsoluteBendpoint(10,30));
  connection.setRoutingConstraint(list);

其中,AbsoluteBendpoint为BendPoint类的一个子类。

实现

由了上面的背景知识,要实现就不难了。不过首先我们修改一下模型。为了记录连接线的路由点,我们需要加一个属性。这里我们都以AbstractConnectionModel来做,因为我们可以假设所有的线都需要支持路由点。我假设我们都已经较熟练了,所以这次我们写得全面一些:

首先我们让我们AbstractConnectionModel继承AbstractModel,因为我们要涉及到了事件通知了。

其次,在AbstractConnectionModel里追加以下内容用以支持增加、移除和移动路由点:

  public static final String P_CONSTRAINT = "p_constraint";
 private List<Bendpoint> constraints = new ArrayList<Bendpoint>();

 public List<Bendpoint> getConstraints() {
  return constraints;
 }

 public void addConstraint(int index, Bendpoint bendpoint) {
  if (!constraints.contains(bendpoint)) {
   constraints.add(index, bendpoint);
   firePropertyChange(P_CONSTRAINT, null, bendpoint);
  }
 }
 
 public void setConstraint(int index, Bendpoint bendpoint) {
  if (!constraints.contains(bendpoint)) {
   constraints.set(index, bendpoint);
   firePropertyChange(P_CONSTRAINT, null, bendpoint);
  }
 }

 public void removeConstraint(int index) {
  Bendpoint bendpoint = constraints.get(index);
  constraints.remove(index);
  firePropertyChange(P_CONSTRAINT, bendpoint, null);
 }

有一点需要注意的:为了保证操作后的路由点显示正确,我们在操作时需要保证操作结点的顺序。所以看上面三个处理方法中,都是基于index来实现的。

接下来还是实现Policy和Command。这下我们应该可以很快就找到我们的Policy了:BendpointEditPolicy。而且我们也应该知道它应该安在哪了:AbstractConnectionModelEditPart。如下:

installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE, new ConnectionBendpointEditPolicy());

最后就是实现Policy里的三个命令。这里我就不一一写了。样子都差不多。就举一个增加的例子:

public class CreateBendPointCommand extends Command {

 private AbstractConnectionModel model;

 private AbsoluteBendpoint point;
 
 private int index;

 public CreateBendPointCommand(AbstractConnectionModel model, Point point, int index) {
  super();
  this.model = model;
  this.point = new AbsoluteBendpoint(point);
  this.index = index;
 }

 @Override
 public void execute() {
  model.addConstraint(index,point);
 }

 @Override
 public void undo() {
  model.removeConstraint(index);
 }
}

最后完成我们的Policy:

  @Override
 protected Command getCreateBendpointCommand(BendpointRequest request) {
  CreateBendPointCommand command = new CreateBendPointCommand(
    (AbstractConnectionModel) request.getSource().getModel(),request.getLocation(),
    request.getIndex());
  return command;
 }

 @Override
 protected Command getDeleteBendpointCommand(BendpointRequest request) {
  RemoveBendPointCommand command = new RemoveBendPointCommand(
    (AbstractConnectionModel) request.getSource().getModel(),
    request.getLocation(),request.getIndex());
  return command;
 }

 @Override
 protected Command getMoveBendpointCommand(BendpointRequest request) {
  MoveBendPointCommand command = new MoveBendPointCommand(
    (AbstractConnectionModel) request.getSource().getModel(),
    request.getIndex(), request.getLocation());
  return command;
 }

 

按照背景知识里的说法,为了支持路由,我们需要给连接线设置一个ConnectionRouter。所以个性createFigure()方法如下:

 @Override
 protected IFigure createFigure() {
  PolylineConnection connection = new PolylineConnection();
  connection.setConnectionRouter(new BendpointConnectionRouter());
  return connection;
 }

好,我们可以试一下现在的效果: 已经可以用鼠标拖出一个一个的路由点了。只是放开后又恢复了。这次好像我们已经写了监听啊。咋回事呢?玩我的吧?发出事件写了是没错的,不过还没完成事件监听和处理。下面我们就要完成我们的事件处理。

修改AbstractConnectionModelEditPart,让它实现PropertyChangeListener监听,然后在propertyChange()方法可以这样写:

 public void propertyChange(PropertyChangeEvent evt) {
  if(evt.getPropertyName().equals(AbstractConnectionModel.P_CONSTRAINT)){
   refreshConnectionRoutes();
  }
 }

注意,这个refreshConnectionRoutes()是我自己写的。editPart本身并不带。好了,现在的任务就是怎么完成这个方法了。终于到最后一步了,死了也值了,哈哈哈哈。

我是这样完成的:

 private void refreshConnectionRoutes() {
  List<Bendpoint> constraints = ((AbstractConnectionModel)getModel()).getConstraints();
  ((PolylineConnection)getFigure()).setRoutingConstraint(constraints);
 }

 再试一下!!!!!唉呀,怎么回来啊,还是没出来。跟踪一下:它根本就没进我的propertyChange()方法里来嘛。知道了,是因为我没有把监听加上。在AbstractConnectionModelEditPart,追加以下内容即可(老东西,照着写就行了):

 @Override
 public void activate() {
  super.activate();
  ((AbstractConnectionModel)getModel()).addPropertyChangeListener(this);
 }
 @Override
 public void deactivate() {
  ((AbstractConnectionModel)getModel()).removePropertyChangeListener(this);
  super.deactivate();
 }

好了,这下肯定会出来了。我保证!!!效果图如下:

bendpoint

分享到:
评论
1 楼 gaddma 2010-03-02  
您好,关于gef中的bendpoint,我想实现一个基于它的连线路由器,但是要求最后的拖拽样式和visio的很像,有没有比较好的建议,或者对于继承bendpoint接口要求实现的一些方法之类的。
[/color][color=darkred][/color][color=darkred][color=darkred][/color]

相关推荐

    GEF理解系列三

    在GEF(Graphical Editing Framework)中,理解其工作流程对于开发图形编辑工具至关重要。GEF主要用于构建基于SWT和JFace的图形用户界面,它提供了丰富的功能来处理图形元素的绘制、操作和交互。本篇文章将深入探讨...

    GEF理解系列二

    【GEF理解系列二】是深入学习GEF框架的第二部分,主要讲解如何配置和初始化Editor,以及如何创建多层结构以支持添加多个图形。GEF(Graphical Editing Framework)是一个用于构建图形编辑器的开源框架,常用于开发...

    Eclipse插件开发:GEF入门系列宝典

    在"GEF入门系列宝典"中,我们将深入探讨如何使用GEF进行Eclipse插件开发,以创建自定义的图形编辑器。以下是一些关键知识点: 1. **Eclipse插件体系结构**: - 插件是Eclipse的核心组成部分,它们通过OSGi模块系统...

    GEF入门必读 GEF入门系列 GEF-whole-upload

    本资料集旨在为初学者提供一个全面的入门指南,帮助理解GEF的基础概念和实现方法。 GEF的核心功能是提供了一套强大的组件和API,用于创建可交互的、图形式的用户界面。通过使用GEF,开发者可以轻松地创建出具有拖放...

    GEF入门系列 pdf 格式资料

    **GEF入门系列 PDF 格式资料** GEF(Graphical Editing Framework)是Eclipse开源组织推出的一个图形编辑框架,主要用于构建可视化的图形编辑...在阅读过程中,建议结合实际编程实践,以便更好地理解和掌握GEF的精髓。

    GEF入门系列

    - 示例代码:Eclipse项目中包含多个GEF示例,是学习和理解GEF的好资料。 - 在线教程:互联网上有许多博客和教程,针对不同水平的学习者提供了丰富的教学内容。 通过这个GEF入门系列,你可以逐步掌握如何利用GEF...

    EMF_GEF_入门系列

    本入门系列旨在帮助初学者快速理解并掌握这两个强大的工具。 EMF是Eclipse项目的一部分,它提供了一种模型驱动的开发方式。EMF允许开发者创建、存储和操作数据模型,这些模型可以用来表示复杂的数据结构或业务逻辑...

    Eclipse插件开发--gef开发指南与入门系列宝典

    "GEF入门系列宝典.doc"可能更侧重于实践,提供逐步的教程和实例,帮助初学者快速上手。它可能包含一些实际的代码示例,教你如何构建一个简单的图形编辑器,例如绘制流程图或网络拓扑图。 通过学习这两份资料,你将...

    GEF教程

    然而,随着“八进制”Blog上一系列GEF教程的出现,这一状况得到了显著改善。 #### GEF框架的核心价值 GEF框架的核心价值在于它能够提供一套完整的图形编辑解决方案,包括但不限于模型管理、视图渲染、编辑操作、...

    GEF-ALL-3.7+GEF-ALL-3.8+GEF_Draw2d学习资料

    2. "GEF入门系列(一、Draw2D).doc" 可能是一个逐步的教学系列,从基础的Draw2D开始,逐步引入GEF的概念和应用。 3. "如何在Eclipse3.3.1.1中安装VE,emf,GEF插件.doc" 提供了在特定版本的Eclipse中安装相关插件的步骤...

    GEF入门学习例子

    这个入门学习例子旨在帮助初学者理解GEF的基本用法和核心概念,通过实例展示如何利用GEF实现工具栏、菜单栏、属性栏以及图形的交互功能,如移动、删除、撤销、连线等,并涵盖了大纲视图和鹰眼功能的实现。...

    GEF.rarGEF.rar

    8. **手势和工具(Gesture and Tool)**:GEF定义了一系列工具,如选择工具、移动工具等,以及手势识别机制,以响应用户的交互行为。 9. **可扩展性**:GEF的设计允许通过插件机制添加新的功能或图形元素,极大地...

    简单gef框架

    4. **流程设计基础**:在gef框架下进行流程设计,首先要明确流程的目标和步骤,这可能涉及到对程序逻辑的理解和拆解,将复杂的任务分解为一系列可执行的子任务。这通常需要扎实的编程基础和问题解决能力。 5. **gef...

    gef-step3.zip_3gef_GEF eclipse_GEF-step2_gef_gef-st

    **3gef**可能是这个系列教程的一个特定版本或者阶段,强调了对GEF的三次迭代改进或深化理解。这可能涉及到更高级的功能,如图形的动态更新、自定义手势识别或者与其他Eclipse插件的集成。 **gef_eclipse**标签表明...

    eclipse_gef_example.rar

    这个"eclipse_gef_example.rar"压缩包提供了一系列的例子,帮助开发者更好地理解和掌握GEF框架。以下是对每个部分的详细解释: 1. **org.eclipse.gef.examples.text** 这个部分主要展示了如何在GEF环境中处理文本...

    gef工程代码

    总结来说,gef工程代码是一个强大的学习资源,对于想要提升调试技能和深入理解代码运行机制的开发者来说,是不可多得的宝藏。通过深入研究和实践,你将能够掌握gef的精髓,从而在日常开发和调试工作中更加游刃有余。

    GEF 入门教程 中文版

    ### GEF(Graphical Editing Framework)入门教程知识点详解 #### 一、简介 GEF(Graphical Editing Framework),即图形编辑框架,是一种基于...希望您能够通过实践加深对GEF的理解,并成功地应用于自己的项目中。

    GEF入门实例代码2《Eclipse插件开发》中实例

    GEF包含了一系列的类和接口,如Command、Model、View、EditPart、Figure等,它们共同构成了图形编辑的基础架构。Command代表可撤销/重做的操作,Model表示数据模型,View负责显示图形,EditPart作为模型和视图之间...

Global site tag (gtag.js) - Google Analytics