Scala SimpleSwingApplication没有重新绘制

时间:2013-11-05 10:33:49

标签: swing scala concurrency repaint scala-swing

我在Scala中有一个简单的swing应用程序。工作由一个单独的对象完成,但必须定期向启动它的GUI报告进度。问题是只有在Thread完成任务后才能看到更新。我尝试向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
      }
  }
}

更新我已经接受了提请注意问题原因的答案。我愚蠢地认为,因为工作者是一个Runnable,EventQueue.invokeLater会为它生成一个单独的线程。我一直指向Swing Worker的方向,这可能是正确的方法。

1 个答案:

答案 0 :(得分:2)

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

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