IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Open source  >

GEF 进阶,第 6 部分: Feedback

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 中级

马 若劼 (maruojie@cn.ibm.com), 软件工程师, IBM 中国软件开发中心

2007 年 10 月 25 日

Feedback(反馈)指的是GEF中对用户操作的一种回显,这种回显一般来说是视觉上的,但是也不一定。完全可以由用户来定制。本文介绍Feedback的相关概念,并通过实例演示其定制过程。

Feedback(反馈)指的是GEF中对用户操作的一种回显,这种回显一般来说是视觉上的,但是也不一定。完全可以由用户来定制。本文介绍Feedback的相关概念,并通过实例演示其定制过程。

Feedback

Feedback(反馈)是对用户操作的某种响应,我们先来一点感性认识,见下图:


图 1. GEF中缺省的反馈形式
GEF中缺省的反馈形式

图1看到,在拖动某个图形时,我们一般会看到一个虚影,这就叫做反馈。它告诉了用户这个图形在松开鼠标之后将会被放置在什么地方,这是一种很好的提高用户友好度的方式,也是反馈的主要目的。

反馈有两种:Source Feedback(源反馈)和Target Feedback(目标反馈)。鼠标操作的图形叫源,鼠 标移动时经过的地方叫目的。在图1中,那个椭圆就是源,而那个虚影就是源反馈,而目标就是你鼠标具 体指向的地方了,如果你的鼠标停在一个矩形上,那么那个矩形就是目标,由目标提供的反馈就叫目标反 馈。一般我们在GEF中见到的反馈都是一些视觉上的效果,比如图1中的虚影。如果你愿意,你可以播放一 段音乐或者别的什么,所以反馈并不限于视觉效果。对于视觉上的效果而言,GEF提供了一个缺省的层, 叫做Feedback Layer(反馈层),我们看到的图形一般都是添加到反馈层的。

提示: 不了解层的概念的请回顾本系列第三部分

还有一个问题就是反馈的触发时机。反馈到底是在什么时候才会出现呢?对于源反馈,它是在拖动的时候触发的,对于目标反馈,鼠标的移动,进入或者拖动都有可能触发。但是这只是一般的情况,是GEF缺省的情况。如果你需要在更多的场合显示反馈,需要多实现一些方法罢了,但是也并不复杂。

最后一个问题是该显示什么样的反馈。我们先来看看EditPart接口中两个和反馈显示有关方法的原型:


清单1. 显示反馈的方法原型
                public interface EditPart extends IAdaptable {
   // other methods
   ......
   
   void showSourceFeedback(Request request);
   void showTargetFeedback(Request request);
}

方法的参数为Request对象。所以Request对象是我们判断显示何种反馈的主要依据。GEF的缺省Request类型都定义在RequestConstants接口中,而我们自己也可以定义Request。于是,“显示什么样的反馈”这个问题也就清楚了。





回页首


自定义Feedback

概念上的东西只有这么多,现在我们来尝试定制反馈行为。我们要实现的功能很简单,拖动一个图形的时候,显示一个字符串表示是什么图形。然后在拖动的过程中,显示一个坐标信息表示当前拖动到了什么位置。

自定义源反馈

观察AbstractEditPart的代码可以发现,它实际是把showSourceFeedback和showTargetFeedback都转发给了EditPolicy来完成,所以自定义Feedback正确的做法应该是实现一个自定义的EditPolicy并安装到EditPart中。这里又有一个问题,应该安装到哪个角色上呢?和拖动图形相关的角色叫Primary Drag,这个角色的Policy是由父类提供的。所以我们找到DiagramEditPart,修改它的ShapesXYLayoutEditPolicy内部类,覆盖其父类的createChildEditPolicy方法。如下所示:


清单2. 改变孩子的EditPolicy
                private static class ShapesXYLayoutEditPolicy extends XYLayoutEditPolicy {
   // other methods
   ......
   
   @Override
   protected EditPolicy createChildEditPolicy(EditPart child) {
      return new CustomResizableEditPolicy();
   }
}

而CustomResizableEditPolicy的代码如下:


