2016-02-16 3 views
1

Недавно я обнаружил, что мои приложения scala swing ведут себя очень странно. Следующее тестовое приложение рисует линию, которая перемещается по экрану. Когда я запускал программу в первый раз, я был в шоке от того, насколько лагги-качели кажутся, так как линия не двигается сглаженно. НО, как только качание распознает события, вызванные, например, курсором мыши или нажатыми клавишами, все кажется плавным и ожидаемым. Однако, как только мышь покидает окно поворота, или больше не нажимаются клавиши, колебание снова ломается. Я не работаю на медленной машине, и, поскольку у меня нет подобных проблем с питоном, я все равно думаю, что библиотека scala.swing мне кажется очень плохой. Есть ли большая ошибка, которую я не вижу здесь? Я использую 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

Вы рассматривали правила EDT (о потоковом)? Этот код выглядит как одно вопиющее нарушение EDT. – Rekin

+0

После вашего комментария я немного прочитал об EDT. Похоже, я действительно нарушаю много вещей, о которых я даже не знаю. Я не вызывал swing ui любым edt-методом вроде invokeLater (или так я и нашел), и я не использовал какой-либо прототипный метод для обработки таких событий, как akka. В соответствии с вашим предложением я могу предположить, что это «отстающее» поведение, скорее всего, будет исправлено, как только я научусь правильно использовать edt? И если да, можете ли вы посоветовать мне какой-то учебник для этого? Я могу найти только java-специфическую документацию по edt, и такие методы, как invokeLater, не существуют в scala ... или они? – Julian

+0

Ну, я ничего не знаю о Scala + Swing, но я использовал Scala и rxScala. Эта библиотека была на самом деле похожа на находку, когда дело доходит до потоков. Я помню, что просто поместил единственный метод «subscribeOnEdt», и все было создано за кулисами. Очень освобождает. Я бы рискнул предположить, что обычная библиотека Scala Swing предоставляет некоторый код оболочки для EDT, так как это самое первое, что нужно позаботиться в области Swing. – Rekin

ответ

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 
+0

да, моя операционная система элементарная os , что на самом деле действительно звучит точно так же, как проблема, которую я получаю! – Julian

0

Сэр, вы знаете, что нарушаете Swing EDT rules?

+0

Вы могли бы привести пример того, как не нарушать правила swing edt? Я все еще не могу найти учебник scala swing, который бы даже упомянул об этом ... довольно забавно, так как это кажется очень важным? – Julian