Implementa la barra dei tag in JavaFX

Dimostrazione di risposta: (ha risposto il 29 maggio alle 3:10)

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

Immagine dei tag campione

Domanda reale prima della risposta: (chiesto il 22 maggio alle 19:53)

Il titolo potrebbe non essere troppo grande, ma quello che voglio fare è qualcosa di simile in JavaFX:

Esempi

YouTube :

Esempio di tag YouTube

StackOverFlow (che ha e completamento automatico) :

Esempio di tag StackOverflow

Domanda: Non ho bisogno di scrivermi il codice per questo. Invece voglio sapere come posso ottenerlo usando JavaFX e alcune idee.

Per i tag è ansible utilizzare uno stile personalizzato HBox contenente un nodo Text (il nome del tag) e un Button (il pulsante di cancellazione (X)). Giocando con lo sfondo e il bordo puoi ottenere l’aspetto desiderato dei tag.

Il gestore onAction del pulsante dovrebbe rimuovere il tag dal suo genitore …

Per l’intera barra dei tag puoi usare un altro HBox . Utilizzare il bordo appropriato per l’aspetto corretto. Oltre ai tag aggiungere un campo di TextField senza sfondo come ultimo elemento e impostare la proprietà Hgrow di quel campo di TextField su Priotity.ALWAYS per coprire il resto dello spazio disponibile.

Il gestore onAction di questo TextField aggiunge nuovi tag e cancella il contenuto del TextField .

Ad esempio, puoi utilizzare le funzionalità di completamento automatico di ControlsFX con TextField o implementarlo da solo per un look personalizzato …

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

Semplice implementazione di questo codice!

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

}

inserisci la descrizione dell'immagine qui

Inoltre, se hai bisogno di eventi diversi per fare clic sul tag e fare clic su “X”, puoi implementare tagButton in questo modo:

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

Questa è anche la mia versione

inserisci la descrizione dell'immagine qui

inserisci la descrizione dell'immagine qui

inserisci la descrizione dell'immagine qui

L’intera class principale

è in qualche modo lungo questo è il motivo.

Ma per riassumere. Avete bisogno di un

1: FlowPane per il contenitore, e non ti devi preoccupare di avvolgere, si avvolgerà, sia verticale che orizzontale.

2: Label ovviamente per il tuo testo, che ha una proprietà GraphicProperty

3: Path : beh, potresti usare Button e aggiungere una Shape o Image , ma ci saranno molti nodes, quindi ho usato Path e ho disegnato un pulsante X rosso.

Il resto è lo styling per il tuo colore preferito

MODIFICA qualcosa del genere?

inserisci la descrizione dell'immagine qui

puoi modellarlo per ottenere quell’output

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

usa questa linea sul TextField

Ecco un esempio di base di una barra di tag (ho scritto del codice, perché penso che sia più facile da seguire). Per la funzione di completamento automatico aggiuntiva è ansible utilizzare ad esempio ControlsFx, come già menzionato da 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); } }