In my view I have three different component to display data. In each of the components I'm using a canvas to draw the data. Since it takes relatively long until to every canvas sequentially, I'm working on a concurrent solution. I'm using a service to draw a canvas and when the service succeeded, I pass the canvas to the pane. I'm using a service like that in two different components and now I rarely get an BufferOverflowException.
java.nio.BufferOverflowException
at com.sun.javafx.sg.prism.GrowableDataBuffer.ensureReadCapacity(GrowableDataBuffer.java:317)
at com.sun.javafx.sg.prism.GrowableDataBuffer.getInt(GrowableDataBuffer.java:527)
at com.sun.javafx.sg.prism.GrowableDataBuffer.getFloat(GrowableDataBuffer.java:563)
This is an simple example of how I implemented the service. How can I avoid the exception? Is there a different (better) approach to draw in canvases concurrent?
private class DrawService extends Service<Void> {
private Canvas[] canvases;
private short[][] data;
private double widthFactor;
private double xFactorCalc;
private DrawService(Canvas[] canvases, short[][] data, double widthFactor, double xFactorCalc) {
this.canvases = canvases;
this.data = data;
this.widthFactor = widthFactor;
this.xFactorCalc = xFactorCalc;
}
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
for (int canvasIndex = 0; canvasIndes < canvases.length; canvasIndex++) {
GraphicsContext gc = canvases[canvasIndex].getGraphicsContext2D();
gc.clearRect(0, 0, canvases[canvasIndex].getWidth(),
canvases[canvasIndex].getHeight());
gc.setStroke(Color.DARKGREY);
gc.strokeLine(0, 0, 0, canvases[canvasIndex].getHeight());
gc.beginPath();
gc.setStroke(Color.BLACK);
drawValues(startTime, data, gc, widthFactor, xFactorCalc, canvasIndex);
gc.stroke();
gc.closePath();
}
return null;
}
};
}
private void drawValues(short[][] data, GraphicsContext gc, double widthFactor, double xFactorCalc, int canvasIndex) {
for (int j = 0; j < data[canvasIndex].length; j++) {
short value = data[canvasIndex][j];
if (j == 0) {
gc.moveTo(j, value);
} else
gc.lineTo(j * xFactorCalc * widthFactor, value);
}
}
}
public class ServiceExample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
int interval = 250;
Pane aPane = new Pane();
Pane bPane = new Pane();
aPane.setPrefSize(600, 400);
bPane.setPrefSize(600, 400);
int canvasSize = 7;
int interval = 250;
Canvas[] aCanvases = new Canvas[canvasSize];
Canvas[] bCanvases = new Canvas[canvasSize];
short[][] data = getData(canvasSize, interval);
for(int i = 0; i < aCanvases.length; i++) {
aCanvases[i].setPrefWidth(aPane.getPrefWidth());
aCanvases[i].setPrefHeight(aPane.getPrefHeight());
bCanvases[i].setPrefwidth(bPane.getPrefWidth());
bCanvases[i].setPrefHeight(bPane.getPrefHeight();
}
double widthFactor = 1;
double xFactorCalc = interval / canvases[0].getWidth();
DrawService drawServiceA = new DrawService(aCanvases, data, widthFactor, xFactorCalc);
drawServiceA.restart();
DrawService drawServiceB = new DrawService(bCanvases, data, widthFactor, xFactorCalc);
drawServiceB.restart();
drawServiceA.setOnSucceeded((e) -> {
aPane.getChildren.addAll(aCanvases);
}
drawServiceB.setOnSucceeded((e) -> {
bPane.getChildren.addAll(bCanvases);
}
VBox vBox = new VBox(aPane, bPane);
Scene scene = new Scene(vBox);
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
private short[][] getData(int canvasSize, int interval) {
// pass random values
}
}