【问题标题】:Implement tags bar in JavaFX在 JavaFX 中实现标签栏
【发布时间】:2016-09-19 14:59:30
【问题描述】:

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

**10/7/2016** you can find the code onGitHub

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

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

例子

YouTube

StackOverFlow(具有自动完成功能)

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

【问题讨论】:

    标签: java javafx tags


    【解决方案1】:

    这也是我的版本

    The whole Main class

    这就是为什么它有点长。

    但是总结一下。你需要一个

    1: FlowPane 用于容器,你不必担心包裹,它会自动包裹,垂直或水平。

    2:Label 当然是你的文本,它有一个GraphicProperty

    3: Path - 你可以使用Button,并添加一个ShapeImage,但这会是很多节点,所以我使用Path 并画了一个@ 987654338@红色按钮。

    剩下的就是你喜欢的颜色了

    编辑 像这样?

    您可以设置它的样式以获得该输出

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

    TextField上使用这一行

    【讨论】:

    • @!)谢谢,非常好!,但我没有看到任何接近问题原始图像的答案。我的意思是下面的文本字段和上面的 FlowPane..2)很好个人资料图片:)
    • @GoXr3Plus 非常欢迎你:),谢谢你:)。关于你的输出检查我的编辑,看看
    • Elltz 我找到了我的答案,请参阅有问题的上图。它包括拖放、标签自动完成等等。这是几个小时的编码。
    【解决方案2】:

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

    按钮的onAction 处理程序应该从它的父级中删除标签...

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

    TextFieldonAction 处理程序添加新标签并清除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;
    }
    
    @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();
    }
    

    【讨论】:

      【解决方案3】:

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

      public class CloseTag extends HBox implements Comparable<CloseTag> {
      
          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<? super MouseEvent> 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);
          }
      
      } 
      

      【讨论】:

        【解决方案4】:

        这段代码的简单实现!

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

        【讨论】:

        • 简单而完美的添加/删除标签。我刚刚将 HBox 更改为 FlowPane,它完美地解决了我的问题。谢谢。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多