级别: 中级 马 若劼 (maruojie@cn.ibm.com), 软件工程师, IBM 中国软件开发中心
2007 年 10 月 25 日 Feedback(反馈)指的是GEF中对用户操作的一种回显,这种回显一般来说是视觉上的,但是也不一定。完全可以由用户来定制。本文介绍Feedback的相关概念,并通过实例演示其定制过程。
Feedback(反馈)指的是GEF中对用户操作的一种回显,这种回显一般来说是视觉上的,但是也不一定。完全可以由用户来定制。本文介绍Feedback的相关概念,并通过实例演示其定制过程。
Feedback
Feedback(反馈)是对用户操作的某种响应,我们先来一点感性认识,见下图:
图 1. 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类型创建反馈图形,添加到反馈层。本文的例子只覆盖了一些很基本的情况,这里我提出一些高级的功能,留给有兴趣的读者完成:
- 实现非图形化的反馈,比如播放声音
- 尝试用反馈实现一个浮动工具条,当鼠标移动到某个图形上时,显示这个工具条,过一段时间后消失。
大家可以想象一下使用反馈能实现什么样的有趣功能。
声明
本文仅代表作者的个人观点,不代表IBM的立场。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| Feedback示例代码 | org.eclipse.gef.examples.shapes_feedback.zip | 47KB | HTTP |
|---|
参考资料
关于作者  | |  | 马若劼,IBM 公司软件工程师,主要从事 Workplace Forms 的设计与开发。他在 Java,Eclipse 以及 Eclipse 插件技术方面拥有多年经验,同时也是开源项目 LumaQQ 的创立者。 |
对本文的评价
|