在javaFX上的特定行上应用css
我在项目中使用了TreeTableView,当用户选择一行时,我想做一些特定的事情: 我希望这一行有一个不同的背景颜色,但我也希望它的孩子和家长也有这种颜色 我找到了访问每一行和子行的方法,但我不知道如何指定这个背景色。我尝试使用我的customs TreeTableCells并在updateItem方法中添加样式来完成此操作,但每次选择一个项目时都不会调用此方法在javaFX上的特定行上应用css,javafx,Javafx,我在项目中使用了TreeTableView,当用户选择一行时,我想做一些特定的事情: 我希望这一行有一个不同的背景颜色,但我也希望它的孩子和家长也有这种颜色 我找到了访问每一行和子行的方法,但我不知道如何指定这个背景色。我尝试使用我的customs TreeTableCells并在updateItem方法中添加样式来完成此操作,但每次选择一个项目时都不会调用此方法 因此,我想尝试在我的treetableview中添加listener,这似乎是一个更好的主意,但事实上,我无法访问行以提供任何样式。
因此,我想尝试在我的treetableview中添加listener,这似乎是一个更好的主意,但事实上,我无法访问行以提供任何样式。这里的基本策略是:
updateItem
方法中更新其伪类状态,并且如果所选项目发生更改,也应该更新其pseudoclass
状态。您可以在表的选定项上放置一个侦听器来执行第二个操作import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener.Change;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;
public class TreeTableViewHighlightSelectedPath extends Application {
private PseudoClass childOfSelected = PseudoClass.getPseudoClass("child-of-selected");
private PseudoClass parentOfSelected = PseudoClass.getPseudoClass("parent-of-selected");
@Override
public void start(Stage primaryStage) {
TreeTableView<Item> table = new TreeTableView<>(createRandomTree(50));
table.setRowFactory(ttv -> {
TreeTableRow<Item> row = new TreeTableRow<Item>() {
@Override
protected void updateItem(Item item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
pseudoClassStateChanged(parentOfSelected, false);
pseudoClassStateChanged(childOfSelected, false);
} else {
updateState(this);
}
}
};
table.getSelectionModel().getSelectedItems().addListener(
(Change<? extends TreeItem<Item>> c) -> updateState(row));
return row ;
});
table.getColumns().add(column("Item", Item::nameProperty));
table.getColumns().add(column("Value", Item::valueProperty));
Scene scene = new Scene(table, 800, 800);
scene.getStylesheets().add("table-row-highlight.css");
primaryStage.setScene(scene);
primaryStage.show();
}
private <T> void updateState(TreeTableRow<T> row) {
TreeTableView<T> table = row.getTreeTableView() ;
TreeItem<T> item = row.getTreeItem();
// if item is selected, just use default "selected" highlight,
// and set "child-of-selected" and "parent-of-selected" to false:
if (item == null || table.getSelectionModel().getSelectedItems().contains(item)) {
row.pseudoClassStateChanged(childOfSelected, false);
row.pseudoClassStateChanged(parentOfSelected, false);
return ;
}
// check to see if item is parent of any selected item:
for (TreeItem<T> selectedItem : table.getSelectionModel().getSelectedItems()) {
for (TreeItem<T> parent = selectedItem.getParent(); parent != null ; parent = parent.getParent()) {
if (parent == item) {
row.pseudoClassStateChanged(parentOfSelected, true);
row.pseudoClassStateChanged(childOfSelected, false);
return ;
}
}
}
// check to see if item is child of any selected item:
for (TreeItem<T> ancestor = item.getParent() ; ancestor != null ; ancestor = ancestor.getParent()) {
if (table.getSelectionModel().getSelectedItems().contains(ancestor)) {
row.pseudoClassStateChanged(childOfSelected, true);
row.pseudoClassStateChanged(parentOfSelected, false);
return ;
}
}
// if we got this far, clear both pseudoclasses:
row.pseudoClassStateChanged(childOfSelected, false);
row.pseudoClassStateChanged(parentOfSelected, false);
}
private <S,T> TreeTableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
TreeTableColumn<S,T> column = new TreeTableColumn<>(title);
column.setCellValueFactory(cellData -> property.apply(cellData.getValue().getValue()));
return column ;
}
private TreeItem<Item> createRandomTree(int numNodes) {
Random rng = new Random();
TreeItem<Item> root = new TreeItem<>(new Item("Item 1", rng.nextInt(1000)));
root.setExpanded(true);
List<TreeItem<Item>> items = new ArrayList<>();
items.add(root);
for (int i = 2 ; i <= numNodes; i++) {
Item item = new Item("Item "+i, rng.nextInt(1000));
TreeItem<Item> treeItem = new TreeItem<>(item);
treeItem.setExpanded(true);
items.get(rng.nextInt(items.size())).getChildren().add(treeItem);
items.add(treeItem);
}
return root ;
}
public static class Item {
private StringProperty name = new SimpleStringProperty();
private IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value) {
setName(name);
setValue(value);
}
public final StringProperty nameProperty() {
return this.name;
}
public final java.lang.String getName() {
return this.nameProperty().get();
}
public final void setName(final java.lang.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);
}
@Override
public String toString() {
return String.format("%s (%d)", getName(), getValue());
}
}
public static void main(String[] args) {
launch(args);
}
}
这将提供以下信息:
此版本将高亮显示树中选定项的所有子节点和所有祖先节点。如果只想突出显示直接的子行和父行,可以简化
updateState()
方法。这基本上与以下内容相同:您只需要调整树表视图的解决方案。非常感谢,我将为我的代码调整它!这正是我想做的事@不客气。如果回答了您的问题,请将答案标记为正确;如果其他人有类似的问题,这将使他们更容易找到它。我试过了,但我只是不知道如何标记它。。。“我只是将它重命名为已解决吗?”WilliamEstupina单击答案旁边的复选标记。多亏了你,我才能够使它工作。但只剩下一个问题:它在选择更改时与侦听器配合得很好,但当我展开表然后取消展开时遇到了问题。一些空行被涂上了颜色。但是,当我再次选择另一项时,这会停止错误。因此,我想在进行或取消ax扩展时触发updateState函数。他们有没有简单的方法让一个侦听器加入到TreeTableView的扩展中?