第四章 GEF框架(1)

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接口,这表明它可以被附着。

你可能感兴趣的:(eclipse,mvc,UI,框架,mfc)