相当于 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时,事件顺序如下:
- w1 receives event WINDOW_HIDING
- w2 focusProperty changes to true
- 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 执行此操作。
在我的例子中,我最终决定我可以只对少数几个对话框这样做,因为它们触发事件会有问题,而忽略其他的。
当然,另一种方法是为我的所有视图引入一个通用的抽象父级 类 来执行上述代码。
在我的 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
andnewValue
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时,事件顺序如下:
- w1 receives event WINDOW_HIDING
- w2 focusProperty changes to true
- 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 执行此操作。
在我的例子中,我最终决定我可以只对少数几个对话框这样做,因为它们触发事件会有问题,而忽略其他的。
当然,另一种方法是为我的所有视图引入一个通用的抽象父级 类 来执行上述代码。