FROM:http://www.blog.edu.cn/user1/19180/archives/2005/375044.shtml
4.1 概述
GEF是一套建立在Draw2D基础之上的eclipse插件,它为Draw2D提供控制功能,它监听各种事件,如鼠标、键盘、Workbench的事件,并进行响应。GEF是一套框架,它提供一套完整的图形用户接口系统的基本处理方式,但是具体的功能需要我们实现,这一点和MFC的窗口系统不同。
GEF使用MVC模式,它成功的将模型、视图、控制器三个部分剥离。模型是由用户编写的任何类,视图则采用Draw2D系统,控制器则是之前提到过的EditPart。
M-V-C三个部分的交互式这样完成的:当用户直接对V进行了操作,比如改变V的形状或者修改了Label中的文字,系统就会产生一个Request,并将这个Request传递给相应的EditPart进行处理;EditPart根据Request的类型生成相应的Command(Command需要用户编写),并将Command在传递出去;系统得到Command后,就会在合适的时机执行这个Command。如果M发生了变化,并且需要更新视图,它可以使用一个PropertyChangeSupport实例,提示EditPart对V进行改变。PropertyChangeSupport实际上是M与EditPart的一个桥梁,只要在EditPart中实现PropertyChangeListener接口,就可以向M的PropertyChangeSupport实例注册自己为监听者。具体的例子将在第3节给出。
实现一个模型是很简单,但是注意一般来说应该让模型包含一个PropertyChangeSupport类的实例。调用PropertyChangeSupport的addPropertyChangeListener方法可以向其中注册一个监听者,调用removePropertyChangeListener的移出一个监听者,调用firePropertyChange方法则向所有注册的监听者通知发生了变化。
实现一个EditPart一般来说需要重载performRequest、getCommand、activate、deactivate和refreshVisuals函数,并实现createEditPolicies、createFigure接口函数,为了让EditPart能够成为PropertyChangeListener,你还必须实现PropertyChangeListener接口。performRequest和getCommand将在第3节介绍,activate和deactivate用于处理当EditPart处于激活或者非激活状态时的操作,一般来说,可以在这两个函数中注册和移除自己监听者的角色。refreshVisuals函数用于更新自己的视图。
下面给出一个模型和它对应的EditPart的例子:
Element.java:
- package com.example.model;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeSupport;
- import java.io.Serializable;
- public abstract class Element implements Cloneable, Serializable {
- PropertyChangeSupport listeners = new PropertyChangeSupport(this);
- public void addPropertyChangeListener(PropertyChangeListener l) {
- listeners.addPropertyChangeListener(l);
- }
- protected void firePropertyChange(String prop, Object old, Object newValue) {
- listeners.firePropertyChange(prop, old, newValue);
- }
- protected void fireStructureChange(String prop, Object child) {
- listeners.firePropertyChange(prop, null, child);
- }
- public void removePropertyChangeListener(PropertyChangeListener l) {
- listeners.removePropertyChangeListener(l);
- }
- }
注意这个Element类中包含了一个PropertyChangeSupport对象。
Node.java:
- package com.example.model;
- import java.util.ArrayList;
- import java.util.List;
- import org.eclipse.draw2d.geometry.Dimension;
- import org.eclipse.draw2d.geometry.Point;
- import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor;
- import org.eclipse.ui.views.properties.IPropertyDescriptor;
- import org.eclipse.ui.views.properties.IPropertySource;
- import org.eclipse.ui.views.properties.TextPropertyDescriptor;
- public class Node extends Element implements IPropertySource {
- final public static String PROP_LOCATION = "LOCATION";
- final public static String PROP_NAME = "NAME";
- final public static String PROP_VISIBLE = "VISIBLE";
- final public static String PROP_INPUTS = "INPUTS";
- final public static String PROP_OUTPUTS = "OUTPUTS";
- protected Point location = new Point(0, 0);
- private Dimension size=new Dimension(150,40);
- protected String name = "Node";
- protected boolean visible = true;
- protected IPropertyDescriptor[] descriptors = new IPropertyDescriptor[] {
- new TextPropertyDescriptor(PROP_NAME, "Name"),
- new ComboBoxPropertyDescriptor(PROP_VISIBLE, "Visible", new String[] { "true", "false" }) };
- protected List outputs = new ArrayList(5);
- protected List inputs = new ArrayList(5);
- public void addInput(Connection connection) {
- this.inputs.add(connection);
- fireStructureChange(PROP_INPUTS, connection);
- }
- public void addOutput(Connection connection) {
- this.outputs.add(connection);
- fireStructureChange(PROP_OUTPUTS, connection);
- }
- public List getIncomingConnections() {
- return this.inputs;
- }
- public List getOutgoingConnections() {
- return this.outputs;
- }
- public void removeInput(Connection connection) {
- this.inputs.remove(connection);
- fireStructureChange(PROP_INPUTS, connection);
- }
- public void removeOutput(Connection connection) {
- this.outputs.remove(connection);
- fireStructureChange(PROP_OUTPUTS, connection);
- }
- public boolean isVisible() {
- return visible;
- }
- public void setVisible(boolean visible) {
- if (this.visible == visible) {
- return;
- }
- this.visible = visible;
- firePropertyChange(PROP_VISIBLE, null, Boolean.valueOf(visible));
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- if (this.name.equals(name)) {
- return;
- }
- this.name = name;
- firePropertyChange(PROP_NAME, null, name);
- }
- public void setLocation(Point p) {
- if (this.location.equals(p)) {
- return;
- }
- this.location = p;
- firePropertyChange(PROP_LOCATION, null, p);
- }
- public Point getLocation() {
- return location;
- }
- public void setSize(Dimension size) {
- this.size = size;
- }
- public Dimension getSize() {
- return size;
- }
- //------------------------------------------------------------------------
- // Abstract methods from IPropertySource
- public Object getEditableValue() {
- return this;
- }
- public IPropertyDescriptor[] getPropertyDescriptors() {
- return descriptors;
- }
- public Object getPropertyValue(Object id) {
- if (PROP_NAME.equals(id))
- return getName();
- if (PROP_VISIBLE.equals(id))
- return isVisible() ? new Integer(0) : new Integer(1);
- return null;
- }
- public boolean isPropertySet(Object id) {
- return true;
- }
- public void resetPropertyValue(Object id) {
- }
- public void setPropertyValue(Object id, Object value) {
- if (PROP_NAME.equals(id))
- setName((String) value);
- if (PROP_VISIBLE.equals(id))
- setVisible(((Integer) value).intValue() == 0);
- }
- }
这个Node继承自Element,并且实现了IPropertySource,这表明它可以作为属性页的数据源。下面再看对应的EditPart:
NodePart.java:
- package com.example.parts;
- import java.beans.PropertyChangeEvent;
- import java.beans.PropertyChangeListener;
- import java.util.List;
- import org.eclipse.draw2d.ChopboxAnchor;
- import org.eclipse.draw2d.ConnectionAnchor;
- import org.eclipse.draw2d.IFigure;
- import org.eclipse.draw2d.geometry.Dimension;
- import org.eclipse.draw2d.geometry.Point;
- import org.eclipse.draw2d.geometry.Rectangle;
- import org.eclipse.gef.ConnectionEditPart;
- import org.eclipse.gef.EditPolicy;
- import org.eclipse.gef.GraphicalEditPart;
- import org.eclipse.gef.NodeEditPart;
- import org.eclipse.gef.Request;
- import org.eclipse.gef.RequestConstants;
- import org.eclipse.gef.commands.Command;
- import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
- import org.eclipse.gef.requests.ChangeBoundsRequest;
- import org.eclipse.gef.requests.DirectEditRequest;
- import org.eclipse.gef.tools.DirectEditManager;
- import org.eclipse.jface.viewers.TextCellEditor;
- import com.example.commands.RenameNodeCommand;
- import com.example.commands.ResizeNodeCommand;
- import com.example.figures.NodeFigure;
- import com.example.model.Node;
- import com.example.policies.NodeDirectEditPolicy;
- import com.example.policies.NodeEditPolicy;
- import com.example.policies.NodeGraphicalNodeEditPolicy;
- public class NodePart extends AbstractGraphicalEditPart implements PropertyChangeListener, NodeEditPart {
- protected DirectEditManager manager;
- public void performRequest(Request req) {
- if (req.getType().equals(RequestConstants.REQ_DIRECT_EDIT)) {
- if (manager == null) {
- NodeFigure figure = (NodeFigure) getFigure();
- manager = new NodeDirectEditManager(this, TextCellEditor.class, new NodeCellEditorLocator(figure));
- }
- manager.show();
- }
- }
- public Command getCommand(Request request) {
- if(REQ_RESIZE.equals(request.getType())) {
- ChangeBoundsRequest req=(ChangeBoundsRequest)request;
- Node node=(Node)getModel();
- ResizeNodeCommand cmd=new ResizeNodeCommand(node,this);
- Rectangle rect=new Rectangle(node.getLocation(),node.getSize());
- cmd.setRectangle(req.getTransformedRectangle(rect));
- return cmd;
- }
- return super.getCommand(request);
- }
- public void propertyChange(PropertyChangeEvent evt) {
- if (evt.getPropertyName().equals(Node.PROP_LOCATION))
- refreshVisuals();
- else if (evt.getPropertyName().equals(Node.PROP_NAME))
- refreshVisuals();
- else if (evt.getPropertyName().equals(Node.PROP_INPUTS))
- refreshTargetConnections();
- else if (evt.getPropertyName().equals(Node.PROP_OUTPUTS))
- refreshSourceConnections();
- }
- protected IFigure createFigure() {
- return new NodeFigure();
- }
- protected void createEditPolicies() {
- installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new NodeDirectEditPolicy());
- installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeEditPolicy());
- installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new NodeGraphicalNodeEditPolicy());
- }
- public void activate() {
- if (isActive()) {
- return;
- }
- super.activate();
- ((Node) getModel()).addPropertyChangeListener(this);
- }
- public void deactivate() {
- if (!isActive()) {
- return;
- }
- super.deactivate();
- ((Node) getModel()).removePropertyChangeListener(this);
- }
- protected void refreshVisuals() {
- Node node = (Node) getModel();
- Point loc = node.getLocation();
- Dimension size = node.getSize();
- Rectangle rectangle = new Rectangle(loc, size);
- ((NodeFigure) this.getFigure()).setName(((Node) this.getModel()).getName());
- //this.getFigure().setBounds(rectangle);
- ((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), rectangle);
- }
- //------------------------------------------------------------------------
- // Abstract methods from NodeEditPart
- public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
- return new ChopboxAnchor(getFigure());
- }
- public ConnectionAnchor getSourceConnectionAnchor(Request request) {
- return new ChopboxAnchor(getFigure());
- }
- public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
- return new ChopboxAnchor(getFigure());
- }
- public ConnectionAnchor getTargetConnectionAnchor(Request request) {
- return new ChopboxAnchor(getFigure());
- }
- protected List getModelSourceConnections() {
- return ((Node) this.getModel()).getOutgoingConnections();
- }
- protected List getModelTargetConnections() {
- return ((Node) this.getModel()).getIncomingConnections();
- }
- }
这个EditPart还实现了NodeEditPart接口,这表明它可以被附着。