Java 如何在FXML控件状态出现之前保存它们';你被抛弃了?

Java 如何在FXML控件状态出现之前保存它们';你被抛弃了?,java,fxml,Java,Fxml,这是我的第一个FXML应用程序。以前我对荡秋千很在行。我只想保存stage上控件中的几个值,以便用户输入值跨运行重新加载。ReliableOneShotCloseHandler是我的东西的JavaFX版本。然而,在调用windowClosing函数时,控件似乎已经被处理掉了?我在指示行中得到一个NullPointerException: package testfxmlloader; import java.net.URL; import java.util.ResourceBundle; i

这是我的第一个FXML应用程序。以前我对荡秋千很在行。我只想保存stage上控件中的几个值,以便用户输入值跨运行重新加载。
ReliableOneShotCloseHandler
是我的东西的JavaFX版本。然而,在调用windowClosing函数时,控件似乎已经被处理掉了?我在指示行中得到一个NullPointerException:

package testfxmlloader;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.scene.control.Label;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

/**
*
* @author maskedcoder
*/
public class FXMLDocumentController implements Initializable {

    @FXML
    private Label label;

    @FXML
    private AnchorPane apMain;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        ReliableOneShotCloseHandler roscSaveSettings = new ReliableOneShotCloseHandler(apMain.getScene().getWindow(), new ReliableOneShotCloseHandler.CloseDuties() {

            @Override
            public boolean confirmClose(WindowEvent e) {
                return true;
            }

            @Override
            public void windowClosing(WindowEvent e) {
                saveSettings();
            }
        });
    }   

    public void saveSettings() {
        System.out.println("save setting: " + label.getText());  // gets NullPointerException because label is null.
    }

}

class ReliableOneShotCloseHandler {

    public interface CloseDuties {
        public boolean confirmClose(WindowEvent e);
        public void windowClosing(WindowEvent e);
    }

    private final CloseDuties closeDuties;
    private boolean windowClosingFired = false;
    private final EventHandler<WindowEvent> openEvent;
    private final EventHandler<WindowEvent> closeEvent;

    public ReliableOneShotCloseHandler(Window thisWindow, CloseDuties iniCloseDuties) {
        super();
        closeDuties = iniCloseDuties;
        openEvent = (WindowEvent event) -> {
            windowClosingFired = false;
        };
        closeEvent = (WindowEvent event) -> {
            if(!windowClosingFired) {
                if(closeDuties.confirmClose(event)) {
                    closeDuties.windowClosing(event);
                    windowClosingFired = true;
                }
                else
                    event.consume();
            }
        };

        thisWindow.setOnShowing(openEvent);
        thisWindow.setOnShown(openEvent);
        thisWindow.setOnCloseRequest(closeEvent);
        thisWindow.setOnHiding(closeEvent);
        thisWindow.setOnHidden(closeEvent);
    }
}

public class TestFXMLLoader extends Application {
    FXMLLoader fxmll;
    FXMLDocumentController fdc;

