对于标签,您可以使用
HBox包含
Text(标签名称)节点和
Button(删除按钮(X))节点的自定义样式。通过玩转
背景和边框,可以获得所需的标签外观。
onAction按钮的处理程序应从其父项中移除标签。
对于整个标签栏,您可以使用另一个HBox。使用适当的边框以获得正确的外观。除了标签添加一个TextField没有
背景的最后一个元素,并设置Hgrow的那个属性
TextField,以
Priotity.ALWAYS覆盖可用空间的其余部分。
此onAction处理程序TextField添加新标签并清除的内容
TextField。
您可以例如将ControlsFX的自动完成功能与一起使用,
TextField也可以自行实现以实现自定义外观…
public class TagBar extends HBox { private final ObservableList<String> tags; private final TextField inputTextField; public ObservableList<String> getTags() { return tags; } public TagBar() { getStyleClass().setAll("tag-bar"); getStylesheets().add(getClass().getResource("style.css").toExternalForm()); tags = FXCollections.observableArrayList(); inputTextField = new TextField(); inputTextField.setonAction(evt -> { String text = inputTextField.getText(); if (!text.isEmpty() && !tags.contains(text)) { tags.add(text); inputTextField.clear(); } }); inputTextField.prefHeightProperty().bind(this.heightProperty()); HBox.setHgrow(inputTextField, Priority.ALWAYS); inputTextField.setBackground(null); tags.addListener((ListChangeListener.Change<? extends String> change) -> { while (change.next()) { if (change.wasPermutated()) { ArrayList<Node> newSublist = new ArrayList<>(change.getTo() - change.getFrom()); for (int i = change.getFrom(), end = change.getTo(); i < end; i++) { newSublist.add(null); } for (int i = change.getFrom(), end = change.getTo(); i < end; i++) { newSublist.set(change.getPermutation(i), getChildren().get(i)); } getChildren().subList(change.getFrom(), change.getTo()).clear(); getChildren().addAll(change.getFrom(), newSublist); } else { if (change.wasRemoved()) { getChildren().subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear(); } if (change.wasAdded()) { getChildren().addAll(change.getFrom(), change.getAddedSubList().stream().map(Tag::new).collect(Collectors.toList())); } } } }); getChildren().add(inputTextField); } private class Tag extends HBox { public Tag(String tag) { getStyleClass().setAll("tag"); Button removeButton = new Button("X"); removeButton.setonAction((evt) -> tags.remove(tag)); Text text = new Text(tag); HBox.setMargin(text, new Insets(0, 0, 0, 5)); getChildren().addAll(text, removeButton); } }}style.css
.tag-bar { -fx-border-color: blue; -fx-spacing: 3; -fx-padding: 3; -fx-max-height: 30;}.tag-bar .tag { -fx-background-color: lightblue; -fx-alignment: center;}.tag-bar .tag .button { -fx-background-color: transparent;}@Overridepublic void start(Stage primaryStage) { Button btn = new Button("Sort"); StackPane.setAlignment(btn, Pos.BOTTOM_CENTER); TagBar tagBar = new TagBar(); btn.setonAction((ActionEvent event) -> { FXCollections.sort(tagBar.getTags()); }); Button btn2 = new Button("add "42""); btn2.setonAction(evt -> { if (!tagBar.getTags().contains("42")) { tagBar.getTags().add("42"); } }); VBox root = new VBox(); root.getChildren().addAll(tagBar, btn, btn2); root.setPrefSize(300, 400); Scene scene = new Scene(root); primaryStage.setScene(scene); primaryStage.show();}


