javafx-8 - 设置表格单元以编程方式禁用奇怪的行为

标签 javafx-8

我有一个表格,其中包含可编辑且未禁用的数量和价格列。该表由 ObservableList<Collection> 填充。 Collection 对象具有 boolean 属性 paid 。我想要实现的是,每当 paid 为 true 时,使价格和数量表格单元都禁用且不可编辑。

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

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

最佳答案

第一个问题是,当单元格从已付费单元格重用到未付费单元格时,您不会重置状态。当您滚动时,这种情况就会发生。如果某个单元格之前在代表“付费”项目的行中使用过(因此它被禁用、不可编辑且具有红色边框),并且被重新用于“未付费”项目,则您的 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();
}

关于javafx-8 - 设置表格单元以编程方式禁用奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39318589/

相关文章:

java - 循环依赖、递归类

JavaFX 8 制作桌面截图

JavaFX:将节点排成一行

java - 如何翻译javaFX中的弹出窗口?

java - PDFBox:将 PDF 转换为图像比预期慢

java - 我所有的 @FXML 引用都是 null

java - 如何在 JavaFX 中可视化 TreeTableView 中无限数量的数据行?

java - 有没有办法更改内置 controlfx 通知弹出窗口的颜色?

java - 切换按钮 .isSelected() 为 true,但在 JavaFX 中视觉上没有变化

javafx - 向 SceneBuilder 2.0 添加自定义组件