0

So I am trying to get a TableView to represent rows of seats. So a row represents an Object of class "Reihe" (german "row").A Reihe has an array of Sitzplatz("seat"). Every seat has got a Button which is supposed to be displayed in the seats cell. So I am a bit confused about the cellFactories for the TableColumns. How do I tell the Columns to display the button of a seat from row.seat[columnIdx] ? I cant return an ObservableValue< Button> right? So what am I using as CellFactories?

Class "Reihe"(=row):

public class Reihe implements DataObject
{
  private Sitzplatz[] seats;

 public Reihe(int seats,int saal)
 {
    this.seats=new Sitzplatz[seats];
    for(int i=0; i<this.seats.length; i++)
    {
        this.seats[i]=new Sitzplatz();
        this.seats[i].setSaal_SID(""+saal);
    }
 }

 public Sitzplatz getSeat(int idx)
 {
    return seats[idx];
 }
    ...

Class "Sitzplatz" ("seat"):

 public class Sitzplatz implements DataObject
 {
  private SimpleStringProperty platz, reihe,saal_SID, reservierung_REID;
  private SeatButton button;

  public Sitzplatz()
  {
    this.platz=new SimpleStringProperty();
    this.saal_SID=new SimpleStringProperty();
    this.reihe=new SimpleStringProperty();
    this.reservierung_REID=new SimpleStringProperty();
    button=new SeatButton();
  }

  public SeatButton getButton()
  {
    return button;
  }
    ...

Initialization of Columns:

   for(int j=0; j<seatColumns; j++)
   {
       TableColumn<Reihe,Button> nColumn=new TableColumn<>("Seat"+j);
       //final int idx=j;
       nColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Reihe, Button>, ObservableValue<Button>>() {

            @Override
            public ObservableValue<Button> call(TableColumn.CellDataFeatures<Reihe, Button> p) {
                    // ???
                }
            });
         nColumn.setMinWidth(50);
         nColumn.setEditable(true);
         //getColumns().add(nColumn);
         getColumns().add(nColumn);
        }

I found something about using Button extends TableCell but again I could not really work out how its supposed to work:

public class SeatButton extends TableCell<Reihe, Button>
{
  Button cellButton;
 //private Sitzplatz seat;

 public SeatButton()
 {
    //seat=row.getSeat(column);
    cellButton=new Button();

    cellButton.setMinWidth(30);
    cellButton.setOnAction(new EventHandler<ActionEvent>(){
        @Override
        public void handle(ActionEvent t) {

            //....
        }
    });
 }
}
PhilKes
  • 78
  • 7
  • This may be more than what you need, but it should get you going in the right direction. https://stackoverflow.com/questions/17067481/javafx-2-tableview-different-cell-factory-depending-on-the-data-inside-the-cel – SedJ601 May 10 '18 at 13:21
  • I recommend you restrict yourself to 1 language for the code. It seems like you have not decided if you want to use German or English. (I recommend using English, since this way you'd be consistent with the API.) – fabian May 10 '18 at 14:02
  • I knew someone would say that and I know this myself Since this is mostly for testing out JavaFX+JDBC with a "german" SQL Database it kinda got a mess of languages – PhilKes May 10 '18 at 14:26

1 Answers1

1

You shouldn't put GUI elements in the model. In this case it makes even less sense, since SeatButton extends TableCell and TableCell creation is independent of the items. Also items are assigned to TableCells by TableView and the item of a TableCell may be changed/removed.

Use the cellValueFactory to return the Sitzplatz for the given column and use a cellFactory that returns TableCell<Reihe, Sitzplatz>:

for(int j=0; j<seatColumns; j++) {
    final index = j;
    TableColumn<Reihe, Sitzplatz> nColumn = new TableColumn<>("Seat"+j);
    nColumn.setCellValueFactory(p -> new SimpleObjectProperty<>(p.getValue().getSeat(index)));
    nColumn.setCellFactory(c -> new SeatButton<>());
    nColumn.setMinWidth(50);
    nColumn.setEditable(false); // you want to modify items not replace them
    getColumns().add(nColumn);
}
public class SeatButton<T> extends TableCell<T, Sitzplatz> {
    Button cellButton;

    public SeatButton() {
        cellButton=new Button();

        cellButton.setMinWidth(30);
        cellButton.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent t) {

                //....
            }
        });
    }

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

        if (empty || item == null) {
            setGraphic(null);
        } else {
            setGraphic(cellButton);
            // TODO: adjust button according to data
        }
    }
}
fabian
  • 80,457
  • 12
  • 86
  • 114
  • Thank you very much that was indeed helpful – PhilKes May 10 '18 at 14:18
  • Just one more thing So the SeatButton only knows its Sitzplatz through the TableView with getItem(), but when is this initialized? Can I access the Sitzplatz for a SeatButton in the constructor of the SeatButton? – PhilKes May 10 '18 at 14:19
  • @PhilKey no. Treat the cell as empty as long as `updateItem` isn't called. A new item may be assigned to the cell and the cell may become empty after being filled. (Make sure to reduce the creation of nodes in the `updateItem` method to a minimum.). Your code shouldn't depend on when the update happens. It's done during the layout process and may be done again due to scrolling ect. – fabian May 10 '18 at 14:32