JavaFX - ListView Item with an Image Button

前端 未结 3 2066
野性不改
野性不改 2020-12-02 17:41

I\'d like to know if there\'s possible to add an Image Button after every ListView Item. For example:\"sample\"

相关标签:
3条回答
  • 2020-12-02 18:08

    I was testing this recently. My 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);
        }
    }
    

    The cells will look like this:

    Custom List Cell with Button

    The relevant part is the XCell.updateItem method and the setGraphic call. With setGraphic() usually an icon shall be set for a label, but it works equally well to set a complex Node - in this case the HBox with label and button.

    You need to make sure, that the Button's event handler refers to the correct item in the list. In the first link below, it is mentioned, that the currently selected item might be sufficient for now. So fetch the currently selected index in the list when handling the button's event.

    You might like to look at these:

    • http://fxexperience.com/2012/05/listview-custom-cell-factories-and-context-menus/
    • http://docs.oracle.com/javafx/2/ui_controls/list-view.htm
    0 讨论(0)
  • 2020-12-02 18:11

    You can also use List of custom HBox objects. Example below shows the use of such custom HBox inner class and process of nesting list of such objects into ListView control.

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

    The result of this implementation will look like this:

    enter image description here

    However, in order to efficacy manage Buttons events, you should consider in adding additional custom Button object into HBoxCustom constructor method, and create a proper method, which will allow you to control buttons click-events.

    0 讨论(0)
  • 2020-12-02 18:30

    The previous solution worked fine when my list was not big and I didn't add more Controls making the Node more complex. When I added more Controls I found a problem with concurrency, maybe it is also because I am drawing maps that have more than 12000 objects (lines and polygons). The problem (what I could see) was that some of the items in ListView will be repeated internally meaning that cellfactory will be created twice and/or not created. It seems "updateItem" is last in the queue of the thread. So to work around the problem I have to create the node before creating the ListView. Something like this:

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

    I used the simple DefaultListCell recommended in fxexperience.com

    0 讨论(0)
提交回复
热议问题