On Thu, 26 Sep 2024 21:17:55 GMT, John Hendrikx <jhendr...@openjdk.org> wrote:
> This change modifies `ScrollPaneBehavior` to only consume keys that are > targetted at it. As `KeyEvent`s are in almost all cases only intended for > the targetted node (as visually that's where the user expects the keyboard > input to go, as per normal UI rules) consuming key events that bubble up is > simply incorrect. When the `ScrollPane` is focused directly (it has the > focused border) then it is fine for it to respond to all kinds of keys. > > In FX controls normally there is no need to check if a `Control` is focused > (although they probably should **all** do this) as they do not have children > that could have received the Key Events involved, and Key Events are always > sent to the focused Node. When `ScrollPane` was developed this was not taken > into account, leading to it consuming keys not intended for it. > > This fixes several unexpected problems for custom control builders. A custom > control normally benefits from standard navigation out of the box > (TAB/shift+TAB) and directional keys. However, this breaks down as soon as > this custom control is positioned within a `ScrollPane`, which is very > surprising behavior and not at all expected. This makes it harder than > needed for custom control developers to get the standard navigation for the > directional keys, as they would have to specifically capture those keys > before they reach the `ScrollPane` and trigger the correct navigation action > themselves (for which as of this writing there is no public API). > > The same goes for all the other keys captured by `ScrollPane` when it does > not have focus, although not as critical as the UP/DOWN/LEFT/RIGHT keys. Here is a minimal working example that demonstrates the issue when people create a custom control. Note that the standard controls and the custom control all have directional navigation working, except in the case where the custom control is embedded inside a `ScrollPane`. This creates a big burden on custom control developers as to make their control work when used in a scroll pane, they now need to implement their own navigation... package app; import javafx.application.Application; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.control.Skin; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class App extends Application { @Override public void start(Stage primaryStage) { GridPane gp = new GridPane(10, 10); gp.add(new VBox(new Label("Standard Buttons in normal container"), new HBox(5, new Button("A"), new Button("B"), new Button("C"))), 0, 0); gp.add(new VBox(new Label("Standard Buttons in ScrollPane"), new ScrollPane(new HBox(5, new Button("A"), new Button("B"), new Button("C")))), 1, 0); gp.add(new VBox(new Label("Custom Buttons in normal container"), new HBox(5, new CustomButton("A"), new CustomButton("B"), new CustomButton("C"))), 0, 1); gp.add(new VBox(new Label("Custom Buttons in ScrollPane"), new ScrollPane(new HBox(5, new CustomButton("A"), new CustomButton("B"), new CustomButton("C")))), 1, 1); Scene scene = new Scene(gp); primaryStage.setScene(scene); primaryStage.show(); } static class CustomButton extends Button { CustomButton(String title) { super(title); setSkin(new CustomButtonSkin(this)); } } static class CustomButtonSkin implements Skin<Button> { private final Button control; private final StackPane container; public CustomButtonSkin(Button button) { this.control = button; this.container = new StackPane(); this.container.getChildren().add(new Label(button.getText())); } @Override public Button getSkinnable() { return control; } @Override public Node getNode() { return container; } @Override public void dispose() { container.getChildren().clear(); } } } ------------- PR Comment: https://git.openjdk.org/jfx/pull/1582#issuecomment-2385454753