Как запретить элементам управления использовать KeyEvent?

Наше приложение использует пользовательский интерфейс JavaFX с одним этапом, который содержит панель меню вверху и ряд других элементов управления под ним.

Мы хотим использовать KeyCode.SPACE (то есть пробел) в качестве ускорителя для одного из элементов меню в нашей панели меню. Да, я знаю, что это не идеальная клавиша для ускорителя меню. Это не мое решение. :)

Так или иначе, поначалу ускоритель SPACE работал нормально:

menuItem.setAccelerator( KeyCombination.valueOf( "SPACE" ) );

Но когда мы начали добавлять другие элементы управления, такие как TableView, в нашу рабочую область, этот ускоритель перестал работать. Оказывается, эти другие элементы управления используют SPACE для своих целей и потребляют KeyEvent, прежде чем он вернется в MenuBar.

Итак, мы решили, что нам не нужен SPACE для работы с этими другими элементами управления, и поэтому я «решил» проблему, используя фильтр событий. Он крадет SPACE KeyEvent для моего MenuItem, прежде чем он когда-либо доберется до этих других элементов управления:

stage.addEventFilter( KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
  public void handle( KeyEvent e ) {
     if ( e.getCode() == KeyCode.SPACE &&
        !(e.getTarget() instanceof TextInputControl) && 
        !menuItem.isDisable() ) {
           e.consume();
           menuItem.fire();
     }
  }
});

Кажется, это работает, но я надеюсь, что может быть более чистое и менее хрупкое решение. В частности, мне бы очень хотелось найти способ сообщить другим элементам управления (например, TableView) просто прекратить использование SPACE KeyEvent.

Это возможно?


person Xanatos    schedule 01.11.2013    source источник
comment
Как вы думаете. Предположим, у вас есть tableView, который использует пространство для выбора. Что он должен делать с выбором, когда вы используете пространство и для других целей?   -  person Alexander Kirov    schedule 02.11.2013
comment
Как я уже упоминал, потеря функциональности пробела в табличном представлении была бы совершенной. На самом деле, это именно то, что я пытаюсь найти (лучший) способ сделать.   -  person Xanatos    schedule 02.11.2013
comment
Попробуйте посмотреть на это, может быть, вы не видели его раньше: /javafx/scene/control/behavior/TableViewBehaviorBase.java?at=default" rel="nofollow noreferrer">bitbucket.org/narya/jfx78/src/   -  person Alexander Kirov    schedule 02.11.2013
comment
Классы поведения говорят, например, как обрабатывать ключи. Вам необходимо удалить соответствующую привязку клавиш. Подкласс класса TableViewBehavior и замените класс поведения вашего табличного представления. Как возможное решение.   -  person Alexander Kirov    schedule 02.11.2013
comment
Спасибо за предложение. Я изучил его, но похоже, что мне нужно будет использовать отражение для доступа к TableViewBehavior, что не так чисто, как решение, которое у меня уже есть. Если я создам подкласс TableViewBehavior, у меня не будет возможности установить его в TableView без создания собственного скина.   -  person Xanatos    schedule 05.11.2013
comment
Да, это правильно. То есть показать вам, где на самом деле живет решение.   -  person Alexander Kirov    schedule 05.11.2013


Ответы (1)


У меня была похожая проблема: некоторые элементы управления, в частности элементы управления вводом текста, используют функциональные клавиши, которые определены как ускорители меню. Чтобы обойти это, я нашел немного более общий способ заставить ускорители меню иметь приоритет над потреблением ключа элемента управления:

control.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
    @Override
    public void handle(KeyEvent event) {
        Scene scene = control.getScene();
        if (scene == null) {
            return;
        }
        Map<KeyCombination,Runnable> accelerators = scene.getAccelerators();
        for (KeyCombination keyCombination : accelerators.keySet()) {
            if (keyCombination.match(event)) {
                accelerators.get(keyCombination).run();
                event.consume();
                return;
            }
        }
    }
});

Это немного менее хрупкое решение, чем решение, представленное в вопросе, поскольку оно не жестко кодирует ключи в фильтре событий и позволяет выполнять всю обработку пунктов меню с помощью Runnables, исходящего от Scene.getAccelerators(). Эти Runnables определены в классе реализации com.sun.javafx.scene.control.ControlAcceleratorSupport в методе doAcceleratorInstall.

Я предпочитаю добавлять этот фильтр к каждому нарушающему элементу управления, но, конечно, его можно установить и на сцене.

person Gerhard    schedule 11.10.2015