On Mon, 7 Oct 2024 15:26:16 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. > > John Hendrikx has updated the pull request incrementally with one additional > commit since the last revision: > > Add information about how ScrollPane acts on key presses. For users to get back to old behavior, some calculations need to be done as `ScrollPane` doesn't offer any helpful programmatic methods to scroll the pane (which is perhaps something that could be addressed in a separate issue, I filed https://bugs.openjdk.org/browse/JDK-8342654). The most useful helper is one that scroll by a fraction, shown below: static void scrollByFraction(ScrollPane scrollPane, double x, double y) { Node content = scrollPane.getContent(); if (content == null) { return; } Bounds viewportBounds = scrollPane.getViewportBounds(); Bounds layoutBounds = content.getLayoutBounds(); if (x != 0) { double visibleFraction = viewportBounds.getWidth() / layoutBounds.getWidth(); double range = scrollPane.getHmax() - scrollPane.getHmin(); double scrollFactor = range * visibleFraction / (1 - visibleFraction); scrollPane.setHvalue(scrollPane.getHvalue() + x * scrollFactor); } if (y != 0) { double visibleFraction = viewportBounds.getHeight() / layoutBounds.getHeight(); double range = scrollPane.getVmax() - scrollPane.getVmin(); double scrollFactor = range * visibleFraction / (1 - visibleFraction); scrollPane.setVvalue(scrollPane.getVvalue() + y * scrollFactor); } } Then to get something similar to the old behavior back is to install an event handler: scrollPane.addEventHandler(KeyEvent.KEY_PRESSED, e -> { double x = 0; double y = 0; switch(e.getCode()) { case KeyCode.LEFT -> x = -0.1; case KeyCode.RIGHT -> x = 0.1; case KeyCode.UP -> y = -0.1; case KeyCode.DOWN -> y = 0.1; case KeyCode.PAGE_UP -> y = -0.9; case KeyCode.PAGE_DOWN -> y = 0.9; case KeyCode.SPACE -> y = 0.9; case KeyCode.HOME -> x = y = Double.NEGATIVE_INFINITY; case KeyCode.END -> x = y = Double.POSITIVE_INFINITY; default -> {} } if (x != 0 || y != 0) { scrollByFraction(scrollPane, x, y); e.consume(); } }); Note that this doesn't exactly replicate the old behavior, but is probably a much more useful implementation than what was provided as standard before. ------------- PR Comment: https://git.openjdk.org/jfx/pull/1582#issuecomment-2425243570