1+ package root .javafx .CustomView ;
2+
3+ import java .util .ArrayList ;
4+ import java .util .stream .Collectors ;
5+
6+ import de .jensd .fx .glyphs .fontawesome .FontAwesomeIcon ;
7+ import de .jensd .fx .glyphs .fontawesome .FontAwesomeIconView ;
8+ import javafx .collections .FXCollections ;
9+ import javafx .collections .ListChangeListener ;
10+ import javafx .collections .ObservableList ;
11+ import javafx .geometry .Insets ;
12+ import javafx .scene .Node ;
13+ import javafx .scene .control .Button ;
14+ import javafx .scene .control .TextField ;
15+ import javafx .scene .layout .FlowPane ;
16+ import javafx .scene .layout .HBox ;
17+ import javafx .scene .paint .Paint ;
18+ import javafx .scene .text .Text ;
19+
20+ public class TagBar extends FlowPane {
21+
22+ private final ObservableList <String > tags ;
23+ private final TextField inputTextField ;
24+
25+ public TagBar () {
26+ getStyleClass ().setAll ("tag-bar" );
27+ getStylesheets ().add (getClass ().getResource ("/css/javaFx.css" ).toExternalForm ());
28+
29+ // Initialize
30+ tags = FXCollections .observableArrayList ();
31+ inputTextField = new TextField ();
32+
33+ // Set on action event on TextField (Add tag to tags and clear TextField text)
34+ inputTextField .setOnAction (e -> {
35+ String text = inputTextField .getText ();
36+ if (!text .isEmpty () && !tags .contains (text )) {
37+ tags .add (text );
38+ inputTextField .clear ();
39+ }
40+ });
41+ getChildren ().add (inputTextField );
42+
43+ // Focusing when mouse click this FlowPane
44+ setOnMouseClicked (e -> {
45+ inputTextField .requestFocus ();
46+ });
47+
48+ // Change TextField width according to length of input text
49+ inputTextField .textProperty ().addListener ((ob , oldValue , newValue ) -> {
50+ Text textWrapper = new Text (newValue );
51+ textWrapper .setFont (inputTextField .getFont ());
52+ inputTextField .setPrefWidth (Math .ceil (textWrapper .getLayoutBounds ().getWidth ()) + 20 );
53+ });
54+
55+ // Set ListChangeListener on tags list
56+ tags .addListener ((ListChangeListener .Change <? extends String > change ) -> {
57+ while (change .next ()) {
58+ if (change .wasPermutated ()) {
59+ ArrayList <Node > newSublist = new ArrayList <>(change .getTo () - change .getFrom ());
60+ for (int i = change .getFrom (), end = change .getTo (); i < end ; i ++) {
61+ newSublist .add (null );
62+ }
63+
64+ for (int i = change .getFrom (), end = change .getTo (); i < end ; i ++) {
65+ newSublist .set (change .getPermutation (i ), getChildren ().get (i ));
66+ }
67+
68+ getChildren ().subList (change .getFrom (), change .getTo ()).clear ();
69+ getChildren ().addAll (change .getFrom (), newSublist );
70+ } else {
71+ if (change .wasRemoved ()) {
72+ getChildren ().subList (change .getFrom (), change .getFrom () + change .getRemovedSize ()).clear ();
73+ }
74+
75+ if (change .wasAdded ()) {
76+ getChildren ().addAll (change .getFrom (),
77+ change .getAddedSubList ().stream ().map (Tag ::new ).collect (Collectors .toList ()));
78+ }
79+ }
80+ }
81+ });
82+ }
83+
84+ public ObservableList <String > getTags () {
85+ return tags ;
86+ }
87+
88+ private class Tag extends HBox {
89+
90+ public Tag (String tag ) {
91+ getStyleClass ().setAll ("tag" );
92+ FlowPane .setMargin (this , new Insets (2.5 ));
93+
94+ FontAwesomeIconView icon = new FontAwesomeIconView (FontAwesomeIcon .TIMES );
95+ icon .setFill (Paint .valueOf ("gray" ));
96+
97+ Button removeButton = new Button ("" , icon );
98+ removeButton .setOnAction ((e ) -> tags .remove (tag ));
99+
100+ Text text = new Text (tag );
101+ HBox .setMargin (text , new Insets (0 , 0 , 0 , 5 ));
102+
103+ getChildren ().addAll (text , removeButton );
104+ }
105+ }
106+
107+ }
0 commit comments