How ListView.setItems() works?


Question

I have a Controller class that implements initializable, it looks like this:

public class FileSharingController implements Initializable {

private ObservableList<User> UsersListData;
@FXML
private ListView<User> UsersList;

@Override
public void initialize(URL location, ResourceBundle resources) {
final Task<Void> UsersListTask=new Task<Void>(){
            protected Void call() throws SQLException{
                DatabaseManager DB=new DatabaseManager();
                UsersListData.clear();
                UsersListData.addAll(DB.returnUsers());
                UsersList.setItems(UsersListData);
                return null;}};
        new Thread(UsersListTask).start();

}

But my ListView Doesn't Update! what should I do?!

1
1
7/28/2013 6:50:15 AM

Accepted Answer

final Task<List<User>> UsersListTask = new Task<List<User>>() {
    protected List<User> call() throws SQLException {
        return new DatabaseManager().returnUsers();
    }
};

UsersListTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
    @Override public void handle(WorkerStateEvent event) {
        UsersList.setItems(
            FXCollections.observableArrayList(UsersListTask.getValue())
        );
    }
});

UsersListTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
    @Override public void handle(WorkerStateEvent event) {
        System.out.println("ERROR: " + UsersListTask.getException());
    }
});

new Thread(UsersListTask).start();

If using java 8:

UsersListTask.setOnSucceeded(event ->
    UsersList.setItems(
        FXCollections.observableArrayList(UsersListTask.getValue())
    )
);

UsersListTask.setOnFailed(event ->
    System.out.println("ERROR: " + UsersListTask.getException())
);

Note that you should never update the item list backing the ListView off of the JavaFX thread as it can trigger scene graph updates that may have unexpected consequences. By performing the updates to the item lists in the setOnSucceeded method, then the JavaFX framework Task implementation will internally ensure that your update occurs on the JavaFX application thread.

Sample Code

Here is an executable sample you can try out and compare with your implementation.

Sample Output

listview

list.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<StackPane fx:controller="ListController" id="StackPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml">
  <children>
    <ListView fx:id="usersList"/>
  </children>
</StackPane>

ListApplication.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.Stage;

public class ListApplication extends Application {
    @Override public void start(Stage stage) throws Exception{
        Parent layout = FXMLLoader.load(getClass().getResource("list.fxml"));
        stage.setScene(new Scene(layout));
        stage.show();
    }

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

ListController.java

import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.concurrent.*;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class ListController {
    @FXML private ListView<User> usersList;

    @FXML void initialize() {
        assert usersList != null : "fx:id=\"usersList\" was not injected: check your FXML file 'list.fxml'.";

        final Task<List<User>> usersListTask = new Task<List<User>>() {
            protected List<User> call() throws SQLException {
                return new DatabaseManager().returnUsers();
            }
        };

        usersListTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent event) {
                usersList.setItems(
                        FXCollections.observableArrayList(usersListTask.getValue())
                );
            }
        });

        usersListTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent event) {
                System.out.println("ERROR: " + usersListTask.getException());
            }
        });

        new Thread(usersListTask).start();
    }


    public static class User {
        private final StringProperty name = new SimpleStringProperty();

        public User(String name) {
            this.name.set(name);
        }

        public String getName() {
            return name.get();
        }

        public StringProperty nameProperty() {
            return name;
        }

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

        @Override
        public String toString() {
            return getName();
        }
    }

    public static class DatabaseManager {
        public List<User> returnUsers() throws SQLException {
            return Arrays.asList(
                new User("Sally"),
                new User("Jenny"),
                new User("Jill"),
                new User("Anne"),
                new User("Carol"),
                new User("Helen")
            );
        }
    }
}
3
7/28/2013 6:48:12 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon