2013-10-28 46 views
6

我收到了一個包含可調焦節點的ScrollPaneJavaFX:使用箭頭鍵滾動與焦點遍歷

當前的默認行爲是:

  • + 移動聚焦

  • 滾動視圖

我希望它周圍的其他方法。 我該如何做到這一點,或者我應該從哪裏開始?


[編輯]嗯,還有另一種脆弱的方法。

而不是亂搞事件,人們可能會混淆KeyBinding s。

scrollPane.skinProperty().addListener(new ChangeListener<Skin<?>>() { 
     @Override 
     public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) { 
      ScrollPaneSkin scrollPaneSkin = (ScrollPaneSkin) scrollPane.getSkin(); 
      ScrollPaneBehavior scrollPaneBehavior = scrollPaneSkin.getBehavior(); 
      try { 
       Field keyBindingsField = BehaviorBase.class.getDeclaredField("keyBindings"); 
       keyBindingsField.setAccessible(true); 
       List<KeyBinding> keyBindings = (List<KeyBinding>) keyBindingsField.get(scrollPaneBehavior); 
       List<KeyBinding> newKeyBindings = new ArrayList<>(); 
       for (KeyBinding keyBinding : keyBindings) { 
        KeyCode code = keyBinding.getCode(); 
        newKeyBindings.add(code == KeyCode.LEFT || code == KeyCode.RIGHT || code == KeyCode.UP || code == KeyCode.DOWN ? keyBinding.shift() : keyBinding); 
       } 
       keyBindingsField.set(scrollPaneBehavior, newKeyBindings); 
      } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 
       LOGGER.warn("private api changed.", e); 
      } 
     } 
    }); 

我想,這可能是更清潔的方式,如果一個KeyBinding更非靜態,modifyable和公衆。

回答

4

使用event filter來捕獲相關的按鍵事件,並在事件開始冒泡之前將其重新映射到不同的按鍵事件。

重新映射默認鍵是一個棘手的事情:

  1. 可以迷惑用戶。
  2. 可能會有意想不到的副作用(例如,TextFields可能無法按預期工作)。

所以請謹慎使用:

import javafx.application.*; 
import javafx.event.*; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.input.KeyEvent; 
import javafx.scene.layout.TilePane; 
import javafx.stage.Stage; 

import java.util.*; 

public class ScrollInterceptor extends Application { 

    @Override 
    public void start(Stage stage) { 
    ScrollPane scrollPane = new ScrollPane(
     createScrollableContent() 
    ); 

    Scene scene = new Scene(
     scrollPane, 
     300, 200 
    ); 

    remapArrowKeys(scrollPane); 

    stage.setScene(scene); 
    stage.show(); 

    hackToScrollToTopLeftCorner(scrollPane); 
    } 

    private void remapArrowKeys(ScrollPane scrollPane) { 
    List<KeyEvent> mappedEvents = new ArrayList<>(); 
    scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() { 
     @Override 
     public void handle(KeyEvent event) { 
     if (mappedEvents.remove(event)) 
      return; 

     switch (event.getCode()) { 
      case UP: 
      case DOWN: 
      case LEFT: 
      case RIGHT: 
      KeyEvent newEvent = remap(event); 
      mappedEvents.add(newEvent); 
      event.consume(); 
      Event.fireEvent(event.getTarget(), newEvent); 
     } 
     } 

     private KeyEvent remap(KeyEvent event) { 
     KeyEvent newEvent = new KeyEvent(
      event.getEventType(), 
      event.getCharacter(), 
      event.getText(), 
      event.getCode(), 
      !event.isShiftDown(), 
      event.isControlDown(), 
      event.isAltDown(), 
      event.isMetaDown() 
     ); 

     return newEvent.copyFor(event.getSource(), event.getTarget()); 
     } 
    }); 
    } 

    private TilePane createScrollableContent() { 
    TilePane tiles = new TilePane(); 
    tiles.setPrefColumns(10); 
    tiles.setHgap(5); 
    tiles.setVgap(5); 
    for (int i = 0; i < 100; i++) { 
     Button button = new Button(i + ""); 
     button.setMaxWidth(Double.MAX_VALUE); 
     button.setMaxHeight(Double.MAX_VALUE); 
     tiles.getChildren().add(button); 
    } 
    return tiles; 
    } 

    private void hackToScrollToTopLeftCorner(final ScrollPane scrollPane) { 
    Platform.runLater(new Runnable() { 
     @Override 
     public void run() { 
     scrollPane.setHvalue(scrollPane.getHmin()); 
     scrollPane.setVvalue(0); 
     } 
    }); 
    } 

    public static void main(String[] args) { 
    launch(args); 
    } 
} 
+0

這正是我一直在尋找。首先嚐試將代碼接管到我的應用程序中,但導致出現StackOverflowError錯誤。我會在晚上看這個。謝謝! –

+1

copyFor語句是關鍵,否則代碼JavaFX系統將在內部複製事件以設置源和目標,因此您將最終處於事件重新映射的無限循環中,打開和關閉切換修改器,導致溢出。我的測試系統是帶有Java 8的OS X. – jewelsea

+0

不知何故,在我的應用程序中,沒有事件從'mappedEvents'列表中移除。你的例子工作正常。我無法弄清楚到目前爲止發生了什麼變化。 –

相關問題