JAVA MouseEvent實(shí)現(xiàn)紀(jì)要
Jre1.7鼠標(biāo)事件以MouseEvent類(lèi)封裝。共有如下8種:
/**
*The"mouseclicked"event.This<code>MouseEvent</code>
*occurswhenamousebuttonispressedandreleased.
*/
publicstaticfinalintMOUSE_CLICKED = MOUSE_FIRST;
/**
*The"mousepressed"event.This<code>MouseEvent</code>
*occurswhenamousebuttonispusheddown.
*/
publicstaticfinalintMOUSE_PRESSED = 1 + MOUSE_FIRST; //Event.MOUSE_DOWN
/**
*The"mousereleased"event.This<code>MouseEvent</code>
*occurswhenamousebuttonisletup.
*/
publicstaticfinalintMOUSE_RELEASED = 2 + MOUSE_FIRST; //Event.MOUSE_UP
/**
*The"mousemoved"event.This<code>MouseEvent</code>
*occurswhenthemousepositionchanges.
*/
publicstaticfinalintMOUSE_MOVED = 3 + MOUSE_FIRST; //Event.MOUSE_MOVE
/**
*The"mouseentered"event.This<code>MouseEvent</code>
*occurswhenthemousecursorenterstheunobscuredpartofcomponent's
*geometry.
*/
publicstaticfinalintMOUSE_ENTERED = 4 + MOUSE_FIRST; //Event.MOUSE_ENTER
/**
*The"mouseexited"event.This<code>MouseEvent</code>
*occurswhenthemousecursorexitstheunobscuredpartofcomponent's
*geometry.
*/
publicstaticfinalintMOUSE_EXITED = 5 + MOUSE_FIRST; //Event.MOUSE_EXIT
/**
*The"mousedragged"event.This<code>MouseEvent</code>
*occurswhenthemousepositionchangeswhileamousebuttonispressed.
*/
publicstaticfinalintMOUSE_DRAGGED = 6 + MOUSE_FIRST; //Event.MOUSE_DRAG
/**
*The"mousewheel"event. Thisistheonly<code>MouseWheelEvent</code>.
*Itoccurswhenamouseequippedwithawheelhasitswheelrotated.
*@since1.4
*/
publicstaticfinalintMOUSE_WHEEL = 7 + MOUSE_FIRST;
鼠標(biāo)事件由AWT-Windows線(xiàn)程從底層系統(tǒng)獲取到并Flush給EDT進(jìn)行處理。EDT在處理時(shí)按一下步驟進(jìn)行:
1. EventDispatchThread中執(zhí)行SunDragSourceContextPeer.checkEvent。其功能含義為拖拽開(kāi)始時(shí)將忽略掉當(dāng)時(shí)還在Post Event Queue等待處理的單純鼠標(biāo)事件。雖然MouseEvent和拖拽的事件有著千絲萬(wàn)縷的聯(lián)系,但是在拖拽過(guò)程中并不會(huì)影響MouseEvent的dispatch.
此前對(duì)java拖拽的實(shí)現(xiàn)分析已經(jīng)知道,拖拽開(kāi)始后AWT-loop到的底層事件將由一個(gè)DragSourcePeer在底層處理后直接包裝成DragSourceEvent發(fā)布到EDT中進(jìn)行處理,同時(shí)由一個(gè)DropTargetPeer在底層處理后包裝成SunDropTargetEvent發(fā)布到EDT中進(jìn)行處理。SunDropTargetEvent是MouseEvent的子類(lèi),而DragSourceEvent就不是。這里面的原因是因?yàn)橥献н^(guò)程中系統(tǒng)只有一個(gè)DragSource,因此DragSourceEvent的target一定是此DragSource組件,只要在拖拽開(kāi)始時(shí)通過(guò)一個(gè)全局變量記錄下來(lái),在封裝過(guò)程source=DragSourceEvent直接定位到組件即可,但是同一個(gè)拖拽過(guò)程卻可能面臨多個(gè)DropTarget,而且最關(guān)鍵的是就此底層事件底層系統(tǒng)只能給出對(duì)重量級(jí)組件的定位,因此對(duì)于SunDropTargetEvent需要經(jīng)過(guò)類(lèi)似MouseEvent的retarget過(guò)程確定目標(biāo)組件,所以SunDropTargetEvent定義為MouseEvent的子類(lèi)。當(dāng)然SunDropTargetEvent在經(jīng)過(guò)retarget后再形成具有準(zhǔn)確目標(biāo)組件的DropTargetEvent就和DragSourceEvent一樣不再是MouseEvent的子類(lèi)了。可見(jiàn),SunDropTargetEvent可以看作是一個(gè)中間過(guò)渡事件,該類(lèi)事件存在的主要意義就是借助EDT對(duì)MouseEvent的統(tǒng)一retarget過(guò)程;也因而在EventQueue,EventDispatchThread類(lèi)的處理中特別針對(duì)該事件有特殊處理。
正因?yàn)?/span>SunDropTargetEvent的存在,checkEvent這個(gè)方法的實(shí)現(xiàn)才是忽略單純的鼠標(biāo)事件,但不能忽略了SunDropTargetEvent。
if (discardingMouseEvents && event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
if (!(mouseEvent instanceof SunDropTargetEvent)) {
returnfalse;
}
}
returntrue;
2. EventQueue中((Component)src).dispatchEvent(event);而在Component中dispatchEventImpl。如果該組件是一個(gè)Container,將進(jìn)入Container. dispatchEventImpl,該方法將通過(guò)Container. LightweightDispatcher進(jìn)行dispatchEvent,其主要功能就是要retarget及在之后針對(duì)Mouse_Move updateCursor.
Awt-windows loop到的Mouse Event只能是針對(duì)重量級(jí)組件的,如果本次點(diǎn)擊是在某重量級(jí)組件比如JFRAME的一個(gè)JTEXTFIELD上點(diǎn)擊,需要通過(guò)這個(gè)過(guò)程將此Mouse Event定位source=JTEXTFIELD;同時(shí)可能一個(gè)重量級(jí)組件的MouseMove對(duì)應(yīng)其包含的兩個(gè)輕量級(jí)組件的exit和enter;所有這些具體retarget在processMouseEvent中完成;完成邏輯主要根據(jù)鼠標(biāo)事件的坐標(biāo)和container的子組件記錄,以及組件提供的publicboolean contains(int x, int y) 方法去尋找最頂層包含此坐標(biāo)的子組件;除了找到該組件外,再根據(jù)一個(gè)targetLastEntered域變量比較是否發(fā)生了變化,如果是則要產(chǎn)生Exit和Enter.
3. Retargeted Mouse Event將進(jìn)入Component. dispatchEventImpl.
A.如果是SunDropTargetEvent將處理掉并返回。
B.MOUSE_WHEEL將由peer處理后可能被dispatchMouseWheelToAncestor,即交由該組件的合適的容器組件處理。
C.Allow the Toolkit to pass this to AWTEventListeners,即交給Toolkit注冊(cè)listener處理。
D.newEventsOnly&& eventEnabled則交給該組件對(duì)應(yīng)listener處理。
E.newEventsOnly will be false for a listenerless ScrollPane, but
MouseWheelEvents still need to be dispatched to it so scrolling
can be done. autoProcessMouseWheel方法提供了一個(gè)處理鼠標(biāo)輪滾動(dòng)的切入點(diǎn),即如果scrollpane沒(méi)有注冊(cè)任何監(jiān)聽(tīng)導(dǎo)致newEventsOnly =false,也可以實(shí)現(xiàn)autoProcessMouseWheel方法來(lái)實(shí)現(xiàn)通用的scroll。