Développement de client en JavaFX (partie 2)

La suite de la création d'une application cliente avec JavaFX.

Développement de client en JavaFX (partie 2)

Après la première partie où nous avons développé un squelette d'interface fonctionnelle, nous allons commencer par traiter son déploiement puis nous ajouterons du contenu.

Dans cette deuxième partie, nous allons voir:

  • un outil de déploiement
  • le debogage du design
  • du changement de design par du theming

Packaging et déploiement d'application JavaFX

Nous utilisons FXLauncher.
Il s'agit d'un programme qui va vérifier la version installée vs la version disponible sur un server et installer cette dernière si besoin. Il y aura donc un splash screen personnalisable dans un projet spécifique (mais non obligatoire) pour indiquer la mise à jour du projet.

L'ajout du launcher se fait en 2 étapes:

  1. création d'un projet spécifique pour avoir une interface personnalisée du launcher, si on le souhaite,
  2. modification du pom.xml de notre projet PortfolioApp pour intégrer et paramétrer le launcher.

Création du projet du launcher

Le plus simple pour le créer est de cloner le repo d'origine de
personnalisation du GUI de FXLauncher
et de le charger dans son IDE pour le modifier.
Vous pouvez aussi partir de notre repo qui contient déjà quelques personnalisations.

Pour la personnalisation, il y a juste une classe qui implémente UIProvider.
Et il y a aussi de la customization de CSS à faire. Donc vraiment simple!

Mise en place du launcher

La mise en place se fait uniquement en modifiant le pom.xml (ou le build si vous utilisez gradle). Dans votre projet JavaFX (celui créé en partie 1), modifiez le pom.xml pour ajouter la lib FXLauncher et tous les paramètres :

  • il faut ajouter la dépendance au projet FXLauncher:
<!-- FXLauncher -->
<dependency>
    <groupId>no.tornado</groupId>
    <artifactId>fxlauncher</artifactId>
    <version>1.0.20</version>
</dependency>
  • ajouter les paramètres dans le tag <properties>:
<!-- properties for FXLauncher -->
<!-- Application Name -->
<app.filename>${project.name}</app.filename>

<!-- The JavaFX Application class name -->
<app.mainClass>io.goovy.portfolioapp.App</app.mainClass>

<!-- The app and launcher will be assembled in this folder -->
<app.dir>${project.build.directory}/app</app.dir>

<!-- Optional override to specify where the cached files are stored. Default is current working directory -->
<app.cacheDir>USERLIB/${project.name}</app.cacheDir>

<!-- Native installers will be build in this folder -->
<app.installerdir>${project.build.directory}/installer</app.installerdir>

<!-- Base URL where you will host the application artifacts -->
<app.url>file:///C:/Temp/app</app.url>

<!-- Optional scp target for application artifacts hosted at the above url -->
<app.deploy.target>C:/Temp/app</app.deploy.target>

<!-- Should the client downgrade if the server version is older than the local version? -->
<app.acceptDowngrade>false</app.acceptDowngrade>

Dans cette exemple, nous précisons un accès disque pour le chargement mais vous pouvez déployer via un server web.

  • puis ajouter les instructions de build avec:

    • la compilation en jar
    <!-- Compile project jar to appdir -->
    <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-jar-plugin</artifactId>
       <version>2.6</version>
       <configuration>
           <outputDirectory>${app.dir}</outputDirectory>
       </configuration>
    </plugin>
    
    • la copie des dépendances
    <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-dependency-plugin</artifactId>
       <version>2.10</version>
       <configuration>
           <excludeScope>provided</excludeScope>
           <outputDirectory>${app.dir}</outputDirectory>
           <stripVersion>true</stripVersion>
       </configuration>
       <executions>
           <execution>
               <phase>package</phase>
               <goals>
                   <goal>copy-dependencies</goal>
               </goals>
           </execution>
       </executions>
    </plugin>
    
    • et la création du manifest app.xml nécessaire à FXLauncher (et la copie des fichiers en local).
    <!-- Create Manifest file for FXLauncher -->
    <plugin>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>exec-maven-plugin</artifactId>
       <version>1.4.0</version>
       <!-- Generate app.xml manifest -->
       <executions>
           <execution>
               <id>create-manifest</id>
               <phase>package</phase>
               <goals>
                   <goal>java</goal>
               </goals>
               <configuration>
                   <mainClass>fxlauncher.CreateManifest</mainClass>
                   <arguments>
                       <argument>${app.url}</argument>
                       <argument>${app.mainClass}</argument>
                       <argument>${app.dir}</argument>
                       <argument>--cache-dir=${app.cacheDir}</argument>
                       <argument>--accept-downgrade=${app.acceptDowngrade}</argument>
                       <argument>--include-extensions=jpg</argument>
                   </arguments>
               </configuration>
           </execution>
           <!-- Embed app.xml inside fxlauncher.xml so we don't need to reference app.xml to start the app -->
           <execution>
               <id>embed-manifest-in-launcher</id>
               <phase>package</phase>
               <goals>
                   <goal>exec</goal>
               </goals>
               <configuration>
                   <executable>jar</executable>
                   <workingDirectory>${app.dir}</workingDirectory>
                   <arguments>
                       <argument>uf</argument>
                       <argument>fxlauncher.jar</argument>
                       <argument>app.xml</argument>
                   </arguments>
               </configuration>
           </execution>
           <!-- Copy application artifacts to remote site using cp (optional) -->
           <execution>
               <id>deploy-app</id>
               <goals>
                   <goal>exec</goal>
               </goals>
               <configuration>
                   <executable>cp</executable>
                   <arguments>
                       <argument>-r</argument>
                       <argument>target/app/.</argument>
                       <argument>${app.deploy.target}</argument>
                   </arguments>
               </configuration>
           </execution>
       </executions>
    </plugin>
    
  • pour indiquer le gui spécifique que l'on vient de développer précédemment, il faut ajouter:

