4

I've a JavaFX table view component, and is dynamically loading the data with ComboBox as setGraphic for individual columns. I want to added ComboBox at cellFactory.

Now when the user select the first ComboBox, the next column ComboBox has to be set accordingly. For this purpose I've used a selection listener, but how can I get ComboBox of other TableColumn?

Please find the snapshot, of what I need: enter image description here

Here is the Snippet of TableView:

        TableColumn< ModelInput, String > colCalibration = new TableColumn<>( "Calibration" );
        TableColumn< ModelInput, String > colSamplingX = new TableColumn<>( "Sampling point X" );
        TableColumn< ModelInput, String > colSamplingY = new TableColumn<>( "Sampling point Y" );
        List< TableColumn< ModelInput, String > > tableColList =
            Stream.of( colCalibration, colSamplingX, colSamplingY )
                  .collect( Collectors.toList() );
        tableviewCalibMatching.getColumns().addAll( tableColList );

        //initialize
        colCalibration.setCellFactory( param -> new TableCell< ModelInput, String >() {

          @Override
          public void updateItem( String item, boolean empty ) {
            super.updateItem( item, empty );
            if( empty ) {
              setText( null );
            } else {
              ComboBox< String > comboBoxCalibMatchingNames = new ComboBox<>( listCalibNames );
              comboBoxCalibMatchingNames.setPrefWidth( splitWidth );
              comboBoxCalibMatchingNames.getSelectionModel().selectedItemProperty()
                                        .addListener( (ChangeListener< String >)( observable, oldValue,
                                            newValue ) -> {

//TODO
//How can I get ComboBox of other TableColumn, need to set according to current //selection

                                        } );
              setGraphic( comboBoxCalibMatchingNames );
              setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
            }
          }
        } );

        colSamplingX.setCellFactory( param -> new TableCell< ModelInput, String >() {

          @Override
          public void updateItem( String item, boolean empty ) {
            super.updateItem( item, empty );
            if( empty ) {
              setText( null );
            } else {
              final ComboBox< String > comboBox = new ComboBox<>();
              setGraphic( comboBox );
              setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
            }
          }
        } );

        colSamplingY.setCellFactory( param -> new TableCell< ModelInput, String >() {

          @Override
          public void updateItem( String item, boolean empty ) {
            super.updateItem( item, empty );
            if( empty ) {
              setText( null );
            } else {
              final ComboBox< String > comboBox = new ComboBox<>();
              setGraphic( comboBox );
              setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
            }
          }
        } );
zIronManBox
  • 4,967
  • 6
  • 19
  • 35
  • How are the three lists related to one another? If I select a particular calibration value, it is supposed to generate a brand new list of sampling point X and Y? Are the lists inside `ModelInput`, and how are they defined? – Jai Apr 18 '17 at 05:32
  • @Jai The SamplingPtX and SamplingPtY combolist is statically loaded. Nothing to do with `ModelInput`. All, I need to perform, is on selection of Calibration comboBox, I've to set a particular item in SamplingPtX & Y, comboBox for the corresponding row. – zIronManBox Apr 18 '17 at 08:05
  • Does ModelInput contains the 3 columns values? as SimpleStringProperty? It also misses the seItems part, and the setCellValueFactory bindings. (globally we need more resource for a full testable example) – pdem Apr 18 '17 at 12:38
  • @pdem No ModelInput doesn't really have the data for 3 Coulmns. There is another column, whose data is taken from ModelInput as SimpleStringProperty. That is not visible in the image. – zIronManBox Apr 20 '17 at 10:40

2 Answers2

1

Try this:

public class Test
{
    private final TableView<ModelInput> tableviewCalibMatching = new TableView<>();

    private final TableColumn<ModelInput, String> colCalibration = new TableColumn<>("Calibration");
    private final TableColumn<ModelInput, String> colSamplingX = new TableColumn<>("Sampling Point X");
    private final TableColumn<ModelInput, String> colSamplingY = new TableColumn<>("Sampling Point Y");

    private final ObservableList<String> listCalibNames = FXCollections.observableArrayList();
    private final ObservableList<String> listSamplingXNames = FXCollections.observableArrayList();
    private final ObservableList<String> listSamplingYNames = FXCollections.observableArrayList();

    private final ObservableList<ModelInput> items = FXCollections.observableArrayList();

