【问题标题】:JavaFX - How to change the color of a selected TableColumn with Java-Code?JavaFX - 如何使用 Java 代码更改选定 TableColumn 的颜色?
【发布时间】:2021-08-07 08:48:15
【问题描述】:

我有一个简单的 TableView,有两列(Id,Valid)。
表格代码如下:

private TableView<List<Object>> createTable()
    {
       TableView<List<Object>> table = new TableView<>();

       TableColumn<List<Object>, String> idCol = new TableColumn<>("ID");
       idCol.setCellValueFactory(new Callback<CellDataFeatures<List<Object>, String>, ObservableValue<String>>()
       {
          public ObservableValue<String> call(CellDataFeatures<List<Object>, String> param)
          {
             return new SimpleStringProperty(param.getValue().get(0).toString());
          }
       });
       TableColumn<List<Object>, String> validCol = new TableColumn<>("Valid");
       validCol.setCellValueFactory(new Callback<CellDataFeatures<List<Object>, String>, ObservableValue<String>>()
       {
          public ObservableValue<String> call(CellDataFeatures<List<Object>, String> param)
          {
             return new SimpleStringProperty(param.getValue().get(1).toString());
          }
       });
       table.getColumns().addAll(idCol, validCol);

       List<Object> firstRow = new ArrayList<Object>();
       firstRow.add(1);
       firstRow.add(0);
       List<Object> secondRow = new ArrayList<Object>();
       secondRow.add(2);
       secondRow.add(1);
       table.getItems().addAll(firstRow, secondRow);

       return table;
    }

有效行的背景应变为绿色,无效行的背景应变为红色。我通过设置行工厂意识到这一点:

table.setRowFactory(new Callback<TableView<List<Object>>, TableRow<List<Object>>>()
   {
      @Override
      public TableRow<List<Object>> call(TableView<List<Object>> param)
      {
         return new TableRow<List<Object>>()
         {
            @Override
            protected void updateItem(List<Object> item, boolean empty)
            {
                super.updateItem(item, empty);
                if (!empty)
                {
                   int valid = Integer.parseInt(item.get(1).toString());
                   if (valid == 1)
                      setBackground(MyCustomBackGround.VALID);
                   else if (valid == 0)
                      setBackground(MyCustomBackGround.NOT_VALID);
                   else
                      setBackground(MyCustomBackGround.WHITE);
                }
            }
         };
      }
   });

这似乎工作正常。但现在我想改变我的选择的颜色。可以说我想使设置的颜色变暗。
我怎么能意识到这一点?

