在TableView中实现Spinner以显示/编辑自定义对象

时间:2018-04-23 09:27:47

标签: java javafx tableview spinner custom-object

我有ObservableList个自定义对象RecipeObject_Fermentable,我通过TableView向用户显示其属性。在大多数情况下它运作良好;当我使用新项填充ObservableList时,TableView会显示其内容。

对每列使用.setCellValueFactory()方法,我可以非常轻松地将简单对象(字符串和双打)显示为TableView中的文本。例如,我可以使用...

访问name类型的属性“String
private TableColumn<RecipeObject_Fermentable, String> tableColumn_rf_name;
tableColumn_rf_name.setCellValueFactory(new PropertyValueFactory<>("name"));

问题是,我想在列weight Double内显示“Spinner”属性(类型为tableColumn_rf_weight) (并让它显示单位并可以通过文字进行编辑,但这不是主要问题),我无法弄清楚我是如何实际做到这一点的,以及最佳做法是什么。

我试图通过其他人的帖子提出解决方案,但我无法让它发挥作用。我将此部分归因于不理解每个.setCellFactory()的{​​{1}}和.setCellValueFactory()方法实际上是什么和做什么,以及它们如何与我的ObservableList中的自定义对象的属性相关联。如果有人可以简单地解释一下,或指出某些事情,我将不胜感激。 [编辑:我尝试研究这个,但我没有找到任何完整的解释,我可以从我目前对Java和JavaFX的理解中掌握]

那么如何让TableView为该列的每个数据条目显示一个Spinner?

以下代码段被删除以仅显示有用信息。如果我错过了什么,请告诉我。

自定义对象

TableColumn

我的控制器中的其他代码

public class RecipeObject_Fermentable {

// Object properties
private String name;            // Displayed and referenced name of the fermentable
private Double srm;             // Colour of fermentable in SRM
private Double pkgl;            // Specific gravity points per kg per liter
private Double weight;          // Weight in kilograms
private Double percent;         // Total percent to grain bill as percentage
private BooleanProperty lateadd;// Late addition toggle

// Constructor
public RecipeObject_Fermentable(String name, Double weight, Double srm, Double pkgl, Double contribution, boolean lateadd) {
    this.name = name;
    this.srm = srm;
    this.pkgl = pkgl;
    this.weight = weight;
    this.percent = contribution;
    this.lateadd = new SimpleBooleanProperty(lateadd);
}

// Constructor from fermentable object
public RecipeObject_Fermentable(Fermentable f) {
    this.name = f.getName();
    this.srm = f.getSrm();
    this.pkgl = f.getPkgl();
    if (f.getType().equals(FermType.GRAIN)) {
        if (f.getSubtype().equals(FermSubtype.BASE_MALT)) {
            this.weight = Double.valueOf(5);
        } else {
            this.weight = Double.valueOf(1);
        }
    } else {
        this.weight = Double.valueOf(0);
    }
    this.percent = Double.valueOf(0);
    this.lateadd = new SimpleBooleanProperty(false);
}

public String getName() {
    return this.name;
}

public Double getSrm() {
    return this.srm;
}

public Double getPkgl() {
    return this.pkgl;
}

public Double getWeight() {
    return this.weight;
}

public Double getContribution() {
    return this.percent;
}

public ObservableBooleanValue isLateadd() {
    return lateadd;
}

public void setName(String name) {
    this.name = name;
}

public void setSrm(Double srm) {
    this.srm = srm;
}

public void setPkgl(Double pkgl) {
    this.pkgl = pkgl;
}

public void setWeight(Double value) {
    this.weight = value;
}

public void setContribution(Double contribution) {
    this.percent = contribution;
}

public void setLateadd(Boolean checked) {
    this.lateadd.set(checked);
}
}

提前致谢。

1 个答案:

答案 0 :(得分:0)

您需要自定义TableCell。此外,应该有一种方法将数据传递回项目。最好使用DoubleProperty,但在您的情况下,如果不允许JavaBeanDoubleProperty,则可以使用null

final JavaBeanDoublePropertyBuilder weightBuilder
                   = JavaBeanDoublePropertyBuilder.create()
                                                  .beanClass(RecipeObject_Fermentable.class)
                                                  .name("weight");
tableColumn_rf_weight.setCellValueFactory(cd -> weightBuilder.bean(cd.getValue()).build());
public class DoubleSpinnerCell<T> extends TableCell<T, Number> {
    private final Spinner<Double> spinner = new Spinner​(0, Double.MAX_VALUE, 0, 0.01);
    private boolean ignoreUpdate; // flag preventing updates triggered from ui/initialisation

    {
        spinner.valueProperty().addListener((o, oldValue, newValue) -> {
            if (!ignoreUpdate) {
                ignoreUpdate = true;
                WritableValue<Number> property = (WritableValue<Number>) getTableColumn().getCellObservableValue((T) getTableRow().getItem());
                property.setValue(newValue);
                ignoreUpdate = false;
            }
        });
    }


    @Override
    protected void updateItem(Number item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            setGraphic(null);
        } else {
            ignoreUpdate = true;
            spinner.getValueFactory().setValue(item.doubleValue());
            setGraphic(spinner);
            ignoreUpdate = false;
        }
    }
}
tableColumn_rf_weight.setCellFactory(c -> new DoubleSpinnerCell<RecipeObject_Fermentable>());

这需要将weight设置为非空值。 (我建议使用原始double代替Double。)

修改

您还需要将列的项类型更改为Number

@FXML
private TableColumn<RecipeObject_Fermentable, Number> tableColumn_rf_weight;