<execution>
    <id>embed-custom-ui-in-launcher</id>
    <phase>package</phase>
    <goals>
        <goal>exec</goal>
    </goals>
    <configuration>
        <executable>jar</executable>
        <workingDirectory>${app.dir}</workingDirectory>
        <arguments>
            <argument>uf</argument>
            <argument>fxlauncher.jar</argument>
            <argument>-C</argument>
            <argument>${project.basedir}/../fxlauncher-custom-ui/target/classes</argument>
            <argument>.</argument>
        </arguments>
    </configuration>
</execution>

Une fois votre pom.xml correctement configuré, vous pouvez builder et executer les commandes avec:

$ mvn clean package
$ mvn exec:exec@deploy-app

Ces commandes seront à éxecuter à chaque nouvelle version.

Vous lancez désormais votre application par le bootstrap java -jar target\app\fxlauncher.jar. Celui-ci va checker la version disponible dans le répertoire "deploy" paramétré (ici temp/app) puis la copier en local et enfin executer votre main class.

A partir de là, vous pouvez aussi créer un installer à l'aide des instructions javapackager indiquées dans le pom exemple et générer l'installer avec mvn install.
Vous avez ensuite un installer classique dans target/installer avec un programme qui s'autoupdatera:
papp-10

Débogage du design

Comme nous l'avons évoqué dans la première partie, un outil fort utile pendant le développement d'application JavaFX est ScenicView.

Téléchargez la version correspondante à votre JDK et executez le jar $ java -jar scenicView.jar et une fenetre va se lancer.
Démarrer ensuite votre application et scenicview va s'attacher et vous montrer l'arbre des éléments graphiques.

client21

Changement de thème

Pour suivre la mode actuelle des "dark-themes", nous aussi nous avons le notre dans un repo dédié.
Il s'agit essentiellement de changement de css.

client12

Ajouter de jolis icons

Il existe plusieurs librairies pour ajouter des icones à vos interfaces. Nous avons déjà utilisé SVGGlyph dans le main. Il y aussi ikonli qui a une doc bien fournie. Ici nous présentons la librairie de Jens Deters qui contient également plusieurs jeux d'icons comme ceux de Material Design, FontAwesome et pleins d'autres.
Par contre il publie sur bintray. Du coup, la version disponible sur maven centrale est un peu vieille (fixe sur les tailles non inclus...), il faut ajouter le repo bintray à vos repos.

Mise en place

Au moins 2 solutions pour cela: a) vous pouvez créer un fichier settings. xml dans votre .m2 repertoire local (ou dans conf de votre ${maven.home}), ou bien b) ajouter le repo dans le pom.xml du projet.

Dans le premier cas, créez (si pas présent) un fichier ~/.m2/settings.xml avec:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
        <profiles>
            <profile>
                <repositories>
                    <repository>
                        <snapshots>
                            <enabled>false</enabled>
                        </snapshots>
                        <id>central</id>
                        <name>bintray</name>
                        <url>https://jcenter.bintray.com</url>
                    </repository>
                </repositories>
                <pluginRepositories>
                    <pluginRepository>
                        <snapshots>
                            <enabled>false</enabled>
                        </snapshots>
                        <id>central</id>
                        <name>bintray-plugins</name>
                        <url>https://jcenter.bintray.com</url>
                    </pluginRepository>
                </pluginRepositories>
                <id>bintray</id>
            </profile>
        </profiles>
        <activeProfiles>
            <activeProfile>bintray</activeProfile>
        </activeProfiles>
</settings>

ou dans le deuxième cas, ajoutez à votre pom.xml:

<repositories>
    <repository>
      <id>jcenter</id>
      <url>https://jcenter.bintray.com/</url>
    </repository>
</repositories>

et n'oubliez pas de mettre à jour vos indexes
maven

puis ajoutez la dépendance dans votre pom:

<dependency>
    <groupId>de.jensd</groupId>
    <artifactId>fontawesomefx-commons</artifactId>
    <version>8.15</version>
    <type>pom</type>
</dependency>

Utilisation

Et maintenant, vous devriez pouvoir ajouter la lib comme dans le menu de navigation en FXML. Cela est aussi possible en Java directement.
client22

et voilà pour cette partie. Nous ajouterons du contenu dans la partie 3.