Reputation: 315
I want arrow keys in a ScrollPane
to work in a way other than the default. Consuming arrow keys in a KeyPressed
handler on the ScrollPane
does not prevent them from being processed by he ScrollPane
. Is there something that works?
In the example program,
h
or left-arrow to move the rect to the left on the grid as expected.l
or right-arrow to move the rect to the right on the grid as expected.Fig 1. Start
Fig 2. Start, then h
key (rect moves left on the grid)
Fig. 3. Start, then left-arrow key (rect moves left on the grid, and the ScrollPane slider makes an unwanted move to the left)
Notes:
KeyClicked
and KeyReleased
are apparently irrelevant.Pane
.ScrollPane
, indicating keyboard focus.Pane
prevents the highlighting for keyboard focus.ScrollPane
behavior of the arrow keys is not a problem for my App.import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ScrollPaneArrowKeys extends Application {
public static void main(String[] args) { launch(args); }
static Rectangle rect;
static ScrollPane sp;
@Override
public void start(Stage stage) {
rect = new Rectangle (100, 50);
var pane = new Pane (rect);
sp = new ScrollPane(pane);
var scene = new Scene (sp);
rect.setFill(Color.PALEGREEN);
pane.setMinWidth (600);
pane.setMinHeight(150);
pane.setStyle(grid);
sp.setMinWidth (300);
sp.setMinHeight(170);
sp.setHvalue(0.5);
sp.setOnKeyPressed(ScrollPaneArrowKeys::onKeyPressed);
sp.requestFocus();
reset();
stage.setScene(scene);
stage.show();
}
private static void onKeyPressed(KeyEvent e) {
switch (e.getCode()) {
case H:
case LEFT: rect.setX(rect.getX() - 10); break;
case L:
case RIGHT: rect.setX(rect.getX() + 10); break;
case ESCAPE: reset(); break;
default: break;
}
e.consume();
}
private static void reset() {
rect.setX(250);
rect.setY( 50);
sp.setHvalue(0.5);
}
String grid = """
-fx-background-color: white,
linear-gradient(from 0px 0px to 10px 0px, repeat, #d8f0f8 6.25%, transparent 6.25%),
linear-gradient(from 0px 0px to 50px 0px, repeat, #b0e0e8 1.25%, transparent 1.25%),
linear-gradient(from 0px 0px to 0px 10px, repeat, #d8f0f8 6.25%, transparent 6.25%),
linear-gradient(from 0px 0px to 0px 50px, repeat, #b0e0e8 1.25%, transparent 1.25%);
""";
}
Upvotes: 0
Views: 293
Reputation: 1708
If you want to override the default key handling of the Scroll Pane, you can achieve it with registering an Event Filter (instead of adding another Event Handler). You can read about this in e. g. this posting: JavaFX: What is the difference between EventHandler and EventFilter?
Considering the User Experience you may want to add another possibility for scrolling (e. g. CTRL
+ LEFT
etc.). Here is a working example (the most part is taken from your code):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ScrollPaneArrowKeys extends Application {
private final Rectangle rect = new Rectangle(100, 50);
private final Pane pane = new Pane(rect);
private final ScrollPane sp = new ScrollPane(pane);
private final Scene scene = new Scene(sp);
@Override
public void start(Stage stage) {
// Register an Event Filter to override the default behaviour:
sp.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
e.consume(); // prevent default key handling
// Allow the user to scroll horizontally with the control key:
if (e.isControlDown())
switch (e.getCode()) {
case LEFT -> sp.setHvalue(sp.getHvalue() - .1);
case RIGHT -> sp.setHvalue(sp.getHvalue() + .1);
}
else
// Move they rectangle only:
switch (e.getCode()) {
case H, LEFT -> rect.setX(rect.getX() - 10);
case L, RIGHT -> rect.setX(rect.getX() + 10);
case ESCAPE -> resetRectPosition();
}
});
initStyling();
resetRectPosition();
stage.setScene(scene);
stage.show();
sp.requestFocus();
}
private void initStyling() {
rect.setFill(Color.PALEGREEN);
pane.setMinWidth(600);
pane.setMinHeight(150);
pane.setStyle("""
-fx-background-color: white,
linear-gradient(from 0px 0px to 10px 0px, repeat, #d8f0f8 6.25%, transparent 6.25%),
linear-gradient(from 0px 0px to 50px 0px, repeat, #b0e0e8 1.25%, transparent 1.25%),
linear-gradient(from 0px 0px to 0px 10px, repeat, #d8f0f8 6.25%, transparent 6.25%),
linear-gradient(from 0px 0px to 0px 50px, repeat, #b0e0e8 1.25%, transparent 1.25%);
""");
sp.setMinWidth(300);
sp.setMinHeight(170);
sp.setHvalue(0.5);
}
private void resetRectPosition() {
rect.setX(250);
rect.setY(50);
sp.setHvalue(0.5);
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 2