JavaFX-TableView在一行上应用样式(过滤数据后)

JavaFX-TableView在一行上应用样式(过滤数据后),java,css,javafx,javafx-2,tableview,Java,Css,Javafx,Javafx 2,Tableview,注意:这是关于一个非常特定的bug,而不是的副本,但它与该问题非常相关 我有一个带有复选框的表格,当用户选择该行(即单击复选框)时,我会更改该行的样式,以明确是否选中了一行 但是,当用户应用过滤器更改TableView上显示的数据时,我无法根据select属性设置每行的样式。当我调试的时候,我发现它实际上是在设置样式,但是没有任何样式的改变 下面是我可以用来重现此错误的最少代码: DataView.java package table; import javafx.application.Ap

注意:这是关于一个非常特定的bug,而不是的副本,但它与该问题非常相关

我有一个带有复选框的表格,当用户选择该行(即单击复选框)时,我会更改该行的样式,以明确是否选中了一行

但是,当用户应用过滤器更改TableView上显示的数据时,我无法根据select属性设置每行的样式。当我调试的时候,我发现它实际上是在设置样式,但是没有任何样式的改变

下面是我可以用来重现此错误的最少代码:

DataView.java

package table;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
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.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class DataView extends Application{
    TableView<DataRow> table = new TableView<DataRow>();
    ComboBox<Integer> cb = new ComboBox<Integer>();
    ObservableList<DataRow> masterData = FXCollections.observableArrayList();
    ObservableList<DataRow> filteredData = FXCollections.observableArrayList();
    @Override
    public void start(Stage stage) throws Exception {
        VBox root = new VBox();
        initializeGUI();
        addDummyData();
        applyFilters();
        root.getChildren().addAll(cb,table);
        Scene scene = new Scene(root);
       // scene.getStylesheets().add("/res/styleSummary.css"); 
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
        stage.setScene(scene);
        stage.show();
    }
    private void applyFilters() {
        filteredData = FXCollections.observableArrayList(new Callback<DataRow, Observable[]>() {
            @Override
            public Observable[] call(DataRow tr) {
                return new Observable[] { tr.selectedProperty() };
            }
        });
        filteredData.addListener(new ListChangeListener<DataRow>() {
            @Override
            public void onChanged(javafx.collections.ListChangeListener.Change<? extends DataRow> change) {
                try{
                    while (change.next()) {
                        if (change.wasUpdated()) {
                            int i = 0;
                            for (Node n: table.lookupAll("TableRow")){
                                if(i==change.getFrom()){
                                    @SuppressWarnings("unchecked")
                                    TableRow<DataRow> row = (TableRow<DataRow>) n;
                                    if (table.getItems().get(i).getSelected())
                                        row.getStyleClass().add("selected");
                                    else
                                        row.getStyleClass().remove("selected");
                                }
                                i++;
                            }
                            updateMaster(filteredData.get(change.getFrom()));
                        }
                    }
                }catch(Exception e){
                }
            }

            private void updateMaster(table.DataRow changed) {
                for (DataRow tr : masterData) {
                    if (tr.getNumSlices()==changed.getNumSlices()) {
                        tr.selectedProperty().set(changed.getSelected());
                        break;
                    }
                }
            }
        });
        filteredData.addAll(masterData);
        for(DataRow dr: masterData){
            if(dr.getNumSlices()==cb.getValue()){
                filteredData.remove(dr);
            }
        }
        table.setItems(filteredData);
        //This fails:
        int i = 0;
        for (Node n: table.lookupAll("TableRow")){
            TableRow<DataRow> row = (TableRow<DataRow>) n;
            if (table.getItems().get(i).getSelected())
                row.getStyleClass().add("selected");
            else
                row.getStyleClass().remove("selected");
            i++;
            if (i == table.getItems().size())
                break;
        }
    }
    @SuppressWarnings("unchecked")
    public void initializeGUI(){
        //combobox
        cb.getItems().addAll(null,2,4,5);
        cb.valueProperty().addListener(new ChangeListener<Number>(){
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
                applyFilters();
            }
        });
        //table
        TableColumn<DataRow, Integer> numColumn = new TableColumn<DataRow, Integer>();
        numColumn.setCellValueFactory(new PropertyValueFactory<DataRow, Integer>("numSlices"));
        TableColumn<DataRow, Boolean> selectionColumn = new TableColumn<DataRow, Boolean>();
        selectionColumn.setCellValueFactory(new PropertyValueFactory<DataRow, Boolean>("selected"));
        final Callback<TableColumn<DataRow, Boolean>, TableCell<DataRow, Boolean>> cellFactory = CheckBoxTableCell
                .forTableColumn(selectionColumn);
        selectionColumn.setCellFactory(new Callback<TableColumn<DataRow, Boolean>, TableCell<DataRow, Boolean>>() {
            @Override
            public TableCell<DataRow, Boolean> call(TableColumn<DataRow, Boolean> column) {
                TableCell<DataRow, Boolean> cell = cellFactory.call(column);
                cell.setAlignment(Pos.CENTER);
                return cell;
            }
        });
        selectionColumn.setCellFactory(cellFactory);
        selectionColumn.setEditable(true);
        table.getColumns().addAll(numColumn,selectionColumn);
        table.setEditable(true);
    }
    public void addDummyData(){
        for(int i=0;i<13;i++)
            masterData.add(new DataRow(i,false));
    }
    public static void main(String[] args) throws Exception { launch(args); }
}
package table;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;

