JavaFX Tutorial - JavaFX ListView








The ListView class allows us to display a scrollable list of items.

Creating a List View

The following code creates a ListView and fills in data afterwards.

ListView<String> list = new ListView<>();

ObservableList<String> items =FXCollections.observableArrayList (
    "A", "B", "C", "D");
list.setItems(items);

To alter the size and height of the list view control, use the setPrefHeight and setPrefWidth methods.

list.setPrefWidth(100);
list.setPrefHeight(70);

To change the oriention of a ListView object

list.setOrientation(Orientation.HORIZONTAL)

SelectionModel and FocusModel track the selection and focus of the ListView object.

  • getSelectionModel().getSelectedIndex() - Returns the selected index
  • getSelectionModel().getSelectedItem() - Returns the selected item
  • getFocusModel().getFocusedIndex() - Returns the index of the focused item
  • getFocusModel().getFocusedItem() - Returns the focused item

The default selectionMode property is SelectionMode.SINGLE. To enable multiple selection in a default ListView instance, use the following code:

listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);




ComboBox Cell

We can add various types of data by using CheckBoxListCell, ChoiceBoxListCell, ComboBoxListCell, and TextFieldListCell.

It is like using the CellRenderer in Swing.

The following code uses ComboBoxListCell class to use a combo box in the list cell.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.ComboBoxListCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/*from  www  .  j  a  v  a  2 s  .  c o  m*/
public class Main extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    ObservableList<String> names = FXCollections
        .observableArrayList();
    ObservableList<String> data = FXCollections.observableArrayList();

    ListView<String> listView = new ListView<String>(data);
    listView.setPrefSize(200, 250);
    listView.setEditable(true);

    names.addAll("A", "B", "C", "D", "E");

    data.add("Double Click to Select Value");

    listView.setItems(data);
    listView.setCellFactory(ComboBoxListCell.forListView(names));

    StackPane root = new StackPane();
    root.getChildren().add(listView);
    primaryStage.setScene(new Scene(root, 200, 250));
    primaryStage.show();
  }
}

The code above generates the following result.

null




Customizing List View

The following code shows how to draw rectangle to a ListView cell.

It creates a custom cell by extending the ListCell. The updateItem receives the cell value from item parameter. Then it draws a rectangle with red color.

  static class ColorRectCell extends ListCell<String> {
    @Override
    public void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);
      Rectangle rect = new Rectangle(100, 20);
      if (item != null) {
        rect.setFill(Color.RED);
        setGraphic(rect);
      }
    }
  }

Full source code

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
//from  ww  w .j a  v  a 2s .co m
public class Main extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {

    ObservableList<String> data = FXCollections.observableArrayList();

    ListView<String> listView = new ListView<String>(data);
    listView.setPrefSize(200, 250);
    listView.setEditable(true);

    data.addAll("A", "B", "C", "D", "E");

    listView.setItems(data);
    listView.setCellFactory((ListView<String> l) -> new ColorRectCell());
    StackPane root = new StackPane();
    root.getChildren().add(listView);
    primaryStage.setScene(new Scene(root, 200, 250));
    primaryStage.show();
  }

  static class ColorRectCell extends ListCell<String> {
    @Override
    public void updateItem(String item, boolean empty) {
      super.updateItem(item, empty);
      Rectangle rect = new Rectangle(100, 20);
      if (item != null) {
        rect.setFill(Color.RED);
        setGraphic(rect);
      }
    }
  }
}

The code above generates the following result.

null

Handle List Item Selection

The following code shows how to handle list view item selection event. It registers an event handler for selected item property in the selection model. The new value is the new selected value from the list view.

    listView.getSelectionModel().selectedItemProperty().addListener(
        (ObservableValue<? extends String> ov, String old_val, 
            String new_val) -> {
                System.out.println(new_val);
                
    });

Full source code

