【飞秋】进一步完善 -- GEF创建助手工具条
昨天討論了在圖形元素上顯示工具條的方法,應該說工作的還不是很完美,因為在選定了創建Connection的工具后,并不能像使用palette那樣,在鼠標移動的過程中,有一個連接動態跟隨,當鼠標釋放后,如果釋放位置在一個圖形元素之上,那么將建立這個Connection,如果不在,那么這個連接將自動消失;今天想討論一下如何實現這個功能;
我們知道GEF是以Draw2D的LightweightSystem作為實現的基礎的,在LightweightSystm中對于mouseDown和mouseMove的實現如下:
事件發布
?1???????? /** @see MouseListener#mouseDoubleClick(MouseEvent) */
?2???????? public void mouseDoubleClick(MouseEvent e) {
?3???????????? getEventDispatcher().dispatchMouseDoubleClicked(e);
?4???????? }
?5
?6???????? /** @see MouseListener#mouseDown(MouseEvent) */
?7???????? public void mouseDown(MouseEvent e) {
?8???????????? getEventDispatcher().dispatchMousePressed(e);
?9???????? }
10
11???????? /** @see MouseTrackListener#mouseEnter(MouseEvent) */
12???????? public void mouseEnter(MouseEvent e) {
13???????????? getEventDispatcher().dispatchMouseEntered(e);
14???????? }
15
16???????? /** @see MouseTrackListener#mouseExit(MouseEvent) */
17???????? public void mouseExit(MouseEvent e) {
18???????????? getEventDispatcher().dispatchMouseExited(e);
19???????? }
20
21???????? /** @see MouseTrackListener#mouseHover(MouseEvent) */
22???????? public void mouseHover(MouseEvent e) {
23???????????? getEventDispatcher().dispatchMouseHover(e);
24???????? }
25
26???????? /** @see MouseMoveListener#mouseMove(MouseEvent) */
27???????? public void mouseMove(MouseEvent e) {
28???????????? getEventDispatcher().dispatchMouseMoved(e);
29???????? }
30
31???????? /** @see MouseListener#mouseUp(MouseEvent) */
32???????? public void mouseUp(MouseEvent e) {
33???????????? getEventDispatcher().dispatchMouseReleased(e);
34???????? }
35
36???????? /** @see DisposeListener#widgetDisposed(DisposeEvent) */
37???????? public void widgetDisposed(DisposeEvent e) {
38???????????? getUpdateManager().dispose();
39???????? }
40
由此可見,Draw2D對于鼠標事件的處理是由Event Dispacher進行派發的。那么這些派發的事件是怎么處理的呢?在org.eclipse.gef.tools.AbstractTool類中有很多相應的handleXXX方法,例如:handleDoubleClick、handleDrag方法等等,這就是處理這些鼠標事件的位置,當然這些方法在這個類中,沒有做什么處理,僅僅返回了false;但是如果我們繼續向下查找的話,會發現其子類AbstractConnectionCreationTool重寫了一些handle方法,其中之一就是handleDrag,而handleDrag調用了handleMove;
handleXXX的實現
/**
???? * @see org.eclipse.gef.tools.AbstractTool#handleDrag()
???? */
??? protected boolean handleDrag() {
??????? if (isInState(STATE_CONNECTION_STARTED))
??????????? return handleMove();
??????? return false;
??? }
??? /**
???? * @see org.eclipse.gef.tools.AbstractTool#handleDragInProgress()
???? */
??? protected boolean handleDragInProgress() {
??????? if (isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS))
??????????? return handleMove();
??????? return false;
??? }
??? /**
???? * @see org.eclipse.gef.tools.AbstractTool#handleFocusLost()
???? */
??? protected boolean handleFocusLost() {
??????? if (isInState(STATE_CONNECTION_STARTED)) {
??????????? eraseSourceFeedback();
??????????? eraseTargetFeedback();
??????????? setState(STATE_INVALID);
??????????? handleFinished();
??????? }
??????? return super.handleFocusLost();
??? }
??? /**
???? * @see org.eclipse.gef.tools.TargetingTool#handleHover()
???? */
??? protected boolean handleHover() {
??????? if (isInState(STATE_CONNECTION_STARTED))
??????????? updateAutoexposeHelper();
??????? return true;
??? }
??? /**
???? * @see org.eclipse.gef.tools.TargetingTool#handleInvalidInput()
???? */
??? protected boolean handleInvalidInput() {
??????? eraseSourceFeedback();
??????? setConnectionSource(null);
??????? return super.handleInvalidInput();
??? }
??? /**
???? * @see org.eclipse.gef.tools.AbstractTool#handleMove()
???? */
??? protected boolean handleMove() {
??????? if (isInState(STATE_CONNECTION_STARTED) && viewer != getCurrentViewer())
??????????? return false;
??????? if (isInState(STATE_CONNECTION_STARTED | STATE_INITIAL
??????????????? | STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) {
??????????? updateTargetRequest();
??????????? updateTargetUnderMouse();
??????????? showSourceFeedback();
??????????? showTargetFeedback();
??????????? setCurrentCommand(getCommand());
??????? }
??????? return true;
??? }
看到handleMove中的那個showSourceFeedback()方法了吧,其實我們今天討論的問題,在GEF框架中就是通過它實現的;爬源碼,我們可以知道這個方法事實上是調用了AbstractEditPart的showSourceFeedback()方法,而后者又調用了GraphicalNodeEditPolicy的showSourceFeedback方法,這個方法又調用了showCreationFeedback方法;
??? /**
???? * Shows feedback during a creation.
???? *
???? * @param request
???? *??????????? CreateConnectionRequest
???? */
??? protected void showCreationFeedback(CreateConnectionRequest request) {
??????? FeedbackHelper helper = getFeedbackHelper(request);
??????? Point p = new Point(request.getLocation());
??????? helper.update(getTargetConnectionAnchor(request), p);
??? }
??? /**
???? * calls {@link #showCreationFeedback(CreateConnectionRequest)} when
???? * appropriate.
???? *
???? * @see org.eclipse.gef.EditPolicy#showSourceFeedback(Request)
???? */
??? public void showSourceFeedback(Request request) {
??????? if (REQ_CONNECTION_END.equals(request.getType()))
??????????? showCreationFeedback((CreateConnectionRequest) request);
??? }
?
這下我們就明白了,我們只要照貓畫虎,在我們的工具條的mouse move方法中實現上面的那個showCreationFeedback方法就行了;以下就是我們的實現:
?
?1 public void mouseDragged(MouseEvent me) {
?3???? request = new CreateConnectionRequest();
?4???? ScalableFreeformRootEditPart root = (ScalableFreeformRootEditPart) getSourceEditPart().getRoot();
?5???? double zoom = root.getZoomManager().getZoom();
?6
?7???? request.setLocation(new Point(hoverX * zoom, hoverY * zoom));
?8???? request.setType("connection start");
?9
10???? FeedbackHelper feedbackHelper = new FeedbackHelper();
11???? Point p = new Point(me.x, me.y);
12???? Connection connectionFeedback = FigureFactory.createNewWorkflowPath(null);
13
14???? connectionFeedback.setConnectionRouter(((ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER)).getConnectionRouter());
15???? connectionFeedback.setSourceAnchor(getSourceConnectionAnchor(request));
16???? feedbackHelper.setConnection(connectionFeedback);
17
18???? IFigure figure = getLayer(LayerConstants.FEEDBACK_LAYER);
19???? for (int i = 0; i < figure.getChildren().size(); i++) {
20???????? if (figure.getChildren().get(i) instanceof Connection) {
21???????????? figure.remove((IFigure) figure.getChildren().get(i));
22???????? }
23???? }
24???? getLayer(LayerConstants.FEEDBACK_LAYER).add(connectionFeedback);
25???? request.setLocation(new Point(me.x * zoom, me.y * zoom));
26???? feedbackHelper.update(null, new Point(me.x + offsetX * zoom, me.y + offsetY * zoom));
27 }
28
至此,我們的問題就解決了。但是還有一個問題,那就是,如果鼠標被釋放了,那么這個被放置在反饋層的Connection應該被擦除掉,而同時還應該根據鼠標的位置決定是不是應該創建Connection;所以我們還應該再改一下mouse released方法,增加如下處理:
IFigure feedBackLayer = getLayer(LayerConstants.FEEDBACK_LAYER);
feedBackLayer.getChildren().clear();
通過以上的處理,我們就可以實現類似于palette中Connection Tool的功能了。當我們在一個圖形元素上Hover時,首先程序先將與懸停位置最近的錨點作為源錨點,并顯示工具條,當我們點擊工具條上的Connection圖標時,隨著鼠標的拖動,一個Connection將動態跟隨鼠標的移動被畫出來,隨著鼠標的釋放,Connection將根據釋放位置決定是否建立一個Connection,還是將這個動態的Connection清除掉;
關注技術文章飛秋:http://www.freeeim.com/,24小時專業轉載。
總結
以上是生活随笔為你收集整理的【飞秋】进一步完善 -- GEF创建助手工具条的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Keras + Windows +Ana
- 下一篇: EIM正在迎来自己的春天