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

时间:2015-03-04 10:28:50

标签: multithreading scala scala-swing boids

所以我正在编写一个boid模拟程序作为学校的项目。我的程序支持这些boid的多个不同组,它们不会聚集在其他组中,它们都有不同的设置,我通过在制作新部落时将BoxPanel添加到程序的主GUI中,并且那些BoxPanel具有设置按钮,使用组设置打开新框架。

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

由于一些奇怪的原因,它添加组很好,正确设置到模拟但它不会将BoxPanel添加到主GUI。它使我在模拟一侧的整个设置栏完全消失。我测试了这个,如果我在计算线程的开头添加部落它会做同样的事情,所以这似乎是多线程和摆动的问题。是什么导致了这个或如何解决这个问题?我对这完全感到困惑。

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

这里是将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()

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

编辑:经过一些挖掘之后,看起来似乎是一个从线程更新摆动的事情。很多地方都建议使用SwingWorker,但是从我收集到的信息中我不认为它适合我的程序,因为它是一个连续的模拟,而且我必须每帧都继续制作新的SwingWorkers。

EDIT2:尝试从这样的线程调用方法:

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

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

2 个答案:

答案 0 :(得分:0)

Swing不是线程安全的。

在我之后重复。

Swing不是线程安全的。

听到合唱? Swing is not thread safeofficial documentation

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

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

在Scala中,支持为:

Swing.invokeLater(/* your stuff */)

答案 1 :(得分:0)

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

Swing.onEDT { GUI2D.addTribe(tribe) }

但正如您已经指出的那样,这不会解决您的问题。我有一个非常类似的问题,我只更改了Swing.Label的文本内容,有时它只是消失了。

事实证明它只是消失了,当文本太长而无法在Label最初为自己保留的区域内显示它时。因此,解决问题的一种方法是在创建选项时使用更大的初始大小。

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

我不确定在首次绘制组件之前是否必须设置它(在调用Frame.open()之前)。