Вы можете установить sh привязку, просто вызвав bind(...)
в свойстве конструктора.
Поскольку differenceProperty()
привязан, вызов setDifference()
вызовет исключение, поэтому вы должны опустить этот метод 1 . Вы можете сделать:
public class Member {
private StringProperty member = new SimpleStringProperty();
private DoubleProperty expenses = new SimpleDoubleProperty();
private DoubleProperty earnings = new SimpleDoubleProperty();
private DoubleProperty difference = new SimpleDoubleProperty();
public Member(String member, double expenses, double earnings) {
this.member = new SimpleStringProperty(member);
this.expenses = new SimpleDoubleProperty(expenses);
this.earnings = new SimpleDoubleProperty(earnings);
this.difference = new SimpleDoubleProperty();
this.difference.bind(this.earnings.subtract(this.expenses));
}
public String getMember() {
return member.get();
}
public void setMember(String name) {
member.set(name);
}
public final StringProperty memberProperty(){
return member;
}
public Double getExpenses() {
return expenses.get();
}
public void setExpenses(Double value) {
expenses.set(value);
}
public final DoubleProperty expensesProperty(){
return expenses;
}
public Double getEarnings() {
return earnings.get();
}
public void setEarnings(Double value) {
earnings.set(value);
}
public final DoubleProperty earningsProperty(){
return earnings;
}
public Double getDifference() {
return difference.get();
}
// public void setDifference(Double value) {
// difference.set(value);
// }
public final DoubleProperty differenceProperty(){
return difference;
}
}
В вашей таблице столбцы earnings
и expenses
представляют числовые значения c, поэтому их следует вводить соответствующим образом. По причинам, объясненным в Свойства JavaFX в TableView , тип здесь должен быть Number
, а не Double
. Также обратите внимание, что если вы скажете своей реализации ячейки таблицы, как преобразовать String
в значение (Number
), которое вы хотите отобразить:
expensesColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
, вам больше не нужно указывать onEditCommit
обработчик (ячейка таблицы позаботится об обновлении).
Таким образом, ваша конфигурация таблицы упрощается до
// Spalte Name mit Edit-Funktion
TableColumn<Member, String> memberColumn = new TableColumn<>("Name");
memberColumn.setMinWidth(150);
memberColumn.setCellValueFactory(new PropertyValueFactory<Member, String>("member"));
memberColumn.setCellFactory(TextFieldTableCell.forTableColumn());
// Spalte Ausgaben mit Edit-Funktion
TableColumn<Member, Number> expensesColumn = new TableColumn<>("Ausgaben");
expensesColumn.setMinWidth(50);
expensesColumn.setCellValueFactory(new PropertyValueFactory<>("expenses"));
expensesColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
// Spalte Pfand mit Edit-Funktion
TableColumn<Member, Number> earningsColumn = new TableColumn<>("Pfand");
earningsColumn.setMinWidth(50);
earningsColumn.setCellValueFactory(new PropertyValueFactory<>("earnings"));
earningsColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
//Spalte Differenz ohne Edit-Funktion
TableColumn<Member, Number> differenceColumn = new TableColumn<>("Differenz");
differenceColumn.setMinWidth(50);
differenceColumn.setCellValueFactory(new PropertyValueFactory<>("difference"));
Обратите внимание, что NumberStringConverter
имеет довольно упрощенная c реализация; Вы можете захотеть реализовать свой собственный StringConverter<Number>
для поддержки, например, анализа строк на основе локали.
Также обратите внимание, что класс модели Member
теперь гарантирует, что difference
всегда является разницей между earnings
и expenses
, поэтому вам не нужно (и нельзя) установить difference
свойство:
btnAdd.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
try {
Member member = new Member(tfMember.getText(),
Double.parseDouble(tfExpenses.getText()),
Double.parseDouble(tfEarnings.getText()));
table.getItems().add(member);
tfMember.clear();
tfExpenses.clear();
tfEarnings.clear();
} catch (NumberFormatException Exception) {}
}
});
Так же, как примечание, использование PropertyValueFactory
на самом деле не является необходимым с Java 8, и потому что оно основано на отражении, склонно к молчанию, если, например, имя свойства набрано неправильно (оно также немного неэффективно). Вы можете предпочесть реализацию обратного вызова напрямую с помощью лямбда-выражения:
// memberColumn.setCellValueFactory(new PropertyValueFactory<Member, String>("member"));
memberColumn.setCellValueFactory(cellData -> cellData.getValue().memberProperty());
// expensesColumn.setCellValueFactory(new PropertyValueFactory<>("expenses"));
expensesColumn.setCellValueFactory(cellData -> cellData.getValue().expensesProperty());
// earningsColumn.setCellValueFactory(new PropertyValueFactory<>("earnings"));
earningsColumn.setCellValueFactory(cellData -> cellData.getValue().earningsProperty());
Этот подход также позволяет полностью исключить свойство difference
из класса Member
и просто использовать привязку непосредственно в столбце таблицы. :
differenceColumn.setCellValueFactory(cd ->
cd.getValue().earningsProperty().subtract(cd.getValue().expensesProperty()));
Выбор здесь зависит в основном от того, считаете ли вы difference
неотъемлемой частью данных (поэтому его следует включить в модель), или же данные просто состоит из earnings
и expenses
, а difference
- это просто то, что вы хотите визуализировать в таблице.
(1) На самом деле, вы должны использовать ReadOnlyProperty
здесь для представления difference
, поскольку вызов differenceProperty().set(...)
также вызовет исключение с кодом так, как он написан. В основном:
private final ReadOnlyDoubleWrapper difference = new ReadOnlyDoubleWrapper() ;
// Constructor and other properties as before ...
public final ReadOnlyDoubleProperty differenceProperty() {
return difference.getReadOnlyProperty();
}
public final double getDifference() {
return differenceProperty().get();
}