【问题标题】:Platform.runLater() is running the code, but GUI is frozen as soon as the runLater() thread starts. How do I make it so the GUI updates?Platform.runLater() 正在运行代码,但只要 runLater() 线程启动,GUI 就会冻结。我如何让它更新 GUI?
【发布时间】:2022-01-26 20:35:51
【问题描述】:

我正在尝试创建 PacMan 游戏,但我正在尝试使用 platform.runLater() 来实现多线程并且 GUI 没有更新,即使我已经检查过代码本身正在运行。以下是相关代码:

这是启动 Platform.runLater() 线程的代码块。

private void startTimer() {
        this.timer = new java.util.Timer();
        TimerTask timerTask = new TimerTask() {
            public void run() {
                Platform.runLater(new Runnable() {
                    public void run() {
                        update();
                        
                    }
                });
            }
        };
        long frameTimeInMilliseconds = (long)(1000.0 / FRAMES_PER_SECOND);
        this.timer.schedule(timerTask, 0, frameTimeInMilliseconds);
    }


private void update() {
        view.update(this.modelo);   
    }

这是它正在运行的代码块。

    public void update(Model gc) {
        updateMap(gc);
    }
//Sets the image on the already initialized imageviews (not updating gui for some reason)   
private void updateMap(Model gc) {
    for(int i = 0; i < rowCount; i++) {
        for(int j = 0; j < columnCount; j++) {
            char valor = gc.getCelulas(i, j);
            if(valor == 'E' || valor == 'W') {
                visaoMapa[i][j].setImage(imgsMapaVazio[i][j]);          
            }
            else {
                if(valor == 'S')
                visaoMapa[i][j].setImage(imgsMapaCheio[i][j]);
            }
        }
    }
    
}

更新 #1 按照 James_D 的建议,我尝试将 startTimer 方法更改为:

private void startTimer() {
        AnimationTimer timer = new AnimationTimer() {
            @Override
            public void handle(long now) {
                update();
            }
        };
        timer.start();
    }

但是,问题仍然存在。

【问题讨论】:

标签: multithreading javafx


【解决方案1】:

如果 updateMap() 中的循环需要很长时间才能完成,而只能在少数索引上运行 UI 更新,那么这可能是你的罪魁祸首,因为你仍在通过 Platform 在 UI 线程上运行 updateMap()。 runLater()

尝试在 UI 线程之外调用 update() :

private void startTimer() {
    this.timer = new java.util.Timer();
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            update();
        }
    };
    long frameTimeInMilliseconds = (long) (1000.0 / FRAMES_PER_SECOND);
    this.timer.schedule(timerTask, 0, frameTimeInMilliseconds);
}

然后使用 Platform.runLater() 在循环内执行 UI 更新:

private void updateMap(Model gc) {
    for (int i = 0; i < rowCount; i++) {
        for (int j = 0; j < columnCount; j++) {
            final int fi = i;
            final int fj = j;
            char valor = gc.getCelulas(i, j);
            if (valor == 'E' || valor == 'W') {
                Platform.runLater(() -> visaoMapa[fi][fj].setImage(imgsMapaVazio[fi][fj]));
            } else if (valor == 'S') {
                Platform.runLater(() -> visaoMapa[fi][fj].setImage(imgsMapaCheio[fi][fj]));
            }
        }
    }
}

请注意,您发布的代码部分不能用于重现问题,因为缺少某些类型,因此我无法测试此解决方案。

【讨论】:

  • 这将使可运行队列充满潜在的数百个可运行项目,以便在每个脉冲之后运行(取决于地图的大小),这可能会正常,但可能不会。
  • 我明白了,我会在 UI 更新之间添加短暂的暂停以允许 UI 更新,但我意识到该任务将在每一帧运行,我认为在每帧的基础上要做很多工作.
猜你喜欢
  • 2014-09-25
  • 2017-12-02
  • 2015-11-21
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多