JavaFX: scrolling vs. focus traversal with arrow keys

后端 未结 1 1072
北海茫月
北海茫月 2020-12-16 05:21

I got a ScrollPane containing focusable Nodes.

The current default behaviour is:

  • Shift + , , →<

相关标签:
1条回答
  • 2020-12-16 06:22

    Use an event filter to capture the relevant key events and remap them to different key events before the events start to bubble.

    Re-mapping default keys is a tricky thing which:

    1. Can confuse the user.
    2. May have unexpected side effects (e.g. TextFields may no longer work as you expect).

    So use with care:

    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 讨论(0)
提交回复
热议问题