Scala SimpleSwingApplication未重新绘制

Scala SimpleSwingApplication未重新绘制,swing,scala,concurrency,repaint,scala-swing,Swing,Scala,Concurrency,Repaint,Scala Swing,我在Scala中有一个简单的swing应用程序。工作由单独的对象完成,但必须定期向启动它的GUI报告进度。问题在于,只有在线程完成任务后,更新才会可见。我尝试过向repaint()top.peer.repaint()和Thread.sleep(0)添加各种调用,但都无济于事,而且我一直觉得我正在添加这些调用,这表明我做错了什么 我记得,当我过去用Java开发时,我一直在努力克服这个问题,并试图根据我所记得的正确方法来构建我的解决方案,但我肯定错过了一些东西 下面是一个简单的例子,再现了这个问题:

我在Scala中有一个简单的swing应用程序。工作由单独的对象完成,但必须定期向启动它的GUI报告进度。问题在于,只有在线程完成任务后,更新才会可见。我尝试过向
repaint()
top.peer.repaint()
Thread.sleep(0)
添加各种调用,但都无济于事,而且我一直觉得我正在添加这些调用,这表明我做错了什么

我记得,当我过去用Java开发时,我一直在努力克服这个问题,并试图根据我所记得的正确方法来构建我的解决方案,但我肯定错过了一些东西

下面是一个简单的例子,再现了这个问题:

import scala.swing._
import scala.swing.event.ButtonClicked
import BorderPanel.Position._
import java.awt.EventQueue

class HeavyLifter extends Runnable {
      override def run = {
        UpdateInterface.say("Performing Useful Work")
        for (i <- 0 until Int.MaxValue) {
              UpdateInterface.say(i.toString)
      }
  }
}

object UpdateInterface extends SimpleSwingApplication {

      private val txtLog = new TextArea(32,64) {
            editable = false
      }
      private val scrollPane = new ScrollPane(txtLog)
      private val btnGo = new Button("Go")

      def say(strWhat : String) = {
        txtLog.append(strWhat + "\n")
      }

      def top = new MainFrame {
            contents = new BorderPanel {
            listenTo(btnGo)

            reactions += {
                case ButtonClicked(`btnGo`) => EventQueue.invokeLater(new HeavyLifter)
            }
            layout(scrollPane) = Center
            layout(btnGo) = South
      }
  }
}
导入scala.swing_
导入scala.swing.event.ButtonClicked
导入BorderPanel.Position_
导入java.awt.EventQueue
类HeavyLifter扩展了Runnable{
覆盖def运行={
UpdateInterface.say(“执行有用的工作”)
对于(i EventQueue.invokeLater)(新的HeavyLifeter)
}
布局(滚动窗格)=居中
布局(btnGo)=南部
}
}
}

Update我已经接受了引起人们注意问题原因的答案。我愚蠢地认为,既然worker是可运行的,那么
EventQueue.invokeLater
将为它生成一个单独的线程。我已经被指向Swing worker的方向,这可能是正确的方向。

EventQueue.invokeLater
使循环在调度线程(即UI线程)中运行,这基本上意味着UI线程被占用来执行for循环,一旦完成,它将更新UI并执行其他任务,毕竟线程一次只能执行一件事。这就是在循环完成后更新UI的原因


您可以做的是,在一个新线程中运行worker runnable,并从该worker代码为每个更新分派一个新的runnable(其run方法更新了文本区域值)使用
EventQueue.invokeLater

如果我为工作程序生成一个新的可运行文件,并且每个更新都有自己的可运行文件,我会不会在更新写入文本区域的顺序方面出现同步问题?我不这么认为,毕竟EventQueue是一个队列,所以您放在第一位的内容将首先被选中。此外,我建议putti在for循环中进行睡眠,以便进度合理啊,没问题,如果没有“每个更新都有自己的可运行”的添加,它似乎可以正常工作。+1到you@DuncanACoulter-这正是Java类的想法。它生成一个单独的线程,并将GUI更新报告委托给事件调度线程。Java类使用Ja但是,请注意,是否有人编写了一个Scala包装,以使其更符合Scala的习惯。关于同步:如果您将变异数据的范围限制在工作线程内,并且最终只返回完成的对象,您就可以了。这与actors的工作方式没有什么不同。Scala swing中有一个SwingWorker我最初没有使用EventQueue,只是生成了一个线程。我刚刚意识到这不起作用。