如何在javafx中将TableCell控件与基础行模型连接?

时间:2016-02-15 16:30:45

标签: javafx tableview spinner fxml

我正在使用由我的模型填充的TableView。

我想在一列中使用微调控件。

我能够在所需列的单元格中创建微调器, 但我正在努力将微调器值绑定到模型属性。

这是fxml

<ScrollPane>
   <content>
      <TableView prefHeight="525.0" prefWidth="814.0">
        <columns>
          <TableColumn prefWidth="75.0">
            <cellValueFactory><PropertyValueFactory property="state"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Side">
            <cellValueFactory><PropertyValueFactory property="side"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Source">
            <cellValueFactory><PropertyValueFactory property="sourceContract"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Reference">
            <cellValueFactory><PropertyValueFactory property="referenceContract"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Destination">
            <cellValueFactory><PropertyValueFactory property="destinationContract"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Margin" editable="true">
            <cellFactory><SpinnerTableCellFactory /></cellFactory>
            <cellValueFactory><PropertyValueFactory property="margin"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Bot">
            <cellValueFactory><PropertyValueFactory property="bot"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Price">
            <cellValueFactory><PropertyValueFactory property="price"/></cellValueFactory>
          </TableColumn>
          <TableColumn prefWidth="75.0" text="Volume">
            <cellValueFactory><PropertyValueFactory property="volume"/></cellValueFactory>
          </TableColumn>
        </columns>
        <items>
          <FXCollections fx:factory="observableArrayList">
            <GridRowModel state="false" side="BID" sourceContract="s01" referenceContract="" destinationContract="d01" margin="0" bot="MinMax" price="15.125" volume="0" />
            <GridRowModel state="false" side="ASK" sourceContract="s02" referenceContract="" destinationContract="d02" margin="0" bot="MinMax" price="15.125" volume="0" />
          </FXCollections>
        </items>
      </TableView>
   </content>
</ScrollPane>

这是SpinnerTableCellFactory

public class SpinnerTableCellFactory<S, T> implements Callback<TableColumn<S, Double>, TableCell<S, Double>> {

  @Override
  public TableCell<S, Double> call(TableColumn<S, Double> param) {

    return new TableCell<S, Double>() {

      Spinner<Double> spinner = new Spinner<>(0d, 1d, 0d, 0.025d);

      protected void updateItem(Double item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
          setText(null);
          setGraphic(null);
        } else {
          if (isEditing()) {
            setText(null);
            setGraphic(null);
          } else {
            spinner.getValueFactory().setValue(getItem());
            setText(null);
            setGraphic(spinner);
          }
        }
      };
    };
  }
}

当加载fxml时,将使用updateItem属性的fxml中的默认值调用margin方法。我可以在细胞中看到并使用旋转器。但是如何将任何新的微调器值传递回GridRowModel对象中的margin属性?

1 个答案:

答案 0 :(得分:2)

只需使用微调器valueProperty()注册一个监听器:

public class SpinnerTableCellFactory<S, T> implements Callback<TableColumn<S, Double>, TableCell<S, Double>> {

  @Override
  public TableCell<S, Double> call(TableColumn<S, Double> param) {

    return new TableCell<S, Double>() {

      Spinner<Double> spinner = new Spinner<>(0d, 1d, 0d, 0.025d);

      {
          spinner.valueProperty().addListener((obs, oldValue, newValue) -> {
              ObservableValue<Double> value = getTableColumn().getCellObservableValue(getIndex());
              if (value instanceof WritableValue) {
                  ((WritableValue<Double>)value).setValue(newValue); 
              }
          });
      }

      protected void updateItem(Double item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
          setText(null);
          setGraphic(null);
        } else {
          if (isEditing()) {
            setText(null);
            setGraphic(null);
          } else {
            spinner.getValueFactory().setValue(getItem());
            setText(null);
            setGraphic(spinner);
          }
        }
      };
    };
  }
}

我假设您的模型类GridRowModel遵循JavaFX properties pattern

如果您不使用JavaFX属性,或者想要避免强制转换,您可以给单元工厂BiConsumer<GridRowModel, Double>处理更新:

public class SpinnerTableCellFactory<S, T> implements Callback<TableColumn<S, Double>, TableCell<S, Double>> {

  private BiConsumer<S, Double> updater = null ;

  public void setUpdater(BiConsumer<S, Double> updater) {
      this.updater = updater ;
  }

  @Override
  public TableCell<S, Double> call(TableColumn<S, Double> param) {

    return new TableCell<S, Double>() {

      Spinner<Double> spinner = new Spinner<>(0d, 1d, 0d, 0.025d);

      {
          spinner.valueProperty().addListener((obs, oldValue, newValue) -> {
              if (updater != null) {
                  updater.accept(getTableView().getItems().get(getIndex()), newValue);
              }
          });
      }

      protected void updateItem(Double item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
          setText(null);
          setGraphic(null);
        } else {
          if (isEditing()) {
            setText(null);
            setGraphic(null);
          } else {
            spinner.getValueFactory().setValue(getItem());
            setText(null);
            setGraphic(spinner);
          }
        }
      };
    };
  }
}

然后您可以向工厂添加fx:id

<cellFactory><SpinnerTableCellFactory fx:id="marginCellFactory" /></cellFactory>

并在您的控制器中执行:

@FXML
private SpinnerTableCellFactory<GridRowModel, Double> marginCellFactory ;

public void initialize() {
    marginCellFactory.setUpdater(GridRowModel::setMargin);
}