【问题标题】:JavaFX TableView cell set value laterJavaFX TableView 单元格设置值稍后
【发布时间】:2016-03-07 09:26:00
【问题描述】:

我有一个有 4 行的 TableView,每行都有一个自定义单元格。第一个只是一个图像,我想更新几次,一个字符串,一个带有自动换行的字符串和第二个图像作为按钮。

// image
tcUrlStatus.setCellValueFactory(new ColumnImageFactory());
tcUrlStatus.setCellFactory(new ColumnCallback());

// one line string
tcUrlName.setCellValueFactory(new ColumnNameFactory());
tcUrlName.setCellFactory(new ColumnCallback());

// two line string
tcUrlDate.setCellValueFactory(new ColumnDateFactory());
tcUrlDate.setCellFactory(new ColumnCallback());

// image as a button
tcDelete.setCellValueFactory(new ColumnDeleteFactory());
tcDelete.setCellFactory(new ColumnCallback());

这里是自定义单元格

class ColumnCallback implements Callback<TableColumn<Quartet<Boolean, String, String, String>, Object>, TableCell<Quartet<Boolean, String, String, String>, Object>>{
    @Override
    public TableCell<Quartet<Boolean, String, String, String>, Object> call(TableColumn<Quartet<Boolean, String, String, String>, Object> column) {
        return new ColumnCell();
    }
}

class ColumnImageFactory implements Callback<TableColumn.CellDataFeatures<Quartet<Object, String, String, String>, String>, ObservableValue<Object>> {
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Quartet<Object, String, String, String>, String> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue().getValue0());
    }
}

class ColumnNameFactory implements Callback<TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, String> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue().getValue1());
    }
}

class ColumnDateFactory implements Callback<TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, Object>, ObservableValue<Object>> {
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, Object> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue().getValue2());
    }
}

class ColumnDeleteFactory implements Callback<TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, Object>, ObservableValue<Object>> {
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Quartet<Boolean, String, String, String>, Object> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue().getValue3());
    }
}

class ColumnCell extends TableCell<Quartet<Boolean, String, String, String>, Object> {
    @Override
    protected void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);

        if (item != null) {
            if (item instanceof Boolean) {
                setText(null);
                Image image;
                AnchorPane pane = new AnchorPane();

                if ((boolean) item) {
                    image = new Image(Main.class.getResourceAsStream("/hourglass.gif"));
                } else {
                    image = new Image(Main.class.getResourceAsStream("/clean.gif"));
                }

                ImageView imageView = new ImageView(image);
                imageView.setFitWidth(30);
                imageView.setY(5);
                imageView.setPreserveRatio(true);
                imageView.setSmooth(true);

                pane.getChildren().add(imageView);

                setGraphic(pane);
            }else {
                if (item instanceof String) {
                    if (item.equals("delete")) {
                        AnchorPane pane = new AnchorPane();

                        Image image = new Image(Main.class.getResourceAsStream("/cross.png"));

                        ImageView imageView = new ImageView(image);
                        imageView.setFitWidth(20);
                        imageView.setY(10);
                        imageView.setPreserveRatio(true);
                        imageView.setSmooth(true);
                        imageView.setCursor(Cursor.HAND);

                        pane.getChildren().add(imageView);

                        imageView.setOnMouseClicked((Event event) -> {
                            Quartet<Boolean, String, String, String> row = this.getTableView().getSelectionModel().getSelectedItem();

                            Controller.localJson.remove(row.getValue1());
                            this.getTableView().getItems().remove(row);
                        });

                        setGraphic(pane);
                    } else {
                        HBox pane = new HBox();
                        Label label = new Label();
                        label.setText((String) item);

                        label.setTextAlignment(TextAlignment.CENTER);

                        if (((String) item).length() < 20) {
                            label.setWrapText(true);
                            label.setAlignment(Pos.CENTER);
                        }

                        pane.setPrefHeight(40);
                        label.setPrefHeight(40);
                        pane.getChildren().add(label);

                        setGraphic(pane);
                    }

                    setText(null);
                }
            }
        } else {
            setText(null);
            setGraphic(null);
        }
    }
}