    @Override
    public void start(Stage stage) throws Exception {
        fdc = new FXMLDocumentController();
        fxmll = new FXMLLoader();
        fxmll.setBuilderFactory(new JavaFXBuilderFactory());
        Parent root = fxmll.load(getClass().getResource("FXMLDocument.fxml"));
        fxmll.setController(fdc);

        Scene scene = new Scene(root);

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

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
        launch(args);
    }

}
包testfxmloader;
导入java.net.URL;
导入java.util.ResourceBundle;
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.event.ActionEvent;
导入javafx.fxml.fxml;
导入javafx.fxml.fxmloader;
导入javafx.fxml.Initializable;
导入javafx.fxml.JavaFXBuilderFactory;
导入javafx.scene.control.Label;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.stage.stage;
导入javafx.stage.WindowEvent;
/**
*
*@author maskedcoder
*/
公共类FXMLDocumentController实现可初始化{
@FXML
自有品牌;
@FXML
私人锚烷;
@FXML
私有无效把手按钮操作(ActionEvent事件){
System.out.println(“你点击了我!”);
label.setText(“你好,世界!”);
}
@凌驾
公共void初始化(URL、ResourceBundle rb){
ReliableOneShotCloseHandler roscSaveSettings=新建ReliableOneShotCloseHandler(apMain.getScene().getWindow(),新建ReliableOneShotCloseHandler.CloseDuctions()){
@凌驾
公共布尔值确认关闭(WindowEvent e){
返回true;
}
@凌驾
公共无效窗口关闭(WindowEvent e){
保存设置();
}
});
}   
公共void saveSettings(){
System.out.println(“保存设置:”+label.getText());//获取NullPointerException,因为label为null。
}
}
类ReliableOneShotCloseHandler{
公共接口职责{
公共布尔确认关闭(WindowEvent e);
公共窗口关闭(窗口事件e);
}
私人最终关闭职责关闭职责;
私有布尔windowClosingFired=false;
私人最终事件处理程序openEvent;
私有最终事件处理程序closeEvent;
公共可靠的OneShotCloseHandler(窗口此窗口,关闭职责在关闭职责中){
超级();
关闭职责=关闭职责;
openEvent=(WindowEvent事件)->{
windowClosingFired=false;
};
closeEvent=(WindowEvent事件)->{
如果(!windowClosingFired){
if(关闭职责。确认关闭(事件)){
关闭职责。窗口关闭(事件);
windowClosingFired=true;
}
其他的
event.consume();
}
};
此窗口。设置显示(openEvent);
thisWindow.setOnShown(openEvent);
thisWindow.setOnCloseRequest(closeEvent);
thisWindow.setOnHiding(closeEvent);
thisWindow.setOnHidden(closeEvent);
}
}
公共类TestFXMLLoader扩展了应用程序{
FXMLLoader fxmll;
fxmlcontroller-fdc;
@凌驾
public void start(Stage)引发异常{
fdc=新的FXMLDocumentController();
fxmll=新的FXMLLoader();
setBuilderFactory(新的JavaFXBuilderFactory());
父根=fxmll.load(getClass().getResource(“FXMLDocument.fxml”);
设置控制器(fdc);
场景=新场景(根);
舞台场景;
stage.show();
}
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
发射(args);
}
}
下面是FXML:

 <?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" fx:id="apMain" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="testfxmlloader.FXMLDocumentController">
    <children>
        <Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me!" />
        <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
    </children>
</AnchorPane>

windowClosing
函数应该在没有关闭权限之前调用,因此所有控件都应该正常工作。上面的测试代码基于NetBeans的默认JavaFXML应用程序,只添加了ReliableOneShotCloseHandler和助理代码。我的逻辑有缺陷吗?还有别的办法吗


更新:包含了一些本不应该包含的代码行。它们已被删除。

从架构的角度来看,这段代码相当混乱。一般来说,我会清楚地将控制器和应用程序类分开。因此,应用程序类仅加载FXML文件,控制器类从该文件中进行仲裁,然后将其分配给场景或更准确地说是舞台。因此,控制器类只负责将来自控制元素的任何事件作为
onCloseRequest
-事件进行管理

另一个问题可能是同时使用
EventFilter
EventHandler
。如果您在stage上使用
EventFilter
,则其所有节点和stage本身将永远不会被调用它们的
EventHandler

因此,最简单的解决方案是直接在控制器类中的阶段上添加一个
EventHandler
,从该阶段可以直接访问所有其他控件(例如标签)

Main.java

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = (Parent) loader.load();
    primaryStage.setTitle("Hello World");
    primaryStage.setScene(new Scene(root, 300, 275));
    primaryStage.show();

    Controller controller = (Controller)loader.getController();
    controller.setStage(primaryStage);
}


public static void main(String[] args) {
    launch(args);
}

} 
sample.fxml

<AnchorPane fx:id="apMain" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <Button fx:id="button" layoutX="39.0" layoutY="35.0" mnemonicParsing="false" onAction="#handleButtonAction" text="Button" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0" />
      <Label fx:id="label" layoutX="52.0" layoutY="102.0" text="Label" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="50.0" />
   </children>
</AnchorPane>

Controller.java

public class Controller implements Initializable {

@FXML
public AnchorPane apMain;

@FXML
public Button button;

@FXML
public Label label;

@Override
public void initialize(URL location, ResourceBundle resources) {

}

public void handleButtonAction() {
    System.out.println("You clicked me!");
    label.setText("Hello World!");
}

public void setStage(Stage stage){
    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent event) {
            System.out.println(label.getText());
        }
    });
}

}
公共类控制器实现可初始化{
@FXML
公共锚烷;
@FXML
公共按钮;
@FXML
公共标签;
@凌驾
公共void初始化(URL位置、ResourceBundle资源){
}
公共无效把手按钮操作(){
System.out.println(“你点击了我!”);
label.setText(“你好,世界!”);
}
公共空间设置阶段(阶段){
stage.setOnCloseRequest(新的EventHandler(){
@凌驾
公共无效句柄(WindowEvent事件){
System.out.println(label.getText());
}
});
}
}
LOL我从来没有做过爱