假设我们有一个带fx:include
的根窗口:
<?import javafx.scene.layout.VBox?>
<VBox fx:controller="sample.StartWindowController"
xmlns:fx="http://javafx.com/fxml" alignment="center">
<fx:include source="startwindow.fxml"/>
</VBox>
startwindow.fxml
代码:
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="mainPane" fx:controller="sample.StartWindowController"
xmlns:fx="http://javafx.com/fxml" alignment="center">
<Button text="Go to New Window" onAction="#goToNewWindow"/>
</VBox>
点击Button
更改窗口,转到新的新窗口。它的控制器StartWindowController
:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import java.io.IOException;
public class StartWindowController {
@FXML
VBox mainPane;
@FXML
private void goToNewWindow() {
Pane parentPane = (Pane) mainPane.getParent();
parentPane.getChildren().clear();
try {
parentPane.getChildren().add(FXMLLoader.load(getClass().getResource("newwindow.fxml")));
} catch (IOException e) {
e.printStackTrace();
}
}
}
在我向您展示“新窗口”的视图和控制器之前,您必须知道应用程序具有带有BooleanProperty
字段的Singleton类。代码MySingleton
:
package sample;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
public class MySingleton {
private static MySingleton instance;
private BooleanProperty booleanProperty;
private MySingleton() {
booleanProperty = new SimpleBooleanProperty(false);
}
public static MySingleton getInstance() {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
public boolean isBooleanProperty() {
return booleanProperty.get();
}
public BooleanProperty booleanPropertyProperty() {
return booleanProperty;
}
}
newwindow.fxml
代码:
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="mainPane" fx:controller="sample.NewWindowController"
xmlns:fx="http://javafx.com/fxml" alignment="center">
<Button text="Change BooleanProperty" onAction="#changeBooleanProperty"/>
<Button text="Back" onAction="#goBack"/>
</VBox>
在“新窗口”创建过程中,我在控制器的MySingleton
方法中为BooleanProperty
的{{1}}添加了一个监听器。新侦听器的代码引用非静态控制器的私有方法initialize
。 printMessage
代码:
NewWindowController
现在,问题。假设第一步是进入“新窗口”:
每次“后退”后 - &gt; “转到新窗口”序列,当我点击“更改布尔属性”时,有“{1}}打印”布尔属性已更改!“,其中package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import java.io.IOException;
public class NewWindowController {
private MySingleton mySingleton;
@FXML VBox mainPane;
private int duplicateCounter = 1;
@FXML private void initialize() {
System.out.println("Initializing New Window's Controller.");
System.out.println("Duplicate counter: " + duplicateCounter);
mySingleton = MySingleton.getInstance();
mySingleton.booleanPropertyProperty().addListener(
(observable, oldValue, newValue) -> printMessage());
duplicateCounter++;
}
@FXML private void changeBooleanProperty() {
mySingleton.booleanPropertyProperty().setValue(!mySingleton.booleanPropertyProperty().getValue());
}
@FXML private void goBack() {
Pane parentPane = (Pane) mainPane.getParent();
parentPane.getChildren().clear();
try {
parentPane.getChildren().add(FXMLLoader.load(getClass().getResource("startwindow.fxml")));
} catch (IOException e) {
e.printStackTrace();
}
}
private void printMessage() {
System.out.println("Boolean property changed!");
}
}
是”开始窗口“的数量 - &gt; “新窗口”转换(从i+1
开始)。为什么不只有一个印刷品?
我知道每次启动“新窗口”时,应用程序都会向i
添加新的侦听器,问题可能是由许多属性的侦听器引起的。但是如果在一个新的监听器代码中我引用窗口转换后销毁的对象的非静态方法怎么可能呢?
我想“也许控制器没有被破坏?也许0
方法以我不理解的方式工作,而控制器的对象仍然存在?”正如您可能看到的那样,我添加了一个额外的变量BooleanProperty
,该变量在initialize
方法的末尾递增。但每次都是duplicateCounter
,所以我假设创建了全新的initialize
对象。
如何防止1
听众重复?
答案 0 :(得分:2)
但是如果在一个新的监听器代码中我引用窗口转换后销毁的对象的非静态方法怎么可能呢?
我想“也许控制器没有被破坏?也许
initialize
方法以我不理解的方式工作,而控制器的对象仍然存在?”正如您可能看到的那样,我添加了一个额外的变量duplicateCounter
,该变量在initialize
方法的末尾递增。但每次都是1
,所以我假设创建了全新的NewWindowController
对象。
确实每次加载fxml时都会创建一个新的控制器,但是旧的控制器不会被“销毁”(可用于垃圾收集),因为仍然存在对该对象的引用:
MySingleton
将实例存储在静态成员中,使其无法用于垃圾回收。此实例包含对BooleanProperty
的引用,其中包含对侦听器的引用,该引用包含对NewWindowController
的引用。
要仅打印一次消息,您必须取消注册监听器:
private final ChangeListener<Boolean> listener = (observable, oldValue, newValue) -> printMessage();
@FXML private void initialize() {
...
mySingleton.booleanPropertyProperty().addListener(listener);
...
}
...
@FXML private void goBack() {
// remove listener
MySingleton.getInstance().booleanPropertyProperty().removeListener(listener);
...
}