将 BigDecimals 的可观察列表的总和绑定到标签
Binding the sum of an observableList of BigDecimals to a Label
我需要获取 ObservableList 中每个对象的两个特定字段,将它们相乘并得到它们所有乘积的总和。我还需要更新总和
目前,我试图首先仅获取其中一个字段的总和(只是因为它更容易并且可能帮助我理解正在发生的事情)。
我发现:
这几乎就是我想要做的。但是,应用相同的代码将抛出 NullPointerException。我认为这是因为幕后还有更多。
另外,根据:
observableList 需要 extractor 以便它可以跟踪每个元素上所需字段的更新。
这是我试过的,首先只有一个字段!!:
// Graphical stuff
void createExempleMenu(){
ObservableList<Itens> orc = FXCollections.observableArrayList(o -> new Observable[] {o.valueProperty()});
Label valueFinalLabel;
valueFinalLabel.textProperty().bind( // this gets NullPointerException
Bindings.createObjectBinding(() ->{
if(orc==null || orc.isEmpty())
return BigDecimal.ZERO; // case orc is empty
else
return orc.stream().map(i->i.getValue()).reduce(BigDecimal.ZERO,BigDecimal::add);},
orc).asString()
);
}
// item
class Itens {
private ObjectProperty<BigDecimal> value;
public BigDecimal getValue() {
return value.get();
}
public void setValue(BigDecimal b){
value.set(b);
}
public void valueProperty(BigDecimal b){
return value;
}
}
永远记得初始化你的变量伙计们:
Label valueFinalLabel = new Label("some text");
我可能会再写一个问题来问两个字段的乘积,这是我最初的objective
对于在这里绊倒的人来说,完整的示例在哪里:
public class Main extends Application{
@Override
public void start(Stage primaryStage) {
ObservableList<Itens> orc = FXCollections.observableArrayList();
Label label = new Label("0.00");
label.textProperty().bind( // this gets NullPointerException
Bindings.createObjectBinding(() ->{
if(orc==null || orc.isEmpty())
return BigDecimal.ZERO; // case orc is empty
else
return orc.stream().map(i->i.getValue()).reduce(BigDecimal.ZERO,BigDecimal::add);},
orc).asString()
);
Button btn = new Button("add stuff");
btn.setOnAction(e->{
orc.addAll(new Itens("1"),new Itens("2"),new Itens("3"),new Itens("4"),new Itens("5"));
});
VBox vbox = new VBox();
vbox.getChildren().addAll(label,btn);
Scene scene = new Scene(vbox);
primaryStage = new Stage();
primaryStage.setScene(scene);
primaryStage.setWidth(200);
primaryStage.setHeight(200);
primaryStage.show();
}
}
public static void main(String[] args) {
launch(args);
}
}
public class Itens {
private SimpleObjectProperty<BigDecimal> value;
Itens(String v){
value = new SimpleObjectProperty<BigDecimal>(new BigDecimal(v));
}
public BigDecimal getValue() {
return value.get();
}
public void setValue(BigDecimal b){
value.set(b);
}
public SimpleObjectProperty<BigDecimal> valueProperty(){
return value;
}
}
您对 Itens
class:
有一些问题
- 你永远不会初始化
value
。
- 方法
valueProperty(BigDecimal b)
必须return
ObjectProperty<BigDecimal>
而不是 void
.
- 您在方法
getValue()
中有一个拼写错误,而不是 returning value.get()
您 returning valor.get()
.
class Itens {
private final ObjectProperty<BigDecimal> value =
new SimpleObjectProperty<>(this, "value");
Itens(BigDecimal value) {
this.value.set(value);
}
public BigDecimal getValue() {
return valueProperty().get();
}
public void setValue(BigDecimal value){
valueProperty().set(value);
}
public ObjectProperty<BigDecimal> valueProperty(){
return value;
}
}
此外,您从未初始化 Label
。
最后,你可以提高你的 Bindings
:
- 您可以直接创建
StringBinding
而不是创建
ObjectBinding
然后创建 StringBinding
.
orc
永远不会是 null
,所以你不需要
检查 null
.
- 你不需要检查
orc.isEmpty()
因为当你减少
stream
您提供的身份是 `BigDecimal.ZERO
Label valueFinalLabel = new Label();
ObservableList<Itens> orc = FXCollections.observableArrayList(
obs -> new Observable[] {obs.valueProperty()});
valueFinalLabel.textProperty().bind(
Bindings.createStringBinding(() -> orc.stream()
.filter(Objects::nonNull)
.map(Itens::getValue)
.reduce(BigDecimal.ZERO, BigDecimal::add).toString(), orc));
测试:
valueFinalLabel.textProperty().addListener((obs, oldVal, newVal) ->
System.out.println(String.format("Label change from %s to %s",
oldVal, newVal)));
Itens i1 = new Itens(BigDecimal.valueOf(1));
Itens i2 = new Itens(BigDecimal.valueOf(2));
Itens i3 = new Itens(BigDecimal.valueOf(3));
orc.add(i1);
orc.add(i2);
orc.add(i3);
i1.setValue(BigDecimal.valueOf(4));
输出:
Label change from 0 to 1
Label change from 1 to 3
Label change from 3 to 6
Label change from 6 to 9
我需要获取 ObservableList 中每个对象的两个特定字段,将它们相乘并得到它们所有乘积的总和。我还需要更新总和
目前,我试图首先仅获取其中一个字段的总和(只是因为它更容易并且可能帮助我理解正在发生的事情)。
我发现:
这几乎就是我想要做的。但是,应用相同的代码将抛出 NullPointerException。我认为这是因为幕后还有更多。
另外,根据:
observableList 需要 extractor 以便它可以跟踪每个元素上所需字段的更新。
这是我试过的,首先只有一个字段!!:
// Graphical stuff
void createExempleMenu(){
ObservableList<Itens> orc = FXCollections.observableArrayList(o -> new Observable[] {o.valueProperty()});
Label valueFinalLabel;
valueFinalLabel.textProperty().bind( // this gets NullPointerException
Bindings.createObjectBinding(() ->{
if(orc==null || orc.isEmpty())
return BigDecimal.ZERO; // case orc is empty
else
return orc.stream().map(i->i.getValue()).reduce(BigDecimal.ZERO,BigDecimal::add);},
orc).asString()
);
}
// item
class Itens {
private ObjectProperty<BigDecimal> value;
public BigDecimal getValue() {
return value.get();
}
public void setValue(BigDecimal b){
value.set(b);
}
public void valueProperty(BigDecimal b){
return value;
}
}
永远记得初始化你的变量伙计们:
Label valueFinalLabel = new Label("some text");
我可能会再写一个问题来问两个字段的乘积,这是我最初的objective
对于在这里绊倒的人来说,完整的示例在哪里:
public class Main extends Application{
@Override
public void start(Stage primaryStage) {
ObservableList<Itens> orc = FXCollections.observableArrayList();
Label label = new Label("0.00");
label.textProperty().bind( // this gets NullPointerException
Bindings.createObjectBinding(() ->{
if(orc==null || orc.isEmpty())
return BigDecimal.ZERO; // case orc is empty
else
return orc.stream().map(i->i.getValue()).reduce(BigDecimal.ZERO,BigDecimal::add);},
orc).asString()
);
Button btn = new Button("add stuff");
btn.setOnAction(e->{
orc.addAll(new Itens("1"),new Itens("2"),new Itens("3"),new Itens("4"),new Itens("5"));
});
VBox vbox = new VBox();
vbox.getChildren().addAll(label,btn);
Scene scene = new Scene(vbox);
primaryStage = new Stage();
primaryStage.setScene(scene);
primaryStage.setWidth(200);
primaryStage.setHeight(200);
primaryStage.show();
}
}
public static void main(String[] args) {
launch(args);
}
}
public class Itens {
private SimpleObjectProperty<BigDecimal> value;
Itens(String v){
value = new SimpleObjectProperty<BigDecimal>(new BigDecimal(v));
}
public BigDecimal getValue() {
return value.get();
}
public void setValue(BigDecimal b){
value.set(b);
}
public SimpleObjectProperty<BigDecimal> valueProperty(){
return value;
}
}
您对 Itens
class:
- 你永远不会初始化
value
。 - 方法
valueProperty(BigDecimal b)
必须returnObjectProperty<BigDecimal>
而不是void
. - 您在方法
getValue()
中有一个拼写错误,而不是 returningvalue.get()
您 returningvalor.get()
.
class Itens {
private final ObjectProperty<BigDecimal> value =
new SimpleObjectProperty<>(this, "value");
Itens(BigDecimal value) {
this.value.set(value);
}
public BigDecimal getValue() {
return valueProperty().get();
}
public void setValue(BigDecimal value){
valueProperty().set(value);
}
public ObjectProperty<BigDecimal> valueProperty(){
return value;
}
}
此外,您从未初始化 Label
。
最后,你可以提高你的 Bindings
:
- 您可以直接创建
StringBinding
而不是创建ObjectBinding
然后创建StringBinding
. orc
永远不会是null
,所以你不需要 检查null
.- 你不需要检查
orc.isEmpty()
因为当你减少stream
您提供的身份是 `BigDecimal.ZERO
Label valueFinalLabel = new Label();
ObservableList<Itens> orc = FXCollections.observableArrayList(
obs -> new Observable[] {obs.valueProperty()});
valueFinalLabel.textProperty().bind(
Bindings.createStringBinding(() -> orc.stream()
.filter(Objects::nonNull)
.map(Itens::getValue)
.reduce(BigDecimal.ZERO, BigDecimal::add).toString(), orc));
测试:
valueFinalLabel.textProperty().addListener((obs, oldVal, newVal) ->
System.out.println(String.format("Label change from %s to %s",
oldVal, newVal)));
Itens i1 = new Itens(BigDecimal.valueOf(1));
Itens i2 = new Itens(BigDecimal.valueOf(2));
Itens i3 = new Itens(BigDecimal.valueOf(3));
orc.add(i1);
orc.add(i2);
orc.add(i3);
i1.setValue(BigDecimal.valueOf(4));
输出:
Label change from 0 to 1
Label change from 1 to 3
Label change from 3 to 6
Label change from 6 to 9