2013-03-27 3 views
17

Я хотел бы узнать, есть ли возможность добавить кнопку изображения после каждого элемента списка ListView. Например: sampleJavaFX - Элемент ListView с кнопкой изображения

, где у этих красных квадратов должна быть кнопка. Если возможно, как я могу обработать событие щелчка кнопки элемента?

EDIT: если есть другой элемент управления, который может это сделать, сообщите мне. Я тестирую TableView.

Заранее благодарен!

ответ

27

Я тестировал это недавно. Мое решение:

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

Клетка будет выглядеть следующим образом:

Custom List Cell with Button

Соответствующая часть является XCell.updateItem метода и setGraphic вызова. С setGraphic() обычно для ярлыка должен быть установлен значок, но он одинаково хорошо подходит для установки сложного узла - в этом случае HBox с меткой и кнопкой.

Вам нужно убедиться, что обработчик событий Button ссылается на правильный элемент в списке. В первом приведенном ниже ссылке упоминается, что текущий выбранный элемент может быть достаточным на данный момент. Поэтому выберите текущий выбранный индекс в списке при обработке события кнопки.

Вы хотели бы посмотреть на них:

+1

Отлично! Большое спасибо за кодирование! Работал отлично! – Leonardo

+0

Нет необходимости хранить текущий элемент в поле 'lastItem'. Вы можете просто вызвать 'getItem()' непосредственно в обработчике кнопок. –

0

Предыдущее решение работало нормально, когда мой список был не большой, и я не добавить больше элементов управления, делающие Узел более сложный. Когда я добавил больше элементов управления, я обнаружил проблему с параллелизмом, возможно, это также потому, что я рисую карты с более чем 12000 объектами (строками и полигонами). Проблема (что я мог видеть) заключалась в том, что некоторые элементы в ListView будут повторяться внутри, что означает, что cellfactory будет создаваться дважды и/или не создаваться. Кажется, что «updateItem» является последним в очереди потока. Чтобы обойти проблему, я должен создать узел перед созданием ListView. Что-то вроде этого:

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

Я использовал простой DefaultListCell рекомендуется в fxexperience.com

2

Вы также можете использовать список объектов пользовательского HBOX. Пример ниже показывает использование такого пользовательского внутреннего класса HBox и процесс вложения списка таких объектов в элемент управления 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); 
    } 
} 

В результате реализации этого будет выглядеть следующим образом:

enter image description here

Однако для того, чтобы эффективность управления Кнопки событий, следует учитывать при добавлении объекта дополнительные пользовательские кнопки в конструкторе HBoxCustom, и создать правильный метод, который позволит вам управлять кнопками click-events.