将 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