设置TableCell禁用编程方式奇怪的行为

时间:2016-09-04 15:33:41

标签: javafx-8

我有一个包含数量和价格列的表格,可以编辑而不是禁用。该表填充了ObservableList<Collection>Collection对象具有boolean属性paid。我要实现的是,只要paid为真,就禁用价格和数量表格,并且不可编辑。

这是我到目前为止所做的:

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.FloatProperty;
import javafx.beans.property.ReadOnlyFloatProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.converter.FloatStringConverter;

public class CollectionTable extends Application{
public static void main(String[] args) {
    launch(args);
}

@Override
public void start(Stage primaryStage) throws Exception {
    TableView<Collection> tv = new TableView();
    tv.setEditable(true);

    TableColumn<Collection, Number> colQty = createQuantityColumn();
    colQty.setCellFactory(
        new Callback<TableColumn<Collection, Number>, TableCell<Collection, Number>>() {
            @Override
            public TableCell<Collection, Number> call(TableColumn<Collection, Number> paramTableColumn) {
                return new TextFieldTableCell<Collection, Number>() {
                    @Override
                    public void updateItem(Number s, boolean b) {
                        super.updateItem(s, b);

                        TableRow row = getTableRow();
                        if (row != null) {
                            Collection item = (Collection) row.getItem();
                            //Test for disable condition
                            if (item != null && item.isPaid()) {
                                setDisable(true);
                                setEditable(false);
                                this.setStyle("-fx-text-fill: grey;-fx-border-color: red");
                            }
                        }
                    }
                };
            }
    });
    TableColumn<Collection, Number> colPrice = createPriceColumn();

    colPrice.setCellFactory(
        new Callback<TableColumn<Collection, Number>, TableCell<Collection, Number>>() {
            @Override
            public TableCell<Collection, Number> call(TableColumn<Collection, Number> paramTableColumn) {
                return new TextFieldTableCell<Collection, Number>() {
                    @Override
                    public void updateItem(Number s, boolean b) {
                        super.updateItem(s, b);

                        TableRow row = getTableRow();
                        if (row != null) {
                            Collection item = (Collection) row.getItem();
                            //Test for disable condition
                            if (item != null && !item.isPaid()) {
                                setDisable(true);
                                setEditable(false);
                                this.setStyle("-fx-text-fill: grey;-fx-border-color: red");
                            }
                        }
                    }
                };
            }
    });
    TableColumn<Collection, Number> colAmount = createAmountColumn();
    TableColumn<Collection, String> colMno = createMNOColumn();

    tv.getColumns().addAll(colMno, colQty, colPrice, colAmount);
    tv.getItems().addAll(getCollection());
    Scene scene = new Scene(new BorderPane(tv), 600, 400);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private TableColumn createQuantityColumn() {
    TableColumn<Collection, Float> colQty = new TableColumn("Quantity");
    colQty.setMinWidth(25);
    colQty.setId("colQty");
    colQty.setCellFactory(TextFieldTableCell.<Collection, Float>forTableColumn(new FloatStringConverter()));
    colQty.setCellValueFactory(cellData -> cellData.getValue().quantityProperty().asObject());
    colQty.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Collection, Float>>() {
        @Override
        public void handle(TableColumn.CellEditEvent<Collection, Float> t) {


        }
    });
    return colQty;
}

private TableColumn createPriceColumn() {
    TableColumn<Collection, Float> colPrice = new TableColumn("Price");
    colPrice.setMinWidth(25);
    colPrice.setId("colPrice");
    colPrice.setCellFactory(TextFieldTableCell.<Collection, Float>forTableColumn(new FloatStringConverter()));
    colPrice.setCellValueFactory(cellData -> cellData.getValue().priceProperty().asObject());
    colPrice.setOnEditStart(new EventHandler<TableColumn.CellEditEvent<Collection, Float>>() {
        @Override
        public void handle(TableColumn.CellEditEvent<Collection, Float> t) {
            Collection c = ((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow()));
            c.setPrice(Math.abs(c.getPrice()));
        }
    });
    colPrice.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Collection, Float>>() {
        @Override
        public void handle(TableColumn.CellEditEvent<Collection, Float> t) {
            Collection c = ((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow()));
            c.setPrice(Math.abs((float)t.getNewValue()));
            //int i = collectionHandler.updateCollection(c);
        }
    });
    return colPrice;
}

private TableColumn createAmountColumn() {
    TableColumn<Collection, Float> colAmount = new TableColumn("Amount");
    colAmount.setMinWidth(25);
    colAmount.setId("colAmount");
    colAmount.setCellValueFactory(cellData -> cellData.getValue().amountProperty().asObject());
    return colAmount;
}

private TableColumn createMNOColumn() {
    TableColumn colMNO = new TableColumn("M/NO");
    colMNO.setMinWidth(25);
    colMNO.setId("colMNO");
    colMNO.setCellValueFactory(new PropertyValueFactory("mno"));
    return colMNO;
}

