Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8340852 ScrollPane should not consume navigation keys when it doesn't have direct focus
  3. JDK-8343066

Release Note: `ScrollPane` Consumes Navigation Keys Only When It Has Direct Focus

XMLWordPrintable

    • Icon: Sub-task Sub-task
    • Resolution: Delivered
    • Icon: P4 P4
    • jfx24
    • jfx24
    • javafx

      `ScrollPane` now only responds to key events when it is the active focus owner. This ensures that custom controls and other UI elements work correctly inside a `ScrollPane`, providing a more consistent and intuitive navigation experience.

      Applications that prefer the previous behavior, where `ScrollPane` always reacts to arrow keys and other navigational inputs, can manually restore it by adding an event handler. See [this note](notes/24/JDK-8340852-ScrollPane.md) for an example of how to do this.

      ------------------------------------------------------------------------------------------------
      notes/24/JDK-8340852-ScrollPane.md:

      # Additional Information for JDK-8340852

      ## Reverting to Previous `ScrollPane` Behavior:

      The fix for [JDK-8340852](https://bugs.openjdk.org/browse/JDK-8340852) changed the behavior of `ScrollPane`. With the latest update, `ScrollPane` only responds to keyboard navigation when it is the focused node. If you prefer the previous behavior, where `ScrollPane` always reacts to arrow keys and other navigational inputs, you can manually restore it by adding an event handler:

      ```java
      scrollPane.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
          double x = 0;
          double y = 0;

          switch (e.getCode()) {
              case LEFT -> x = -0.1;
              case RIGHT -> x = 0.1;
              case UP -> y = -0.1;
              case DOWN -> y = 0.1;
              case PAGE_UP -> y = -0.9;
              case PAGE_DOWN, SPACE -> y = 0.9;
              case HOME -> x = y = Double.NEGATIVE_INFINITY;
              case END -> x = y = Double.POSITIVE_INFINITY;
              default -> {}
          }

          if (x != 0 || y != 0) {
              scrollByFraction(scrollPane, x, y);
              e.consume();
          }
      });
      ```
      Using this helper method to convert scroll fractions to values for the scrollbars, and set them:
      ```java
      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);
          }
      }
      ```
      Adding this event handler will make `ScrollPane` react to navigation keys as it did before the update.


            jhendrikx John Hendrikx
            kcr Kevin Rushforth
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: