低級事件類型
在本節中,将詳細讨論與具體使用者界面元件無關,但與敲擊鍵盤和活動滑鼠有關的事件。下一章将詳細讨論有關由使用者界面元件産生的語義事件。
鍵盤事件
當使用者按下鍵盤上的一個鍵時,就會産生一個ID為KEY_PRESSED的KeyEvent事件。當使用者釋放一個鍵時,将會觸發ID為KEY_RELEASED的KeyEvent事件。可以使用實作了KeyListener接口的任意類的KeyPressed和KeyReleased方法處理這些事件。這兩個方法可以捕獲敲擊鍵盤的事件。将這兩個方法組合起來就形成了第三個方法KeyTyped,它可以報告由使用者敲擊鍵盤所産生的字元。
講述鍵盤事件處理過程的最好方法是舉例說明。但在此之前,先要介紹幾個術語。Java明确區分字元和虛拟鍵碼(virtual key code)。虛拟鍵碼用字首VK_表示,例如,VK_A或VK_SHIFT。虛拟鍵碼與鍵盤上的鍵一一對應。例如,VK_A表示被标記為A的鍵。虛拟鍵碼沒有單獨的小寫鍵,即鍵盤沒有單獨的小寫鍵。
注意:虛拟鍵碼涉及“掃描碼”,這是在按下一個實體鍵或釋放一個實體鍵時,鍵盤向計算機發送的編碼。
假設使用者采用按下SHIFT鍵的同時按下A鍵的方式鍵入大寫字母A。為了響應這個使用者動作,Java将會産生5個事件,下面是動作和相關的事件:
1)按下SHIFT鍵(為VK_SHIFT調用keyPressed)。
2)按下A鍵(為VK_A調用keyPressed)。
3)鍵入“A”(為“A”調用keyTyped)。
4)釋放A鍵(為VK_A調用keyReleased)。
5)釋放SHIFT鍵(為VK_SHIFT調用keyReleased)。
另一方面,如果使用者隻是按下A鍵來鍵入小寫字母“a”,那麼隻産生3個事件:
1)按下A鍵(為VK_A調用keyPressed)。
2)鍵入“a”(為“a”調用keyTyped)。
3)釋放A鍵(為VK_A調用keyReleased)。
是以,keyTyped過程報告鍵入的字元(“A”或“a”),而keyPressed和keyReleased方法報告使用者按下的實際鍵。
為了能夠讓keyPressed和keyReleased方法執行,首先需要檢查鍵碼(key code)。
鍵碼等于下列(有利于記憶的)常量之一。它們都定義在KeyEvent類中。
為了查明SHIFT、CONTROL、ALT和META鍵的目前狀态,當然可以跟蹤VK_SHIFT、VK_CONTROL、VK_ALT和VK_META鍵是否被按下,但是這樣做很麻煩。另外,可以使用sShiftDown、isControlDown、isAltDown和isMetaDown方法。(Sun和Macintosh鍵盤有一個專門的META鍵。在Sun鍵盤上,這個按鍵标記為菱形。在Macintosh鍵盤上,這個按鍵用一個蘋果或苜蓿葉标記。)
例如,下列代碼檢測使用者是否按下SHIFT+“→”:
在keyTyped方法中,調用getKeyChar方法得到鍵入的實際字元。
注意:并不是所有的敲擊鍵盤都會産生ketTyped調用。隻有那些産生Unicode字元的敲擊才能夠在keyTyped方法中捕獲。可以使用keyPressed方法檢查光标鍵和其他指令鍵。
例8-3給出了處理敲擊鍵盤事件的方式。這個程式(如圖8-7所示)是Etch-A-Sketch™玩具的簡單實作。
使用者可以利用光标鍵,向上、下、左、右移動畫筆。如果向下的同時按下SHIFT鍵,畫筆移動的增量比較大。如果你熟悉vi編輯器,就可以使用小寫字母h、j、k和l鍵代替光标鍵來移動畫筆;大寫H、J、K和L将更大增量地移動畫筆。在這裡用keyPressed方法捕獲光标鍵,用keyTyped方法捕獲字元。
這裡有一個技巧:通常,面闆不接受任何鍵盤事件。是以,可以調用setFocusable方法對預設情形進行覆寫。本章稍後将讨論鍵盤焦點的概念。
例8-3 Sketch.java
java.awt.event.KeyEvent 1.1
• char getKeyChar( )
傳回使用者鍵入的字元。
• int getKeyCode( )
傳回該鍵盤事件的虛拟鍵碼。
• boolean isActionKey( )
如果事件中的鍵是一個“動作”鍵,傳回true。下面列出的是動作鍵:HOME、END、PAGE UP、PAGE DOWN、UP、DOWN、LEFT、RIGHT、F1. . .F24、PRINT SCREEN、SCROLL LOCK、CAPS LOCK、NUM LOCK、PAUSE、INSERT、DELETE、ENTER、BACKSPACE、DELETE和TAB。
• static String getKeyText(int keyCode)
傳回描述鍵碼的字元串。例如,getKeyText(KeyEvent VK_END)傳回字元串"End"。
• static String getKeyModifiersText(int modifiers)
傳回描述SHIFT或CTRL+SHIFT這類修飾符鍵的字元串。
參數:modifiers
修飾符狀态,由getModifiers報告
java.awt.event.InputEvent 1.1
• int getModifiers( )
傳回一個整型數值,它用位描述SHIFT、CONTROL、ALL和META修飾符的狀态。這個方法
既可以應用于鍵盤事件,也可以應用于滑鼠事件。要想檢測某一位是否被設定,可以測試傳回值
是否對應于位掩碼SHIFT_MASK、CTRL_MASK、ALT_MASK、ALT_GRAPH_MASK、
META_MASK或調用下列某一個方法。
• boolean isShiftDown( )
• boolean isControlDown( )
• boolean isAltDown( )
• boolean isAltGraphDown( ) 1.2
• boolean isMetaDown( )
在事件發生時,如果某個修飾符鍵被按下,方法傳回true。
滑鼠事件
如果隻希望使用者能夠點選按鈕或菜單,就不需要顯式地處理滑鼠事件。滑鼠操作将由使用者界面中的各種元件内部處理,并轉換成對應的語義事件。然而,如果希望使用者使用滑鼠畫圖,就需要捕獲滑鼠移動點選和拖動事件。
在本節中,将展示一個簡單的圖形編輯器應用程式,它允許使用者在畫布上(如圖8-8所示)放置、移動和擦除方塊。
當使用者點選滑鼠按鈕時,将會調用三個監聽器方法:滑鼠第一次被按下時調用mousePressed;滑鼠被釋放時調用mouseReleased;最後調用mouseClicked。如果隻對最終的點選事件感興趣,就可以忽略前兩個方法。用MouseEvent類對象作為參數,調用getX和getY方法可以獲得滑鼠被按下時滑鼠指針所在的x和y坐标。要想區分單擊、輕按兩下和三擊(!),需要使用getClickCount方法。
有些使用者界面設計者喜歡讓使用者采用滑鼠點選與鍵盤修飾符組合(例如,CONTROL+SHIFT+CLICK)的方式進行操作。我們感覺這并不是一種值得贊許的方式。如果對此持有不同的觀點,可以看看同時檢測滑鼠按鍵和鍵盤修飾符所帶來的混亂。在最初的API中,有兩個滑鼠按鈕的掩碼與兩個鍵盤修飾符的掩碼一樣,即
BUTTON2_MASK == ALT_MASK
BUTTON3_MASK == META_MASK
這樣做是為了能夠讓使用者使用僅有一個按鈕的滑鼠通過按下修飾符鍵來模拟按下其他滑鼠鍵的操作。然而,在JDK 1.4中,建議使用一種不同的方式。有下列掩碼:
BUTTON1_DOWN_MASK
BUTTON2_DOWN_MASK
BUTTON3_DOWN_MASK
SHIFT_DOWN_MASK
CTRL_DOWN_MASK
ALT_DOWN_MASK
ALT_GRAPH_DOWN_MASK
META_DOWN_MASK
getModifiersEx方法能夠準确地報告滑鼠事件的滑鼠按鈕和鍵盤修飾符。
需要注意,在Windows環境下,使用BUTTON3_DOWN_MASK檢測滑鼠右鍵(非主要的)的狀态。例如,可以使用下列代碼檢測滑鼠右鍵是否被按下:
if ((event.getModifiersEx( )&InputEvent.BUTTON3_DOWN__MASK)! = )
. . . //code for right click
在列舉的簡單例子中,提供了mousePressed和mouseClicked方法。當滑鼠點選在所有小方塊的像素之外時,就會繪制一個新的小方塊。這個操作是在mousePressed方法中實作的,這樣可以讓使用者的操作立即得到響應,而不必等到釋放滑鼠按鍵。如果使用者在某個小方塊中輕按兩下滑鼠,就會将它擦除。由于需要知道點選次數,是以這個操作是在mouseClick方法中實作。
當滑鼠在視窗上移動時,視窗将會收到一連串的滑鼠移動事件。大多數應用程式忽略了這些事件。然而,我們給出的測試程式将捕獲這些事件,以便在光标位于不同的小方塊之上時變成另外一種形狀(十字)。實作這項操作需要使用Cursor類中的getPredefinedCursor方法。表8-2列出了在Windows環境下,滑鼠的形狀和方法對應的常量。(注意,有若幹個光标的形狀完全一樣,但在其他平台上未必如此。)
提示:可以在jre/lib/images/cursors目錄中找到光标圖像。在檔案cursors.properties中定義了光标“熱點”。熱點是訓示光标引起動作的點。例如,如果光标變成放大鏡形狀,熱點就是該鏡的中心。
下面是例子程式中MouseMotionListener類的mouseMoved方法:
注意:可以利用Toolkit類中的createCustomCursor方法自定義光标類型:
createCustomCursor的第一個參數指向光标圖像。第二個參數給出了光标的“熱點”偏移。第三個參數是一個描述光标的字元串。這個字元串可以用于通路性支援,例如,可以将光标形式讀給視力受損或沒有在螢幕前面的人。
如果使用者在移動滑鼠的同時按下滑鼠,就會調用mouseMoved而不是調用mouseDragged。在測試應用程式中,使用者可以用光标拖動小方塊。在程式中,僅僅用拖動的矩形更新目前光标位置。
然後,重新繪制畫布,以顯示新的滑鼠位置。
注意:隻有滑鼠在一個元件内部停留才會調用mouseMoved方法。然而,即使滑鼠拖動到元件外面,mouseDragged方法也會被調用。
還有兩個滑鼠事件方法:mouseEntered和mouseExited。這兩個方法是在滑鼠進入或移出元件時被調用。
最後,解釋一下如何監聽滑鼠事件。滑鼠點選由mouseClick過程報告,它是MouseListener接口的一部分。由于大部分應用程式僅對滑鼠點選感興趣,而對滑鼠移動并不太感興趣,但滑鼠移動事件發生的頻率又很高,是以将滑鼠移動事件與拖動事件定義在一個稱為MouseMotionListener的獨立接口中。
在例8-4的程式中,對兩種滑鼠事件類型都感興趣。這裡定義了兩個内部類:MouseHandler和MouseMotionHandler。MouseHandler類擴充于MouseAdapter類,這是因為它隻定義了5個MouseListener方法中的兩個方法。MouseMotionHandler實作了MouseMotionListener接口,并定義了這個接口中的兩個方法。
例8-4是這個程式的清單。
例8-4 MouseTest.java
java.awt.event.MouseEvent 1.1
• int getX( )
• int getY( )
• point getPoint( )
傳回事件發生時,事件源元件左上角的坐标x(水準)和y(豎直),或點資訊。
• void translatePoint(int x, int y)
通過水準移動x機關,垂直移動y機關來轉換事件坐标。
• int getClickCount( )
傳回與事件關聯的滑鼠連擊次數。(“連擊”所指定的時間間隔與具體系統有關。)
java awt.event.InputEvent 1.1
• int getModifiersEx( ) 1.4
傳回事件擴充的或“按下”(down)的修飾符。使用下面的掩碼值檢測傳回值:
BUTTON1_DOWN_MASK
BUTTON2_DOWN_MASK
BUTTON3_DOWN_MASK
SHIFT_DOWN_MASK
CTRL_DOWN_MASK
ALT_DOWN_MASK
ALT_GRAPH_DOWN_MASK
META_DOWN_MASK
• static String getModifiersExText(int modifiers) 1.4
傳回用給定标志集描述的擴充或“按下”(down)的修飾符字元串,例如“Shift+Button1”。
java.awt.Toolkit 1.0
• public Cursor createCustomCursor(Image image, Point hotSpot, String name) 1.2
建立一個新的定制光标對象。
參數:image
光标活動時顯示的圖像
hotSpot
光标熱點(箭頭的頂點或十字中心)
name
光标的描述,用來支援特殊的通路環境
java.awt.Component 1.0
• public void setCursor(Cursor cursor) 1.1
用光标圖像設定給定光标。
焦點事件
用滑鼠可以指向螢幕上的任何一個對象。但是在使用鍵盤輸入時,敲擊鍵盤必須定位于一個特定的螢幕對象。視窗管理器(window manager,例如,Windows或X Windows)直接将所有的擊鍵定位于活動視窗(active window)。通常,活動視窗用高亮度顯示的标題欄進行區分。在任何時刻,隻有一個視窗可以是活動的。
現在假設活動視窗在一個Java程式控制之下。當Java視窗接收到敲擊鍵盤的操作,并定位于某個特定的元件時,這個元件就具有了焦點(focus)。正像活動視窗可以采用某種方式進行辨識一樣,大多數的Swing元件在具有焦點的時候,也可以擁有一個明顯的提示。文本域會顯示閃爍的光标;按鈕上的标簽周圍有一個矩形等等。當文本域具有焦點的時候,可以将文本輸入到文本域中;當按鈕有焦點的時候,可以通過敲擊空格鍵來“點選”這個按鈕。
在一個視窗中,最多隻有一個元件擁有焦點。如果使用者點選另一個元件,那麼剛才擁有焦點的元件就會失去(lose)焦點,而被點選的元件就會獲得焦點。使用者還可以使用TAB鍵在各個元件上輪流切換焦點。這樣可以周遊到所有能夠接收輸入焦點的元件。在預設情況下,Swing元件按照放置在容器中的位置,從上到下,從左到右的順序周遊。也可以改變焦點周遊的順序,有關這個主題更加詳細的内容請參閱下一章。
幸運的是,大多數應用程式程式員不必過分地為焦點處理而擔憂。在JDK 1.4之前,對元件焦點事件的捕獲主要用于核查錯誤與校驗資料。假設在一個文本域中包含信用卡号。當使用者編輯完畢這個域,并将焦點移至另外一個域上時,就應該捕獲失去焦點事件。如果信用卡号的格式不正确,就立即顯示一個錯誤消息,并将焦點傳回到信用卡域上。然而,JDK 1.4有一個更加健壯、更加簡易的資料校驗機制。有關這部分内容将在第9章中讨論。
有些元件,例如,标簽和面闆,在預設情況下無法得到焦點,這是因為它們主要用于裝飾或分組。如果希望編寫一個程式,能夠根據使用者的擊鍵操作在面闆上繪制圖形,就要對預設處理進行覆寫。在JDK 1.4中,可以通過簡單地調用下面這個方法達到目的。
panel.setFocusable(true);
注意:在舊版本的JDK中,要想達到同樣的效果,必須覆寫元件的isFocusTraversable方法。
然而,在舊版本的焦點實作中,獲得焦點與周遊焦點在概念上是分開的。這種分離導緻行為上的混淆,現在已經被廢除。isFocusTraversable方法已經不再提倡使用了。
在本節的剩餘部分,将讨論焦點事件的詳細内容,這些内容完全可以等到需要精心設計焦點控制時再閱讀。
在JDK 1.4中,可以很容易地發現:
• 焦點擁有者,也就是擁有焦點的那個元件。
• 焦點視窗,也就是包含焦點擁有者的視窗。
• 活動視窗,也就是包含焦點擁有者的架構或對話框。
焦點視窗通常與活動視窗是一樣的。隻有在焦點擁有者包含在沒有架構修飾的頂層視窗(例如,彈出式菜單)中時才有所差别。
為了得到這些資訊,首先要獲得鍵盤焦點管理器:
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager( );
然後,調用:
Component owner = manager.getFocusOwner( );
Window focused = manager.getFocusedWindow( );
Window active = manager.getActiveWindow( ); //a frame or dialog
為了能夠得到焦點變化的通知,需要将焦點監聽器安裝到元件或視窗中。一個元件焦點監聽器必須實作FocusListener接口及兩個方法focusGained和focusLost。當元件獲得或失去焦點時将會觸發這兩個方法。這兩個方法都有一個FocusEvent類的參數。在這個類中有幾個很有用的方法。getComponent方法負責報告獲得或失去焦點的元件;isTemporary方法将在焦點發生臨時性地改變時傳回true。臨時性的焦點改變是指元件臨時性地失去控制,但又可以自動地找回焦點。例如,當使用者選擇不同的活動視窗時就會發生這種情況。隻要使用者再次選擇目前的視窗,同一個元件就會重新獲得焦點。
JDK 1.4引入了視窗焦點事件的傳遞,為此,需要将WindowFocusListener添加到視窗,并實作windowGainedFocus和windowLostFocus方法。
在JDK 1.4中,當焦點轉移的時候,可以找到“對等物”元件或視窗。對等物是指在元件或視窗失去焦點時獲得焦點的元件或視窗。相反地,當元件或視窗獲得焦點時,對等物是剛剛失去焦點的那個元件或視窗。FocusEvent類中的getOppositeComponent方法将報告對等元件,WindowEvent類中的getOppositeWindow方法将報告對等的視窗。
可以通過調用Component類中的requestFocus方法,利用程式将焦點從一個元件移到另一個元件上。然而,如果元件沒有包含在目前的焦點視窗中,其行為将與平台有關。為了能夠讓程式員開發與平台無關的代碼,JDK 1.4在Component類中增加了一個方法requestFocusInWindow。這個方法隻有在元件包含在焦點視窗内時才會成功。
注意:不應該在requestFocus或requestFocusInWindow傳回true時就認定元件擁有焦點,而應該等待FOCUS_GAINED事件的發送。
注意:有些程式員覺得FOCUS_LOST事件有些混亂,并試圖在focusLost處理器中通過請求獲得焦點來阻止其他元件。然而,在這個時候,焦點已經失去了。如果必須在一個特定的元件中捕獲焦點,就需要在KeyboardFocusManager中安裝“禁止改變監聽器”,并禁用focusOwner屬性。有關禁用屬性的詳細介紹請參閱卷II第8章。
java.awt.Component 1.0
• void requestFocus( )
請求元件獲得焦點。
• boolean requestFocusInWindow( ) 1.4
請求元件獲得焦點。如果該元件沒有包含在焦點視窗内,傳回true,或者請求由于其他原因請求沒有實作,傳回flase。
• void setFocusable(boolean b) 1.4
• boolean isFocusable( ) 1.4
設定或擷取該元件的“focusable”狀态。如果b為true,則該元件可以獲得焦點。
• boolean isFocusOwner( ) 1.4
如果該元件目前擁有焦點,傳回true。
java.awt.KeyboardFocusManager 1.4
• static KeyboardFocusManager getCurrentKeyboardFocusManager( )
獲得目前焦點管理器。
• Component getFocusOwner( )
得到擁有焦點的元件,如果焦點管理器沒有管理擁有焦點的元件,傳回null。
• Window getFocusedWindow( )
得到包含擁有焦點元件的視窗,如果焦點管理器沒有管理擁有焦點的元件,傳回null。
• Window getActiveWindow( )
得到對話框或包含焦點視窗的架構,如果焦點管理器沒有管理焦點視窗,傳回null。
java.awt.Window( ) 1.0
• boolean isFocused( ) 1.4
如果該視窗是目前的焦點視窗,傳回true。
• boolean isActive( ) 1.4
如果該架構或對話框是目前的活動視窗,傳回true。活動架構和對話框的标題欄通常由視窗管理器辨別出來。
java.awt.event.FocusEvent 1.1
• Component getOppositeComponent( ) 1.4
傳回在focusGained處理器中失去焦點的元件,或者在focusLost處理器中獲得焦點的元件。
java.awt.event.WindowEvent 1.4
• Window getOppositeWindow( ) 1.4
傳回在windowGainedFocus處理器中丢失焦點的視窗,在windowLostFocus處理器中獲得焦點的視窗,在windowActivated處理器中變為不活動的視窗,或者在windowDeactivated處理器中被激活的視窗。
java.awt.event.WindowFocusListener 1.4
• void windowGainedFocus(WindowEvent event)
當事件源視窗獲得焦點時調用這個方法。
• void windowLostFocus(WindowEvent event)
當事件源視窗失去焦點時調用這個方法。
覺得文章不錯的話,可以轉發關注一下小編,小編每天都會持續更新的!
加油~~~~~~