2017-10-23 4 views
1

Ich bin eine Anwendung mit TornadoFX 1.7.11 mit Kotlin 1.1.51 auf JDK 8u121 bauen.Label Text wird nicht aktualisiert, obwohl UI-Thread reagiert scheint

Ich versuche, eine lange laufende Aufgabe in einem separaten Thread auszuführen und Fortschritt in der Benutzeroberfläche anzuzeigen, die eine Fortschrittsleiste und eine Beschriftung verwendet. Seltsamerweise wird das Etikett nicht aktualisiert. Ich dachte, dass ich die Aufgabe irgendwie auf dem UI-Thread ausgeführt habe und es hängt, aber der Fortschrittsbalken funktioniert und die Benutzeroberfläche reagiert anders (steuert die Arbeit usw.).

Screenshot with progressbar half-filled and console messages showing that message is updated. A red arrow is pointing to a place where label should be, but no text is visible there.

Ich habe auch versucht, das Etikett mit Scenic manuell bearbeiten und es funktionierte. Ich habe keine Ideen mehr, könnt ihr mir helfen?

sind hier etwas vereinfacht Code-Schnipsel:

MainView.kt
class MainView : View("") { 
    private val controller: MainController by inject() 

    override val root = borderpane { 
     bottom(TasksView::class) 
    } 

    init { 
     controller.reloadTranslations().completed.onChange { 
      // do some lightweight UI stuff 
     } 
    } 
} 
MainController.kt
class MainController : Controller() { 
    private val tasksController: TasksController by inject() 

    fun reloadTranslations(): TaskStatus { 
     val task = TaskStatus() 
     tasksController.tasks.add(task) 
     runAsync(task) { 
      updateMessage(messages["loadingTranslations"]) 
      BibxCache.rebuild().subscribe { 
       updateMessage(messages["loadingTranslations"] + " " + it.loaded) // for debugging 
       updateProgress(it.loaded.toLong(), it.total.toLong()) 
      } 
     } 
     return task 
    } 

    fun getTranslations() = BibxCache.values.toSortedSet() 
} 
TasksView.kt
class TasksView : View() { 
    override val root = vbox() 

    val controller: TasksController by inject() 

    init { 
     controller.tasks.onChange { 
      root.clear() 
      controller.tasks.map { TaskRow(it) }.forEach { root.add(it) } 
     } 
    } 
} 

class TaskRow(task: TaskStatus) : HBox() { 
    init { 
     val progressBar = ProgressBar(task.progress.get()) 
     progressBar.bind(task.progress) 
     val label = Label(task.message.get()) 
     label.bind(task.message) 
     task.message.onChange { println(it) } // for debugging 
     children.addAll(
       progressBar, 
       Label(task.message.get()) 
     ) 
    } 
} 
TasksController.kt
class TasksController : Controller() { 
    val tasks: ObservableList<TaskStatus> = FXCollections.observableArrayList() 

    init { 
     tasks.onChange { change -> 
      change.next() 
      change.addedSubList.forEach { added -> 
       added.completed.onChange { 
        tasks.remove(added) 
       } 
      } 
     } 
    } 
} 

Antwort

2

Ihr Code isn nicht lauffähig, aber ich habe eine minimale Stichprobe basierend auf diesen Konzepten erstellt, die einen eher idiomatischen Ansatz verwendet.

class MainView : View("Tasks") { 
    private val mainController: MainController by inject() 

    override val root = borderpane { 
     setPrefSize(600.0, 400.0) 
     top { 
      button("Start task").action { 
       mainController.reloadTranslations() 
      } 
     } 
     bottom(TasksView::class) 
    } 
} 

class MainController : Controller() { 
    private val tasksController: TasksController by inject() 

    fun reloadTranslations(): TaskStatus { 
     val task = TaskStatus() 
     tasksController.tasks.add(task) 
     runAsync(task) { 
      updateMessage(messages["loadingTranslations"] + " $this...") 
      Thread.sleep(Random().nextInt(2000).toLong()) 
      updateMessage(messages["loadingTranslations"] + " $this - half way") 
      updateProgress(50.0, 100.0) 
      Thread.sleep(Random().nextInt(2000).toLong()) 
     } 
     return task 
    } 
} 

class TasksView : View() { 
    val controller: TasksController by inject() 

    override val root = vbox { 
     bindChildren(controller.tasks) { task -> 
      hbox { 
       progressbar(task.progress) 
       label(task.message) 
      } 
     } 
    } 
} 

class TasksController : Controller() { 
    val tasks: ObservableList<TaskStatus> = FXCollections.observableArrayList() 

    init { 
     tasks.onChange { change -> 
      change.next() 
      change.addedSubList.forEach { added -> 
       added.completed.onChangeOnce { 
        tasks.remove(added) 
       } 
      } 
     } 
    } 
} 

Dies kann auch mit weniger Tamtam gemacht werden, aber ich weiß nicht, die Komplexität und Anforderungen Ihrer Anwendung, so habe ich es so wenig wie möglich :)

+0

Thank you! Ich mag deinen Ansatz, er ist prägnant, lesbar und funktioniert wie erwartet. – gronostaj

+0

Freut mich das zu hören :)) –

Verwandte Themen