这是我的第一个 FXML 应用程序。以前我对 Swing 已经很熟悉了。我只是想保存舞台上控件中的多个值,以便用户输入值在运行期间重新加载。 ReliableOneShotCloseHandler
是我 posted a while ago here 的 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);
}
}
这是 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 和附带代码。我的逻辑有问题吗?还有其他方法可以做到这一点吗?
更新:包含了一些不应该包含的代码行。它们已被删除。
最佳答案
从架构的角度来看,这段代码相当困惑。一般来说,我会明确区分 Controller 和应用程序类。因此,应用程序类仅加载 FXML 文件(从该文件引用 Controller 类),然后将其分配给场景或更准确地说是舞台。因此, Controller 类仅负责管理来自控制元素的任何事件作为 onCloseRequest
-Event。
另一个问题可能是同时使用 EventFilter
和 EventHandler
。如果您在舞台上使用 EventFilter
,则其所有节点和舞台本身将永远不会被调用其 EventHandler
。
因此,最简单的解决方案是直接在 Controller 类的舞台上添加一个 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);
}
}
样本.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());
}
});
}
}
关于java - 如何在 FXML 控件状态被丢弃之前保存它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32486570/