在JavaFX中实现标签栏

答案示范:( 5月29日凌晨3点10分回答)

**10/7/2016** you can find the code on GitHub上 **10/7/2016** you can find the code on

示例标签图像

回答前的实际问题:( 5月22日19:53问)

标题可能不是太大,但我想要做的是在JavaFX中这样的事情:

例子

YouTube

YouTube代码示例

StackOverFlow(具有和自动完成)

StackOverflow标签示例

问题:我不需要为此编写代码。 相反,我想知道如何使用JavaFX和一些想法实现这一目标。

对于标签,您可以使用包含Text (标签名称)节点和Button (删除按钮(X))的自定义样式HBox 。 通过使用背景和边框,您可以获得所需的标签外观。

onAction处理程序应从其父级中删除标记…

对于整个标签栏,您可以使用另一个HBox 。 使用适当的边框以获得正确的外观。 除了标签之外,添加一个没有背景的TextField作为最后一个元素,并将该TextFieldHgrow属性设置为Priotity.ALWAYS以覆盖剩余的可用空间。

TextFieldonAction处理程序添加新标记并清除TextField的内容。

例如,你可以使用ControlsFX的TextField自动完成function,或者自己实现它以获得自定义外观……

 public class TagBar extends HBox { private final ObservableList tags; private final TextField inputTextField; public ObservableList 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 change) -> { while (change.next()) { if (change.wasPermutated()) { ArrayList 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; } 
 @Override public 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(); } 

简单实现这段代码!

 import .... public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ BorderPane root = new BorderPane(); HBox tagsPane = new HBox(10); tagsPane.setStyle("-fx-border-color: #F1F1F1;" + " -fx-border-width: 1px;" + " -fx-border-radius: 10;" + " -fx-border-insets: 5"); root.setBottom(tagsPane); TextField textField = new TextField(); textField.setPromptText("Tag name - ENTER to add"); textField.setOnKeyPressed(event -> { if (event.getCode() == KeyCode.ENTER) { tagButton(tagsPane, textField.getText()); textField.clear(); } }); root.setTop(textField); primaryStage.setTitle("Hello World"); primaryStage.setScene(new Scene(root, 450, 275)); primaryStage.show(); } public static void main(String[] args) { launch(args); } //little image as 15x15 for example Image toUse = new Image("sample/delete.png"); //box is the pane where this buttons will be placed public void tagButton(HBox box,String tag){ ImageView closeImg = new ImageView(toUse); Button result = new Button(tag,closeImg); result.setPrefHeight(20); result.setContentDisplay(ContentDisplay.RIGHT); result.setOnAction(event -> box.getChildren().remove(result)); box.getChildren().add(result); } 

}

在此处输入图像描述

此外,如果您需要不同的事件来点击标签并点击“X”,您可以像这样实现tagButton:

 public void tagButton(HBox box,String tag){ ImageView closeImg = new ImageView(toUse); HBox button = new HBox(); button.setStyle("-fx-padding:4;" + " -fx-border-width: 2;" + " -fx-border-color: black;" + " -fx-border-radius: 4;" + " -fx-background-color: f1f1f1;" + " -fx-border-insets: 5;"); button.setPrefHeight(20); button.getChildren().addAll(new Label(tag),closeImg); closeImg.setOnMouseClicked(event -> box.getChildren().remove(button) ); button.setOnMouseClicked(event -> { //doSomethig }); box.getChildren().add(button); } 

这也是我的版本

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

整个主类

它不知何故长,这就是原因。

但总结一下。 你需要一个

1:容器的FlowPane ,您不必担心包装,它会自行包裹,包括垂直或水平。

2:文本的Label ,具有GraphicProperty

3: Path – 你可以使用Button ,并为它添加一个ShapeImage ,但这将是很多节点,所以我使用Path ,我画了一个X红色按钮。

其余的是你喜欢的颜色造型

编辑这样的东西?

在此处输入图像描述

你可以设计它来获得输出

 setFont(Font.font("Serif Regular", FontWeight.SEMI_BOLD,12)); 

TextField上使用此行

这是一个标签栏的基本示例(我写了一些代码,因为我觉得它更容易理解)。 对于附加的自动完成function,您可以使用例如ControlsFx,正如fabian已经提到的那样。

 public class CloseTag extends HBox implements Comparable { private Label label; private Label closeIcon; public CloseTag(String text) { setStyle("-fx-padding:8;"); Text icon = GlyphsDude.createIcon(FontAwesomeIcon.TIMES_CIRCLE); closeIcon = new Label(null, icon); label = new Label(text, new StackPane(closeIcon)); label.setContentDisplay(ContentDisplay.RIGHT); getChildren().add(label); } public void setOnCloseAction(EventHandler action) { closeIcon.setOnMouseClicked(action); } public String getText() { return label.getText(); } @Override public int compareTo(CloseTag other) { return getText().compareTo(other.getText()); } } public class TagPane extends FlowPane { private TextField textField; public TagPane() { setStyle("-fx-padding:8;" + "-fx-hgap:10;"); setOnMouseClicked(evt -> onMouseClickedd(evt)); textField = new TextField(); textField.setOnKeyPressed(evt -> onKeyPressed(evt, textField)); } private void onMouseClickedd(MouseEvent mouseEvent) { if (mouseEvent.getTarget() != this || textField.getParent() != null ) { return; } getChildren().add(textField); textField.requestFocus(); } private void onKeyPressed(KeyEvent evt, TextField textField) { if (evt.getCode() == KeyCode.ENTER || evt.getCode() == KeyCode.TAB) { createTag(textField.getText()); textField.clear(); } } private void createTag(String text) { CloseTag tag = new CloseTag(text); tag.setOnCloseAction(evt -> removeTag(tag)); getChildren().remove(textField); getChildren().add(tag); } private void removeTag(CloseTag tag) { getChildren().remove(tag); } }