所以我实际上不确定问题到底是什么。它可能与我处理线程的方式有关,但我不知道如何解决这个问题。
该程序是一个具有不同“部落”生物的简单生物模拟,我希望拥有它,以便当我创建一个新部落时它在 GUI 中有自己的面板。现在这在我启动线程之前完美运行,但之后它总是冻结。我知道 Swing 不是线程安全的,但我不确定如何解决这个问题。
这是添加面板的代码:
val tribeBoxPanels = Buffer.empty[TribeBoxPanel]
val tribeFrames = Buffer.empty[TribeSettingFrame]
val addTribeFrame = ChooseTribeFrame.frame
val addFlockingFrame = AddFlockingFrame.frame
def addTribe(tribe: Tribe) = {
pause()
tribeFrames += new TribeSettingFrame(tribe)
tribeBoxPanels += new TribeBoxPanel(tribe)
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
}
pause()
}
这是(可运行)线程的代码:
private var running = true
def pause() = {
if (running) {
running = false
t.stop()
}
else {
running = true
t = new Thread(BoidSimulation)
t.start()
}
}
var t = new Thread(BoidSimulation)
t.start()
我试图在添加部落时停止线程,但这似乎不起作用,GUI 仍然冻结。我也尝试了 t.interrupt() (因为这是更好的方法),但这也不起作用。
编辑:我的问题可能是我试图从另一个不是 GUI2D 的对象(该方法所在的对象)调用 AddTribe 方法。也许如果我将所有代码粘贴到 GUI2D 类中它会起作用吗?
编辑2:尝试调用这样的方法:
def invoke(tribe: Tribe) = new Runnable() { def run() = addTribe(tribe) }
但没有帮助,我试图添加东西的栏仍然冻结。
我还尝试打印出调用该方法的线程,这就是我得到的:
Thread[Thread-2,5,main] <- println(t)
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- After this it freezes.
所以该方法是从 AWT 线程调用的,但它仍然冻结 GUI。所以线程不是我的问题?
编辑3:我想我发现了我的问题!其实是很倒退的。因为该方法在按下按钮时被调用 Swing 试图完成用于计算线程的代码,这就是导致它冻结的原因。现在我需要找出与 SwingUtilities.invokelater() 完全相反的东西
编辑 4:尝试创建一个新的可运行文件来运行该代码,但它仍然以某种方式从 AWT 线程中调用。这是什么原因以及如何让代码从计算线程中运行?
class AddTribe(dist: Int, maxSpeed: Int, boidMass: Int, color: Color, behavior: Behavior, boidAmount: Int) extends Runnable {
println(Thread.currentThread())
def run() = BoidSimulation.addTribe(dist: Int, maxSpeed: Int, boidMass: Int, color: Color, behavior: Behavior, boidAmount: Int)
}
case ButtonClicked(e) if (e == addButton) => {
new AddTribe(distSlider.value, maxSpdSlider.value / 10, massSlider.value / 10, color, new Flocking(separationSlider.value, alignmentSlider.value, cohesionSlider.value), boidSlider.value).run()