RCP学习:GEF编辑器的鼠标的hover policy以及一个预览窗口效果

GEF编辑器遵循MVC模式。在这里Controller既是org.eclipse.gef.EditPart。它的行为是可以被一系列的策略(org.eclipse.gef.EditPolicy)确定的,见AbstractEditPolicy的方法:

    /**
     * Creates the initial EditPolicies and/or reserves slots for dynamic ones.
     * Should be implemented to install the inital EditPolicies based on the
     * model's initial state. <code>null</code> can be used to reserve a "slot",
     * should there be some desire to guarantee the ordering of EditPolcies.
     * 
     * @see EditPart#installEditPolicy(Object, EditPolicy)
     */
    protected abstract void createEditPolicies();

我们自己定义的Policy可以在这个位置添加。

下面来定义一个鼠标移动到节点上即可以做某些事情的Policy,该Policy要实现如下功能:

1、鼠标移动到节点上的时候,绘制handle

2、鼠标点击任何位置,handle消失

3、鼠标移动到其他节点,绘制新的handle,之前的handle消失。

先看下效果图:

1、这是一个普通的GEF节点,红色和绿色手型标示着连线的端点

2、当鼠标移动到节点上,并且停留数秒的时候,绘制一个橙色手型覆盖红色手型:

3、当鼠标点击该橙色手型,则出现可拖拽的连线提示(该部分功能由handle实现,暂不讨论):

先来看看Policy的实现:

/**
 * 
 * @author caiyu
 * 
 */
public abstract class CommonHoverEditPolicy extends GraphicalEditPolicy {
    public static final String ROLE = "CommonLineAssistantEditPolicy";

    protected IFigure handleLayer;
    /* the List of handles */
    protected List<Handle> handles;

    /* the Hover Listener */
    private MouseMotionListener hoverListener;

    /* listener for every handle */
    private MouseMotionListener handleListener;

    private LayoutListener removeListener;

    private Timer timer;

    private boolean hovering = false;

    protected int TIME_INTERVAL = 1000;

  
public void activate() { super.activate(); addHoverListener(); addHandleListener(); } private void addHandleListener() { handleListener = new MouseMotionListener() { public void mouseDragged(MouseEvent me) { } public void mouseEntered(MouseEvent me) { } public void mouseExited(MouseEvent me) { cancelTimer(); startTimer(); } public void mouseHover(MouseEvent me) { } public void mouseMoved(MouseEvent me) { } }; } protected void addHoverListener() { final IFigure figure = getHostFigure(); hoverListener = new MouseMotionListener() { public void mouseDragged(MouseEvent me) { } public void mouseEntered(MouseEvent me) { } public void mouseExited(MouseEvent me) { startTimer(); } public void mouseHover(MouseEvent me) { cancelTimer(); addHoverHandles(); hovering = true; } public void mouseMoved(MouseEvent me) { } }; /** * 被删除的时候清除监听 */ removeListener = new LayoutListener() { @Override public void invalidate(IFigure container) { } @Override public boolean layout(IFigure container) { return false; } @Override public void postLayout(IFigure container) { } @Override public void remove(IFigure child) { if (child == figure) { clearHoverHandles(); cancelTimer(); figure.getParent().removeLayoutListener(removeListener); } } @Override public void setConstraint(IFigure child, Object constraint) { } }; if (figure != null) { figure.addMouseMotionListener(hoverListener); if (figure.getParent() != null) figure.getParent().addLayoutListener(removeListener); } } /** * Adds the handles to the handle layer. */ protected void addHoverHandles() { clearHoverHandles(); handleLayer = getLayer(LayerConstants.HANDLE_LAYER); handles = createHoverHandles(); for (int i = 0; i < handles.size(); i++) { IFigure handle = (IFigure) handles.get(i); handleLayer.add(handle); handle.addMouseMotionListener(handleListener); } } protected void clearHoverHandles() { if (handles == null) return; if (handleLayer == null) handleLayer = getLayer(LayerConstants.HANDLE_LAYER); for (int i = 0; i < handles.size(); i++) { IFigure handle = (IFigure) handles.get(i); try { handleLayer.remove(handle); } catch (Exception e) { e.printStackTrace(); } if (handleListener != null) handle.removeMouseMotionListener(handleListener); } handles = null; } protected void cancelTimer() { if (timer != null) { timer.cancel(); } } protected void startTimer() { if (!hovering) return; if (timer != null) { timer.cancel(); } timer = new Timer(true); timer.schedule(new TimerTask() { public void run() { Display.getDefault().syncExec(new Runnable() { public void run() { clearHoverHandles(); } }); } }, TIME_INTERVAL); } protected abstract List<Handle> createHoverHandles(); }

代码有点多,不熟悉Policy的话,可以先从activate()方法读起。这个Policy的作用是为hostFigure(就是MVC中的Viewer部分,也是该policy的宿主)添加监听,通过一个Timer来控制handle的展示和消失。

