Skip to content

Conversation

@abhinayagarwal
Copy link
Member

Fixes #1073

// Fix for Issue #522: Prevent NotificationPane from receiving focus
ParentTraversalEngine engine = new ParentTraversalEngine(getSkinnable());
ReflectionUtils.setTraversalEngine(control, engine);
engine.setOverriddenFocusTraversability(false);
Copy link
Member Author

@abhinayagarwal abhinayagarwal Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a fix for these 3 lines has made me realized the importance of a Traversal Engine in JavaFX. Most of the heavy lifting was already done by @JonathanGiles in JDK-8091673. @Maxoudela @eugener Do you think its worth pursuing this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the purpose of these 3 lines?

Copy link
Member Author

@abhinayagarwal abhinayagarwal Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU, it disables the Parent nodes in a custom control from receiving focus. However, the child (non-parent) nodes can still receive focus.

It was implemented as a fix for #713 by @effad

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm what @abhinayagarwal has said about these lines. The issue-number #522 refers to BitBucket-Issues (no longer existant ...).
I also would appreciate if the TraversalEngine would be part of the public API. After all, the above lines are very hacky :-).

actionsBar.opacityProperty().bind(transition);
actionsBar.focusedProperty().addListener((o, ov, hasFocus) -> {
if (!actionsBar.getButtons().isEmpty()) {
actionsBar.getButtons().get(0).requestFocus();
Copy link

@ghost ghost Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care about thread-safety? If so, then it's possible that the button is removed between lines 175 and 176, resulting in a NullPointerException. Thoughts on an OOP alternative that upholds encapsulation? Maybe it's not possible, but something like:

actionBar.giveButtonFocus(OK_BUTTON);  // OK_BUTTON constant = 0

That would eliminate the need for the conditional (in this method anyway). The actionsBar class would need a method like:

private final Object mutex = new Object();

public void giveButtonFocus( final int index ) {
  final var buttons = getButtons();

  // Don't allow multiple threads to enter this block. This would have to
  // be sync'd on removal. Or use a synchronized collection.
  synchronized( mutex ) {
    // index is 0-based, size starts at 1 if not empty, so use >
    if( buttons.size() > index ) {
      buttons.get( index ).requestFocus();
    }
  }
}

That's then reusable, thread-safe, and will throw neither an NullPointerException nor an ArrayIndexOutOfBounds exception.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaFX is a single threaded GUI framework i.e. all scene-graph activities are done on the JavaFX application thread. Therefore, activities like removing of nodes, focus etc. are all inherently executed synchronously.

@abhinayagarwal abhinayagarwal marked this pull request as ready for review November 11, 2021 09:16
@abhinayagarwal
Copy link
Member Author

Marking this PR as RFR

@abhinayagarwal abhinayagarwal merged commit e2ac714 into controlsfx:jfx-13 Nov 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Need various --add-exports to have RangeSlider work in modularized project.

3 participants