import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
//w  ww.j a va 2  s .  c  o m
public class Main extends Application {
  public static void main(String[] args) {
    launch(args);
  }
  @Override
  public void start(Stage primaryStage) {
    ObservableList<String> data = FXCollections.observableArrayList();

    ListView<String> listView = new ListView<String>(data);
    listView.setPrefSize(200, 250);

    data.addAll("A", "B", "C", "D", "E");

    listView.setItems(data);
    listView.getSelectionModel().selectedItemProperty().addListener(
        (ObservableValue<? extends String> ov, String old_val, 
            String new_val) -> {
                System.out.println(new_val);
                
    });
    StackPane root = new StackPane();
    root.getChildren().add(listView);
    primaryStage.setScene(new Scene(root, 200, 250));
    primaryStage.show();
  }
}

The code above generates the following result.

null

Dual ListView

The ObservableList is a collection that is capable of notifying UI controls when objects are added, updated, and removed. JavaFX ObservableLists are typically used in list UI controls such as ListView and TableView.

The following code shows how to use ObservableList to work with ListView. It has two ListView controls and two buttons. We can use the two buttons to move items from one list view to another list view.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
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.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/*from  w w  w. j a  va 2 s .  co m*/
public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    BorderPane root = new BorderPane();
    Scene scene = new Scene(root, 400, 250, Color.WHITE);

    GridPane gridpane = new GridPane();
    gridpane.setPadding(new Insets(5));
    gridpane.setHgap(10);
    gridpane.setVgap(10);
    ColumnConstraints column1 = new ColumnConstraints(150, 150,
        Double.MAX_VALUE);
    ColumnConstraints column2 = new ColumnConstraints(50);
    ColumnConstraints column3 = new ColumnConstraints(150, 150,
        Double.MAX_VALUE);
    column1.setHgrow(Priority.ALWAYS);
    column3.setHgrow(Priority.ALWAYS);
    gridpane.getColumnConstraints().addAll(column1, column2, column3);

    Label candidatesLbl = new Label("Candidates");
    GridPane.setHalignment(candidatesLbl, HPos.CENTER);
    gridpane.add(candidatesLbl, 0, 0);

    Label selectedLbl = new Label("selected");
    gridpane.add(selectedLbl, 2, 0);
    GridPane.setHalignment(selectedLbl, HPos.CENTER);

    // Candidates
    final ObservableList<String> candidates = FXCollections
        .observableArrayList("Z", "A", "B", "C", "D");
    final ListView<String> candidatesListView = new ListView<>(candidates);
    gridpane.add(candidatesListView, 0, 1);

    final ObservableList<String> selected = FXCollections.observableArrayList();
    final ListView<String> heroListView = new ListView<>(selected);
    gridpane.add(heroListView, 2, 1);

    Button sendRightButton = new Button(" > ");
    sendRightButton.setOnAction((ActionEvent event) -> {
      String potential = candidatesListView.getSelectionModel()
          .getSelectedItem();
      if (potential != null) {
        candidatesListView.getSelectionModel().clearSelection();
        candidates.remove(potential);
        selected.add(potential);
      }
    });

    Button sendLeftButton = new Button(" < ");
    sendLeftButton.setOnAction((ActionEvent event) -> {
      String s = heroListView.getSelectionModel().getSelectedItem();
      if (s != null) {
        heroListView.getSelectionModel().clearSelection();
        selected.remove(s);
        candidates.add(s);
      }
    });
    VBox vbox = new VBox(5);
    vbox.getChildren().addAll(sendRightButton, sendLeftButton);

    gridpane.add(vbox, 1, 1);
    root.setCenter(gridpane);

    GridPane.setVgrow(root, Priority.ALWAYS);
    primaryStage.setScene(scene);
    primaryStage.show();
  }
  public static void main(String[] args) {
    launch(args);
  }
}

The code above generates the following result.

null

Drag and drop between two ListViews

The following code shows how to drag and drop between two listviews for custom objects.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Callback;
// w ww .  ja v  a 2  s. co m
public class Main extends Application {

  private static final ListView<Student> leftListView = new ListView<Student>();

  private static final ObservableList<Student> leftList = FXCollections
      .observableArrayList();
  private static final ObservableList<Student> rightList = FXCollections
      .observableArrayList();
  private static final ListView<Student> rightListView = new ListView<Student>();

