1. 程式人生 > >JavaFX學習筆記——用法技巧總結(五)

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子節點的鍵盤監聽