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

时间:2014-07-02 19:56:51

标签: java css javafx javafx-2 tableview

注意:这是一个非常具体的错误,而不是Programmatically change the TableView row appearance的重复,但它与该问题非常相关。

我有一个带有CheckBox的表,当用户选择该行时(即点击CheckBox),我改变了该行的样式,以明确选择了一行。

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

Illustration of the current behavior

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

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); }
}

DataRow本质上是一个整数和布尔类型:

DataRow.java

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

.selected { 
    -fx-font-weight: bold;
    -fx-font-size: 13;  
}

只是为了使其更具体,错误可能在这里:

    //(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;
    }

1 个答案:

答案 0 :(得分:2)

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

我刚刚在您的initializeGUI()中添加了此内容,并删除了复杂的侦听器。似乎工作正常。如果你真的想要一个样式类,那么使用像james_D链接的答案中的监听器。或者甚至更好,制作一个psuedoClass。

    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;
        }
    });