【发布时间】:2014-10-11 08:25:44
【问题描述】:
更新:找到了一种更简单的方法来重现错误行为
当我在三个变量之间设置双向 JavaFX 绑定时,此绑定有时会被不相关的代码破坏。
我创建了一个能够重现错误行为的小示例程序:
在 MainController 中设置绑定并添加三个监听器以输出变量的新值:
package bug;
import java.nio.file.Path;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
public class MainController {
@FXML
private Foo foo;
@FXML
private Bar bar;
private ObjectProperty<Path> pathProperty = new SimpleObjectProperty<>();
@FXML
private void initialize() {
pathProperty.addListener((observablePath, oldPath,
newPath) -> {
System.out.println(newPath);
});
foo.pathProperty().addListener((observablePath, oldPath,
newPath) -> {
System.out.println(newPath);
});
bar.pathProperty().addListener((observablePath, oldPath,
newPath) -> {
System.out.println(newPath);
});
bar.pathProperty()
.bindBidirectional(pathProperty);
foo.pathProperty()
.bindBidirectional(pathProperty);
}
}
FooController 使用由单击按钮触发的计数器更改其中一个变量。因为我们设置了三个监听器,所以按下按钮应该输出相同的值三次。只要不更改 DatePicker 的值,这将按预期工作。但是之后每个数字只输出一次。
package bug;
import java.nio.file.Paths;
import java.time.LocalDate;
import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.DatePicker;
public class FooController extends Base {
int counter = 0;
@FXML
private DatePicker startDatePicker;
private ChangeListener<LocalDate> breakThings;
@FXML
private void onBugClicked(ActionEvent event) {
for (int i = 0; i < 3; i++) {
pathProperty.set(Paths.get(String.valueOf(counter++)));
}
}
@FXML
private void initialize() {
breakThings = (observableDate, oldDate, newDate)->{
System.out.println("Triggered");
};
startDatePicker.valueProperty().addListener(breakThings);
}
}
Foo 和 Bar 控制器的基类
package bug;
import java.nio.file.Path;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public abstract class Base {
protected ObjectProperty<Path> pathProperty = new SimpleObjectProperty<>();
public ObjectProperty<Path> pathProperty() {
return pathProperty;
}
}
栏控制器:
package bug;
public class BarController extends Base {
}
富:
package bug;
import java.io.IOException;
import java.nio.file.Path;
import javafx.beans.property.ObjectProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.BorderPane;
public class Foo extends BorderPane {
private final FooController controller;
public Foo() {
controller = new FooController();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(
"Foo.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(controller);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public ObjectProperty<Path> pathProperty() {
return controller.pathProperty();
}
}
酒吧:
package bug;
import java.nio.file.Path;
import javafx.beans.property.ObjectProperty;
import javafx.scene.layout.BorderPane;
public class Bar extends BorderPane {
private final BarController controller;
public Bar() {
controller = new BarController();
}
public ObjectProperty<Path> pathProperty() {
return controller.pathProperty();
}
}
预期输出(点击四次按钮后):
0
0
0
1
1
1
2
2
2
3
3
3
4
4
4
5
5
5
6
6
6
7
7
7
8
8
8
9
9
9
10
10
10
11
11
11
实际输出(点击四次按钮后):
0
0
0
1
1
1
2
2
2
3
3
3
4
4
4
5
5
5
6
6
6
7
7
7
8
8
8
(Select date with DatePicker)
9
10
11
Java 版本:1.8.0_20
JavaFX 版本:8.0.20-b26
【问题讨论】:
标签: data-binding javafx