Créer un tableau de bord en JavaFX avec la librairie TilesFX

Partagée sur Bitbucket, odelia-tilesfx est une application JavaFX que j'ai développée en langage Kotlin, et qui construit un tableau de bord constitué d'informations relatives au Bitcoin.

L'application est écrite avec le framework TornadoFX ; et sa fenêtre principale présente un tableau de bord constitué de trois tuiles provenant du projet TilesFX :

De gauche à droite, la première tuile affiche l'évolution du bitcoin en dollar, au cours des sept derniers jours ; la seconde, plus sophistiquée, présente la valeur d'un bitcoin (BTC) en dollar et sa tendance ; la troisième tuile affiche simplement la longueur de la blockchain (nombre de blocks minés).

Les données utilisées sont obtenues grâce à l'API en ligne proposée par le site web Blockchain.info, et que l'on interroge par l'envoi de requêtes HTTP de type GET, au moyen de la librairie Fuel.
Les fonctions qui interrogent l'API sont regroupées dans le fichier source Requests.kt.

A titre d'exemple, voici la fonction getBlockCount() permettant de récupérer la hauteur de la blockchain Bitcoin :

1
2
3
4
5
6
7
fun getBlockCount(): Optional<String> {
    val (_, _, result) = "https://blockchain.info/fr/q/getblockcount".httpGet().responseString()
    return when (result) {
        is Result.Failure -> Optional.empty()
        is Result.Success -> Optional.of(result.get())
    }
}

Notez que nous effectuons ici une requête HTTP GET synchrone, alors que le framework Fuel permet d'effectuer des appels asynchrones ; c'est que dans l'application, nous avons recours aux observables de RxJava pour effectuer des interrogations à intervalle de temps régulier, afin de rafraîchir les deux dernières tuiles (les requêtes s'effectueront dans leur propre thread), tandis que les données de la première tuile sont obtenues qu'une seule fois au moment de la création de la vue.

Voyons de quelle manière les deuxième et troisième tuiles sont mises à jour.

Pour cela, on s'appuie sur RxJava et le bus d'événements de TornadoFX ; tout part de la méthode générique startTimer de la classe vue Dashboard qui étend la classe View de TornadoFX ; cette méthode est définie ainsi :

1
2
3
4
5
6
private fun <R, E: FXEvent>startTimer(fetchData: ()-> Optional<R>, 
	delay: Long, unit: TimeUnit, eventFactory: (R)-> E) {
    Observable.fromCallable({ fetchData() })
            .repeatWhen( { o -> o.concatMap( { Observable.timer(delay, unit) }) })
            .subscribe { if (it.isPresent) fire(eventFactory(it.get())) }
}

Elle a l'air quelque peu complexe, mais en résumé, elle permet de réaliser la séquence suivante :

  • appel de la fonction passée dans le paramètre fetchData, qui doit être une fonction ne prenant aucun paramètre et renvoyant un Optional Java, contenant les données récupérées ou non ;
  • attente d'une durée définie par les paramètres delay et unit ;
  • si des données ont été retournées par la fonction fetchData, émission d'un événement TornadoFX par l'exécution de fire() dont l'argument doit être un objet de type FXEvent.

Le timer permettant la mise à jour de la tuile donnant la longueur de la blockchain se lance simplement par cet appel :

1
startTimer(::getBlockCount, 10, TimeUnit.MINUTES, { BlockCountData(it) })

Et dans le bloc init de la vue Dashboard, comme on souscrit à l'événement de type BlockCountData, on peut alors procéder à la mise à jour de notre tuile en utilisant sa référence (la tuile étant construite au moyen du builder TileBuilder de la librairie TilesFX) :

1
2
3
subscribe<BlockCountData> {
	blockHeightTile.description = it.data
}

Ici, it est la variable implicite référençant l'objet événement de type BlockCountData, et dont la propriété data contient la donnée en prendre en compte.

Pour conclure, disons que tout est en place pour que vous puissiez insérer une nouvelle tuile, avec le mécanisme en place pour la mettre à jour automatiquement grâce à RxJava et les événements de TornadoFX !