@sanex3339

Как сделать repaint canvas'а в цикле?

Есть канвас, который у которого вызывается repaint в бесконечном цикле. При репаинте канвасу задается случайный цвет.

Ожидание: у канваса должны меняться постоянно цвета, (в данный момент 1 итерация цикла проходит быстро, потом будет обрабатываться около 1-2 секунд).

Реальность: цвет у канваса не обновляется. Если сделать не бесконечный цикл, а конечный - визуально канвас обновится, как только закончится этот цикл.

Как сделать так, что бы канвас обновлялся визуально в процессе цикла?

Ниже показан callback, который вызывается в цикле (метод update() - repaint() + установка цвета перед repaint'ом):
public void redrawCanvas (Color color) {
        System.out.println(color.getRed() + ", " + color.getGreen() + ", " + color.getBlue());

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


В консоль выводятся корректные цвета.

UPD: если делать через Timer вместо while вылетает java.util.concurrent.RejectedExecutionException эксепшн, я так понял из за того, что у меня получение рандомного цвета разбросано по потокам, через ExecutorService.

Полный код:
Основной класс - handler клика по кнопке запускает цикл, redrawCanvas - коллбэк, выполняющийся каждый раз, когда получен цвет внутри цикла.

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() возвращает массив из 3-х случайных int 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();
        }
    }
}
  • Вопрос задан
  • 328 просмотров
Решения вопроса 1
@zelan
Кратко обо мне не получится.
Скорее всего цикл у вас запущен в потоке отрисовки и, тем самым, пока идут вычисления в цикле - поток отрисовки блочится. Если цикл завершится, то и отрисовка выполнится. Попробуйте выделить логику изменения параметров и принудительного вызова отрисовки в отдельном потоке.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы