我遇到了一个看起来很奇怪的情况。
下面是一个简单的javaFX应用程序,其中包含一个包含在ScollPane中的TextFlow容器。为了将ScrollBar发送到ScrollPane的底部,因为Text被添加到TextFlow容器中,DoubleProperty绑定到了TextFlow容器的heightProperty(在TextFlow容器在最新添加Text之后呈现后更改),添加了ChangeListener以将ScollPane的vValue移动到vMax(底部)。
添加按钮只是测试将Text添加到TextFlow容器。
现在奇怪的部分 - ChangeListener完美地适用于前9到11个文本添加,之后看起来不会通过绑定触发heightProperty更改(好吧,至少ChangeListener不再执行)。是否在9,10或11次之后发生似乎随着点击添加按钮的速度而变化。
现在更奇怪的部分 - 当应用程序在调试中运行时,ChangeListener可以正常工作(不需要断点)!
我在Windows 8.1笔记本电脑上使用带有JDK1.8.0的Netbeans 8,全部是x64。
我希望有人可以复制这个并告诉我为什么在x Text添加之后ChangeListener没有执行的原因(以及为什么 它在调试模式下工作 < /强>)。
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
public class TextFlowTest extends Application {
final GridPane grid = new GridPane();
final Button addbtn = new Button();
final Button scrollbtn = new Button();
final TextFlow textflow = new TextFlow();
final ScrollPane textflowSP = new ScrollPane();
int counter = 0;
@Override
public void start(Stage primaryStage) {
// Attach a listener to the TextFlow component height property which
// is set after component has been rendered so we can set scroll bar to
// bottom.
DoubleProperty hProperty = new SimpleDoubleProperty();
hProperty.bind(textflow.heightProperty());
hProperty.addListener(new ChangeListener() {
@Override
public void changed(ObservableValue ov, Object t, Object t1) {
System.out.println("In listener " + ++counter + " with height of "
+ Double.toString((Double)t1));
textflowSP.setVvalue(textflowSP.getVmax());
}
}) ;
// Create Scroll Pane for TextFlow component
textflowSP.setPrefHeight(200);
textflowSP.setPrefWidth(200);
textflowSP.setFitToHeight(true);
textflowSP.setFitToWidth(true);
textflowSP.setContent(textflow);
grid.add(textflowSP,0,1);
// Button to add Text to TextFlow component
addbtn.setText("Add Text");
addbtn.setOnAction((ActionEvent e) -> {
textflow.getChildren().add(new Text("Line 1\nLine 2\nLine 3\n-\n"));
// Print shows that height property has not changed after adding Text
// but before rendering.
System.out.println(Double.toString(textflow.heightProperty().get()));
});
// Button to scoll to bottom of Scroll Pane
scrollbtn.setText("Scroll to Bottom");
scrollbtn.setOnAction((ActionEvent e) -> {
textflowSP.setVvalue(textflowSP.getVmax());
});
VBox btnVB = new VBox();
btnVB.getChildren().addAll(addbtn,scrollbtn);
grid.add(btnVB,1,1);
Scene scene = new Scene(grid, 330, 210);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
提前感谢您提供的任何帮助。
答案 0 :(得分:1)
查看bind
函数中的文档:
请注意,JavaFX具有通过弱侦听器实现的所有绑定调用。这意味着绑定属性可以被垃圾收集并停止更新。
hProperty和textflow.heightProperty之间的绑定是通过弱侦听器完成的。因此,没有什么能阻止hProperty收集垃圾。
细节会发生什么:
这就是你的装订工作到下一个GC循环的原因。
为了防止这种情况,你必须在本地函数范围之外的某个地方存储对hProperty的引用,就像在TextFlowTest的范围内一样。或者直接在height-property上注册你的听众:
textflow.heightProperty().addListener((obs, ov, nv) -> { ... });
答案 1 :(得分:0)
我遇到了类似的问题。我通过在任何方法之外声明要绑定的属性(在本例中为DoubleProperty hProperty = new SimpleDoubleProperty();
)来解决它,因此它不仅仅是一个局部变量。