  private static final GridPane rootPane = new GridPane();

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

  @Override
  public void start(Stage primaryStage) {
    initializeComponents();
    initializeListeners();

    buildGUI();

    populateData();

    primaryStage.setScene(new Scene(rootPane, 400, 325));
    primaryStage.show();
  }

  private void initializeListeners() {
    // drag from left to right
    leftListView.setOnDragDetected(new EventHandler<MouseEvent>() {
      @Override
      public void handle(MouseEvent event) {
        if (leftListView.getSelectionModel().getSelectedItem() == null) {
          return;
        }

        Dragboard dragBoard = leftListView.startDragAndDrop(TransferMode.MOVE);
        ClipboardContent content = new ClipboardContent();
        content.putString(leftListView.getSelectionModel().getSelectedItem()
            .getName());
        dragBoard.setContent(content);
      }
    });

    rightListView.setOnDragOver(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent dragEvent) {
        dragEvent.acceptTransferModes(TransferMode.MOVE);
      }
    });

    rightListView.setOnDragDropped(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent dragEvent) {
        String player = dragEvent.getDragboard().getString();
        rightListView.getItems().addAll(new Student(player));
        leftList.remove(new Student(player));
        leftListView.setItems(leftList);
        dragEvent.setDropCompleted(true);
      }
    });
    // drag from right to left
    rightListView.setOnDragDetected(new EventHandler<MouseEvent>() {
      @Override
      public void handle(MouseEvent event) {
        Dragboard dragBoard = rightListView.startDragAndDrop(TransferMode.MOVE);
        ClipboardContent content = new ClipboardContent();
        content.putString(rightListView.getSelectionModel().getSelectedItem()
            .getName());
        dragBoard.setContent(content);
      }
    });

    leftListView.setOnDragOver(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent dragEvent) {
        dragEvent.acceptTransferModes(TransferMode.MOVE);
      }
    });

    leftListView.setOnDragDropped(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent dragEvent) {
        String player = dragEvent.getDragboard().getString();
        leftListView.getItems().remove(new Student(player));

        rightList.remove(new Student(player));
        dragEvent.setDropCompleted(true);
      }
    });
  }

  private void buildGUI() {
    rootPane.setPadding(new Insets(10));
    rootPane.setPrefHeight(30);
    rootPane.setPrefWidth(100);
    rootPane.setVgap(10);
    rootPane.setHgap(20);

    Label playersLabel = new Label("Players");
    Label teamLabel = new Label("Team");

    rootPane.add(playersLabel, 0, 0);
    rootPane.add(leftListView, 0, 1);
    rootPane.add(teamLabel, 1, 0);
    rootPane.add(rightListView, 1, 1);
  }

  private void populateData() {
    leftList.addAll(new Student("Adam"), new Student("Alex"), new Student(
        "Alfred"));

    leftListView.setItems(leftList);
    rightListView.setItems(rightList);
  }

  private void initializeComponents() {
    initializeListView(leftListView);

    initializeListView(rightListView);
  }

  private void initializeListView(ListView<Student> listView) {
    listView.setPrefSize(250, 290);
    listView.setEditable(false);
    listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    listView.setCellFactory(new StringListCellFactory());
  }

  class StringListCellFactory implements
      Callback<ListView<Student>, ListCell<Student>> {
    @Override
    public ListCell<Student> call(ListView<Student> playerListView) {
      return new StringListCell();
    }

    class StringListCell extends ListCell<Student> {
      @Override
      protected void updateItem(Student player, boolean b) {
        super.updateItem(player, b);

        if (player != null) {
          setText(player.getName());
        }
      }
    }
  }
}

class Student {
  private String name;

  public Student(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o)
      return true;
    if (o == null || getClass() != o.getClass())
      return false;

    Student player = (Student) o;

    if (name != null ? !name.equals(player.name) : player.name != null)
      return false;

    return true;
  }

  @Override
  public int hashCode() {
    return name != null ? name.hashCode() : 0;
  }
}