#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
System.out.println("confirmed");
this.refreshData( e -> true);
this.pieTriState.getData().forEach(this::clickOnPie);
Arrays.stream(gList).forEach(e -> {
var checkBox = new CheckBox(e.getState());
checkBox.setPrefSize(60,15);
this.fpStates.getChildren().add(checkBox);
System.out.println(checkBox);
checkBox.setOnAction((ActionEvent event) -> {
if(checkBox.isSelected()){
//I tried to count the checkbox by using this. but its not work for me
for(int i =0; i <1; i++){
System.out.println(i);
}
System.out.println(checkBox.getText());
//btnRefresh.setVisible(false);
//lblStatus.setText("more than 4 states selected is invalid.");
}
});
});
I am trying to count the checkbox. if 4 checkboxes are selected, so I can hide a button. But the problem is the checkbox is in the flow pane. So I don't know how to count it.
This answer uses the same concept (a filtered list) as this solution to:
Use a listener to get selected rows (mails) in tableView and add mails to my list of mails
but without a backing model or table.
The solution:
creates a list of checkboxes.
defines an extractor on the checkbox list so that a list change event occurs when the selection property of any checkbox in the list changes.
creates a filtered list of selected checkboxes based on the list of all checkboxes.
binds integer properties to the size of the two lists.
displays labels that represent the size properties as text counts of the number of elements in each list.
places the checkboxes in a FlowPane.
To understand the approach in more detail, read the text accompanying the linked solution.
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class CheckApp extends Application {
private static final int NUM_CHECKBOXES = 5;
#Override
public void start(Stage stage) {
// lists to track checkboxes and selected checkboxes.
ObservableList<CheckBox> checkBoxes = FXCollections.observableArrayList(
c -> new Observable[] { c.selectedProperty() }
);
FilteredList<CheckBox> selectedCheckBoxes = checkBoxes.filtered(
CheckBox::isSelected
);
// properties to track the size of the checkbox and selected checkbox lists.
IntegerProperty numCheckboxes = new SimpleIntegerProperty();
numCheckboxes.bind(Bindings.size(checkBoxes));
IntegerProperty numSelectedCheckboxes = new SimpleIntegerProperty();
numSelectedCheckboxes.bind(Bindings.size(selectedCheckBoxes));
// create the checkboxes.
for (int i = 0; i < NUM_CHECKBOXES; i++) {
checkBoxes.add(new CheckBox("" + (i+1)));
}
// create a flow pane to hold the checkboxes and put them inside.
FlowPane flowPane = new FlowPane(Orientation.VERTICAL, 10, 10);
flowPane.setPadding(new Insets(10));
flowPane.getChildren().addAll(checkBoxes);
// create text labels for the checkbox and selected checkbox counts.
Label numCheckboxesLabel = new Label();
numCheckboxesLabel.textProperty().bind(
numCheckboxes.asObject().asString()
);
Label numSelectedCheckboxesLabel = new Label();
numSelectedCheckboxesLabel.textProperty().bind(
numSelectedCheckboxes.asObject().asString()
);
// create some summary info
GridPane summaryInfo = new GridPane();
summaryInfo.setHgap(10);
summaryInfo.setVgap(5);
summaryInfo.addRow(0, new Label("# checkboxes:" ), numCheckboxesLabel);
summaryInfo.addRow(1, new Label("# selected checkboxes:" ), numSelectedCheckboxesLabel);
// layout the scene.
final VBox layout = new VBox(
10,
summaryInfo,
flowPane
);
layout.setPadding(new Insets(10));
layout.setPrefHeight(200);
stage.setScene(new Scene(layout));
stage.show();
}
}
Of the many ways, below is one of the approach you may give a try.
The idea is:
create a counter and create a boolean listener to increment the counter and check if it satisfies the condition
add this listener all the checkboxes selected property.
Outside the loop you need to include the below code:
IntegerProperty count = new SimpleIntegerProperty();
ChangeListener<Boolean> selectedListener = (obs,old,selected)->{
count.setValue(selected?count.get()+1:count.get()-1);
if(count.get()>=4){
// hide the button, set the error text
}else{
// unhide the button, clear the error text
}
};
And in the loop, after the checkbox is created , add the listener to checkbox:
checkBox.selectedProperty().addListener(selectedListener);
Related
I have been trying to create a javafx.scene.control.TableView such that all the selection events are blocked when their origin is user interaction. In other words, it must be possible for me to programmatically alter the selection in a given table view.
I tried solutions from the following questions:
Setting the whole table view as mouse transparent (see article). This approach is unacceptable, because, for instance, user cannot change the width of the columns
Setting the selection model to null (see article). This one is unacceptable, because the currently selected row is not highlighted properly- see image below:
Originally, I wanted to decorate the default existing table view selection model with my own. Something like this was created:
private final class TableViewSelectionModelDecorator< S >extends TableViewSelectionModel< S >
{
private final TableViewSelectionModel< S > delegate;
private TableViewSelectionModelDecorator( TableViewSelectionModel< S > aDelegate )
{
super( aDelegate.getTableView() );
delegate = Objects.requireNonNull( aDelegate );
}
// Overriding the methods and delegating the calls to the delegate
}
The problem with my decorator is that the function getSelectedIndex() from the selection model is marked as final, which means I cannot override it and delegate the call to my decorated selection model. As a result, whenever a client asks for currently selected index the result is -1.
Requirements that I must meet:
Selection change events coming from either the mouse click or the keyboard (or any other input source) is blocked.
User must be able to interact with the table as long as the selection is not modified (e.g. changing the width of the columns)
Selected entry is properly highlighted (instead of just some frame around the selected index)
For now there is no multiselection support involved, but preferably I'd appreciate a solution that does support it.
Last note is I use Java 11.
Thanks for any pointers.
Please do consider the comments mentioned about the xy problem and other alternatives mentioned.
If you still want to solve this as the way you mentioned, you can give a try as below.
The idea is to
block all KEY_PRESSED events on tableView level and
set mouse transparent on tableRow level
so that we are not tweaking with any default selection logic. This way you can still interact with columns and scrollbar using mouse.
Below is the quick demo of the implementation:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TableViewSelectionBlockingDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
for (int i = 1; i < 11; i++) {
persons.add(new Person(i + "", "A" + i));
}
TableView<Person> tableView = new TableView<>();
TableColumn<Person, String> idCol = new TableColumn<>("Id");
idCol.setCellValueFactory(param -> param.getValue().idProperty());
idCol.setPrefWidth(100);
TableColumn<Person, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(param -> param.getValue().nameProperty());
nameCol.setPrefWidth(150);
tableView.getColumns().addAll(idCol,nameCol);
tableView.setItems(persons);
// Selection Blocking logic
tableView.addEventFilter(KeyEvent.KEY_PRESSED, e->e.consume());
tableView.setRowFactory(personTableView -> new TableRow<Person>(){
{
setMouseTransparent(true);
}
});
ComboBox<Integer> comboBox = new ComboBox<>();
for (int i = 1; i < 11; i++) {
comboBox.getItems().add(i);
}
comboBox.valueProperty().addListener((obs, old, val) -> {
if (val != null) {
tableView.getSelectionModel().select(val.intValue()-1);
} else {
tableView.getSelectionModel().clearSelection();
}
});
HBox row = new HBox(new Label("Select Row : "), comboBox);
row.setSpacing(10);
VBox vb = new VBox(row, tableView);
vb.setSpacing(10);
vb.setPadding(new Insets(10));
VBox.setVgrow(tableView, Priority.ALWAYS);
Scene scene = new Scene(vb, 500, 300);
primaryStage.setScene(scene);
primaryStage.setTitle("TableView Selection Blocking Demo");
primaryStage.show();
}
class Person {
private StringProperty name = new SimpleStringProperty();
private StringProperty id = new SimpleStringProperty();
public Person(String id1, String name1) {
name.set(name1);
id.set(id1);
}
public StringProperty nameProperty() {
return name;
}
public StringProperty idProperty() {
return id;
}
}
}
Note: This may not be the approach for editable table.
Suppose I have an ObservableList and a Button in the same controller class:
private ObservableList<NameItem> _selectedList = _database.getONameList();
#FXML
private Button nextButton;
How do I make it so that the Button is only enabled while the ObservableList is not empty? Is there a binding property I can use to set this?
This can be done fairly easily with just a couple of simple Bindings, actually.
First, you want to create an IntegerBinding that is bound to the size of your ObservableList:
IntegerBinding listSize = Bindings.size(_selectedList);
Then create a new BooleanBinding that is bound to whether or not the listSize binding is greater than 0:
BooleanBinding listPopulated = listSize.greaterThan(0);
Now, all you need to do is bind the button's disableProperty to the opposite of the listPopulated property using the not() method (since listPopulated will be true if items are in the list, you want to actually pass false to the button's disableProperty):
button.disableProperty().bind(listPopulated.not());
Here is a quick MCVE to demonstrate:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple interface
VBox root = new VBox(5);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// Create an empty ObservableList
ObservableList<String> list = FXCollections.observableArrayList();
// Create a binding to extract the list's size to a property
IntegerBinding listSizeProperty = Bindings.size(list);
// Create a boolean binding that will return true only if the list has 1 or more elements
BooleanBinding listPopulatedProperty = listSizeProperty.greaterThan(0);
// Create the button we want to enable/disable
Button button = new Button("Submit");
// Bind the button's disableProperty to the opposite of the listPopulateProperty
// If listPopulateProperty is false, the button will be disabled, and vice versa
button.disableProperty().bind(listPopulatedProperty.not());
// Create another button to add an item to the list, just to demonstrate the concept
Button btnAddItem = new Button("Add Item");
btnAddItem.setOnAction(event -> {
list.add("New Item");
System.out.println(list.size());
});
// Add the buttons to the layout
root.getChildren().addAll(btnAddItem, button);
// Show the Stage
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
In the above example, the "Submit" button is disabled until you add an item to the ObservableList using the "Add Item" button.
EDIT: As Lukas excellently points out in the comments below, these Bindings can also all be chained together to simplify things (either method is equally valid; it just depends on which you find more readable, really):
button.disableProperty().bind(Bindings.size(list).greaterThan(0).not())
Another Method
Another way to do this is with a ListChangeListener that enables or disables the button any time the list changes:
list.addListener((ListChangeListener<String>) c -> {
// If the size of the list is less than 1, disable the button; otherwise enable it
button.setDisable(c.getList().size() < 1);
});
This will essentially do exactly the same thing as the first method, but you'll need to set the initial state of the button yourself before the listener can keep it updated for you.
I have a javafx application with multiple textboxes that the user can enter information in. I also have a keyboard built into the application that when pressed adds that text to the textbox.
My issue is that since I have multiple textboxes, I don't know which one to add the buttons text to. Is there a way in javafx to check if a user has clicked on a certain textbox so I can check which one has been selected and add the text there?
You can use the Scene.focusOwner property of the active scene to get the focused node. Check, if it's a TextInputControl and call the appropriate method for the button clicked. Note that clicking a button may move the focus, if focusTraversable is true for that button. (By default this is the case.)
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
final Scene scene = new Scene(grid);
for (int i = 0; i < 4; i++) {
grid.add(new TextField(), 0, i);
final String buttonValue = Character.toString((char) ('a'+i));
Button button = new Button(buttonValue);
button.setFocusTraversable(false); // prevent buttons from stealing focus
button.setOnAction(evt -> {
Node fo = scene.getFocusOwner();
if (fo instanceof TextInputControl) {
((TextInputControl) fo).replaceSelection(buttonValue);
}
});
grid.add(button, 1, i);
}
primaryStage.setScene(scene);
primaryStage.show();
}
You should create a listener for each TextField's focusProperty and set an instance variable.
Once you have a global reference to the currently focused TextField, you can do any processing on it that you choose.
Here is a quick application to demonstrate. I've included a couple extra details in the code itself:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
// Instance variable to hold the currently-selected TextField
private TextField selectedTextField;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Create TextFields
TextField txt1 = new TextField();
TextField txt2 = new TextField();
TextField txt3 = new TextField();
TextField txt4 = new TextField();
// This method sets the same change listener on each textfield
installListener(txt1, txt2, txt3, txt4);
VBox pane = new VBox(5);
pane.setPadding(new Insets(5));
// Add the TextFields to the layout
pane.getChildren().addAll(
new HBox(5, new Label("Txt1: "), txt1),
new HBox(5, new Label("Txt2: "), txt2),
new HBox(5, new Label("Txt3: "), txt3),
new HBox(5, new Label("Txt4: "), txt4)
);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
// Accepts multiple TextFields
private void installListener(TextField... textFields) {
// Install the same listener on all of them
for (TextField textField : textFields) {
textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {
// Set the selectedTextField to null whenever focus is lost. This accounts for the
// TextField losing focus to another control that is NOT a TextField
selectedTextField = null;
if (newValue) {
// The new textfield is focused, so set the global reference
selectedTextField = textField;
System.out.println("Selected Text: " + selectedTextField.getText());
}
});
}
}
}
I am trying to implement a search function for a TreeView in JavaFX. I want to highlight all the matches when the user hits the enter key. So I added a boolean isHighlighted to my TreeItem and in my TreeCells updateItem, I check whether the item isHighlighted and if so I apply a certain CSS. Everything works fine with the items/cells not visible at the moment of the search -- when I scroll to them, they are properly highlighted. The problem is: How can I "repaint" the TreeCells visible at search so that they reflect whether their item isHighlighted? My Controller does currently not have any reference to the TreeCells the TreeView creates.
This answer is based on this one, but adapted for TreeView instead of TableView, and updated to use JavaFX 8 functionality (greatly reducing the amount of code required).
One strategy for this is to maintain an ObservableSet of TreeItems that match the search (this is sometimes useful for other functionality you may want anyway). Use a CSS PseudoClass and an external CSS file to highlight the required cells. You can create a BooleanBinding in the cell factory that binds to the cell's treeItemProperty and the ObservableSet, evaluating to true if the set contains the cell's current tree item. Then just register a listener with the binding and update the pseudoclass state of the cell when it changes.
Here's a SSCCE. It contains a tree whose items are Integer-valued. It will update the search when you type in the search box, matching those whose value is a multiple of the value entered.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TreeWithSearchAndHighlight extends Application {
#Override
public void start(Stage primaryStage) {
TreeView<Integer> tree = new TreeView<>(createRandomTree(100));
// keep track of items that match our search:
ObservableSet<TreeItem<Integer>> searchMatches = FXCollections.observableSet(new HashSet<>());
// cell factory returns an instance of TreeCell implementation defined below.
// pass the cell implementation a reference to the set of search matches
tree.setCellFactory(tv -> new SearchHighlightingTreeCell(searchMatches));
// search text field:
TextField textField = new TextField();
// allow only numeric input:
textField.setTextFormatter(new TextFormatter<Integer>(change ->
change.getControlNewText().matches("\\d*")
? change
: null));
// when the text changes, update the search matches:
textField.textProperty().addListener((obs, oldText, newText) -> {
// clear search:
searchMatches.clear();
// if no text, or 0, just exit:
if (newText.isEmpty()) {
return ;
}
int searchValue = Integer.parseInt(newText);
if (searchValue == 0) {
return ;
}
// search for matching nodes and put them in searchMatches:
Set<TreeItem<Integer>> matches = new HashSet<>();
searchMatchingItems(tree.getRoot(), matches, searchValue);
searchMatches.addAll(matches);
});
BorderPane root = new BorderPane(tree, textField, null, null, null);
BorderPane.setMargin(textField, new Insets(5));
BorderPane.setMargin(tree, new Insets(5));
Scene scene = new Scene(root, 600, 600);
// stylesheet sets style for cells matching search by using the selector
// .tree-cell:search-match
// (specified in the initalization of the Pseudoclass at the top of the code)
scene.getStylesheets().add("tree-highlight-search.css");
primaryStage.setScene(scene);
primaryStage.show();
}
// find all tree items whose value is a multiple of the search value:
private void searchMatchingItems(TreeItem<Integer> searchNode, Set<TreeItem<Integer>> matches, int searchValue) {
if (searchNode.getValue() % searchValue == 0) {
matches.add(searchNode);
}
for (TreeItem<Integer> child : searchNode.getChildren()) {
searchMatchingItems(child, matches, searchValue);
}
}
// build a random tree with numNodes nodes (all nodes expanded):
private TreeItem<Integer> createRandomTree(int numNodes) {
List<TreeItem<Integer>> items = new ArrayList<>();
TreeItem<Integer> root = new TreeItem<>(1);
root.setExpanded(true);
items.add(root);
Random rng = new Random();
for (int i = 2 ; i <= numNodes ; i++) {
TreeItem<Integer> item = new TreeItem<>(i);
item.setExpanded(true);
TreeItem<Integer> parent = items.get(rng.nextInt(items.size()));
parent.getChildren().add(item);
items.add(item);
}
return root ;
}
public static class SearchHighlightingTreeCell extends TreeCell<Integer> {
// must keep reference to binding to prevent premature garbage collection:
private BooleanBinding matchesSearch ;
public SearchHighlightingTreeCell(ObservableSet<TreeItem<Integer>> searchMatches) {
// pseudoclass for highlighting state
// css can set style with selector
// .tree-cell:search-match { ... }
PseudoClass searchMatch = PseudoClass.getPseudoClass("search-match");
// initialize binding. Evaluates to true if searchMatches
// contains the current treeItem
// note the binding observes both the treeItemProperty and searchMatches,
// so it updates if either one changes:
matchesSearch = Bindings.createBooleanBinding(() ->
searchMatches.contains(getTreeItem()),
treeItemProperty(), searchMatches);
// update the pseudoclass state if the binding value changes:
matchesSearch.addListener((obs, didMatchSearch, nowMatchesSearch) ->
pseudoClassStateChanged(searchMatch, nowMatchesSearch));
}
// update the text when the item displayed changes:
#Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : "Item "+item);
}
}
public static void main(String[] args) {
launch(args);
}
}
The CSS file tree-highlight-search.css just has to contain a style for the highlighted cells:
.tree-cell:search-match {
-fx-background: yellow ;
}
I am trying to implement onMouseEnter and onMouseExit events on a JavaFX ListView. What I want to do is if the mouse moves over a node of the list view, I want to change the background color of the nodes that are currently visible children in the current view.
This post has a great code sample, but is not quite what I am looking for.
Apply style to TreeView children nodes in javaFX
Using that code as a reference, what I am looking for is a given tree:
Root -> Item: 1 -> Item: 100 -> Item 1000, Item 1001, Item 1002, Item 1003
When I mouse over "Item: 100" I would like it and Item 1000* to have a background color change.
This seems difficult to me because the getNextSibling and getPreviousSibling interface is on the TreeItem and though you can get a TreeItem from a TreeCell on the MouseEvent, you can't (that I know of) update CSS on a TreeItem and have it take effect in a TreeCell -- because the setStyle method is on the TreeCell.
Suggestions on how this can be done?
[Update note: I originally had a solution using a subclass of TreeItem. The solution presented here is much cleaner than the original.]
Create an ObservableSet<TreeItem<?>> containing the TreeItems that should be highlighted. Then in the cell factory, observe that set, and the cell's treeItemProperty(), and set the style class (I used a PseudoClass in the example below) so the cell is highlighted if the tree item belonging to the cell is in the set.
Finally, register mouseEntered and mouseExited handlers with the cell. When the mouse enters the cell, you can get the tree item, use it to navigate to any other tree items you need, and add the appropriate items to the set you defined. In the mouseExited handler, clear the set (or perform other logic as needed).
import java.util.HashSet;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class HighlightingTree extends Application {
private final PseudoClass highlighted = PseudoClass.getPseudoClass("highlighted");
#Override
public void start(Stage primaryStage) {
TreeView<Integer> tree = new TreeView<>();
tree.setRoot(buildTreeRoot());
ObservableSet<TreeItem<Integer>> highlightedItems = FXCollections.observableSet(new HashSet<>());
tree.setCellFactory(tv -> {
// the cell:
TreeCell<Integer> cell = new TreeCell<Integer>() {
// indicates whether the cell should be highlighted:
private BooleanBinding highlightCell = Bindings.createBooleanBinding(() ->
getTreeItem() != null && highlightedItems.contains(getTreeItem()),
treeItemProperty(), highlightedItems);
// listener for the binding above
// note this has to be scoped to persist alongside the cell, as the binding
// will use weak listeners, and we need to avoid the listener getting gc'd:
private ChangeListener<Boolean> listener = (obs, wasHighlighted, isHighlighted) ->
pseudoClassStateChanged(highlighted, isHighlighted);
// anonymous constructor: register listener with binding
{
highlightCell.addListener(listener);
}
};
// display correct text:
cell.itemProperty().addListener((obs, oldItem, newItem) -> {
if (newItem == null) {
cell.setText(null);
} else {
cell.setText(newItem.toString());
}
});
// mouse listeners:
cell.setOnMouseEntered(e -> {
if (cell.getTreeItem() != null) {
highlightedItems.add(cell.getTreeItem());
highlightedItems.addAll(cell.getTreeItem().getChildren());
}
});
cell.setOnMouseExited(e -> highlightedItems.clear());
return cell ;
});
BorderPane uiRoot = new BorderPane(tree);
Scene scene = new Scene(uiRoot, 600, 600);
scene.getStylesheets().add("highlight-tree-children.css");
primaryStage.setScene(scene);
primaryStage.show();
}
private TreeItem<Integer> buildTreeRoot() {
return buildTreeItem(1);
}
private TreeItem<Integer> buildTreeItem(int n) {
TreeItem<Integer> item = new TreeItem<>(n);
if (n < 10_000) {
for (int i = 0; i<10; i++) {
item.getChildren().add(buildTreeItem(n * 10 + i));
}
}
return item ;
}
public static void main(String[] args) {
launch(args);
}
}
highlight-tree-children.css:
.tree-cell:highlighted {
-fx-background: yellow ;
}