Multithreading 尝试更改内容时Scala swing面板消失(仅在运行线程时)

Multithreading 尝试更改内容时Scala swing面板消失(仅在运行线程时),multithreading,scala,scala-swing,boids,Multithreading,Scala,Scala Swing,Boids,所以我正在为学校写一个boid模拟程序。我的程序支持多个不同的BOID组,这些BOID组不与其他组聚集,它们都有不同的设置,我在创建新部落时通过在程序的主GUI中添加一个BoxPanel来完成这些设置,并且这些BoxPanel有一个设置按钮,可以打开带有组设置的新框架 当我启动程序并添加代码中所有预定义的部落时,这一点非常有效。现在,我在GUI中创建了一个新的部分,让您可以创建这些BOID的新组,并在模拟运行时添加它们,现在是我开始遇到问题的时候了 出于某种奇怪的原因,它添加了组,在模拟中有正确

所以我正在为学校写一个boid模拟程序。我的程序支持多个不同的BOID组,这些BOID组不与其他组聚集,它们都有不同的设置,我在创建新部落时通过在程序的主GUI中添加一个BoxPanel来完成这些设置,并且这些BoxPanel有一个设置按钮,可以打开带有组设置的新框架

当我启动程序并添加代码中所有预定义的部落时,这一点非常有效。现在,我在GUI中创建了一个新的部分,让您可以创建这些BOID的新组,并在模拟运行时添加它们,现在是我开始遇到问题的时候了

出于某种奇怪的原因,它添加了组,在模拟中有正确的设置,但它不会将BoxPanel添加到主GUI中。它使我在模拟一侧的整个设置栏完全消失。我对此进行了测试,如果我在我的计算线程开始时添加部落,它会做同样的事情,因此这似乎是多线程和swing的问题。你知道是什么原因造成的吗?或者如何修复?我对此完全感到困惑

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

以下是将BoxPanel添加到主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()
哦,我测试了如果它真的通过打印出内容的大小来添加它应该添加的内容,并且所有内容都匹配得很好,它只是不会绘制它们

编辑:经过一番挖掘之后,似乎真的需要从线程更新swing。很多地方都建议使用SwingWorker,但从我收集的信息来看,我认为它不适合我的程序,因为它是一个连续的模拟,而且我必须在每一帧都不断地制作新的SwingWorker

EDIT2:尝试从线程调用方法,如下所示:

SwingUtilities.invokeLater(new Runnable() {
  override def run() {
    GUI2D.addTribe(tribe)
  }
});

没什么区别我开始认为这是我如何使用TribeBoxPanel和TribeSettingFrame的问题。这些对象都只包含一个返回所需BoxPanel或Frame的方法。这个实现糟糕吗?如果是这样的话,创建动态箱面板和框架的更好方法是什么?

Swing不是线程安全的

跟我说


Swing不是线程安全的

听到合唱了吗?有

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

SwingUtilities.invokeLater(new Runnable() {
    @Override public void run() {
        // your stuff
    }
});
在Scala中,支持这一点的方式如下:

Swing.invokeLater(/* your stuff */)

首先,您应该让UI线程处理所有UI操作。 简单的方法应该遵循Scala代码:

Swing.onEDT { GUI2D.addTribe(tribe) }
但正如你已经指出的,这并不能解决你的问题。我遇到了一个非常类似的问题,我只更改了
Swing.Label
的文本内容,有时它就消失了

事实证明,只有当文本太长,无法在标签最初为自己保留的区域内显示时,它才会消失。因此,解决问题的一种方法是在创建optionPanel时为其提供更大的初始尺寸

Swing.onEDT { top.optionPanel.preferredSize = new Dimension(width,height) }

我不确定是否必须在第一次绘制组件之前(在调用Frame.open()之前)设置此选项。

嘿,Rusina,欢迎使用堆栈溢出。上面的区块文本是很难阅读的,如果你想要一个快速简洁的答案,考虑总结你的问题:)格式化一点点,并添加一个TL;医生,我希望这样更好。谢谢你的回答!但这似乎不起作用,我尝试将修改GUI的代码放在那里,但它仍然冻结。。我开始认为这就是我实现TribeSettingFrame和TribeBoxPanel的方式,这些只是具有返回所需BoxPanel或Frame的定义的对象,可能是在线程中没有正确处理它们吗?我现在正在测试这个。