1

I have a simple swing application in Scala. Work is done by a separate object but progress must be periodically reported to the GUI which launched it. The problem is that the updates are only visible once the Thread has completed its task. I've tried adding various calls to repaint() top.peer.repaint() and Thread.sleep(0) all to no avail and all the while feeling that the fact that I'm resorting to adding these is a sign I'm doing something wrong.

I remember struggling and overcoming this issue with this back when I used to develop in Java and have tried to structure my solution based on what I recall being the right approach but I must be missing something.

Here is a simple example which reproduces the problem:

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
      }
  }
}

Update I've accepted the answer which drew attention to the cause of the problem. I stupidly thought that since the worker was a Runnable that EventQueue.invokeLater would spawn a separate thread for it. I have been pointed in the direction of Swing Worker which is probably the right way to go.

4

1 回答 1

2

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

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

于 2013-11-05T11:17:49.030 回答