在javafx中检测特定窗格外的焦点

在javafx中检测特定窗格外的焦点,java,javafx,Java,Javafx,如何检测焦点已离开特定窗格?由于窗格(StackPane)不可聚焦,因此我在执行此操作时遇到问题。例如,我有一个带有TextFields的StackPane,如果我多次按tab键,它将离开焦点窗格并转到另一个窗格。如果您离开StackPane的焦点,我想通过将焦点设置回窗格中的第一个TextField来防止这种行为 这是我的尝试: myStackPane().focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {

如何检测焦点已离开特定窗格?由于窗格(
StackPane
)不可聚焦,因此我在执行此操作时遇到问题。例如,我有一个带有
TextField
s的
StackPane
,如果我多次按tab键,它将离开焦点窗格并转到另一个窗格。如果您离开
StackPane
的焦点,我想通过将焦点设置回窗格中的第一个
TextField
来防止这种行为

这是我的尝试:

myStackPane().focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
            if (! isNowFocused) {
                setFocus(node);
            }
        });
但我认为这不起作用,因为
StackPane
不可聚焦。我还尝试了
isFocused()
这样的方法:

myStackPane.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
            if(pane.isFocused()){
                System.out.println("not focused");
                setFocus(node);
            }else{
                System.out.println("is focused");
            }
        });

myStackPane.focusedProperty().addListener((ObservalEvalue正如您所发现的,当一个子节点被聚焦时,父节点的
聚焦
属性没有设置为
true
,因此检查父节点是否聚焦对您没有帮助。您必须测试新聚焦的
节点
是否是您希望保持聚焦的父节点的后代;如果不是,则请求聚焦他是个合适的孩子。下面是一个初步的例子:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

    private static boolean isParentAncestorOfNode(Parent parent, Node node) {
        if (parent == null || node == null || parent == node || node.getParent() == null) {
            return false;
        }

        Parent current = node.getParent();
        do {
            if (current.equals(parent)) {
                return true;
            }
            current = current.getParent();
        } while (current != null);
        return false;
    }

    @Override
    public void start(Stage primaryStage) {
        VBox innerBox = new VBox(15);
        for (int i = 1; i <= 3; i++) {
            innerBox.getChildren().add(new TextField("Field #" + i));
        }

        VBox root = new VBox(15, innerBox, new TextField("Field #4"));
        root.setPadding(new Insets(25));
        root.setAlignment(Pos.CENTER);
        VBox.setVgrow(innerBox, Priority.ALWAYS);

        Scene scene = new Scene(root);
        scene.focusOwnerProperty().addListener((observable, oldNode, newNode) -> {
            if (!isParentAncestorOfNode(innerBox, newNode)) {
                innerBox.getChildren().get(0).requestFocus();
            }
        });

        primaryStage.setScene(scene);
        primaryStage.show();
    }

}
导入javafx.application.application;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.Node;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.TextField;
导入javafx.scene.layout.Priority;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类应用程序扩展应用程序{
私有静态布尔isParentAncestorOfNode(父-父,节点-节点){
if(parent==null | | node==null | | parent==node | | node.getParent()==null){
返回false;
}
当前父节点=node.getParent();
做{
if(当前等于(父级)){
返回true;
}
current=current.getParent();
}while(当前!=null);
返回false;
}
@凌驾
公共无效开始(阶段primaryStage){
VBox innerBox=新的VBox(15);
对于(int i=1;i{
if(!isParentAncestorOfNode(innerBox,newNode)){
innerBox.getChildren().get(0.requestFocus();
}
});
初级阶段。场景(场景);
primaryStage.show();
}
}
一旦焦点尝试转到第四个
文本字段
,它将聚焦第一个
文本字段
,这是绝对的。换句话说,无论发生什么情况(例如,选项卡,用鼠标单击,以编程方式请求焦点)第四个
TextField
将无法聚焦,也不会有任何东西不是
innerBox
的后代。我不确定这是否是所需的行为。要禁用该行为,只需从
focusOwner
属性中删除
ChangeListener
(需要保留对侦听器的引用)。当然,您可以尝试修改代码,使其更加细致