zoukankan      html  css  js  c++  java
  • [Eclipse]GEF入门系列(一、Draw2D)

    鸡年第一天,首先向大家拜个年——恭祝新春快乐,万事如意。一年之计在于春,你对新的一年有什么安排呢?好的,下面还是进入正题吧。

    关于Java2D相信大家都不会陌生,它是基于AWT/Swing的二维图形处理包, JDK附带的示例程序向我们展示了Java2D十分强大的图形处理能力。在Draw2D出现以前,SWT应用程序在这方面一直处于下风,而Draw2D这个SWT世界里的Java2D改变了这种形势。

    可能很多人还不十分了解GEF和Draw2D的关系:一些应用程序是只使用Draw2D,看起来却和GEF应用程序具有相似的外观。原因是什么,下面先简单解释一下:

    GEF是具有标准MVC(Model-View-Control)结构的图形编辑框架,其中Model由我们自己根据业务来设计,它要能够提供某种模型改变通知的机制,用来把Model的变化告诉Control层;Control层由一些EditPart实现,EditPart是整个GEF的核心部件,关于EditPart的机制和功能将在以后的帖子里介绍;而View层(大多数情况下)就是我们这里要说的Draw2D了,其作用是把Model以图形化的方式表现给使用者。

    虽然GEF可以使用任何图形包作为View层,但实际上GEF对Draw2D的依赖是很强的。举例来说:虽然EditPart(org.eclipse.gef.EditPart)接口并不要求引入任何Draw2D的类,但我们最常使用的AbstractGraphicalEditPart类的createFigure()方法就需要返回IFigure类型。由于这个原因,在GEF的SDK中索性包含了Draw2D包就不奇怪了,同样道理,只有先了解Draw2D才可能掌握GEF。

    这样,对于一开始提出的问题可以总结如下:Draw2D是基于SWT的图形处理包,它适合用作GEF的View层。如果一个应用仅需要显示图形,只用Draw2D就够了;若该应用的模型要求以图形化的方式被编辑,那么最好使用GEF框架。

    现在让我们来看看Draw2D里都有些什么,请看下图。


    图1 Draw2D的结构

    Draw2D通过被称为LightweightSystem(以下简称LWS)的部件与SWT中的某一个Canvas实例相连,这个Canvas在Draw2D应用程序里一般是应用程序的Shell,在GEF应用程序里更多是某个Editor的Control(createPartControl()方法中的参数),在界面上我们虽然看不到LWS的存在,但其他所有能看到的图形都是放在它里面的,这些图形按父子包含关系形成一个树状的层次结构。

    LWS是Draw2D的核心部件,它包含三个主要组成部分:RootFigure是LWS中所有图形的根,也就是说其他图形都是直接或间接放在RootFigure里的;EventDispatcher把Canvas上的各种事件分派给RootFigure,这些事件最终会被分派给适当的图形,请注意这个RootFigure和你应用程序中最顶层的IFigure不是同一个对象,前者是看不见的被LWS内部使用的,而后者通常会是一个可见的画布,它是直接放在前者中的;UpdateManager用来重绘图形,当Canvas被要求重绘时,LWS会调用它的performUpdate()方法。

    LWS是连接SWT和Draw2D的桥梁,利用它,我们不仅可以轻松创建任意形状的图形(不仅仅限于矩形),同时能够节省系统资源(因为是轻量级组件)。一个典型的纯Draw2D应用程序代码具有类似下面的结构:

    //创建SWT的Canvas(Shell是Canvas的子类) 
    Shell shell = new Shell(); 
    shell.open(); 
    shell.setText("A Draw2d application"); 
    //创建LightweightSystem,放在shell上 
    LightweightSystem lws = new LightweightSystem(shell); 
    //创建应用程序中的最顶层图形 
    IFigure panel = new Figure(); 
    panel.setLayoutManager(new FlowLayout()); 
    //把这个图形放置于LightweightSystem的RootFigure里 
    lws.setContents(panel);  
     
    //创建应用程序中的其他图形,并放置于应用程序的顶层图形中 
    panel.add(); 
    while (!shell.isDisposed ()) { 
    if (!display.readAndDispatch ()) 
       display.sleep (); 
    }

    接下来说说图形,Draw2D中的图形全部都实现IFigure(org.eclipse.draw2d.IFigure)接口,这些图形不仅仅是你看到的屏幕上的一块形状而已,除了控制图形的尺寸位置以外,你还可以监听图形上的事件(鼠标事件、图形结构改变等等,来自LWS的EventDispatcher)、设置鼠标指针形状、让图形变透明、聚焦等等,每个图形甚至还拥有自己的Tooltip,十分的灵活。

    Draw2D提供了很多缺省图形,最常见的有三类:1、形状(Shape),如矩形、三角形、椭圆形等等;2、控件(Widget),如标签、按钮、滚动条等等;3、层(Layer),它们用来为放置于其中的图形提供缩放、滚动等功能,在3.0版本的GEF中,还新增了GridLayer和GuideLayer用来实现"吸附到网格"功能。在以IFigure为根节点的类树下有相当多的类,不过我个人感觉组织得有些混乱,幸好大部分情况下我们只用到其中常用的那一部分。


    图2 一个Draw2D应用程序

    每个图形都可以拥有一个边框(Border),Draw2D所提供的边框类型有GroupBoxBorder、TitleBarBorder、ImageBorder、ButtonBorder,以及可以组合两种边框的CompoundBorder等等,在Draw2D里还专门有一个Insets类用来表示边框在图形中所占的位置,它包含上下左右四个整型数值。

    我们知道,一个图形可以包含很多个子图形,这些被包含的图形在显示的时候必须以某种方式被排列起来,负责这个任务的就是父图形的LayoutManager。同样的,Draw2D已经为我们提供了一系列可以直接使用的LayoutManager,如FlowLayout适合用于表格式的排列,XYLayout适合让用户在画布上用鼠标随意改变图形的位置,等等。如果没有适合我们应用的LayoutManager,可以自己定制。每个LayoutManager都包含某种算法,该算法将考虑与每个子图形关联的Constraint对象,计算得出子图形最终的位置和大小。

    图形化应用程序的一个常见任务就是在两个图形之间做连接,想象一下UML类图中的各种连接线,或者程序流程图中表示数据流的线条,它们有着不同的外观,有些连接线还要显示名称,而且最好能不交叉。利用Draw2D中的Router、Anchor和Locator,可以实现多种连接样式,其中Router负责连接线的外观和操作方式,最简单的是设置Router为null(无Router),这样会使用直线连接,其他连接方式包括折线、具有控制点的折线等等(见图3),若想控制连接线不互相交叉也需要在Router中作文章。Anchor控制连接线端点在图形上的位置,即"锚点"的位置,最易于使用的是ChopBoxAnchor,它先假设图形中心为连接点,然后计算这条假想连线与图形边缘的交汇点作为实际的锚点,其他Anchor还有EllipseAnchor、LabelAnchor和XYAnchor等等;最后,Locator的作用是定位图形,例如希望在连接线中点处以一个标签显示此连线的名称/作用,就可以使用MidpointLocator来帮助定位这个标签,其他Locator还有ArrowLocator用于定位可旋转的修饰(Decoration,例如PolygonDecoration)、BendpointerLocator用于定位连接控制点、ConnectionEndpointLocator用于定位连接端点(通过指定uDistance和vDistance属性的值可以设置以端点为原点的坐标)。


    图3 三种Router的外观

    此外,Draw2D在org.eclipse.draw2d.geometry包里提供了几个很方便的类型,如Dimension、Rectangle、Insets、Point和PointList等等,这些类型既在Draw2D内部广泛使用,也可以被开发人员用来简化计算。例如Rectangle表示的是一个矩形区域,它提供getIntersection()方法能够方便的计算该区域与另一矩形区域的重叠区域、getTransposed()方法可以得到长宽值交换后的矩形区域、scale()方法进行矩形的拉伸等等。在自己实现LayoutManager的时候,由于会涉及到比较复杂的几何计算,所以更推荐使用这些类。

    以上介绍了Draw2D提供的大部分功能,利用这些我们已经能够画出十分漂亮的图形了。但对大多数实际应用来说这样还远远不够,我们还要能编辑它,并把对图形的修改反映到模型里去。为了漂亮的完成这个艰巨任务,GEF绝对是不二之选。从下一次开始,我们将正式进入GEF的世界。

    参考资料:

  • 相关阅读:
    TCP源码—连接建立
    TCP系列02—连接管理—1、三次握手与四次挥手
    TCP系列01—概述及协议头格式
    ubuntu软件管理apt与dpkg
    318. Maximum Product of Word Lengths
    317. Shortest Distance from All Buildings
    316. Remove Duplicate Letters
    315. Count of Smaller Numbers After Self
    314. Binary Tree Vertical Order Traversal
    313. Super Ugly Number
  • 原文地址:https://www.cnblogs.com/bjzhanghao/p/103595.html
Copyright © 2011-2022 走看看