public class DataRow {
    private Integer numSlices;
    private BooleanProperty selected;
    public DataRow(int numSlices, boolean selected) {
        this.selected = new SimpleBooleanProperty(selected);
        this.numSlices =  numSlices;
    }
    public Integer getNumSlices() {return numSlices;}
    public void setNumSlices(int num){this.numSlices = num;}
    public void setSelected(boolean value) {selected.set(value);}
    public boolean getSelected() {return selected.get();}
    public BooleanProperty selectedProperty(){return selected;}
}
style.css

更具体地说,错误可能在这里:

    //(DataView.java) -- line 89
    //This fails:
    int i = 0;
    for (Node n: table.lookupAll("TableRow")){
        TableRow<DataRow> row = (TableRow<DataRow>) n;
        if (table.getItems().get(i).getSelected())
            row.getStyleClass().add("selected");
        else
            row.getStyleClass().clear();
        i++;
        if (i == table.getItems().size())
            break;
    }
/(DataView.java)——第89行
//这失败了:
int i=0;
对于(节点n:table.lookupAll(“TableRow”)){
TableRow row=(TableRow)n;
if(table.getItems().get(i).getSelected())
row.getStyleClass().add(“选定”);
其他的
row.getStyleClass().clear();
i++;
if(i==table.getItems().size())
打破
}

为什么不在链接答案中使用该方法呢。您永远不知道哪个单元格是哪个,因此在创建单元格(或行)时,必须将所需的所有内容添加到该单元格中

我刚刚在您的
初始化gui()
中添加了这个,并删除了复杂的侦听器。看起来很好用。如果你真的想要一个style类,那么就使用一个类似james_D的链接答案中的侦听器。或者更好的是,创建一个psuedo类

    table.setRowFactory(new Callback<TableView<DataRow>, TableRow<DataRow>>() {
        @Override
        public TableRow<DataRow> call(TableView<DataRow> tableView) {
            final TableRow<DataRow> row = new TableRow<DataRow>() {
                @Override
                protected void updateItem(DataRow row, boolean empty) {
                    super.updateItem(row, empty);
                    if (!empty)
                        styleProperty().bind(Bindings.when(row.selectedProperty())
                            .then("-fx-font-weight: bold; -fx-font-size: 16;")
                            .otherwise(""));
                }
            };
            return row;
        }
    });
table.setRowFactory(新回调(){
@凌驾
公共TableRow调用(TableView TableView){
最终TableRow行=新TableRow(){
@凌驾
受保护的void updateItem(数据行,布尔空){
super.updateItem(行,空);
如果(!空)
styleProperty().bind(Bindings.when(row.selectedProperty())
。然后(“-fx字体大小:粗体;-fx字体大小:16;”)
。否则以““””号填列;
}
};
返回行;
}
});
    table.setRowFactory(new Callback<TableView<DataRow>, TableRow<DataRow>>() {
        @Override
        public TableRow<DataRow> call(TableView<DataRow> tableView) {
            final TableRow<DataRow> row = new TableRow<DataRow>() {
                @Override
                protected void updateItem(DataRow row, boolean empty) {
                    super.updateItem(row, empty);
                    if (!empty)
                        styleProperty().bind(Bindings.when(row.selectedProperty())
                            .then("-fx-font-weight: bold; -fx-font-size: 16;")
                            .otherwise(""));
                }
            };
            return row;
        }
    });