现在我想更改 tcUrlStatus 列/单元格的图像。我已经想出了如何获取行或它的值,但我不知道如何设置值或者更确切地说从 true 更改为 false 或从 false 更改为 true 以更新图像。

获取行和值:

private int getTableRowIndex(String url){ // url is the second column
    int counter = 0;
    for (Object row:tvUrls.getItems()){
        if ((((Quartet) row).getValue1() == url)){
            return counter;
        }
        counter ++;
    }

    return -1;
}

int rowIndex = getTableRowIndex(url);
Object item = tvUrls.getItems().get(rowIndex);

【问题讨论】:

    标签: java javafx set tableview tablecell


    【解决方案1】:

    Quartet 类中使用 javafx 属性是最简单的方法,例如假设用于value0 bean 的类型是T

    // TODO: Is using a readonly property really needed here ???
    //       if not, use SimpleObjectProperty instead
    private final ReadOnlyObjectWrapper<T> value0 = new ReadOnlyObjectWrapper<>();
    
    public T getValue0() {
         return value0.get();
    }
    
    // TODO: should the setter really be public ???
    public void setValue0(T newValue) {
         value0.set(newValue);
    }
    
    public ReadOnlyObjectProperty<T> value0Property() {
        return value0.getReadOnlyProperty();
    }
    

    这允许您使用new PropertyValueFactory&lt;&gt;("value0") 而不是您的自定义单元格值工厂,更重要的是,这意味着TableView 组件将在Quartet 实例中收到更改通知。

    这样你就可以简单地使用

    quartetInstance.setValue0(newValue0);
    

    并且单元格将得到更新。

    在这种情况下,使用PropertyValueFactory 与使用以下cellValueFactory 具有相同的效果:

    class ColumnImageFactory implements Callback<TableColumn.CellDataFeatures<Quartet<Object, String, String, String>, String>, ObservableValue<Object>> {
        @Override
        public ObservableValue<Object> call(TableColumn.CellDataFeatures<Quartet<Object, String, String, String>, String> data) {
            return data.getValue().value0Property();
        }
    }
    

    如果您无法将 javaFX 属性添加到 Quartet 类,您需要在更改后以其他方式更新 TableViewTableView.refresh() 可以工作(前提是您使用 JavaFX 版本 >= 8u60)或编写 an adapter,以防您以其他方式在 Quartet 类中实现了观察者模式......

    【讨论】:

    • 我没有尝试,但我用另一种解决方案解决了“问题”。我使用了 SimpleObjectProperty。它比使用 Quartet 类更干净。我会马上发布它作为我的解决方案:)
    • @Mr.Tr33 是的,通常你有包含属性的项目,cellValueFactorys 返回这些属性之一,而不是创建一个新的;然后单元格将显示哪些属性,无论属性是否为只读。
    【解决方案2】:

    我通过从 Quartet 类转换为 SimpleObjectProperty 类解决了这个问题。

    初始化:

    tcUrlStatus.setCellValueFactory(new PropertyValueFactory<ColumnCellValue, Boolean>("status"));
    tcUrlName.setCellValueFactory(new PropertyValueFactory<ColumnCellValue, String>("url"));
    tcUrlDate.setCellValueFactory(new PropertyValueFactory<ColumnCellValue, String>("date"));
    tcDelete.setCellValueFactory(new PropertyValueFactory<ColumnCellValue, Boolean>("delete"));
    
    tcUrlStatus.setCellFactory(new ColumnStatusCell());
    tcUrlName.setCellFactory(new ColumnStringCell(false));
    tcUrlDate.setCellFactory(new ColumnStringCell(true));
    tcDelete.setCellFactory(new ColumnDeleteCell());
    

    添加行:

    tvUrls.getItems().add(new ColumnCellValue(true, url, date));
    

    更新单元格:

    ColumnCellValue statusRow = (ColumnCellValue)
    tvUrls.getItems().get(rowIndex);
    

    列类:

    public class ColumnCellValue{
        private final ObjectProperty status;
        private final ObjectProperty url;
        private final ObjectProperty date;
        private final ObjectProperty delete = new SimpleObjectProperty<Boolean>(true);
    
        ColumnCellValue(Boolean status, String url, String date) {
            this.status = new SimpleObjectProperty<Boolean>(status);
            this.url = new SimpleObjectProperty<String>(url);
            this.date = new SimpleObjectProperty<String>(date);
        }
    
        public Object getDate() {
            return date.get();
        }
    
        public ObjectProperty dateProperty() {
            return date;
        }
    
        public void setDate(Object date) {
            this.date.set(date);
        }
    
        public Object getDelete() {
            return delete.get();
        }
    
        public ObjectProperty deleteProperty() {
            return delete;
        }
    
        public void setDelete(Object delete) {
            this.delete.set(delete);
        }
    
        public Object getStatus() {
            return status.get();
        }
    
        public ObjectProperty statusProperty() {
            return status;
        }
    
        public void setStatus(Object status) {
            this.status.set(status);
        }
    
        public Object getUrl() {
            return url.get();
        }
    
        public ObjectProperty urlProperty() {
            return url;
        }
    
        public void setUrl(Object url) {
            this.url.set(url);
        }
    }
    
    class ColumnStatusCell implements Callback<TableColumn<Boolean, Boolean>,TableCell<Boolean, Boolean>>{
        @Override
        public TableCell<Boolean, Boolean> call(TableColumn<Boolean, Boolean> param) {
            AnchorPane pane = new AnchorPane();
    
            ImageView imageView = new ImageView();
            imageView.setFitWidth(30);
            imageView.setY(5);
            imageView.setPreserveRatio(true);
            imageView.setSmooth(true);
    
            TableCell<Boolean,Boolean> cell = new TableCell<Boolean,Boolean>(){
                public void updateItem(Boolean item, boolean empty) {
                    if(item!=null){
                        Image image;
    
                        if (item) {
                            image = new Image(Main.class.getResourceAsStream("/hourglass.gif"));
                        } else {
                            image = new Image(Main.class.getResourceAsStream("/clean.gif"));
                        }
    
                        imageView.setImage(image);
                    }
                }
            };
    
            pane.getChildren().add(imageView);
            cell.setGraphic(pane);
    
            return cell;
        }
    }
    
    class ColumnStringCell implements Callback<TableColumn<String, String>,TableCell<String, String>>{
        private boolean wrap = false;
    
        ColumnStringCell(boolean wrap){
            this.wrap = wrap;
        }
    
        @Override
        public TableCell<String, String> call(TableColumn<String, String> param) {
            TableCell<String,String> cell = new TableCell<String,String>(){
                public void updateItem(String item, boolean empty) {
                    if(item!=null){
                        Label label = new Label();
                        label.setText(item);
                        label.setPrefHeight(40);
                        label.setTextAlignment(TextAlignment.CENTER);
    
                        label.setWrapText(wrap);
    
                        setGraphic(label);
                    }
                }
            };
    
            return cell;
        }
    }
    
    class ColumnDeleteCell implements Callback<TableColumn<Boolean, Boolean>,TableCell<Boolean, Boolean>>{
        @Override
        public TableCell<Boolean, Boolean> call(TableColumn<Boolean, Boolean> param) {
            AnchorPane pane = new AnchorPane();
    
            ImageView imageView = new ImageView();
            imageView.setFitWidth(20);
            imageView.setY(10);
            imageView.setPreserveRatio(true);
            imageView.setSmooth(true);
            imageView.setCursor(Cursor.HAND);
    
            TableCell<Boolean,Boolean> cell = new TableCell<Boolean,Boolean>(){
                public void updateItem(Boolean item, boolean empty) {
                    if (item != null) {
                        Image image = new Image(Main.class.getResourceAsStream("/cross.png"));
                        imageView.setImage(image);
                    }
                }
            };
    
            imageView.setOnMouseClicked((Event event) -> {
                TableView table = (TableView) ((ImageView) event.getSource()).getParent().getParent().getParent().getParent().getParent().getParent().getParent();
                ColumnCellValue row = (ColumnCellValue) (table).getSelectionModel().getSelectedItem();
    
                Controller.localJson.remove(row.getUrl().toString());
                table.getItems().remove(row);
    
                table.refresh();
            });
    
            pane.getChildren().add(imageView);
            cell.setGraphic(pane);
    
            return cell;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 2014-02-22
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多