【问题讨论】:

    标签: java javafx tableview


    【解决方案1】:

    您可以使用Bindings,例如如下所示。或者,您可以使用CSSPseudoClasses

    table.setRowFactory(tv -> new TableRow<>() {
        private final Background
                validBackground = new Background(new BackgroundFill(Color.LIGHTGREEN, CornerRadii.EMPTY, Insets.EMPTY)),
                validSelectedBackground = new Background(new BackgroundFill(Color.DARKGREEN, CornerRadii.EMPTY, Insets.EMPTY)),
                invalidBackground = new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)),
                invalidSelectedBackground = new Background(new BackgroundFill(Color.DARKRED, CornerRadii.EMPTY, Insets.EMPTY));
    
        @Override
        public void updateItem(Item item, boolean empty) {
            super.updateItem(item, empty);
    
            if (item == null || empty)
                backgroundProperty().unbind();
            else
                backgroundProperty().bind(Bindings.when(item.validProperty())
                        .then(Bindings.when(selectedProperty())
                                .then(validSelectedBackground)
                                .otherwise(validBackground))
                        .otherwise(Bindings.when(selectedProperty())
                                .then(invalidSelectedBackground)
                                .otherwise(invalidBackground)));
        }
    });
    

    更新:css 示例。

    App.java:

    package org.example;
    
    import javafx.application.Application;
    import javafx.css.PseudoClass;
    import javafx.scene.Scene;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableRow;
    import javafx.scene.control.TableView;
    import javafx.scene.layout.Pane;
    import javafx.stage.Stage;
    
    import java.util.Objects;
    import java.util.stream.IntStream;
    import java.util.stream.Stream;
    
    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
    
            // Create table with columns:
            TableView<Item> table = new TableView<>();
    
            TableColumn<Item, Integer> idCol = new TableColumn<>("ID");
            TableColumn<Item, Boolean> validCol = new TableColumn<>("Valid");
    
            Stream.of(idCol, validCol).forEach(col -> table.getColumns().add(col));
    
            idCol.setCellValueFactory(cellData -> cellData.getValue().idProperty().asObject());
            validCol.setCellValueFactory(cellData -> cellData.getValue().validProperty());
    
            // Create pseudo classes:
            PseudoClass validPseudoClass = PseudoClass.getPseudoClass("valid"),
                    invalidPseudoClass = PseudoClass.getPseudoClass("invalid");
    
            // Customized row factory:
            table.setRowFactory(tv -> {
                TableRow<Item> row =  new TableRow<>();
                row.itemProperty().addListener((observable, oldValue, newValue) -> {
                    if (newValue != null) {
                        row.pseudoClassStateChanged(validPseudoClass, newValue.isValid());
                        row.pseudoClassStateChanged(invalidPseudoClass, !newValue.isValid());
                    } else {
                        row.pseudoClassStateChanged(validPseudoClass, false);
                        row.pseudoClassStateChanged(invalidPseudoClass, false);
                    }
                    table.refresh();
                });
                return row ;
            });
    
            // Create test data:
            IntStream.range(0, 5).forEach(i -> table.getItems().add(new Item(i, true)));
            IntStream.of(1, 3).forEach(i -> table.getItems().get(i).setValid(false));
    
            // Prepare and show scene:
            Scene scene = new Scene(new Pane(table));
            scene.getStylesheets().add(Objects.requireNonNull( // Load the css file
                    App.class.getResource("styling.css")).toExternalForm()); 
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }
    }
    

    styling.css:

    .table-row-cell:valid {
        -fx-background: green;
    }
    
    .table-row-cell:valid:selected {
        -fx-background: darkgreen;
    }
    
    .table-row-cell:invalid {
        -fx-background: red;
    }
    
    .table-row-cell:invalid:selected {
        -fx-background: darkred;
    }
    

    【讨论】:

    • 与您最近的答案之一相同的错误:不要在 updateItem 中创建东西 .. 可以共享背景。可以说,通过代码设置可样式化的属性并不是最好的 ide - 虽然 OP 的真正问题(在之前的一个现已删除的问题中看到)是他/她尝试 1:1 迁移将摇摆应用程序转换为 fx - 这是一个非常糟糕的主意。
    • @kleopatra 好的,现在我明白了!我才真正开始使用 javaFX,所以目前创建新实例等性能问题并不是我关注的重点。是的,将 Swing 迁移到 FX 可能是个坏主意,但这在这个问题中并不重要。我只想要我在 Swing 中使用的相同功能 - 根据表格内容为表格视图着色!
    • @anko 你能提供一个 CSS 和 PseudoClasses 的例子吗?或者至少告诉我一个可以阅读更多相关信息的来源。
    • @Toni 做一些研究 - 有很多你想做的例子,只需将它们应用到你的上下文中 :) 目前像创建新实例这样的性能东西不是我的重点可能是:但请注意,不是您是答案的焦点,而是未来的读者。在建立知识体系时,大量不良做法会适得其反。
    • @Toni 我添加了一个带有 CSS 和 PseudoClasses 的示例(顺便说一句,没有看到您删除的问题。)现在您可以选择。 :)
    【解决方案2】:

    我的解决方案

    我像@anko 回答的那样做了,因为我没有数据模型对象。我使用了伪类和合适的 css。

    TableView

    public TableView<List<Object>> getTableView()
    {
       TableView<List<Object>> table = new TableView<List<Object>>();
       table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
       fillTableWithData();
       table.setColumnResizePolicy(STFTableView.CONSTRAINED_RESIZE_POLICY);
    
       // Create pseudo classes to be available in CSS:
       PseudoClass validPseudoClass = PseudoClass.getPseudoClass("valid"),
             invalidPseudoClass = PseudoClass.getPseudoClass("invalid");
    
       // Customized row factory:
       table.setRowFactory(tv ->
          {
             int validIdx = /*calculated*/;
             TableRow<List<Object>> row = new TableRow<>();
             row.itemProperty().addListener((observable, oldValue, newValue) ->
                {
                    if (newValue != null && newValue.get(validIdx) != null)
                    {
                       row.pseudoClassStateChanged(validPseudoClass, newValue.get(validIdx).equals(1));
                       row.pseudoClassStateChanged(invalidPseudoClass, newValue.get(validIdx).equals(0));
                    }
                    else
                    {
                       row.pseudoClassStateChanged(validPseudoClass, false);
                       row.pseudoClassStateChanged(invalidPseudoClass, false);
                    }
                    table.refresh();
                });
             return row;
          });
       return table;
    }
    

    样式.css


    .table-row-cell:valid {
        -fx-background: white
    }
    
    .table-row-cell:valid:selected {
        -fx-background: gray
    }
    
    .table-row-cell:invalid {
        -fx-background: red;
    }
    
    .table-row-cell:invalid:selected {
        -fx-background: darkred;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多