1

i need to create a Service and a Task to calculate the Mandelbrot and JuliaSet. The calculation is working pretty good and now we need to give it into a Service and call it inside the task. I have now the Problem, that every Time the task is executed, the Parameters are different. I wrote a little Setter Function to parse those Arguments to the Service first. But i'm not sure if this is the right Way?! I'm also not sure how to correctly call the service in the main Function?

Now it works like this: First time the service is executed, everything seems to work, but when i call it a secound Time, nothing seems to happen..... Just to make sure: A Service can execute the Task multiple Times at the same Time? Is it also posible with different Parameters?

Code Task:


    private MandelbrotRenderOptions mandelbrot;
    private JuliaRenderOptions juliaset;
    private Canvas leftCanvas;
    private Canvas rightCanvas;

    //Constructor
    public RenderTask(Canvas leftCanvas, Canvas rightCanvas) {
        this.leftCanvas = leftCanvas;
        this.rightCanvas = rightCanvas;
    }

    public void setOptions(MandelbrotRenderOptions mandelbrot, JuliaRenderOptions juliaset) {
        this.mandelbrot = mandelbrot;
        this.juliaset = juliaset;
    }

    @Override
    protected Void call() throws Exception {
        try {
            System.out.println("HALLO SERVICE");
            // instances for rendering the left canvas [pixel.data -> PixelWriter -> WritableImage -> GraphicsContext -> Canvas]
            // creates an writable image which contains the dimensions of the canvas
            WritableImage wimLeftCanvas = new WritableImage((int) leftCanvas.getWidth(), (int) leftCanvas.getHeight());
            // instance which can write data into the image (instance above)
            PixelWriter pwLeftCanvas = wimLeftCanvas.getPixelWriter();
            // instance which fills the canvas
            GraphicsContext gcLeftCanvas = leftCanvas.getGraphicsContext2D();

            // instances for rendering the right canvas [pixel.data -> PixelWriter -> WritableImage -> GraphicsContext -> Canvas]
            WritableImage wimRightCanvas = new WritableImage((int) rightCanvas.getWidth(), (int) rightCanvas.getHeight());
            PixelWriter pwRight = wimRightCanvas.getPixelWriter();
            GraphicsContext gcRightCanvas = rightCanvas.getGraphicsContext2D();

            gcLeftCanvas.clearRect(0, 0, leftCanvas.getWidth(), leftCanvas.getHeight());
            //Pixel[][] pixels; // contains pixel data for rendering canvas


            // instances for logging the rendered data
            SimpleImage simpleImageLeftCanvas = new SimpleImage((int) leftCanvas.getWidth(), (int) leftCanvas.getHeight());
            SimpleImage simpleImageRightCanvas = new SimpleImage((int) rightCanvas.getWidth(), (int) rightCanvas.getHeight());
            short dataSimpleImage[] = new short[3]; // contains pixel data for logging rendered data

            // fills left canvas (mandelbrot) PixelWriter instance with data
            Pixel[][] pixels = mandelbrot.setAllPixels();

            FractalLogger.logRenderCall(mandelbrot);

            for (int y = 0; y < (int) leftCanvas.getHeight(); y++) {
                for (int x = 0; x < (int) leftCanvas.getWidth(); x++) {

                    // parses color data to PixelWriter instance
                    Color color = Color.rgb(pixels[y][x].getRed(), pixels[y][x].getGreen(), pixels[y][x].getBlue());
                    pwLeftCanvas.setColor(x, y, color);

                    for (int depth = 0; depth < 3; depth++) {
                        if (depth == 0) {
                            dataSimpleImage[depth] = pixels[y][x].getRed();
                        } else if (depth == 1) {
                            dataSimpleImage[depth] = pixels[y][x].getGreen();
                        } else {
                            dataSimpleImage[depth] = pixels[y][x].getBlue();
                        }
                    }

                    try {
                        simpleImageLeftCanvas.setPixel(x, y, dataSimpleImage); // because data must not be null
                    } catch (InvalidDepthException e) {
                        e.printStackTrace();
                    }
                }
            }

            // logs that rendering of mandelbrot is finished
            FractalLogger.logRenderFinished(FractalType.MANDELBROT, simpleImageLeftCanvas);

            // fills left canvas (juliaset) PixelWriter instance with data
            pixels = juliaset.setAllPixels();

            FractalLogger.logRenderCall(mandelbrot);

            for (int y = 0; y < (int) rightCanvas.getHeight(); y++) {
                for (int x = 0; x < (int) rightCanvas.getWidth(); x++) {

                    // pareses color to PixelWriter instance
                    Color color = Color.rgb(pixels[y][x].getRed(), pixels[y][x].getGreen(), pixels[y][x].getBlue());
                    pwRight.setColor(x, y, color);

                    for (int depth = 0; depth < 3; depth++) {
                        if (depth == 0) {
                            dataSimpleImage[depth] = pixels[y][x].getRed();
                        } else if (depth == 1) {
                            dataSimpleImage[depth] = pixels[y][x].getGreen();
                        } else {
                            dataSimpleImage[depth] = pixels[y][x].getBlue();
                        }
                    }

                    try {
                        simpleImageRightCanvas.setPixel(x, y, dataSimpleImage); // because data must not be null
                    } catch (InvalidDepthException e) {
                        e.printStackTrace();
                    }
                }
            }

            // logs that rendering of juliaset is finished
            FractalLogger.logRenderFinished(FractalType.JULIA, simpleImageRightCanvas);


            // writes data from WriteableImage instance to GraphicsContext instance, which finally parses renders it into the canvas
            gcLeftCanvas.drawImage(wimLeftCanvas, 0, 0);
            FractalLogger.logDrawDone(FractalType.MANDELBROT);

            gcRightCanvas.drawImage(wimRightCanvas, 0, 0);
            FractalLogger.logDrawDone(FractalType.JULIA);
            return null;
        } catch (Exception e) {
            System.out.println("ERROR");
            System.out.println(e);
            return null;
        }
    }
    @Override
    protected void cancelled()
    {
        super.cancelled();
        updateMessage("The task was cancelled.");
    }

    @Override
    protected void failed()
    {
        super.failed();
        updateMessage("The task failed.");
    }

    @Override
    public void succeeded()
    {
        super.succeeded();
        updateMessage("The task finished successfully.");
    } ```


And i call it like this in the main:
   ``` Service service = new Service() {
            @Override
            protected Task createTask() {
                return new RenderTask(leftCanvas, rightCanvas);
            }
        };

    task.setOptions(mandelbrot, juliaset);
                    service.restart(); ```
  • The `FirstLineService` example in the [service javadoc](https://openjfx.io/javadoc/17/javafx.graphics/javafx/concurrent/Service.html) shows how to set a parameter (a url) for a service task invocation. Study that, actually copy it's code, make it run and try it with different URLs, then use what you learned to solve your problem. – jewelsea Dec 28 '21 at 10:42
  • I don't need to change the Parameters the first time, but every Time i call the Service i need different Parameters. – Thomas Perl Dec 28 '21 at 10:51
  • 2
    Please follow my advice to work out what you need to do. If you can't work it out with a simple example, it will be more difficult with your more complex example. Each time, prior to starting the FirstLineService, set the url, if you do that, it will run with a different parameter for that execution . . . try it . . . – jewelsea Dec 28 '21 at 11:01
  • It doesn’t look like your `createTask` method is doing enough to warrant the use of a `Service`. Is there a reason not to make the options into constructor arguments, instead of setting them via a setter method? Then you could just create the task and submit it directly to an appropriate executor. – James_D Dec 28 '21 at 11:29
  • 1
    Also consider `updateValue()` to signal intermediate results, for [example](https://stackoverflow.com/a/44056730/230513). – trashgod Dec 28 '21 at 17:46

0 Answers0