我最近发现,我的scala swing应用程序表现得非常奇怪。 以下测试应用程序绘制一条在屏幕上移动的线。 当我第一次运行程序时,我感到震惊的是看起来有多么迟钝,因为线路至少没有顺畅地移动。 但是,一旦swing似乎识别出由例如鼠标悬停或按下的键触发的事件,一切似乎都按预期顺利运行。然而,只要鼠标离开摆动窗口,或者没有按下更多按键,摆动就会再次延迟。我不是在慢速机器上工作,因为我没有类似的python问题,所以我仍然认为scala.swing库对我来说似乎非常糟糕。 有没有我在这里看不到的重大错误?我不正确地使用scala.swing吗?是什么让scala.swing变得如此滞后,但只有在用户没有触发事件时才会出现这种情况?
这是我创建的非常小的测试应用程序。请复制并亲自试用。
object PerformanceTest {
def main(args:Array[String]): Unit ={
var i =0
val (x1, y1) = (0,0)
val (x2, y2) = (400,300)
val frame = new MainFrame{
title = "performance test"
centerOnScreen()
contents = new BorderPanel{
layout += new Panel{
override def paint(g:Graphics2D): Unit ={
g.drawLine(x1+i, y1,x2-i, y2)
}
} -> BorderPanel.Position.Center
listenTo()
}
size = new Dimension(400, 300)
visible = true
}
while(true){
frame.repaint()
i += 1
Thread.sleep(20)
}
}
}
答案 0 :(得分:2)
你有没有机会在Linux上看到这个?我最近在JDK Linux中发现了一个刷新错误,听起来像是一回事。请参阅this question。
所以我所做的就是致电.toolkit.sync()
。这有点可怕,因为它根据我的理解同步整个窗口系统,而你实际上只想同步一个单独的组件。但我还没有找到更好的解决方法。
另请注意,您应该只刷新面板而不是框架。然后你必须填充背景矩形或声明它不透明。您也不应该在事件派发线程之外创建框架。而不是在Thread.sleep
的主线程上等待,更好的方法是使用Swing计时器。通过这些更改,我得到了:
object PerformanceTest {
import scala.swing._
def main(args: Array[String]): Unit = Swing.onEDT /* ! */ {
var i = 0
val (x1, y1) = (0,0)
val (x2, y2) = (400,300)
val panel = new Panel {
opaque = false // !
override def paint(g: Graphics2D): Unit =
g.drawLine(x1 + i, y1, x2 - i, y2)
}
lazy val frame = new Frame {
title = "performance test"
contents = new BorderPanel {
layout += panel -> BorderPanel.Position.Center
}
size = new Dimension(400, 300)
centerOnScreen()
override def closeOperation(): Unit = {
timer.stop()
dispose()
}
}
lazy val timer: javax.swing.Timer = new javax.swing.Timer(20,
Swing.ActionListener { _ =>
i = (i + 1) % 400
panel.repaint()
panel.toolkit.sync() // linux bug?
}
)
timer.start()
frame.open()
}
}
PerformanceTest.main(null) // test
答案 1 :(得分:0)