簡體   English   中英

JavaFX:如何在TreeView中突出顯示某些項

[英]JavaFX: How to highlight certain Items in a TreeView

我正在嘗試為JavaFX中的TreeView實現搜索功能。 我想在用戶按下Enter鍵時突出顯示所有匹配項。 因此,我在我的TreeItem添加了一個boolean isHighlighted ,在TreeCellupdateItem ,我檢查了該項目是否為isHighlighted ,如果是的話,我會應用某種CSS。 在搜索時不可見的項目/單元格中一切正常,當我滾動到它們時,它們會正確突出顯示。 問題是:如何“重繪”在搜索時可見的TreeCell,以便它們反映其項目是否為isHighlighted 我的控制器當前沒有對TreeView創建的TreeCells的任何引用。

此答案是基於這一個 ,但適合於TreeView的代替TableView ,並更新為使用JavaFX的8功能(大大減少的代碼所需的量)。

一種策略是維護一個與搜索匹配的TreeItemsObservableSet (有時這對於您可能想要的其他功能很有用)。 使用CSS PseudoClass和外部CSS文件突出顯示所需的單元格。 你可以創建一個BooleanBinding在電池工廠結合細胞的treeItemPropertyObservableSet ,計算到true ,如果集合包含電池的電流樹項目。 然后只需向綁定注冊一個偵聽器,並在其更改時更新單元的偽類狀態。

這是SSCCE。 它包含一棵樹,其項目是Integer數值。 當您在搜索框中鍵入內容時,它將匹配值是輸入值倍數的內容,從而更新搜索。

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

CSS文件tree-highlight-search.css只需包含突出顯示的單元格的樣式即可:

.tree-cell:search-match {
    -fx-background: yellow ;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM