ddron
ddron

Reputation: 13

Add Button to TableView and bind Button's textProperty to property of TableView object

I've got an Order object I'm representing in TableView. One of the column should contain a Button. Button's text property should be bind to String property on Order object.

I used this post as a starting point: http://java-buddy.blogspot.ru/2013/03/javafx-embed-button-in-tableview.html

How can I bind Button's text property to string property of Order object?

Order object:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Order {

    private String id;
    private StringProperty action = new SimpleStringProperty("CANCEL"); // initial value, to be changed later 

    public String getAction() {
        return action.get();
    }

    public StringProperty actionProperty() {
        return action;
    }

    public void setAction(String action) {
        this.action.set(action);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

OrderManager:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class OrdersManager {

    private Map<String, Order> orders = new ConcurrentHashMap<>();
    private ObservableList<Order> ordersView = FXCollections.observableArrayList(orders.values());

    public ObservableList<Order> getOrdersView() {
        return ordersView;
    }

    // other code below...
}

Controller:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.util.Callback;

public class Controller {

    @FXML
    private TableView<Order> ordersView;

    private OrdersManager ordersManager;

    public void initController() {

        // other code above...

        // init orders view table
        initOrdersViewTable();
    }

    private void initOrdersViewTable() {

        // create other columns. Removed as not important

        //Insert Button
        TableColumn<Order, String> actionCol = new TableColumn<>("Action");
        actionCol.setSortable(false);

        actionCol.setCellValueFactory(
                new Callback<TableColumn.CellDataFeatures<Order, String>, ObservableValue<String>>() {

                    @Override
                    public ObservableValue<String> call(TableColumn.CellDataFeatures<Order, String> p) {
                        return new SimpleStringProperty(p.getValue().getId()); //order.id is used as cell value
                    }
                });

        actionCol.setCellFactory(
                new Callback<TableColumn<Order, String>, TableCell<Order, String>>() {

                    @Override
                    public TableCell<Order, String> call(TableColumn<Order, String> p) {
                        ButtonCell buttonCell = new ButtonCell();

                        // HOW TO BIND TO Order.action stringProperty ???
                        //buttonCell.textProperty().bind(???);

                        return buttonCell;
                    }

                });

        ordersView.setItems(ordersManager.getOrdersView());
        ordersView.getColumns().addAll(actionCol);
    }

    //Define the button cell
    private class ButtonCell extends TableCell<Order, String> {
        final Button cellButton = new Button();

        ButtonCell(){
            cellButton.setOnAction(new EventHandler<ActionEvent>(){
                @Override
                public void handle(ActionEvent t) {
                    String id = getItem(); // it will be order.id
                    String action = cellButton.getText(); // it's actually will be order.action field

                    // orderManager.doSomethingWithIdandAction
                }
            });
        }

        //Display button if the row is not empty
        @Override
        protected void updateItem(String t, boolean empty) {
            super.updateItem(t, empty);
            if (!empty) {
                setGraphic(cellButton);
            }
        }
    }

    public void setOrdersManager(OrdersManager ordersManager) {
        this.ordersManager = ordersManager;
    }
}


UPDATE after James_D answer:
was suggested too put into ButtonCell constructor:

cellButton.textProperty().bind(itemProperty());

itemProperty() returns value associated with cell so to make solution work I had to modify CellValueFactory (need to set action field as cell value)

actionCol.setCellValueFactory(
        new Callback<TableColumn.CellDataFeatures<Order, String>, ObservableValue<String>>() {

            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<Order, String> p) {
                return p.getValue().actionProperty();
            }
        });

Next required change is to update button's handle method. So now it is:

    cellButton.setOnAction(new EventHandler<ActionEvent>(){
        @Override
        public void handle(ActionEvent t) {
            String id = ((Order) getTableRow().getItem()).getId(); // it will be order.id
            String action = getItem(); // it's actually will be order.action field

            // orderManager.doSomethingWithIdandAction
        }
    });

Upvotes: 1

Views: 1994

Answers (1)

James_D
James_D

Reputation: 209684

In the ButtonCell constructor, just do

cellButton.textProperty().bind(itemProperty());

Upvotes: 1

Related Questions