如何使用JavaFX8和javafx.concurrent.Task实现AreaChart的实时数据更新

时间:2014-03-30 12:37:17

标签: java javafx javafx-8

我想弄清楚这一点,但我想我错过了一些东西。我已经了解How to Chart real time streaming data using AreaChart in JAVAFX 2 - Concurrency, Animation, Charting中提供的解决方案。但我真的尝试使用Task http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html来完成实时图表。

我按照上面提到的javadoc中的示例,但是我没有得到数据生成(PartialResultsTask)和图表绘制之间的联系。目前我有以下设置:

控制器:

import javafx.scene.chart.XYChart;

public class FXMLDocumentController implements Initializable {

@FXML
private AreaChart<?, ?> areaChart;
private XYChart.Series serie;

@FXML
private void handleButtonAction(ActionEvent event) {
    PartialResultsTask task = new PartialResultsTask();
    serie = new XYChart.Series(task.getPartialResults());
    areaChart.getData().clear();
    areaChart.getData().add(serie);
    Thread t = new Thread(task);
    t.setDaemon(true);
    t.start();
}

@Override
public void initialize(URL url, ResourceBundle rb) {
}    

}

FXML     

<?import java.lang.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxconcurrenttest.FXMLDocumentController">
    <children>
        <AreaChart fx:id="areaChart" >
            <xAxis>
                <NumberAxis />
            </xAxis>
            <yAxis>
                <NumberAxis side="LEFT" />
            </yAxis>
        </AreaChart>
        <Button mnemonicParsing="false" onAction="#handleButtonAction" text="Button" />
    </children>
</VBox>

应用

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class FXConcurrentTest extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

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

}

任务

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.chart.XYChart;

public class PartialResultsTask extends Task<ObservableList<XYChart.Data>> {

    // Uses Java 7 diamond operator
    private ReadOnlyObjectWrapper<ObservableList> partialResults
            = new ReadOnlyObjectWrapper<>(this, "partialResults",
                    FXCollections.observableArrayList(new ArrayList()));

    public final ObservableList getPartialResults() {
        return partialResults.get();
    }

    public final ReadOnlyObjectProperty partialResultsProperty() {
        return partialResults.getReadOnlyProperty();
    }

    @Override
    protected ObservableList call() throws Exception {
        for (int i = 0; i < 100; i++) {
            if (isCancelled()) {
                break;
            }
            final Double latency = Math.random() * 100;
            final Integer count = i;
            Platform.runLater(() -> {
                partialResults.get().add(new XYChart.Data<>(count, latency));
                System.out.println("adding new Data:" +count +":" + latency);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(PartialResultsTask.class.getName()).log(Level.SEVERE, null, ex);
                }
            });
            updateProgress(i, 100);
            //didn't make a change
            //updateValue(getPartialResults());
        }
        return partialResults.get();
    }
}

我在System.out()中添加了call(),以便您可以看到ObservableList正确更新,但图表仅在循环后绘制。我想要实现的是立即绘制新值&#34;。

非常感谢任何帮助。

提前致谢!

1 个答案:

答案 0 :(得分:0)

您正在Thread.sleep()内执行Platform.runLater()。这意味着您将阻止FX应用程序线程,并且在整个循环完成之前不会给它重绘图表的机会。 (你在工作中睡觉:)。

你需要这个:

protected ObservableList<XYChart.Data<Number, Number>> call() throws Exception {
    for (int i = 0; i < 100; i++) {
        if (isCancelled()) {
            break;
        }
        final Double latency = Math.random() * 100;
        final Integer count = i;
        Platform.runLater(() -> {
            partialResults.get().add(new XYChart.Data<>(count, latency));
            System.out.println("adding new Data:" +count +":" + latency);
        });
        try {
            Thread.sleep(100);
        } catch (InterruptedException ex) {
            Logger.getLogger(PartialResultsTask.class.getName()).log(Level.SEVERE, null, ex);
        }
        updateProgress(i, 100);
        //didn't make a change
        //updateValue(getPartialResults());
    }
    return partialResults.get();
}