JavaFX: How to highlight certain Items in a TreeView -


i trying implement search function treeview in javafx. want highlight matches when user hits enter key. added boolean ishighlighted treeitem , in treecells updateitem, check whether item ishighlighted , if apply css. works fine items/cells not visible @ moment of search -- when scroll them, highlighted. problem is: how can "repaint" treecells visible @ search reflect whether item ishighlighted? controller not have reference treecells treeview creates.

this answer based on this one, adapted treeview instead of tableview, , updated use javafx 8 functionality (greatly reducing amount of code required).

one strategy maintain observableset of treeitems match search (this useful other functionality may want anyway). use css pseudoclass , external css file highlight required cells. can create booleanbinding in cell factory binds cell's treeitemproperty , observableset, evaluating true if set contains cell's current tree item. register listener binding , update pseudoclass state of cell when changes.

here's sscce. contains tree items integer-valued. update search when type in search box, matching value multiple of 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 match our search:         observableset<treeitem<integer>> searchmatches = fxcollections.observableset(new hashset<>());          // cell factory returns instance of treecell implementation defined below.          // pass cell implementation reference set of search matches         tree.setcellfactory(tv -> new searchhighlightingtreecell(searchmatches));          // search text field:         textfield textfield = new textfield();          // allow numeric input:         textfield.settextformatter(new textformatter<integer>(change ->              change.getcontrolnewtext().matches("\\d*")                  ? change                  : null));          // when text changes, update search matches:         textfield.textproperty().addlistener((obs, oldtext, newtext) -> {              // clear search:             searchmatches.clear();              // if no text, or 0, exit:             if (newtext.isempty()) {                 return ;             }             int searchvalue = integer.parseint(newtext);             if (searchvalue == 0) {                 return ;             }              // search matching nodes , 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 cells matching search using selector          // .tree-cell:search-match         // (specified in initalization of pseudoclass @ top of code)         scene.getstylesheets().add("tree-highlight-search.css");         primarystage.setscene(scene);         primarystage.show();     }      // find tree items value multiple of search value:     private void searchmatchingitems(treeitem<integer> searchnode, set<treeitem<integer>> matches, int searchvalue) {         if (searchnode.getvalue() % searchvalue == 0) {             matches.add(searchnode);         }         (treeitem<integer> child : searchnode.getchildren()) {             searchmatchingitems(child, matches, searchvalue);         }     }      // build random tree 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();         (int = 2 ; <= 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 binding prevent premature garbage collection:         private booleanbinding matchessearch ;          public searchhighlightingtreecell(observableset<treeitem<integer>> searchmatches) {              // pseudoclass highlighting state             // css can set style selector             // .tree-cell:search-match { ... }             pseudoclass searchmatch = pseudoclass.getpseudoclass("search-match");              // initialize binding. evaluates true if searchmatches              // contains current treeitem              // note binding observes both treeitemproperty , searchmatches,             // updates if either 1 changes:             matchessearch = bindings.createbooleanbinding(() ->                 searchmatches.contains(gettreeitem()),                  treeitemproperty(), searchmatches);              // update pseudoclass state if binding value changes:             matchessearch.addlistener((obs, didmatchsearch, nowmatchessearch) ->                  pseudoclassstatechanged(searchmatch, nowmatchessearch));         }           // update text when 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 has contain style highlighted cells:

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

Comments

Popular posts from this blog

sql - VB.NET Operand type clash: date is incompatible with int error -

SVG stroke-linecap doesn't work for circles in Firefox? -

python - TypeError: Scalar value for argument 'color' is not numeric in openCV -