    public Test()
    {
        tableviewCalibMatching.setItems(items);
        tableviewCalibMatching.getColumns().addAll(colCalibration, colSamplingX, colSamplingY);

        colCalibration.setCellFactory(ComboBoxTableCell.forTableColumn(listCalibNames));
        colSamplingX.setCellFactory(ComboBoxTableCell.forTableColumn(listSamplingXNames));
        colSamplingY.setCellFactory(ComboBoxTableCell.forTableColumn(listSamplingYNames));

        colCalibration.setCellValueFactory(new PropertyValueFactory<>("calibration"));
        colSamplingX.setCellValueFactory(new PropertyValueFactory<>("samplingX"));
        colSamplingY.setCellValueFactory(new PropertyValueFactory<>("samplingY"));

        colCalibration.setOnEditCommit(event ->
        {
            final String newCalibrationValue = event.getNewValue();

            event.getRowValue().setCalibration(newCalibrationValue);

            // You can change the logic here based on what you need
            event.getRowValue().setSamplingX(listSamplingXNames.get(1));
            event.getRowValue().setSamplingY(listSamplingXNames.get(1));
        });

        colSamplingX.setOnEditCommit(event ->
        {
            final String newSamplingXValue = event.getNewValue();

            event.getRowValue().setSamplingX(newSamplingXValue);
        });

        colSamplingY.setOnEditCommit(event ->
        {
            final String newSamplingYValue = event.getNewValue();

            event.getRowValue().setSamplingY(newSamplingYValue);
        });
    }

    public static class ModelInput
    {
        private final StringProperty calibration = new SimpleStringProperty();
        private final StringProperty samplingX = new SimpleStringProperty();
        private final StringProperty samplingY = new SimpleStringProperty();

        public final StringProperty calibrationProperty()
        {
            return this.calibration;
        }

        public final String getCalibration()
        {
            return this.calibrationProperty().get();
        }

        public final void setCalibration(final String calibration)
        {
            this.calibrationProperty().set(calibration);
        }

        public final StringProperty samplingXProperty()
        {
            return this.samplingX;
        }

        public final String getSamplingX()
        {
            return this.samplingXProperty().get();
        }

        public final void setSamplingX(final String samplingX)
        {
            this.samplingXProperty().set(samplingX);
        }

        public final StringProperty samplingYProperty()
        {
            return this.samplingY;
        }

        public final String getSamplingY()
        {
            return this.samplingYProperty().get();
        }

        public final void setSamplingY(final String samplingY)
        {
            this.samplingYProperty().set(samplingY);
        }
    }
}
Jai
  • 8,165
  • 2
  • 21
  • 52
  • Here by default, the `ComboBox` are not visible. You have to explicitly make double click, on the row element. – zIronManBox Apr 19 '17 at 08:16
  • The idea is the user has to use ComboBox and accordingly has to set the other ComboBox. Nothing is committed on edit of each row. – zIronManBox Apr 19 '17 at 08:17
  • @zIronManBox Although I don't see why you insist not to do the usual ComboBox-TextField style (I cannot imagine a table with 20 rows showing 60 ComboBoxes), but the alternative is to make a `Map`, then manually set and get the `ComboBox` in `updateItem()`. – Jai Apr 19 '17 at 08:45
-1

You can get current row from TableCell::getIndex(). First, update objects contained within the TableView items.

comboBoxCalibMatchingNames.setOnAction(event -> {
    tableView.getItems().get(getIndex()).someProperty().set(anyValue1);
    tableView.getItems().get(getIndex()).otherProperty().set(anyValue2);
});

It fires TableCell::updateItem(T, boolean) of updated columns with new value. You must update selection of ComboBox on updateItem.

// in updteItem code on colSamplingX
final ComboBox< String > comboBox = new ComboBox<>();
comboBox.getSelectionModel().select(item);    // Select updated item.
setGraphic( comboBox );
setContentDisplay( ContentDisplay.GRAPHIC_ONLY );
monolith52
  • 886
  • 2
  • 6
  • 9
  • The question, I've asked is 'On selection of one comboBox , I need to select item in another ComboBox'. What you have told is already added in selection listener. Also, I only need to know, how can I get `GraphicNode` already set on another `TableColumn` for the corresponding row. – zIronManBox Apr 17 '17 at 05:03
  • Sorry, the point of my answer is that there is no need gettnig GraphicNode to set another ComboBox in this case. – monolith52 Apr 17 '17 at 05:46
  • If you see, I'm not using the root element to modify stuff. The data populated onto other columns is not coming from parent element. Its loaded during the runtime of `update` method of `cellFactory` of each column. – zIronManBox Apr 17 '17 at 09:03
  • It is mentioned that accessing the Cell isn't good approach in [this question](http://stackoverflow.com/questions/26815442/javafx-8-iterate-through-tableview-cells-and-get-graphics?rq=1). And you can find how to use Defining Data Model in [Example 12-5 Setting Data Properties to Columns](http://docs.oracle.com/javafx/2/ui_controls/table-view.htm). Don't forget **each** updating Model's property fires `updateItem(T, boolean)` automatically. – monolith52 Apr 17 '17 at 12:44