Jfoenix: Disable default Left/Right Arrow Navigation from Keyboard

Created on 22 Oct 2018  ·  12Comments  ·  Source: sshahine/JFoenix

Is there any way to disable the default right/left arrow from changing tabs on the TabPane :) ?

Most helpful comment

Sure:

This suppresses(consumes) all incoming KeyEvents:

...
    tabPane.addEventFilter(KeyEvent.ANY, Event::consume);
...

or use it more specific only on LeftRight Keys:

...
    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {
          if (EnumSet.of(KeyCode.LEFT, KeyCode.RIGHT).contains(event.getCode())) {
            event.consume();
          }
        });
...

Greetings

All 12 comments

currently no, however you can set visibility to false through css

@jfoenixadmin Sorry for miss undestanding . I mean when the user presses the Left/Right arrows from the Keyboard :)

I see, I think adding a key press/release filter will fix the issue.

Can i have some code? I have tried but no success.

Sure:

This suppresses(consumes) all incoming KeyEvents:

...
    tabPane.addEventFilter(KeyEvent.ANY, Event::consume);
...

or use it more specific only on LeftRight Keys:

...
    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {
          if (EnumSet.of(KeyCode.LEFT, KeyCode.RIGHT).contains(event.getCode())) {
            event.consume();
          }
        });
...

Greetings

3 years writing JavaFX and still i am impressed by the provided code.

Thank you unlimited ❤ @

You are welcome :smiley:
Ah and you could also use the "isArrowKey()" method included in KeyCode Enum:

...
    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {
          if (event.getCode().isArrowKey()) {
            event.consume();
          }
        });
...

But this also includes the UP and DOWN and Numpad Arrow Keys.
I dont know if this is the desired behaviour :wink:

Exactly what i was looking forrr, unlimited thanks :) :) :)

On Thu, Nov 8, 2018, 03:44 Marcel Schlegel notifications@github.com wrote:

You are welcome 😃
Ah and you could also use the "isArrowKey()" method included in KeyCode
Enum:

...
tabPane.addEventFilter(
KeyEvent.ANY,
event -> {
if (event.getCode().isArrowKey()) {
event.consume();
}
});...

But this also includes the UP and DOWN and Numpad Arrow Keys.
I dont know if this is the desired behaviour 😉


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/jfoenixadmin/JFoenix/issues/854#issuecomment-436843029,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATbiwOOzLJLOgiPOZihW8-k11ROPj7NXks5us4xvgaJpZM4X0C83
.

@schlegel11 I have one problem with that ... all the children that belong inside JFXTabPane don't receive arrow events anymore :( .

What i really want is only the children inside to receive arrow events and not the JFXTabPane.

Ah ok I see :wink:
So you have to distinguish between the JFXTabPane and other Nodes in the dispatch hierarchy.
You can do it the following way:

We use the "event.getTarget()" method to get our target element. The event target is more or less the target element where this event belongs to or better where it was triggered.

If you have direct access to your JFXTabPane instance the solution is more simple:

...
    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {
          if (event.getCode().isArrowKey() && event.getTarget() == tabPane) {
            event.consume();
          }
        });
...

So in any case where a KeyEvent was triggered from a child element of tabPane the target element is not the tabPane instance itself and therefore the event isn't consumed.

if you don't have direct access to your JFXTabPane instance we could use the common Node Id as an identifier:

...
    //We have to set an Id to the JFXTabPane
    tabPane.setId("__MyUniqueTabPaneId__");

...

    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {
          // I think we can expected that the EventTarget represents always a Node but if a child element 
          // in tabPane isn't a Node we do a type check for safety.
         // If the cast or the getId method returns null we get an empty String.
          String eventTargetId =
              Optional.of(event.getTarget())
                      .filter(Node.class::isInstance)
                      .map(Node.class::cast)
                      .map(Node::getId).orElse("");

          if (event.getCode().isArrowKey() && eventTargetId.equals("__MyUniqueTabPaneId__")) {
            event.consume();
          }
        });
...

Now If the event target id is equal to our tabPane instance we consume the event.

Socked ©_©. In Love. Thank you soo much, o my god you know so much!!!

On Sun, Nov 11, 2018, 16:47 Marcel Schlegel notifications@github.com
wrote:

Ah ok I see 😉
So you have to distinguish between the JFXTabPane and other Nodes in the
dispatch hierarchy.
You can do it the following way:

We use the "event.getTarget()" method to get our target element. The event
target is more or less the target element where this event belongs to or
better where it was triggered.

If you have direct access to your JFXTabPane instance the solution is more
simple:

...
tabPane.addEventFilter(
KeyEvent.ANY,
event -> {
if (event.getCode().isArrowKey() && event.getTarget() == tabPane) {
event.consume();
}
});...

So in any case where a KeyEvent was triggered from a child element of
tabPane the target element is not the tabPane instance itself and therefore
the event isn't consumed.

if you don't have direct access to your JFXTabPane instance we could use
the common Node Id as an identifier:

...
//We have to set an Id to the JFXTabPane
tabPane.setId("__MyUniqueTabPaneId__");
...

tabPane.addEventFilter(
    KeyEvent.ANY,
    event -> {
      // I think we can expected that the EventTarget represents always a Node but if a child element
      // in tabPane isn't a Node we do a type check for safety.
     // If the cast or the getId method returns null we get an empty String.
      String eventTargetId =
          Optional.of(event.getTarget())
                  .filter(Node.class::isInstance)
                  .map(Node.class::cast)
                  .map(Node::getId).orElse("");

      if (event.getCode().isArrowKey() && eventTargetId.equals("__MyUniqueTabPaneId__")) {
        event.consume();
      }
    });...

Now If the event target id is equal to our tabPane instance we consume the
event.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/jfoenixadmin/JFoenix/issues/854#issuecomment-437675960,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATbiwDDwLray2g2FDr7PW7bcECdTXbvCks5uuDiAgaJpZM4X0C83
.

No problem :smile: You are welcome.
So if you go with the second approach I would remove the isInstance check because currently I don't see any situation where event.getTarget() isn't a Node type. So you could write:

...

    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {

          String eventTargetId =
              Optional.of(event.getTarget())
                      .map(Node.class::cast)
                      .map(Node::getId).orElse("");

          if (event.getCode().isArrowKey() && eventTargetId.equals("__MyUniqueTabPaneId__")) {
            event.consume();
          }
        });
...

Maybe I'd still do it a little bit differently, because I tried to use a more functional approach with Optional. I'm currently not sure how the JVM handles such an Optional or if the performance decreases (ok anyway this small code part is so minimal I don't think the performance would suffer at all). So we could use also this approach:

...

    tabPane.addEventFilter(
        KeyEvent.ANY,
        event -> {

          Node eventTarget = (Node) event.getTarget();
          String eventTargetId = eventTarget.getId();
          if (eventTargetId == null || !eventTargetId.equals("__MyUniqueTabPaneId__")) {
            return;
          }

          if (event.getCode().isArrowKey()) {
            event.consume();
          }
        });
...

Overall the impact of readability or performance should be minimal, so you can decide :wink:

Was this page helpful?
0 / 5 - 0 ratings