sirwilliam sirwilliam - 5 months ago 41
Java Question

How to add button in JavaFX table view

I have searched at Google and Stackoverflow for this and I just don't get the given examples. Can someone please explain it to me.

I want to add a button to the last column of a table view and when it gets clicked it should trigger a listener and pass the object of the buttons row. I just do not get the following example from gist.github.com:

This is my full current code:

public class SchermdeelWerkplaats extends BorderPane{

//ATD moeder klasse met alle collecties etc.
private ATD $;

TableView tabel = new TableView();
Button nieuwTaak = new Button("Nieuwe taak inboeken");
final ObservableList<Task> data = FXCollections.observableArrayList();

public SchermdeelWerkplaats(ATD a) {

$ = a;

data.addAll($.agenda);

tabel.setEditable(false);
tabel.setPlaceholder(new Label("Geen taken"));

TableColumn c1 = new TableColumn("datum");
c1.setMinWidth(200);
TableColumn c2 = new TableColumn("type");
c2.setMinWidth(100);
TableColumn c3 = new TableColumn("uren");
c3.setMinWidth(100);
TableColumn c4 = new TableColumn("klaar");
c4.setMinWidth(200);
TableColumn c5 = new TableColumn("Werknemer");
c5.setMinWidth(100);
TableColumn c6= new TableColumn("Auto");
c6.setMinWidth(400);
TableColumn c7= new TableColumn("Actie");
c7.setMinWidth(400);

TableColumn col_action = new TableColumn<>("Action");

col_action.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<Task, Boolean>,
ObservableValue<Boolean>>() {

@Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Task, Boolean> p) {
return new SimpleBooleanProperty(p.getValue() != null);
}
});

col_action.setCellFactory(
new Callback<TableColumn<Task, Task>, TableCell<Task, Task>>() {

@Override
public TableCell<Task, Task> call(TableColumn<Task, Task> p) {
return new ButtonCell();
}
}
);

c1.setCellValueFactory(
new PropertyValueFactory<Task,Date>("date")
);
c2.setCellValueFactory(
new PropertyValueFactory<Task,Task.TaskType>("type")
);
c3.setCellValueFactory(
new PropertyValueFactory<Task,Double>("hours")
);
c4.setCellValueFactory(
new PropertyValueFactory<Task,Boolean>("done")
);
c5.setCellValueFactory(
new PropertyValueFactory<Task,Employee>("employee")
);
c6.setCellValueFactory(
new PropertyValueFactory<Task,Car>("car")
);

tabel.getColumns().addAll(c1, c2, c3, c4, c5, c6, c7);
tabel.setItems(data);

setCenter(tabel);
setBottom(nieuwTaak);

}

//letterlijk van internet geplukt en datatype aangepast
private class ButtonCell extends TableCell<Task, Task> {


private Button cellButton;

ButtonCell(){
cellButton = new Button("jjhjhjh");
cellButton.setOnAction(new EventHandler<ActionEvent>(){

@Override
public void handle(ActionEvent t) {
// do something when button clicked
Task record = getItem();
// do something with record....
}
});
}

//Display button if the row is not empty
@Override
protected void updateItem(Task record, boolean empty) {
super.updateItem(record, empty);
if(!empty){
cellButton.setText("Something with "+record);
setGraphic(cellButton);
} else {
setGraphic(null);
}
}
}

}


Now the part where I have to create a
ButtonCell extends TableCell
is understandable. But how to assign this to the column?

I understand this:

c1.setCellValueFactory(
new PropertyValueFactory<Task,Date>("date")
);


But not this:

TableColumn col_action = new TableColumn<>("Action");

col_action.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<Task, Boolean>,
ObservableValue<Boolean>>() {

@Override
public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Task, Boolean> p) {
return new SimpleBooleanProperty(p.getValue() != null);
}
});

col_action.setCellFactory(
new Callback<TableColumn<Task, Task>, TableCell<Task, Task>>() {

@Override
public TableCell<Task, Task> call(TableColumn<Task, Task> p) {
return new ButtonCell();
}
}
);

Answer

To be able to render the column, TableColumn needs cellValueFactory. But the "action" column does not exist in underlying data model. In this case, I just give some dummy value to cellValueFactory and move on:

public class JustDoIt extends Application
{

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data
            = FXCollections.observableArrayList(
                    new Person( "Jacob", "Smith" ),
                    new Person( "Isabella", "Johnson" ),
                    new Person( "Ethan", "Williams" ),
                    new Person( "Emma", "Jones" ),
                    new Person( "Michael", "Brown" )
            );


    public static void main( String[] args )
    {
        launch( args );
    }


    @Override
    public void start( Stage stage )
    {
        stage.setWidth( 450 );
        stage.setHeight( 500 );

        TableColumn firstNameCol = new TableColumn( "First Name" );
        firstNameCol.setCellValueFactory( new PropertyValueFactory<>( "firstName" ) );

        TableColumn lastNameCol = new TableColumn( "Last Name" );
        lastNameCol.setCellValueFactory( new PropertyValueFactory<>( "lastName" ) );

        TableColumn actionCol = new TableColumn( "Action" );
        actionCol.setCellValueFactory( new PropertyValueFactory<>( "DUMMY" ) );

        Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory = //
                new Callback<TableColumn<Person, String>, TableCell<Person, String>>()
                {
                    @Override
                    public TableCell call( final TableColumn<Person, String> param )
                    {
                        final TableCell<Person, String> cell = new TableCell<Person, String>()
                        {

                            final Button btn = new Button( "Just Do It" );

                            @Override
                            public void updateItem( String item, boolean empty )
                            {
                                super.updateItem( item, empty );
                                if ( empty )
                                {
                                    setGraphic( null );
                                    setText( null );
                                }
                                else
                                {
                                    btn.setOnAction( ( ActionEvent event ) ->
                                            {
                                                Person person = getTableView().getItems().get( getIndex() );
                                                System.out.println( person.getFirstName() + "   " + person.getLastName() );
                                    } );
                                    setGraphic( btn );
                                    setText( null );
                                }
                            }
                        };
                        return cell;
                    }
                };

        actionCol.setCellFactory( cellFactory );

        table.setItems( data );
        table.getColumns().addAll( firstNameCol, lastNameCol, actionCol );

        Scene scene = new Scene( new Group() );

        (( Group ) scene.getRoot()).getChildren().addAll( table );

        stage.setScene( scene );
        stage.show();
    }


    public static class Person
    {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;


        private Person( String fName, String lName )
        {
            this.firstName = new SimpleStringProperty( fName );
            this.lastName = new SimpleStringProperty( lName );
        }


        public String getFirstName()
        {
            return firstName.get();
        }


        public void setFirstName( String fName )
        {
            firstName.set( fName );
        }


        public String getLastName()
        {
            return lastName.get();
        }


        public void setLastName( String fName )
        {
            lastName.set( fName );
        }

    }
}