清单3. CustomResizableEditPolicy的实现
                public class CustomResizableEditPolicy extends ResizableEditPolicy {
   @Override
   protected IFigure createDragSourceFeedbackFigure() {
      IFigure f = null;
      if(getHostFigure() instanceof Ellipse)
         f = new Label("Source: Ellipse");
      else
         f = new Label("Source: Rectangle");
      addFeedback(f);
      return f;
   }
}

由于我只是继承了现成的ResizableEditPolicy, 所以留给我的工作并不多,简单的替换成我们想显示的Feedback即可。从以上代码上可以看出,我返回的是一个标签,所以我们的源反馈从一个虚影变成了一个标签。如下图所示:


图2. 自定义源反馈效果
自定义源反馈效果

自定义目标反馈

现在我们再来考虑目标反馈。我们希望在拖动的时候显示一个坐标信息,那么拖动这个动作是一个布局相关的东西,应该是归一个具有Layout角色的EditPart负责的。在我们的例子里,图形是放在Diagram里面的,所以对于目标反馈,我们仍然需要修改ShapesXYLayoutEditPolicy。代码如下所示:


清单4. 实现目标反馈
                protected void showLayoutTargetFeedback(Request request) {
   if(request instanceof ChangeBoundsRequest) {
      ChangeBoundsRequest r = (ChangeBoundsRequest)request;
      Point mouse = r.getLocation();
      if(feedback == null) {
         feedback = new Label("" + mouse.x + ", " + mouse.y);
         addFeedback(feedback);
      } else 
         ((Label)feedback).setText("" + mouse.x + ", " + mouse.y);
         
      feedback.setBounds(new Rectangle(mouse.translate(0, 20), 
         feedback.getPreferredSize()));
   }
}

protected void eraseLayoutTargetFeedback(Request request) {
   if(feedback != null)
      removeFeedback(feedback);
   feedback = null;
}

我们只需要覆盖两个方法,因为父类已经为我们处理了其它情况。如果你要追根究底的话,我们来看看LayoutEditPolicy中的showTargetFeedback()方法:


清单5. 父类做了什么
                public void showTargetFeedback(Request request) {
   if (REQ_ADD.equals(request.getType())
      || REQ_CLONE.equals(request.getType())
      || REQ_MOVE.equals(request.getType())
      || REQ_RESIZE_CHILDREN.equals(request.getType())
      || REQ_CREATE.equals(request.getType()))
      showLayoutTargetFeedback(request);
      
   if (REQ_CREATE.equals(request.getType())) {
      CreateRequest createReq = (CreateRequest)request;
      if (createReq.getSize() != null)
         showSizeOnDropFeedback(createReq);
   }
}

LayoutEditPolicy为我们判断了很多request类型,和拖动相关的就是REQ_MOVE。所以我们不用再做判断了。我们添加的方法中,一个用来创建反馈图形,一个用来移除反馈图形,逻辑上非常简单。要注意addFeedback和removeFeedback的实现,它先得到反馈层,再把我们创建的图形添加到反馈层。现在运行整个例子,可以看到鼠标拖动的时候有一个坐标信息显示在附近。如图所示:


图3. 自定义目标反馈效果
自定义目标反馈效果




回页首


结束语

我们介绍了Feedback的概念并给出了具体示例。需要强调的是:学习GEF,重要的是了解它的流程, 了解了流程之后才能更好的理解细节。对于Feedback而言,它由EditPart负责,转发给EditPolicy,再根据Request类型创建反馈图形,添加到反馈层。本文的例子只覆盖了一些很基本的情况,这里我提出一些高级的功能,留给有兴趣的读者完成:

  1. 实现非图形化的反馈,比如播放声音
  2. 尝试用反馈实现一个浮动工具条,当鼠标移动到某个图形上时,显示这个工具条,过一段时间后消失。
大家可以想象一下使用反馈能实现什么样的有趣功能。





回页首


声明

本文仅代表作者的个人观点,不代表IBM的立场。






回页首


下载

描述名字大小下载方法
Feedback示例代码org.eclipse.gef.examples.shapes_feedback.zip47KBHTTP
关于下载方法的信息


参考资料



关于作者

马若劼,IBM 公司软件工程师,主要从事 Workplace Forms 的设计与开发。他在 Java,Eclipse 以及 Eclipse 插件技术方面拥有多年经验,同时也是开源项目 LumaQQ 的创立者。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款