JavaFX學習筆記——用法技巧總結(五)
如何正確監聽鍵盤事件
問題
對於一個事件的觸發,這裡摘取JavaFx China對於常用的滑鼠事件和鍵盤事件的描述
當一個動作發生時,系統根據內部規則決定哪一個Node是事件目標。規則如下:
● 對於鍵盤事件,事件目標是已獲取焦點的Node。
● 對於滑鼠事件,事件目標是游標所在位置處的Node。
對於一個可輸入可聚焦的類似於textField的物件,鍵盤事件的使用也完全沒有任何問題,因為用的是ActionEvent,不再贅述。
但倘若有如下場景,需要為一個不可聚焦的circle註冊一個Y快捷鍵,讓你單擊Y鍵使得circle半徑增大一倍,你可能會編寫如下程式碼
Circle circle = new Circle(100,100,50);
Pane pane = new Pane();
ObservableList<Node> list = pane.getChildren();
list.add(circle);
//註冊快捷鍵明顯用lambda表示式建立匿名物件更合適
circle.setOnKeyTyped(e->{
if(e.getCode() == KeyCode.Y)
circle.setRadius(circle.getRadius()*2);
});
執行後介面如下
你會發現如何按Y鍵這個圓也沒有變大
分析
你通過查詢API文件中對setOnKeyType的描述,
Defines a function to be called when this Node
or its child Node
has input focus and a key has been typed. The function is called only if the event hasn't been already consumed during its capturing or bubbling phase.
你會留意到紅色註明的地方,猜想事件無響應的原因就是沒有focus,對circle呼叫輸出isFocused()結果為false,證實了我們的猜想
System.out.println(circle.isFocused())
機智的你可能會查到使用requestFocus來手動讓circle獲取焦點,從而可以正常監聽鍵盤事件,但結果……
circle.requestFocus();
System.out.println(circle.isFocused())
納尼!明明上一句程式碼requestFocus緊接著輸出怎麼還是false,md一定是requestFocus沒用,這JavaFX什麼鬼!
並非requestFocus無用,而是JavaFX的另一個機制在作怪(具體測試方法就是不斷變換上述程式碼的位置):焦點只能在stage.show()了之後才能獲取,而且預設由stage.setScene(scene)中的scene獲取。所以circle.requestFocus()要在scene.setOnKeyType中進行才有用
結論
1.對於快鍵鍵這類需要全域性監聽的鍵盤事件,對scene進行setOnKeyType,然後根據e.getCode的值來呼叫相應的方法
2.對於確實需要讓該子節點獲得焦點的情況,需要其他可順利觸發的事件的處理器中node.requestFocus()來開啟這個node子節點的鍵盤監聽