因此,我正在编写一个boid模拟程序,作为一个学校项目。我的程序支持这些boid的多个不同组,这些组不与其他组成群,它们都具有不同的设置,我可以通过在创建新部落时将BoxPanel添加到程序的主GUI来实现,并且这些BoxPanel具有设置按钮,使用组设置打开一个新框架。

当我启动程序并添加代码中的所有预定义部落时,此方法非常有效。现在,我制作了GUI的新部分,使您可以对这些boid进行新的分组,并在模拟运行时(这是问题开始于我的时候)添加它们。

出于某种奇怪的原因,它在模拟中添加了正确的设置,从而很好地添加了该组,但不会将BoxPanels添加到主GUI中。它使我在仿真侧拥有的整个设置栏完全消失。我对此进行了测试,如果我在计算线程的开头添加部落,它也会做同样的事情,因此这似乎是多个线程和摆动的问题。任何想法是什么原因造成的或如何解决此问题?我对此完全感到困惑。

tl; dr: 当我尚未启动线程时,以下添加部落的代码可以正常工作,但是如果我在启动线程后尝试使用它,则optionPanel显示为空。

这是将BoxPanels添加到主gui的代码:

      def addTribe(tribe: Tribe) = {
        tribeFrames += new TribeSettingFrame(tribe)
        tribeBoxPanels += new TribeBoxPanel(tribe)
        this.refcontents
      }

      private def refcontents = {
        top.optionPanel.contents.clear()
        top.optionPanel.contents += new BoxPanel(Orientation.Vertical) {
          tribeBoxPanels.foreach(contents += _.tribeBoxPanel)
        }
        top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
          contents += top.addTribeButton
        }
        top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
          contents += top.vectorDebugButton
        }
      }


  new Thread(BoidSimulation).start()

哦,我通过打印出内容的大小来测试它是否真的添加了应该添加的内容,并且一切都很好,只是不会绘制它们。

编辑:经过一些挖掘后,似乎确实是从线程更新挥杆的一件事。很多地方都建议使用SwingWorker,但是从我收集的信息中,我认为它不适合我的程序,因为它是连续的模拟,而且我必须继续在每一帧制作新的SwingWorker。

EDIT2:尝试从线程中像下面这样调用方法:
SwingUtilities.invokeLater(new Runnable() {
  override def run() {
    GUI2D.addTribe(tribe)
  }
});

没有任何区别。 我开始认为这与我使用TribeBoxPanel和TribeSettingFrame有关。这些对象都只包含一种返回所需BoxPanel或Frame的方法。这个实现不好吗?如果是这样,那么创建动态BoxPanels和Frames的更好方法是什么?

最佳答案

摆动不是线程安全的。

在我之后重复。

摆动不是线程安全的。

听到合唱吗? Swing is not thread safeofficial documentation

也有一个非常简单的解决方法。

SwingUtilities.invokeLater(new Runnable() {
    @Override public void run() {
        // your stuff
    }
});

在Scala中,这受以下支持:
Swing.invokeLater(/* your stuff */)

09-16 05:11