【问题标题】:The function call blocks GUI from updating in java函数调用阻止 GUI 在 java 中更新
【发布时间】:2017-12-17 14:35:26
【问题描述】:

我目前正在使用 AI 游戏算法在 java 中实现一个 quoridor 游戏。在“人类”点击移动后,需要更新 gui 并让 AI 开始思考。 我在面板中有这样的东西:

public void mouseClicked(MouseEvent e)
    {
       gameBoard.executeMove( movePawn );
       repaint();
       gameboard.callAi();
    }

在调用函数 callAi() 之后,我进入了一个循环,该循环需要花费太多时间才能完成。另一方面,gui 冻结了,它没有更新,甚至认为在 AI“开始思考”之前调用了 repaint 方法。我试图在调用 AI 之前延迟,但它不起作用。我写了这个:

try
{ TimeUnit.MILLISECONDS.sleep(5);}
catch{}

我能做些什么来解决这个问题?也许它与线程有关,但我对 Java 中的线程不太友好。

【问题讨论】:

  • @VasylLyashkevych updateUI 不是用于生成 UI 状态已更改并应更新的通知,而是指示组件外观委托已更改,它们应重新安装更新 - 除非您尝试在运行时更改外观和感觉,否则永远不需要调用此方法 - 它甚至无法解决 OP 遇到的问题
  • 您已经绊倒了 Swing 的单线程特性,基本上,您阻塞了负责处理绘制事件的线程。有关更多详细信息和可能的解决方案,请参阅Concurrency in Swing
  • @JoanPlepi 当您阻塞负责处理绘制请求的线程时,如何更新 GUI?您假设 repaint 执行实际的绘画,如果没有,它只是向 RepaintManager 发出请求,然后确定需要绘画的内容并将绘画事件安排到事件队列中,然后由事件调度线程处理 - 您正在阻止
  • @JoanPlepi 我想你需要去看看Painting in AWT and Swing 以更好地了解绘画实际是如何工作的......加上我提到的上一个链接
  • @JoanPlepi 按照 Concurrency in Swing 链接中的建议,使用SwingWorker 执行长时间运行的操作,然后使用它的功能更新 UI 安全- 因为 Swing 也不是线程安全的

标签: java multithreading swing loops


【解决方案1】:

我强烈建议您阅读一下 EDT(事件调度线程)是什么。

Java Event-Dispatching Thread explanation

其中一个答案很好地解释了它。快速 TLDR:基本上,GUI 冻结的原因之一是因为您在 EDT 中包含的 AI 方法(我不能肯定地说 gameBoard.executeMove(...) 方法)。 EDT 旨在更新 GUI,而不是运行需要大量计算时间的方法。

从 GUI 中获取游戏逻辑代码并进入主线程/新线程(不是 EDT)。如果您绝对需要 EDT 中的游戏逻辑,则在 EDT 中创建一个新线程,让它进行游戏计算,最后使用 Swing.Utilties.invokeLater(...) 方法更新 GUI。

可能跟线程有关,不过我对Java中的线程不太友好。

在制作游戏时一定要熟悉线程,尤其是 EDT。

【讨论】:

    【解决方案2】:

    您应该使用SwingWorker 来完成 AI 工作。所有的更新和处理都发生在 Swing 中的单个线程上,所以如果你阻止它,那么你将冻结 UI。

    https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-18
      • 2016-03-18
      • 1970-01-01
      • 2015-04-13
      • 1970-01-01
      • 2021-05-14
      相关资源
      最近更新 更多