【问题标题】:Paint the rows inside the tableview [duplicate]绘制表格视图内的行[重复]
【发布时间】:2019-01-28 08:35:01
【问题描述】:

我有一个 TableView 和两个文本字段。当用户将数字写入文本字段并按下按钮时。所有的 tablerows 都应该按百分比绘制。例如,30% 应该是黄色,70% 应该是绿色。

我尝试使用查找方法来查找 TableView 对象。添加新的 css 类改变了 tablerows 的颜色。但是这个解决方案并不好。 Lookup 只能找到可见元素。

@FXML
void confirmPercentage(ActionEvent event) {
    clearSelectionsOfTestingTbaleView();
    TableRow[] tableRows = selectTrainingDataTableView.lookupAll(".table-row-cell").toArray(new TableRow[0]);

    double percent = Double.parseDouble(this.trainingSetPercentageTextField.getText());
    percent = percent > 1 ? percent / 100 : percent;
    int trainIndexes = (int) (Math.round(tableRows.length * percent));

    for (int i = 0 ; i < trainIndexes; i++){
        tableRows[i].getStyleClass().add("selected-as-train");
    }
}

我有 15 个音符,但只有 13 个...

那么绘制所有表格行的方法是什么?

解决方案

我终于看到了!

所以我创建了两组来保留选定的索引。而且,我只是根据这个索引设置 PseudoClass...

void init()
    Set<Integer> testSetIndexes = new HashSet<>();
    Set<Integer> trainSetIndexes = new HashSet<>();
    tableView.setRowFactory( tableView2 -> {

        PseudoClass train = PseudoClass.getPseudoClass("train");
        PseudoClass test = PseudoClass.getPseudoClass("test");
        PseudoClass trainAndTest = PseudoClass.getPseudoClass("train-and-test");
        /*Percentage selection with button*/
        final TableRow<List<Double>> row = new TableRow<List<Double>>(){

            @Override
            public void updateItem(List<Double> item, boolean empty){

                if (item != null) {
                    int index = dataInsideTableView.indexOf(item);
                    this.pseudoClassStateChanged(train, trainSetIndexes.contains(index));
                    this.pseudoClassStateChanged(test, testSetIndexes.contains(index));
                    this.pseudoClassStateChanged(trainAndTest, trainSetIndexes.contains(index) && testSetIndexes.contains(index));
                } else {
                    this.pseudoClassStateChanged(train, false);
                    this.pseudoClassStateChanged(test, false);
                    this.pseudoClassStateChanged(trainAndTest, false);
                }
            }
        };

        /*Mouse selection*/
        row.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (manualSelectionCheckBox.isSelected()) {
                    if (event.isPrimaryButtonDown()) {
                        int index = dataInsideTableView.indexOf(row.getTableView().getItems().get(row.getIndex()));
                        if(trainSetIndexes.contains(index)){
                            trainSetIndexes.remove(index);
                        } else {
                            trainSetIndexes.add(index);
                        }
                        selectTrainingDataTableView.refresh(); //call update
                    } else if (event.isSecondaryButtonDown()) {
                        int index = dataInsideTableView.indexOf(row.getTableView().getItems().get(row.getIndex()));
                        if(testSetIndexes.contains(index)){
                            testSetIndexes.remove(index);
                        } else {
                            testSetIndexes.add(index);
                        }
                        tableView.refresh();
                    }
                }
            }
        });

        return row;
    });

我点击“刷新”按钮,confirmPercentage 方法只是重新计算索引并刷新表格。

@FXML
void confirmPercentage(ActionEvent event) {
    trainSetIndexes.clean();
    testSetIndexes.clean();

    double percent = Double.parseDouble(this.trainingSetPercentageTextField.getText());
    percent = percent > 1 ? percent / 100 : percent;
    trainSize = (int) (Math.floor(usedData.size() * percent));
    percent = Double.parseDouble(this.testingSetPercentageTextField .getText());
    percent = percent > 1 ? percent / 100 : percent;
    testSize = (int) (Math.floor(usedData.size() * percent));

    //put indexes
    for (int i = 0 ; i < trainSize; i++){
        trainSetIndexes.add(i);
    }

    for (int i = usedData.size()-1 ; i >= usedData.size()-1-testSize; i--){
        testSetIndexes.add(i);
    }
    this.tableView.refresh();
}

【问题讨论】:

  • 完全错误的方法:永远不要考虑场景图中的 tableRow,而是使用自定义 cellFactory 来根据模型中的状态配置自身的行(并且不要忘记 模型那个状态)
  • @JanS。它不是重复的,因为 UpdateItem 适用于可见行。我尝试了 RowFactory - 它也适用于可见行。当他们因为滚动 RowFactory 不与他们一起工作而隐藏时
  • 没有不可见的行,它们不存在 ;) 请阅读单元格的重用机制
  • 请不要删除您的问题只是为了再次提出相同的问题 - 所有输入都将丢失,这对所有相关人员来说都是浪费时间
  • @kleopatra 但我不认为这个问题是重复的。另一个主题中提出的解决方案让我添加了一个新列以某种方式解决问题。我认为这是我的任务的拐杖,它在某种程度上破坏了数据。

标签: java javafx javafx-8


【解决方案1】:

您可以将 TableRow StyleClass 作为 TableView 数据模型中的字段

fxml 视图