private List<Collection> getCollection(){
    List<Collection> collections = new ArrayList<>();
    collections.add(new Collection(1, 10, "1", false));
    collections.add(new Collection(2, 10, "12", true));
    collections.add(new Collection(3, 10, "123", true));
    collections.add(new Collection(4, 10, "312", true));
    collections.add(new Collection(5, 10, "311", false));
    collections.add(new Collection(6, 10, "322", true));
    collections.add(new Collection(7, 10, "333", true));
    collections.add(new Collection(8, 10, "321", false));
    collections.add(new Collection(9, 10, "456", true));
    collections.add(new Collection(10, 10, "551", true));
    collections.add(new Collection(11, 10, "515", false));
    collections.add(new Collection(12, 10, "134", true));
    collections.add(new Collection(13, 10, "789", true));
    collections.add(new Collection(14, 10, "879", false));
    collections.add(new Collection(15, 10, "987", true));
    collections.add(new Collection(16, 10, "856", true));
    collections.add(new Collection(17, 10, "956", true));
    collections.add(new Collection(18, 10, "589", true));
    collections.add(new Collection(19, 10, "852", false));
    collections.add(new Collection(20, 10, "456", false));
    collections.add(new Collection(21, 10, "623", true));
    collections.add(new Collection(22, 10, "147", false));
    collections.add(new Collection(23, 10, "125", true));
    collections.add(new Collection(24, 10, "258", false));
    collections.add(new Collection(25, 10, "325", true));
    collections.add(new Collection(26, 10, "753", true));
    collections.add(new Collection(27, 10, "357", false));
    collections.add(new Collection(28, 10, "159", false));
    return collections;
}

public class Collection{
    private final FloatProperty quantity  = new SimpleFloatProperty();
    private final FloatProperty price  = new SimpleFloatProperty();
    private final FloatProperty amount  = new SimpleFloatProperty();
    private final BooleanProperty paid = new SimpleBooleanProperty(false);
    private String mno;

    public Collection(){
        this(0f, 0f, null, false);
    }

    public Collection(float quantity, float price, String mno, boolean paid) {
        setQuantity(quantity);
        setPrice(price);
        setMno(mno);
        setPaid(paid);
        this.amount.bind(this.quantity.multiply(this.price));
    }

    public String getMno() {
        return mno;
    }

    public void setMno(String mno) {
        this.mno = mno;
    }

    public float getQuantity() {
        return quantityProperty().get();
    }

    public void setQuantity(float quantity) {
        quantityProperty().set(quantity);
    }

    public FloatProperty quantityProperty() {
        return quantity ;
    }

    public float getPrice() {
        return priceProperty().get();
    }

    public void setPrice(float price) {
        priceProperty().set(price);
    }

    public FloatProperty priceProperty() {
        return price ;
    }

    public float getAmount() {
        return amountProperty().get();
    }

    public ReadOnlyFloatProperty amountProperty() {
        return amount ;
    }

    public BooleanProperty paidProperty() {
        return paid;
    }

    public void setPaid(boolean approved) {
        this.paid.set(approved);
    }

    public boolean isPaid() {
        return paid.get();
    }
}
}

我的代码存在的问题是,当我向下滚动表格时,先前已启用且可编辑的单元格将更改为已禁用且无法编辑。

滚动之前enter image description here滚动后:enter image description here

1 个答案:

答案 0 :(得分:2)

第一个问题是,当一个单元从一个单元被重新使用时,你不会重置状态。当您滚动时,这将发生。如果一个单元格先前已用于表示“付费”字样的行中。 item(因此它被禁用,不可编辑,并且有一个红色边框),并被重用于&#34; unpaid&#34; item,您的updateItem()方法不会更改可编辑或禁用状态(或样式)。所以你应该有类似的东西:

if (item != null && item.isPaid()) {
    setDisable(true);
    setEditable(false);
    this.setStyle("-fx-text-fill: grey;-fx-border-color: red");
} else {
    setDisable(false);
    setEditable(true);
    setStyle("");
}

第二个问题是您无法控制更新单元格状态的顺序。似乎有时在调用updateItem()方法之后更新了行属性,因此最终会出现不一致的状态。您可以安全地使用单元格索引从表格数据中获取正确的项目。

另请注意,由于两个单元工厂都相同,因此无需复制代码。这对我有用:

@Override
public void start(Stage primaryStage) throws Exception {
    TableView<Collection> tv = new TableView();
    tv.setEditable(true);

    TableColumn<Collection, Number> colQty = createQuantityColumn();
    Callback<TableColumn<Collection, Number>, TableCell<Collection, Number>> cellFactory = new Callback<TableColumn<Collection, Number>, TableCell<Collection, Number>>() {
        @Override
        public TableCell<Collection, Number> call(TableColumn<Collection, Number> paramTableColumn) {
            return new TextFieldTableCell<Collection, Number>() {
                @Override
                public void updateItem(Number s, boolean b) {
                    super.updateItem(s, b);

                    if (! isEmpty()) {
                        Collection item = getTableView().getItems().get(getIndex());
                        // Test for disable condition
                        if (item != null && item.isPaid()) {
                            setDisable(true);
                            setEditable(false);
                            this.setStyle("-fx-text-fill: grey;-fx-border-color: red");
                        } else {
                            setDisable(false);
                            setEditable(true);
                            setStyle("");
                        }
                    } 
                }
            };
        }
    };
    colQty.setCellFactory(cellFactory);
    TableColumn<Collection, Number> colPrice = createPriceColumn();


    colPrice.setCellFactory(cellFactory);
    TableColumn<Collection, Number> colAmount = createAmountColumn();
    TableColumn<Collection, String> colMno = createMNOColumn();

    tv.getColumns().addAll(colMno, colQty, colPrice, colAmount);
    tv.getItems().addAll(getCollection());
    Scene scene = new Scene(new BorderPane(tv), 600, 400);
    primaryStage.setScene(scene);
    primaryStage.show();
}