在 JavaFX 中实现标签栏

2022-09-03 05:28:09

答题演示:(5月29日凌晨3:10答题)

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

Sample Tags Image

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

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

例子

优酷视频:

YouTube tags example

StackOverFlow(具有并自动完成):

StackOverflow tags example

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


答案 1

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

按钮的处理程序应从其父级中删除标记...onAction

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

此程序的处理程序将添加新标记并清除 .onActionTextFieldTextField

例如,您可以使用 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);
        }
    }

}

风格.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();
}

答案 2

此代码的简单实现!

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

}

enter image description here

另外,如果您需要不同的事件来单击标签并单击“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);
}