S
S
sanex33392016-01-04 19:57:36
Java
sanex3339, 2016-01-04 19:57:36

How to repaint a canvas in a loop?

There is a canvas that calls repaint in an endless loop. When repainting the canvas, a random color is set.
Expectation: the canvas should change colors constantly, (at the moment, 1 iteration of the loop is fast, then it will be processed for about 1-2 seconds).
Reality: the color of the canvas is not updated. If you make not an infinite loop, but a final one, visually the canvas will be updated as soon as this loop ends.
How do I make the canvas update visually as it cycles?
Below is a callback that is called in a loop (update() method - repaint() + setting color before repaint):

public void redrawCanvas (Color color) {
        System.out.println(color.getRed() + ", " + color.getGreen() + ", " + color.getBlue());

        this.renderCanvas.update(color);
        this.renderWindow.repaint();
    }

The correct colors are output to the console.
UPD: if you do it through Timer instead of while, a java.util.concurrent.RejectedExecutionException exception occurs, as I understand it, due to the fact that my receipt of a random color is scattered across threads, through the ExecutorService.
Full code:
Main class - button click handler starts the loop, redrawCanvas is a callback that runs every time a color is received inside the loop.
private void renderButtonHandler (ActionEvent event) {
        RenderThreadsController renderThreadsController = new RenderThreadsController(this::redrawCanvas);
        renderThreadsController.run();
    }

    public void redrawCanvas (Color color) {
        System.out.println(color.getRed() + ", " + color.getGreen() + ", " + color.getBlue());

        this.renderCanvas.update(color);
        this.renderWindow.repaint();
    }

RenderThreadsController.java
thread.get() returns an array of 3 random ints 0-255
public class RenderThreadsController implements Runnable {
    final private int threadsCount = 8;

    private ExecutorService executorService;
    private List<Future<int[]>> threadsPool;
    private int currentSample = 1;
    private RedrawCanvas callback;

    RenderThreadsController(RedrawCanvas callback) {
        Thread thread = new Thread(this);
        thread.start();

        this.executorService = Executors.newCachedThreadPool();
        this.threadsPool = new ArrayList<>();
        this.callback = callback;
    }

    public void run() {
        for (int i = 0; i < this.threadsCount; i++) {
            this.threadsPool.add(
                this.executorService.submit(
                    new RenderThread(
                        this.currentSample++
                    )
                )
            );
        }

        int t = 20;

        /*while (t > 0) {
            this.startThread();
            t--;
        }*/

        while (this.threadsPool.size() > 0) {
            this.startThread();
        }

        executorService.shutdown();
    }

    private void startThread () {
        try {
            Future<int[]> thread = this.threadsPool.get(0);

            int[] color = thread.get();

            this.callback.redrawCanvas(new Color(color[0], color[1], color[2]));

            this.threadsPool.remove(0);
            this.threadsPool.add(
                this.executorService.submit(
                    new RenderThread(
                        this.currentSample++
                    )
                )
            );
        } catch (InterruptedException|ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Kornachev, 2016-01-04
@sanex3339

Most likely, your cycle is running in the rendering thread and, thus, while the calculations are in progress in the cycle, the rendering thread is blocked. If the loop ends, then the rendering will be executed. Try to isolate the logic for changing parameters and forcing a draw call in a separate thread.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question