What is the best strategy for populating a TableView from a service?

Posted by alrutherford on Stack Overflow See other posts from Stack Overflow or by alrutherford
Published on 2012-12-09T23:01:07Z Indexed on 2012/12/09 23:03 UTC
Read the original article Hit count: 188

Filed under:
|

I have an application which has a potentially long running background process. I want this process to populate a TableView as results objects are generated. The results objects are added to an observableList and have properties which are bound to the columns in the usual fashion for JavaFX.

As an example of this consider the following sample code

Main Application

import java.util.LinkedList;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DataViewTest extends Application
{
    private TableView<ServiceResult> dataTable = new TableView<ServiceResult>();

    private ObservableList<ServiceResult> observableList;

    private ResultService resultService;

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

    @Override
    public void start(Stage stage)
    {
        observableList = FXCollections.observableArrayList(new LinkedList<ServiceResult>());

        resultService = new ResultService(observableList);

        Button refreshBtn = new Button("Update");
        refreshBtn.setOnAction(new EventHandler<ActionEvent>()
        {
            @Override
            public void handle(ActionEvent arg0)
            {
                observableList.clear();

                resultService.reset();
                resultService.start();
            }
        });

        TableColumn<ServiceResult, String> nameCol = new TableColumn<ServiceResult, String>("Value");
        nameCol.setCellValueFactory(new PropertyValueFactory<ServiceResult, String>("value"));

        nameCol.setPrefWidth(200);

        dataTable.getColumns().setAll(nameCol);

        // productTable.getItems().addAll(products);
        dataTable.setItems(observableList);

        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(300);
        stage.setHeight(500);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(refreshBtn, dataTable);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
    }

}

Service

public class ResultService extends Service<Void>
{
public static final int ITEM_COUNT = 100;

private ObservableList<ServiceResult> observableList;

/**
 * Construct service.
 * 
 */
public ResultService(ObservableList<ServiceResult> observableList)
{
    this.observableList = observableList;
}

@Override
protected Task<Void> createTask()
{
    return new Task<Void>()
    {
        @Override
        protected Void call() throws Exception
        {
            process();

            return null;
        }
    };
}

public void process()
{
    for (int i = 0; i < ITEM_COUNT; i++)
    {
        observableList.add(new ServiceResult(i));
    }

}
}

Data

public class ServiceResult
{
    private IntegerProperty valueProperty;

    /**
     * Construct property object.
     * 
     */
    public ServiceResult(int value)
    {
        valueProperty = new SimpleIntegerProperty();

        setValue(value);
    }

    public int getValue()
    {
        return valueProperty.get();
    }

    public void setValue(int value)
    {
        this.valueProperty.set(value);
    }

    public IntegerProperty valueProperty()
    {
        return valueProperty;
    }
}

Both the service and the TableView share a reference to the observable list? Is this good practise in JavaFx and if not what is the correct strategy?

If you hit the the 'Update' button the list will not always refresh to the ITEM_COUNT length. I believe this is because the observableList.clear() is interfering with the update which is running in the background thread. Can anyone shed some light on this?

© Stack Overflow or respective owner

Related posts about java

Related posts about javafx