JavaFX TableView不更新UI

时间:2014-12-16 14:28:57

标签: javafx tableview javafx-8

我有一个Tableview<ObservableList<Item>>,在更新基础数据时没有更新。通过调试,我知道基础ObservableList<Item>>正在正确更新。我确保所有Item的属性都可见,格式为myFieldProperty()

这是我创建的表格:

pattern= new TableView<>(mainApp.getItemList());

    for (ObservableList<Item> row : pattern.getItems()) {

        for (int i= pattern.getColumns().size(); i<row.size(); i++){
            final int columnIndex = i ;

            TableColumn<ObservableList<Item>, Color> column = new TableColumn<>();

            column.setCellValueFactory( rowData -> 
                    rowData.getValue()
                    .get(columnIndex).displayColorProperty()); // the Item for this cell

            column.setCellFactory(col -> {
                ItemCell cell = new ItemCell();

                cell.setOnMouseEntered( e -> {
                    if (cell.getItem() != null) {
                        @SuppressWarnings("unchecked")
                        ObservableList<Item> stitchRow = 
                        (ObservableList<Item>) cell.getTableRow().getItem();
                        mainApp.getRLController().setItemLabel(itemRow.get(columnIndex).toString());
                    }
                });

                cell.setOnMouseExited( e -> {
                    mainApp.getRLController().setItemLabel(null);
                });

                cell.setOnMouseClicked((MouseEvent e) -> {
                    Item newItem = mainApp.getTBController().getSelectedItem();
                    if (e.getButton() == MouseButton.PRIMARY && newItem != null) {

                        ObservableList<Item> itemRow = 
                                (ObservableList<Item>) cell.getTableRow().getItem();
                        itemRow.set(columnIndex, newItem);  
                        mainApp.getRLController().setItemLabel(itemRow.get(columnIndex).toString());
                    }
                });

                return cell; 
                });

            column.setMinWidth(7);
            column.setPrefWidth(7);
            column.setMaxWidth(7);
            pattern.getColumns().add(column);
        }
    }
    pattern.setFixedCellSize(7);
    pattern.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);`

我的自定义单元工厂的代码:

public class ItemCell extends TableCell<ObservableList<Item>, Color> {

@Override 
protected void updateItem(Color color, boolean empty) {
    super.updateItem(color, empty); 

    if (empty || color == null) {
        setText(null);
        setStyle(null);
    } else {

        int r = (int) (color.getRed() * 255);
        int g = (int) (color.getGreen() * 255);
        int b = (int) (color.getBlue() * 255);

        this.setStyle("-fx-background-color: rgb(" + r + "," + g + "," + b + ");" 
             + "-fx-border-color: black; -fx-table-cell-border-color: black;");
    }
    }
}

1 个答案:

答案 0 :(得分:0)

基本问题是您要更改的对象(表示该行的列表元素的项目)不是单元格观察到更改的属性(属于该项目的displayColorProperty()) 。您需要安排更改单元格正在观察的属性的值。

三种可能的解决方案:

如果可能,只需更改单元格显示的项目的displayColor(以及其他数据)。即

            cell.setOnMouseClicked((MouseEvent e) -> {
                if (e.getButton() == MouseButton.PRIMARY && newItem != null) {

                    ObservableList<Item> itemRow = 
                            (ObservableList<Item>) cell.getTableRow().getItem();
                    Item item = itemRow.get(columnIndex);
                    item.setDisplayColor(...);
                    item.set...(...);  
                    // ...
                    mainApp.getRLController().setItemLabel(item.toString());
                }
            });

或者,替换整行:

            cell.setOnMouseClicked((MouseEvent e) -> {
                Item newItem = mainApp.getTBController().getSelectedItem();
                if (e.getButton() == MouseButton.PRIMARY && newItem != null) {

                    ObservableList<Item> itemRow = 
                            (ObservableList<Item>) cell.getTableRow().getItem();
                    ObservableList<Item> newRow = FXCollections.observableArrayList(itemRow);
                    newRow.set(columnIndex, newItem);  
                    pattern.getItems().set(cell.getTableRow().getIndex(), newRow);
                    mainApp.getRLController().setItemLabel(newRow.get(columnIndex).toString());
                }
            });

否则,您可以将表格设为TableView<ObservableList<ObjectProperty<Item>>>。这有点棘手,但不是太糟糕。这样,您只需将对象属性的值设置为新项即可。

以下是使用第三种技术的完整示例:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ColorTableExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<ObservableList<ObjectProperty<Item>>> table = new TableView<>();


        int NUM_ROWS = 20 ;
        int NUM_COLS = 15 ;

        ObservableList<ObservableList<ObjectProperty<Item>>> data = table.getItems() ;

        for (int y = 0 ; y < NUM_ROWS; y++) {

            ObservableList<ObjectProperty<Item>> row = FXCollections.observableArrayList();
            data.add(row);

            double saturation = (1.0 * y) / NUM_ROWS ;
            for (int x = 0 ; x < NUM_COLS; x++) {
                double hue = x * 360.0 / NUM_COLS ;

                Color color = Color.hsb(hue, saturation, 1.0);
                row.add(new SimpleObjectProperty<>(new Item(color)));
            }

        }

        for (ObservableList<ObjectProperty<Item>> row : table.getItems()) {
            for (int i = table.getColumns().size() ; i < row.size(); i++) {
                int columnIndex = i ;
                TableColumn<ObservableList<ObjectProperty<Item>>, Item> column = new TableColumn<>(Integer.toString(i+1));
                column.setCellValueFactory(rowData -> rowData.getValue().get(columnIndex));
                column.setCellFactory(c -> {
                    TableCell<ObservableList<ObjectProperty<Item>>, Item> cell = new TableCell<ObservableList<ObjectProperty<Item>>, Item>() {
                        @Override
                        public void updateItem(Item item, boolean empty) {
                            super.updateItem(item, empty);
                            if (empty) {
                                setStyle("");
                            } else {
                                Color color = item.getDisplayColor() ;
                                int r = (int) (color.getRed() * 255) ;
                                int g = (int) (color.getGreen() * 255) ;
                                int b = (int) (color.getBlue() * 255) ;
                                String style = String.format(
                                        "-fx-background-color: rgb(%d, %d, %d);"
                                        + "-fx-border-color: black ;"
                                        + "-fx-table-cell-border-color: black ;"
                                        ,r, g, b);
                                setStyle(style);
                            }
                        }
                    };

                    cell.setOnMousePressed(evt -> {
                        if (! cell.isEmpty()) {
                            ObservableList<ObjectProperty<Item>> rowData = (ObservableList<ObjectProperty<Item>>) cell.getTableRow().getItem();
                            Color currentColor = cell.getItem().getDisplayColor();
                            double newHue = ( currentColor.getHue() + 15 ) % 360 ;
                            Color newColor = Color.hsb(newHue, currentColor.getSaturation(), currentColor.getBrightness());
                            rowData.get(columnIndex).set(new Item(newColor));
                        }
                    });

                    return cell ;
                });
                table.getColumns().add(column);
            }
        }

        BorderPane root = new BorderPane(table, null, null, null, null);
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();
    }

    public static class Item {
        private final ObjectProperty<Color> displayColor = new SimpleObjectProperty<>() ;

        public Item(Color color) {
            this.displayColorProperty().set(color);
        }

        public final ObjectProperty<Color> displayColorProperty() {
            return this.displayColor;
        }

        public final javafx.scene.paint.Color getDisplayColor() {
            return this.displayColorProperty().get();
        }

        public final void setDisplayColor(final javafx.scene.paint.Color displayColor) {
            this.displayColorProperty().set(displayColor);
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}

(在某些时候,重构一切可能更容易,因此你有一个实际的类代表表中的每一行,而不是使用列表。)

可能还有一个聪明的解决方法,使用提取器列表,但我无法做到这一点。