I have an application where I'm transforming an XML document using XSL transformation (XSLT). This is build using TornadoFX (source code can be found here). I'm trying to update a status label with the status of the transformation, which is done inside a class that extends Controller. But for some reason, the status label shows nothing.
The source for my transformer class:
class Transformer : Controller() {
private val statusProperty = SimpleStringProperty("")
var status by statusProperty
fun transform(xml: File, xslt: File, result: StreamResult) {
runLater { status = "" }
// create the DOM Source
val factory = DocumentBuilderFactory.newInstance()
factory.isNamespaceAware = true
val builder = factory.newDocumentBuilder()
val bbcDoc = builder.parse(xml)
val source = DOMSource(bbcDoc)
// Create an instance of the TransformerFactory
val transfomerFactory = TransformerFactory.newInstance()
val transformer = transfomerFactory.newTransformer(StreamSource(xslt))
.apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4")
}
runLater {
try {
transformer.transform(source, result)
status = "Completed successful"
} catch (e: Exception) {
status = e.message
}
}
}
}
The mainscreen class:
class MainScreen : View("XSLT Transformer") {
val status: TaskStatus by inject()
val model: TransformerModel by inject()
val transformer: Transformer by inject()
private val xmlFilter = arrayOf(FileChooser.ExtensionFilter("XML Filer (*.xml)", "*.xml"))
private val xsltFilter = arrayOf(FileChooser.ExtensionFilter("XSLT Filer (*.xslt)", "*.xslt"))
private lateinit var xmlInput: TextField
private lateinit var xsltInput: TextField
override val root = form {
fieldset(labelPosition = Orientation.VERTICAL) {
field("XSLT fil") {
...
}
field("XML Input Fil") {
...
}
button("Konverter") {
enableWhen(model.valid)
isDefaultButton = true
useMaxWidth = true
action {
// An object to hold the results. It can be a file.
// val writer = System.out
val output = StreamResult(StringWriter())
runAsyncWithProgress {
try {
transformer.status = "Konverterer xml fil..."
transformer.transform(File(xmlInput.text), File(xsltInput.text), output)
transformer.status = "Færdig"
} catch (e: Exception) {
transformer.status = e.message
}
} ui {
showDialogResult(output)
transformer.status = "Completed"
}
}
}
}
label(transformer.status) {
style {
paddingTop = 10
textFill = Color.RED
fontWeight = FontWeight.BOLD
}
}
}
}
You must bind to transformer.statusProperty
, not to transformer.status
. The status
property is simply a getter/setter and have no way of updating the label. The statusProperty
howevere is an observable, so changes to it will reflect in the label.
You must also make sure not to perform long running tasks on the UI thread. runLater
schedules work to be done on the UI thread. What you want to do is to perform the long running tasks in a runAsync
block and add a ui
block which receives the result. In the ui
block you can update the UI.