Эквивалент FocusEvent.getOppositeComponent в JavaFx - PullRequest
13 голосов
/ 16 мая 2019

В моем приложении JavaFx я хочу вызвать метод, когда основной кадр получает фокус. Однако я хочу реагировать только в том случае, если фокус был за пределами моего приложения и вернулся (не при закрытии диалога, например).

Когда приложение было в Swing, я мог использовать метод

FocusEvent.getOppositeComponent

(что соответствует элементу, который потерял фокус), и если он был нулевым, я знал, что фокус ранее находился вне моего приложения.

Я не нашел никакого эквивалента в JavaFX.

Я попытался просмотреть события окна, добавив фильтр событий в моем окне:

primaryStage.addEventFilter(Event.ANY, e -> System.out.println("event " + e));

но он не отслеживает события фокуса.

Ответы [ 3 ]

5 голосов
/ 19 мая 2019

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

В JavaFX нет «FocusEvent», вы можете найти все типы событий, перечисленные в Event.

Вы можете запросить функцию здесь .

2 голосов
/ 24 мая 2019

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

Когда окно w1 закрывается, фокусируясь на окне w2, порядок событий следующий:

  1. w1 получает событие WINDOW_HIDING
  2. w2 focusProperty изменяется на true
  3. w1 получает событие WINDOW_HIDDEN

Итак, я написал следующий код, чтобы я мог знать, исходит ли фокус от внутреннего окна:

public class MainStage {
    private Stage primaryStage;
    private AtomicBoolean triggerEventOnFocusGain = new AtomicBoolean(true);

    ...

    primaryStage.focusedProperty.addListener((prop, oldVal, newVal) -> {
        if(newVal.booleanValue() && triggerEventOnFocusGain.get()) {
            doStuff();
        }
    });
}

public class SomeDialog {
    private MainStage mainStage;
    private Window dialogWindow;

    ...

    dialogWindow.addEventHandler(WindowEvent.WINDOW_HIDING, event ->
        mainStage.setTriggerEventOnFocusGain(false));
    dialogWindow.addEventHandler(WindowEvent.WINDOW_HIDDEN, event ->
        mainStage.setTriggerEventOnFocusGain(true));
}

Единственная проблема заключается в том, что я должен сделать это для всех внутренних окон / диалогов.

В моем случае я в конечном итоге решил, что могу сделать это только для нескольких диалогов, для которых запуск события будет проблематичным, и игнорировать другие.

Другим способом, конечно, было бы введение общего абстрактного родителя всех моих классов представлений, который выполняет приведенный выше код.

1 голос
/ 18 мая 2019

JavaFX иерархия основана на: Stage -> Scene -> Nodes -> ... -> Nodes:

enter image description here

Если вы хотите прослушать фокус Stage (окно), вы можете добавить слушателя к Сосредоточенному на сцене свойству из Stage:

Stage stage = ...
stage.focusedProperty()
        .addListener((observable, oldValue, newValue) -> {
                    if (!stage.isFocused()) { 
                       //action
                    }
                }
        );

Это не решает проблему в вопросе.Вы не можете сказать здесь, какой компонент был в центре внимания.oldValue и newValue являются логическими значениями, поэтому ваш if тривиален

Вы можете проверить, что все Stage s потеряли фокусы (реализовать пользовательский ChangeListener):

class AllStageUnfocusedListener implements ChangeListener<Boolean>{
    //IdentitySet and Runnable use only as example
    private final Set<Stage> stageSet;
    private final Runnable runnable;

    public AllStageUnfocusedListener(Runnable runnable) {
        this.stageSet =  Collections.newSetFromMap(new IdentityHashMap<>());
        this.runnable =  runnable;
    }

    public ChangeListener<Boolean> add(Stage stage){
        stageSet.add(stage);
        return this;
    }

    @Override
    public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
        if(isAllStageLostFocus()){
            runnable.run();
        }
    }

    private boolean isAllStageLostFocus() {
        for (Stage stage : stageSet) {
            if (stage.isFocused()) {
                return false;
            }
        }
        return true;
    }
} 

и добавьте Listener к Focused Property:

AllStageUnfocusedListener changeListener = new AllStageUnfocusedListener(() -> { /* action */ });
Stage stage = ...
stage.focusedProperty()
            .addListener(changeListener.add(stage))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...