该类为abstract类型,其实现子类需要提供createHoverHandles()的实现,该方法返回一个List<Handle>。

如此,就可以把handle的效果和这个Policy结合起来了。

下面再提供一个利用CommonHoverEditPolicy实现预览效果的例子。

先看效果图:

1、这是一个普通的GEF编辑器:

2、其中的每一个节点内容是被另一个表格编辑器所确定的:

3、当鼠标移动到节点上,稍作停留,便会弹出一个预览框:

该预览框具备之前的表格编辑器的所有浏览功能,可以点击,可以切换子页。

实现方式:

1、重写CommonHoverEditPolicy的createHoverHandles()方法。

TablePreviewDialog dialog = null;

    @Override
    protected List<Handle> createHoverHandles() {
        if (dialog != null && !dialog.close()) {
            dialog.close();
        }
        try {
            BtdFormEditor editor = new BtdFormEditor(false);
            ModelEditorInput input = new ModelEditorInput(
                    (IBaseModel) getHost().getModel());
            IWorkbenchWindow dw = PlatformUI.getWorkbench()
                    .getActiveWorkbenchWindow();
            editor.init(new MultiPageEditorSite((MultiPageEditorPart) dw
                    .getActivePage().getActiveEditor(), editor), input);
            dialog = TablePreviewDialog.getTablePreviewDialog(editor);
            dialog.open();
        } catch (PartInitException e) {
            e.printStackTrace();
        }
        return new ArrayList<Handle>();
    }

可以看到,这里并没有提供可用的Handle(List<Handle>的内容是空的)。但是我们提供了一个Dialog,该Dialog为单例模式,通过对它的close和open控制,来实现handle一样的效果。使用dialog而非handle的主要原因是,handle是基于draw2d的,内容需要绘制,但是我们需要的内容是一个SWT\Jface构成的表格编辑器。所以使用dialog比较合适。

TablePreviewDialog定义如下:
/**
 * 表格内容预览
 * 
 * @author caiyu
 * @date 2012-8-17
 */
public class TablePreviewDialog extends Dialog {
    private static TablePreviewDialog INSTANCE = null;

    public static TablePreviewDialog getTablePreviewDialog(FormEditor editor) {
        if (INSTANCE != null) {
            INSTANCE.setEditor(editor);
            return INSTANCE;
        }
        INSTANCE = new TablePreviewDialog(editor);
        return INSTANCE;
    }

    private int x;
    private int y;
    private int width = 560;
    private int height = 420;

    private FormEditor editor;

    private TablePreviewDialog(FormEditor editor) {
        super(Display.getDefault().getActiveShell());
        this.editor = editor;
        setRectangle(getRectangle());
    }

    protected Control createContents(Composite parent) {
        // create the top level composite for the dialog
        Composite composite = new Composite(parent, 0);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.verticalSpacing = 0;
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        applyDialogFont(composite);
        // initialize the dialog units
        initializeDialogUnits(composite);
        // create the dialog area and button bar
        dialogArea = createDialogArea(composite);

        getShell().addShellListener(new ShellAdapter() {
            public void shellDeactivated(ShellEvent e) {
                close();
            }
        });
        return composite;
    }

    protected Rectangle getRectangle() {
        Rectangle rectangle = Display.getCurrent().getBounds();
        rectangle.x = Display.getCurrent().getCursorLocation().x;
        rectangle.y = Display.getCurrent().getCursorLocation().y;
        return rectangle;
    }

    public void setEditor(FormEditor editor) {
        this.editor = editor;
        setRectangle(getRectangle());
    }

    public void setRectangle(Rectangle rectangle) {
        this.x = rectangle.x;
        this.y = rectangle.y;
        int max_width = rectangle.width;
        int max_height = rectangle.height;
        if (x + width > max_width) {
            x = x - width;
        }
        if (y + height > max_height) {
            y = y - height;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets
     * .Composite)
     */
    protected Control createDialogArea(Composite parent) {
        parent.setLayout(new GridLayout(1, false));

        parent.addMouseListener(new MouseAdapter() {
            public void mouseUp(MouseEvent e) {
                // okPressed();
            }
        });
        parent.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (e.keyCode == SWT.ESC)
                    okPressed();
            }
        });

        Composite client = new Composite(parent, SWT.NONE);
        client.setLayout(new FillLayout());
        client.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        editor.createPartControl(client);
        return parent;
    }

    protected Point getInitialLocation(Point initialSize) {
        return new Point(x, y);
    }

    protected Point getInitialSize() {
        return new Point(width, height);
    }

    protected int getShellStyle() {
        return SWT.NO_TRIM;
    }

    protected void createButtonsForButtonBar(Composite parent) {

    }

    protected void okPressed() {
        // toolkit.dispose();
        super.okPressed();
    }

    public void dispose() {
        okPressed();
    }
}
以上,即完成了为GEF添加一个预览策略及内容。
原文地址:https://www.cnblogs.com/anrainie/p/2651978.html