由GEF所構(gòu)建的圖形編輯器用戶通常的操作流程描述如下:
1、創(chuàng)建需要繪制圖形的文件,并根據(jù)文件類型使用相應(yīng)的編輯器打開文件,為繪制工作初始化一個圖形編輯視圖。
2、根據(jù)圖形編輯器所提供的圖元工具創(chuàng)建具體圖元,將圖元繪制于編輯器所提供的圖形編輯視圖之上
3、已繪制圖形元素的持久化
根據(jù)這個流程,GEF中的各個類所需要執(zhí)行的操作基本步驟如下:
1、創(chuàng)建文件,根據(jù)文件類型選擇相應(yīng)的Editor及Editor和相關(guān)的Viewer的初始化(此部分在以后會詳細(xì)說明)
2、使用Editor所提供的Palette在Viewer上繪制圖形
a、用戶選擇想要繪制的圖元,EditDomain會將用戶選擇的Palette中的相應(yīng)的ToolEntry激活。
{
ToolEntry entry = getPaletteViewer().getActiveTool();
if (entry !=null)
setActiveTool(entry.createTool());
else
setActiveTool(getDefaultTool());
}
b、用戶在畫板視圖上按下鼠標(biāo)左鍵后,DomainEventDispatcher會監(jiān)聽鼠標(biāo)事件
* @see EventDispatcher#dispatchMousePressed(org.eclipse.swt.events.MouseEvent)
*/
public void dispatchMousePressed(org.eclipse.swt.events.MouseEvent me)
{
if (!editorCaptured)
{
super.dispatchMousePressed(me);
if (draw2dBusy())
return;
}
if (okToDispatch())
{
setFocus(null);
control.forceFocus();
setRouteEventsToEditor(true);
domain.mouseDown(me, viewer);
}
}
然后根據(jù)事件相應(yīng)的類型將其路由到EditDomain,EditDomain則根據(jù)事件的類型執(zhí)行相應(yīng)的操作。這些操作的主要工作就是獲取EditDomain中當(dāng)前被激活的工具(getActiveTool()),然后執(zhí)行該工具對這些鼠標(biāo)事件的響應(yīng)。
{
Tool tool = getActiveTool();
if (tool !=null)
tool.mouseDown(mouseEvent, viewer);
}
以CreationTool為例,它對ButtonDown事件的響應(yīng)(handleButtonDown(int))就是創(chuàng)建一個CreateRequest,并賦予其相應(yīng)的位置信息(setLocation(Point))
* The creation tool only works by clicking mouse button 1 (the left mouse button in a
* right-handed world). If any other button is pressed, the tool goes into an invalid
* state. Otherwise, it goes into the drag state, updates the request's location and
* calls {@link TargetingTool#lockTargetEditPart(EditPart)} with the edit part that was
* just clicked on.
*
* @see org.eclipse.gef.tools.AbstractTool#handleButtonDown(int)
*/
protected boolean handleButtonDown(int button)
{
if (button !=1)
{
setState(STATE_INVALID);
handleInvalidInput();
return true;
}
if (stateTransition(STATE_INITIAL, STATE_DRAG))
{
getCreateRequest().setLocation(getLocation());
lockTargetEditPart(getTargetEditPart());
// Snap only when size on drop is employed
helper = (SnapToHelper)getTargetEditPart().getAdapter(SnapToHelper.class);
}
return true;
}
c、CreationTool還會根據(jù)Request的類型及位置將其分派給相應(yīng)的EditPart。[Targeting tools work with a target request. This request is used along with the mouse location to obtain an active target from the current EditPartViewer. This target is then asked for the Command that performs the given request. The target is also asked to show target feedback. (摘自org.eclipse.gef.tools.TargetingTool)]
d、此后的流程基本上就如GEF EMF Redbook中3.3.3Requests節(jié)中的Communication chain
Request-EditPart-Command所述
Command執(zhí)行所做的操作只是對它所涉及到的模型進(jìn)行相應(yīng)的設(shè)置,譬如大小、位置、顏色等屬性。那么圖元如何顯示在視圖之上呢?這一部分正是由GEF中所使用的MVC模式實(shí)現(xiàn)。
GEF中的每一個模型都實(shí)現(xiàn)了某種Notifier(org.eclipse.emf.common.notify.Notifier)或者IPropertySource(org.eclipse.ui.views.properties.IPropertySource)接口作為消息源,每個EditPart則相應(yīng)的實(shí)現(xiàn)了Adapter(org.eclipse.emf.common.notify.Adapter)或PropertyChangeListener(java.beans.PropertyChangeListener)等接口作為偵聽器。并在EditPart初始化時,將其本身注冊為所對應(yīng)的模型的一個偵聽器,當(dāng)模型中的屬性發(fā)生變化時,EditPart會執(zhí)行相應(yīng)的操作。
在EditPart初始化時,將其本身注冊為所對應(yīng)的模型的一個偵聽器,并在銷毀之前注銷注冊:
* Upon activation, attach to the model element as a notification change
* listener.
*/
public void activate() {
if (!isActive()) {
super.activate();
((ModelElement) getModel()).eAdapters().add(this);
}
}
/**
* Upon deactivation, detach from the model element as a notification change
* listener.
*/
public void deactivate() {
if (isActive()) {
super.deactivate();
((ModelElement) getModel()).eAdapters().remove(this);
}
}
當(dāng)模型中的屬性發(fā)生變化時,會向所有的偵聽器發(fā)出消息:
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setName(String newName) {
String oldName = name;
name = newName;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, ModelPackage.ARC_MODEL__NAME, oldName, name));
}
對于所有在該模型上注冊的偵聽器(EditPart)都會接收到屬性變化的消息,根據(jù)消息做出相應(yīng)的反應(yīng):
* (non-Javadoc)
*
* @see org.eclipse.emf.common.notify.Adapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
*/
public void notifyChanged(Notification notification) {
int featureID = notification.getFeatureID(ModelPackage.class);
if (ModelPackage.NODE_MODEL__HEIGHT == featureID
|| ModelPackage.NODE_MODEL__WIDTH == featureID
|| ModelPackage.NODE_MODEL__X == featureID
|| ModelPackage.NODE_MODEL__Y == featureID) {
refreshVisuals();
} else if (ModelPackage.NODE_MODEL__INPUT_ARCS == featureID) {
refreshTargetConnections();
} else if (ModelPackage.NODE_MODEL__OUTPUT_ARCS == featureID) {
refreshSourceConnections();
}
}
(注意:上述示例代碼中,模型部分代碼是由EMF自動生成,因此使用了Notifier-Adapter偵聽機(jī)制)