Javafx: how do I reference a particular cell within a row in setRowFactory?

≯℡__Kan透↙ 提交于 2020-01-13 19:21:08

问题


I have a tableView, where each table row represents an object and each column represents the attributes of the object. Within the tableView, I am defining a setRowFactory.

Within the setRowFactory, I want to be able to have access to a particular cell within the row and highlight it by doing this: ThisCellofThisRow.pseudoClassStateChanged(...)

Problem is: I have no idea how to reference this ThisCellofThisRow.


回答1:


Not sure exactly what you want to do, but you could change the pseudoclass state of the row, and then use CSS to select the particular column. That way the row factory doesn't have to access the cell at all.

Example:

highlight-cell-in-row.css:

/*
** Gives a yellow background to a table cell with style class "value-cell"
** that is inside a row with the "high" psuedoclass set 
*/

.table-row-cell:high .value-cell {
    -fx-background-color: transparent, yellow ;
}

TableViewHighlightItem.java:

import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;


public class TableViewHighlightItem extends Application {

    @Override
    public void start(Stage primaryStage) {

        // create table and columns:
        TableView<Item> table = new TableView<>();
        TableColumn<Item, String> nameCol = column("Name", Item::nameProperty);
        TableColumn<Item, Number> valueCol = column("Value", Item::valueProperty);
        table.getColumns().add(nameCol);
        table.getColumns().add(valueCol);

        // basic default cell, but with "value-cell" always added as a CSS class:
        valueCol.setCellFactory(col -> {
            TableCell<Item, Number> cell = new TableCell<Item, Number>(){
                @Override
                public void updateItem(Number value, boolean empty) {
                    super.updateItem(value, empty);
                    if (empty) {
                        setText(null);
                    } else {
                        setText(value.toString());
                    }
                }
            };
            cell.getStyleClass().add("value-cell");
            return cell ;
        });

        PseudoClass high = PseudoClass.getPseudoClass("high");

        // Table row toggles "high" pseudoclass according to state of current item in row:
        table.setRowFactory(tv -> {
            TableRow<Item> row = new TableRow<>();

            ChangeListener<Boolean> highListener = (obs, wasHigh, isNowHigh) -> 
                row.pseudoClassStateChanged(high, isNowHigh);

            row.itemProperty().addListener((obs, oldItem, newItem) -> {
                if (oldItem != null) {
                    oldItem.highProperty().removeListener(highListener);
                }
                if (newItem == null) {
                    row.pseudoClassStateChanged(high, false);
                } else {
                    row.pseudoClassStateChanged(high, newItem.isHigh());
                    newItem.highProperty().addListener(highListener);
                }
            });

            return row ;
        });

        Random rng = new Random();

        // Button to test changing data to random values:
        Button changeButton = new Button("Change Data");
        changeButton.setOnAction(e -> 
                table.getItems().forEach(item -> item.setValue(rng.nextInt(20))));

        // add data to table:
        for (int i = 1 ; i <= 40 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(20)));
        }

        // layout:
        BorderPane root = new BorderPane(table, null, null, changeButton, null);
        BorderPane.setAlignment(changeButton, Pos.CENTER);
        BorderPane.setMargin(changeButton, new Insets(10));
        Scene scene = new Scene(root, 600, 600);
        scene.getStylesheets().add("highlight-cell-in-row.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // utility method for creating columns:
    private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
        TableColumn<S,T> column = new TableColumn<>(title);
        column.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return column ;
    }

    // model class:
    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();
        private final ReadOnlyBooleanWrapper high = new ReadOnlyBooleanWrapper();

        public Item(String name, int value) {
            setName(name);
            setValue(value);
            high.bind(this.value.greaterThanOrEqualTo(10));
        }

        public final StringProperty nameProperty() {
            return this.name;
        }

        public final String getName() {
            return this.nameProperty().get();
        }

        public final void setName(final String name) {
            this.nameProperty().set(name);
        }

        public final IntegerProperty valueProperty() {
            return this.value;
        }

        public final int getValue() {
            return this.valueProperty().get();
        }

        public final void setValue(final int value) {
            this.valueProperty().set(value);
        }

        public final ReadOnlyBooleanProperty highProperty() {
            return this.high.getReadOnlyProperty();
        }

        public final boolean isHigh() {
            return this.highProperty().get();
        }


    }

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


来源:https://stackoverflow.com/questions/32310912/javafx-how-do-i-reference-a-particular-cell-within-a-row-in-setrowfactory

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!