<VBox fx:id="root" prefHeight="300.0" prefWidth="600.0" fx:controller="sample.View"
      xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" >
    <stylesheets>
        <URL value="@app.css" />
    </stylesheets>

    <ToolBar>
        <Button fx:id="set" mnemonicParsing="false" onAction="#set" text="Set" />
        <Button fx:id="reset" mnemonicParsing="false" onAction="#reset" text="Reset" />
    </ToolBar>


    <TableView fx:id="tvDevices" VBox.vgrow="ALWAYS">
        <columns>
            <TableColumn fx:id="colNum1" text="Num1">
                <cellValueFactory>
                    <PropertyValueFactory property="num1" />
                </cellValueFactory>
            </TableColumn>
            <TableColumn fx:id="colNum2" text="Num2">
                <cellValueFactory>
                    <PropertyValueFactory property="num2" />
                </cellValueFactory>
            </TableColumn><TableColumn fx:id="colNum3" text="Num3">
                <cellValueFactory>
                    <PropertyValueFactory property="num3" />
                </cellValueFactory>
            </TableColumn>
        </columns>
    </TableView>
</VBox>

数据视图模型类

public class Foo {
    private DoubleProperty num1;
    private DoubleProperty num2;
    private DoubleProperty num3;
    private StringProperty styleClass;

    public Foo(int num1, int num2, int num3) {
        this.num1 = new SimpleDoubleProperty(num1);
        this.num2 = new SimpleDoubleProperty(num2);
        this.num3 = new SimpleDoubleProperty(num3);
        this.styleClass = new SimpleStringProperty();
    }

    public double getNum1() {
        return num1.get();
    }

    public DoubleProperty num1Property() {
        return num1;
    }

    public void setNum1(double num1) {
        this.num1.set(num1);
    }

    public double getNum2() {
        return num2.get();
    }

    public DoubleProperty num2Property() {
        return num2;
    }

    public void setNum2(double num2) {
        this.num2.set(num2);
    }

    public double getNum3() {
        return num3.get();
    }

    public DoubleProperty num3Property() {
        return num3;
    }

    public void setNum3(double num3) {
        this.num3.set(num3);
    }

    public String getStyleClass() {
        return styleClass.get();
    }

    public StringProperty styleClassProperty() {
        return styleClass;
    }

    public void setStyleClass(String styleClass) {
        this.styleClass.set(styleClass);
    }
}

视图控制器

public class View implements Initializable {

    @FXML
    private TableView<Foo> tvDevices;

    @Override
    public void initialize(URL location, ResourceBundle resources) {    
            tvDevices.setRowFactory(param -> {
            TableRow<Foo> row = new TableRow<>();
            //This listener will monitor the Change in the Modal StyleClass to keep row updated when StyleClass value chenge.
            ChangeListener<String> listener = (observable, oldValue, newValue) -> {
                if (newValue == null) {
                    //reset StyleClass to default by removing any additional class's
                    row.getStyleClass().remove(3,row.getStyleClass().size());
                } else {
                    //removing any additional class's and add the new one
                    row.getStyleClass().remove(3,row.getStyleClass().size());
                    row.getStyleClass().add(newValue);
                }
            };
            //This listener will monitor the particular Modal attached to this row.
            row.itemProperty().addListener((observable, oldValue, newValue) -> {
                if (oldValue != null) {
                    //remover the listener from the old item
                    oldValue.styleClassProperty().removeListener(listener);
                }
                if (newValue != null) {
                    // attach the listener to the new item
                    newValue.styleClassProperty().addListener(listener);
                    // update row StyleClass to new item StyleClass
                    if (newValue.styleClassProperty() == null) {
                        row.getStyleClass().remove(3,row.getStyleClass().size());
                    } else {
                        row.getStyleClass().remove(3,row.getStyleClass().size());
                        row.getStyleClass().add(newValue.getStyleClass());
                    }
                } else {
                    //reset StyleClass to default because new item is null
                    row.getStyleClass().remove(3,row.getStyleClass().size());
                }
            });
            return row;
        });

        for (int i = 0; i < 50; i++) {
            tvDevices.getItems().add(new Foo(1, 2, 3));
        }
    }

    @FXML
    private void reset(ActionEvent actionEvent) {
        tvDevices.getItems().forEach(foo -> foo.setStyleClass(null));
        actionEvent.consume();
    }

    @FXML
    private void set(ActionEvent actionEvent) {
        tvDevices.getItems().get(10).setStyleClass("class1");
        tvDevices.getItems().get(20).setStyleClass("class2");
        tvDevices.getItems().get(40).setStyleClass("class3");
        actionEvent.consume();
    }
}

【讨论】:

  • 不要混合视图和数据方面 - 样式不属于您的数据!
  • 无论如何,我怀疑这根本不起作用:没有人在听该属性,并且这些项目没有连接到触发任何通知,以便 tableView 可以自行更新。好像你没有尝试过,是吗;)
  • tvDevices.getItems().forEach(foo -> foo.resetStyleClass()); foo - 是数据,它不包含样式
  • 对不起我的旧代码,更新了代码并添加了一些现在应该可以工作的 cmets
  • sry,但这完全是错误的(除了将样式作为数据属性之外) - 如果数据设置正确,则不需要 tableRow 中的侦听器...
猜你喜欢
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 2021-12-20
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 2012-06-22
相关资源
最近更新 更多