相当于 JavaFx 中的 FocusEvent.getOppositeComponent

Equivalent of FocusEvent.getOppositeComponent in JavaFx

在我的 JavaFx 应用程序中,我想在主框架获得焦点时调用一个方法。但是,我只想在焦点在我的应用程序之外并返回的情况下做出反应(例如,当对话框关闭时)。

当应用程序在 Swing 中时,我可以使用方法

FocusEvent.getOppositeComponent

(对应于失去焦点的元素),如果它为空,我知道焦点之前在我的应用程序之外。

我没有在 JavaFX 中找到任何等效项。

我尝试查看 window 事件,方法是在我的 window:

上添加事件过滤器
primaryStage.addEventFilter(Event.ANY, e -> System.out.println("event " + e));

但它不跟踪焦点事件。

JavaFX 层次结构基于:Stage -> Scene -> Nodes -> ... -> Nodes:

如果想监听Stage(window)的焦点,可以在Stage focused属性添加监听器Stage:

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

This doesn't solve the problem in the question. You can't tell here what component had the focus. oldValue and newValue are booleans, so your if is trivial

你可以检查你是否都Stage丢失了 重点(实现自定义 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))

JavaFX 中没有等效项。每个 window 的焦点更改分别作为 boolean property 处理,因此您只能判断 window 是收到焦点还是失去焦点。如果您为应用程序中的所有 windows 注册一个侦听器,您可以判断其中一个是否在另一个获得焦点时失去了焦点。

JavaFX中没有"FocusEvent",你可以找到Event中列出的所有事件类型。

您可以请求功能 here

我终于找到了 semi-satisfactory 处理问题的方法,使用 JavaFX 中的事件顺序,所以我将其作为答案发布,以防它能帮助其他人。

当windoww1关闭,焦点转移到windoww2时,事件顺序如下:

  1. w1 receives event WINDOW_HIDING
  2. w2 focusProperty changes to true
  3. w1 receives event WINDOW_HIDDEN

所以我写了下面的代码让我知道焦点是否来自内部 window:

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));
}

唯一的问题是我必须对所有内部 windows/dialogs 执行此操作。

在我的例子中,我最终决定我可以只对少数几个对话框这样做,因为它们触发事件会有问题,而忽略其他的。

当然,另一种方法是为我的所有视图引入一个通用的抽象父级 类 来执行上述代码。