【问题标题】:Add Button to TableView and bind Button's textProperty to property of TableView object将 Button 添加到 TableView 并将 Button 的 textProperty 绑定到 TableView 对象的属性
【发布时间】:2014-01-12 08:52:46
【问题描述】:

我有一个我在 TableView 中表示的 Order 对象。 其中一列应包含一个按钮。 Button 的 text 属性应该绑定到 Order 对象上的 String 属性。

我以这篇文章为起点: http://java-buddy.blogspot.ru/2013/03/javafx-embed-button-in-tableview.html

如何将 Button 的 text 属性绑定到 Order 对象的 string 属性?

订单对象:

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;
    }
}

订单管理器:

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...
}

控制器:

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;
    }
}


更新在 James_D 之后回答:
建议也放入 ButtonCell 构造函数:

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

itemProperty() 返回与单元格关联的值,因此为了使解决方案有效,我必须修改 CellValueFactory(需要将操作字段设置为单元格值)

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

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

下一个需要更改的是更新按钮的句柄方法。所以现在是:

    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
        }
    });

【问题讨论】:

    标签: java javafx javafx-2 tableview


    【解决方案1】:

    在 ButtonCell 构造函数中,只需这样做

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

    【讨论】:

    • 非常感谢您的回答。它有效,我更新了初始帖子以反映使此解决方案有效所需的更改(更新单元格值工厂)。虽然它解决了我的问题并且我会使用它,但我想知道以下几点:实际上您在这里建议将“操作”字段放入单元格值中。然后做绑定。但是想象一下,我需要两个不同按钮属性的绑定。两者都来自订单对象字段。建议的解决方案不起作用。有什么想法在这种情况下该怎么做?
    • 您可以使用 Bindings.select(tableRowProperty(), "x") 绑定到其他属性(除了作为单元格值的属性),其中表示表中项目的类具有 xProperty() 或 getX() 方法.但我不太确定问题是什么:看起来你更新中的代码应该做你想做的事。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-23
    • 2011-11-20
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多