JavaFX-ListView élément avec un bouton Image

j'aimerais savoir s'il est possible d'ajouter un bouton Image après chaque élément ListView. Par exemple:sample

où ces carrés rouges devrait avoir un bouton à la place. Si c'est possible, Comment puis-je gérer l'événement de clic de bouton de l'élément?

EDIT: s'il y a un autre contrôle qui peut le faire, merci de me le faire savoir. Je suis en essais TableView.

Merci d'avance!

18
demandé sur Leonardo 2013-03-27 18:33:33

3 réponses

Je l'ai testé récemment. Ma solution:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class SO extends Application {
    static class XCell extends ListCell<String> {
        HBox hbox = new HBox();
        Label label = new Label("(empty)");
        Pane pane = new Pane();
        Button button = new Button("(>)");
        String lastItem;

        public XCell() {
            super();
            hbox.getChildren().addAll(label, pane, button);
            HBox.setHgrow(pane, Priority.ALWAYS);
            button.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    System.out.println(lastItem + " : " + event);
                }
            });
        }

        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            setText(null);  // No text in label of super class
            if (empty) {
                lastItem = null;
                setGraphic(null);
            } else {
                lastItem = item;
                label.setText(item!=null ? item : "<null>");
                setGraphic(hbox);
            }
        }
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        StackPane pane = new StackPane();
        Scene scene = new Scene(pane, 300, 150);
        primaryStage.setScene(scene);
        ObservableList<String> list = FXCollections.observableArrayList(
                "Item 1", "Item 2", "Item 3", "Item 4");
        ListView<String> lv = new ListView<>(list);
        lv.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> param) {
                return new XCell();
            }
        });
        pane.getChildren().add(lv);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

les cellules ressembleront à ceci:

Custom List Cell with Button

La partie pertinente est l' XCell.updateItem la méthode et le setGraphic appel. setGraphic() habituellement une icône doit être définie pour une étiquette, mais cela fonctionne aussi bien pour définir un noeud complexe - dans ce cas la HBox avec étiquette et bouton.

vous devez vous assurer que le gestionnaire d'événements du bouton se réfère à l'élément correct de la liste. Dans le premier lien ci-dessous, il est mentionné que l'élément actuellement sélectionné peut être suffisant pour l'instant. Récupérez donc l'index actuellement sélectionné dans la liste lors de la manipulation de l'Événement du bouton.

Vous aimeriez regarder ces:

29
répondu Rainer Schwarze 2013-03-28 20:02:53

Vous pouvez également utiliser la liste des objets hbox personnalisés. L'exemple ci-dessous montre l'utilisation d'une telle classe intérieure hbox personnalisée et le processus d'imbrication de la liste de tels objets dans le contrôle de ListView.

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;


public class ListViewDemo extends Application {

     public static class HBoxCell extends HBox {
          Label label = new Label();
          Button button = new Button();

          HBoxCell(String labelText, String buttonText) {
               super();

               label.setText(labelText);
               label.setMaxWidth(Double.MAX_VALUE);
               HBox.setHgrow(label, Priority.ALWAYS);

               button.setText(buttonText);

               this.getChildren().addAll(label, button);
          }
     }

     public Parent createContent() {
          BorderPane layout = new BorderPane();

          List<HBoxCell> list = new ArrayList<>();
          for (int i = 0; i < 12; i++) {
               list.add(new HBoxCell("Item " + i, "Button " + i));
          }

          ListView<HBoxCell> listView = new ListView<HBoxCell>();
          ObservableList<HBoxCell> myObservableList = FXCollections.observableList(list);
          listView.setItems(myObservableList);

          layout.setCenter(listView);

          return layout;
     }

     @Override
     public void start(Stage stage) throws Exception {
          stage.setScene(new Scene(createContent()));
          stage.setWidth(300);
          stage.setHeight(200);
          stage.show();
     }

     public static void main(String args[]) {
          launch(args);
     }
}

le résultat de cette implémentation ressemblera à ceci:

enter image description here

cependant, afin de gérer efficacement les événements de boutons, vous devriez considérer en ajoutant l'objet de bouton personnalisé supplémentaire dans la méthode de constructeur HBoxCustom, et créer une méthode appropriée, ce qui vous permettra de boutons de contrôle cliquez sur événements.

3
répondu bluevoxel 2014-07-11 10:21:11

la solution précédente fonctionnait bien quand ma liste n'était pas grande et je n'ai pas ajouté plus de contrôles rendant le noeud plus complexe. Quand j'ai ajouté plus de contrôles j'ai trouvé un problème avec la simultanéité, peut-être est-ce aussi parce que je dessine des cartes qui ont plus de 12000 objets (lignes et polygones). Le problème (ce que j'ai pu voir) est que certains éléments de ListView seront répétés à l'interne, ce qui signifie que cellfactory sera créé deux fois et/ou non. Il semble que "updateItem" soit le dernier dans la file d'attente de le fil. Donc, pour contourner le problème, j'ai créer le nœud avant de créer la liste. Quelque chose comme ceci:

    ObservableList<Node> list = FXCollections.observableArrayList();
    for (AisaLayer layer : listLayers) {
        mapLayers.put(layer.getLayerName(), layer);
        list.add(new AisaNode(layer));
        System.out.println("Ordered:" + layer.getLayerName());
    }
    lv.setItems(list);
    lv.setCellFactory(new Callback<ListView<Node>, ListCell<Node>>() {
        @Override
        public ListCell<Node> call(ListView<Node> param) {
            return new DefaultListCell<>();
        }
    });

j'ai utilisé le Defaullistcell simple recommandé dans fxexperience.com

0
répondu HSal 2013-07-31 17:26:23