Publié par
Il y a 3 années · 20 minutes · Front

JavaFX 8 : La résistance des applications lourdes

javafx_logoA l’heure des single page applications, des architectures orientées web, du cloud et autres frameworks javascript, Oracle a mis à jour son framework de création d’interface graphique à l’occasion de la sortie de Java 8.

JavaFX permet la création d’applications desktop (ou lourdes) ainsi que la création de RIAs (Rich Internet Application) qui s’exécutent dans le navigateur en utilisant le plugin Java.

Je vous propose à travers cet article de créer une application simple en JavaFX qui va nous permettre de voir quelques concepts du framework.

Un peu d’histoire

Avant de commencer l’application, un peu d’histoire sur JavaFX.

Sun a sorti la première release stable de JavaFX en 2008. Son but était de concurrencer les environnements Silverlight de Microsoft et Flex d’Adobe. Le framework est également le remplaçant de Swing, l’ancienne librairie de composants graphiques de Java.

Depuis, Silverlight est mort et Flex a été donné à la fondation Apache en 2011.

De son coté, Oracle continue de faire évoluer JavaFX en lui donnant de nouvelles fonctionnalités et en le déployant sur iOS et Android.

Dans sa première version, JavaFX ne permettait pas de développer en Java – il fallait passer par le langage JavaFX Script. Celui-ci fut abandonné à partir de JavaFX 2. Toutefois, le framework ne faisait toujours pas parti du JDK par défaut, imposant des manipulations supplémentaires pour déployer une application JavaFX.

Ce défaut est maintenant corrigé et JavaFX est entièrement intégré au JDK, ce qui simplifie son déploiement, surtout sur des systèmes embarqués. De plus, depuis cette version, JavaFX a été opensourcé, ce qui aide grandement au développement.

 

Créer une application JavaFX

L’application que je vous propose de créer est simple. Elle se compose d’une fenêtre dans laquelle on saisit un code d’action boursier et une durée. Une fois ces éléments saisis, l’application affiche le tableau des cinq derniers jours de cotation ainsi qu’un graphique représentant l’évolution de l’action sur la durée choisie.

Ce simple exemple va nous permettre d’aborder plusieurs points de JavaFX.

Pour la partie récupération des données, je m’appuie sur le service de yahoo finance qui permet de récupérer l’historique de valeurs sur une période donnée. Je ne rentrerai pas dans les détails de l’implémentation dans l’article mais le service est disponible dans le code source.

Commençons par créer la fenêtre principale de l’application. Comme toute application Java, une application JavaFX a besoin d’un point d’entrée. Il s’agit d’une classe étendant la classe javafx.application.Application.

Cette classe définit le cycle de vie d’une application JavaFX :

  • Au lancement de l’application, la méthode launch() doit être appelée
  • Cette méthode appelle la méthode init()
  • Puis la méthode start() obligatoirement implémentée par le client
  • Une boucle est lancée pour gérer les évènements
  • Si un signal d’exit est lancé, la méthode stop() est appelée

La classe abstraite Application fournie déjà des implémentations pour les méthodes init() et stop() qui ne font rien. Seule la méthode start() doit être implémentée obligatoirement.

Ce qui nous donne un code comme celui-ci :

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setWidth(1024);
        primaryStage.setHeight(968);
        primaryStage.setTitle("JavaFX Xebia");
        primaryStage.show();
    }
}

La méthode static main(), (point d’entré de toute application Java) appelle la méthode launch() d’Application.

Nous implémentons la méthode start() qui reçoit l’objet javafx.stage.Stage qui représente la fenêtre principale de notre application. show()

La fenêtre est totalement vide, nous allons donc ajouter des éléments à celle-ci.

En JavaFX, il est possible de tout faire en Java pur. Nous pourrions écrire quelque chose comme ça :

Group group = new Group();
VBox vbox = new VBox();
vbox.getChildren().addAll(new Text("Code Java pur"));
group.getChildren().add(vbox);
primaryStage.setScene(new Scene(group));

Ce qui afficherait un texte « Code Java pur » en haut à gauche de la fenêtre.

Créer des composants graphiques à l’aide de code Java est possible (bien qu’ennuyeux) mais peut vite devenir un peu trop verbeux.

Heureusement, il est possible de faire autrement grâce aux fichiers FXML.

 

La présentation : FXML

Les fichiers FXML sont des fichiers XML qui vont permettre de décrire notre interface de manière un peu plus visuelle que le code brut. De plus, il est possible de binder les éléments FXML directement sur des classes Java. C’est ce que nous allons faire pour créer notre interface.

Il n’y a pas de schéma prédéfini pour un fichier FXML, vous pouvez donc créer n’importe quelle partie de votre interface dans un fichier FXML, et pas obligatoirement une fenêtre entière.

Commençons par créer le formulaire de notre application :

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.lang.*?>
<AnchorPane prefHeight="968.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
    fx:controller="fr.xebia.blog.jfx.Controller">
    <children>
        <VBox>
            <children>
                <HBox prefWidth="200.0">
                    <children>
                        <Label prefHeight="16.0" prefWidth="187.0" text="Code action" />
                        <TextField fx:id="code" prefWidth="150.0" />
                    </children>
                    <padding>
                        <Insets left="10.0" top="10.0" />
                    </padding>
                </HBox>
                <HBox prefWidth="200.0">
                    <children>
                        <Label prefHeight="16.0" prefWidth="187.0" text="Période (mois)" />
                        <ChoiceBox fx:id="duration" prefHeight="26.0" prefWidth="150.0">
                        </ChoiceBox>
                    </children>
                    <padding>
                        <Insets left="10.0" top="10.0" />
                    </padding>
                </HBox>
                <HBox>
                    <children>
                        <Button mnemonicParsing="false" onAction="#run" text="Lancer" />
                    </children>
                    <padding>
                        <Insets left="10.0" top="10.0" />
                    </padding>
                </HBox>
            </children>
        </VBox>
    </children>
</AnchorPane>

Il est obligatoire dans un fichier FXML d’importer les classes utilisées comme pour du code Java, d’où la présence des balises <?import?>

Le premier élément de notre fichier est un AnchorPane. Les différents types de panes disponibles sont des conteneurs qui permettent d’englober vos éléments dans des panneaux. Il existe plusieurs types de panes en fonction de la disposition que vous souhaitez (fixe, flottant, avec bordure, …).

Un fichier FXML est une description de nos objets, on peut donc directement setter tous les attributs que l’on souhaite comme la hauteur de notre AnchorPane.

Remarquez ensuite les Vbox et HBox utilisées régulièrement. Ces « boites » très utiles permettent d’aligner leurs enfants automatiquement de manière verticale (VBox) ou horizontale (HBox). Ainsi les labels et leurs inputs (TextField ou ChoiceBox) sont alignés de manière horizontale sans manipulation particulière.

Comme je l’ai dit plus haut, il est possible de binder notre FXML directement avec nos classes Java. Remarquez sur le AnchorPane l’attribut suivant :

fx:controller="fr.xebia.blog.jfx.Controller"

Il indique à JavaFX que le comportement de notre scène est lié à la classe Controller. Celle-ci sera donc directement instanciée lors de la lecture du fichier FXML.

Regardons cette classe Controller :

public class Controller implements Initializable {
 
    @FXML
    private TextField code;
    @FXML
    private ChoiceBox duration;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
    }
}

Rien de particulier n’est nécessaire pour indiquer que cette classe est utilisée par JavaFX. Toutefois, il est possible (mais non obligatoire) d’implémenter l’interface javafx.fxml.Initializable, ce qui lancera la méthode initialize() à l’instanciation de la classe si l’on souhaite faire des choses particulières.

Notez l’annotation @FXML, qui permet de binder un objet du fichier FXML avec la classe Java et de pouvoir intervenir dessus. Le binding se fait sur le nom de l’attribut. Par exemple, le TextField « code » sera bindé comme suit grâce à l’attribut fx:id :

<TextField fx:id="code" prefWidth="150.0" />

Même chose pour le menu déroulant « duration ».

Enfin dernier point de binding sur notre FXML, l’attribut onAction sur notre bouton qui bind directement sur la méthode associée du controller.

Cette méthode à la signature suivante :

public void run(ActionEvent event);

L’event peut nous servir pour retrouver les données associées au clic sur le bouton. Il existe des attributs similaires pour d’autres events comme : onMousePressed ou onKeyPressed.

Si l’écriture de XML à la main est une tâche qui vous rebute, sachez qu’il est possible d’utiliser l’outil SceneBuilder qui propose une interface graphique pour créer nos fichiers FXML. Il est plutôt bien fait : il propose l’ensemble des composants disponibles, crée un code propre et s’intègre très facilement avec IntelliJ, ce qui le rend vraiment utile.

Il est possible de créer ses propres composants FXML afin de les réutiliser plusieurs fois dans une application. Certains frameworks, comme AquaFX proposent d’ailleurs des ensembles de composants évolués.

Le CSS est également de la partie, puisqu’on peut l’utiliser pour styliser notre application, malheureusement c’est un CSSFX, c’est à dire avec certaines limitations par rapport au vrai CSS. Enfin, il est possible d’écrire des fonctions javascript dans les fichiers FXML. Cela peut servir par exemple pour des traitements simples lors d’un clic sur un bouton.

Le formulaire est prêt, il ne reste plus qu’à l’afficher. Afficher du FXML avec JavaFX ne se fait pas de manière automatique, il faut lui indiquer le fichier à charger.

Nous allons créer une classe JFxUtils qui s’occupe de charger les fichiers :

public class JfxUtils {

    public static Node loadFxml(String fxml) {
        FXMLLoader loader = new FXMLLoader();
        try {
            loader.setLocation(JfxUtils.class.getResource(fxml));
            Node root = (Node) loader.load(Main.class.getResource(fxml).openStream());
            return root;
        } catch (IOException e) {
            throw new IllegalStateException("cannot load FXML screen", e);
        }
    }
}

La méthode loadFxml() de cette classe fait deux choses simples :

  • Création d’une nouvelle instance de FXMLLoader. C’est elle qui s’occupera du binding, etc.
  • Chargement du fichier dont le chemin est passé en paramètre. Le FXMLLoader créé alors un javafx.scene.Node qui sera retourné.

Pour utiliser cette méthode, il suffit de rajouter dans la méthode start() :

primaryStage.setScene(new Scene((Parent) JfxUtils.loadFxml("/fr/xebia/blog/fxml/screen.fxml"), 1024, 968));

Nous créons une scène dans notre fenêtre à partir du nœud retourné par la méthode créée précédemment.

Nous avons maintenant un formulaire qui s’affiche à l’écran, mais rien ne se passe lors du clic sur le bouton et le menu déroulant de durée est vide.

 

La manipulation de liste

La manipulation de liste en JavaFX est un peu particulière puisque toutes les collections utilisées à travers le framework doivent être wrappées dans une collection propre à JavaFX tirée de FXCollections. Ce choix a été fait pour permettre de notifier les collections des événements se produisant sur les listes dans l’application. Il est possible d’ajouter des listeners à toutes ces collections dans ce but.

Il existe deux façons de créer des listes en JavaFX :

  • directement dans le FXML – si vous connaissez les éléments
  • par du code Java – pour les éléments dynamiques (il est effectivement impossible de boucler sur une liste directement dans le FXML, un peu comme un ng-repeat en Angular)

Comme nous connaissons le nombre de durées dans notre menu déroulant, nous pouvons passer directement par FXML :

<ChoiceBox fx:id="duration" prefHeight="26.0" prefWidth="150.0">
  <items>
      <FXCollections fx:factory="observableArrayList">
         <Integer fx:value="3" />
         <Integer fx:value="4" />
         <Integer fx:value="5" />
         <Integer fx:value="6" />
         <Integer fx:value="7" />
         <Integer fx:value="8" />
         <Integer fx:value="9" />
         <Integer fx:value="10" />
         <Integer fx:value="11" />
         <Integer fx:value="12" />
      </FXCollections>
   </items>
</ChoiceBox>

JavaFX crée alors une observableArrayList avec les éléments voulus à l’intérieur.

Si vous ne connaissez pas les éléments à l’avance, vous devez passer par le Java. C’est ce que nous allons faire avec notre tableau. Pour rappel, nous voulons afficher les cinq derniers cours de notre action dans un tableau.

Premièrement ajoutons un tableau dans notre FXML à la suite de notre bouton :

<HBox fx:id="hboxTable" prefWidth="200.0" visible="false">
 <children>
     <TableView fx:id="tableView" prefHeight="150.0">
         <columns>
             <TableColumn minWidth="100.0" prefWidth="75.0" text="Date" fx:id="columnDate">
                 <cellValueFactory>
                     <PropertyValueFactory property="date" />
                 </cellValueFactory>
             </TableColumn>
             <TableColumn minWidth="100.0" prefWidth="75.0" text="Prix">
                 <cellValueFactory>
                     <PropertyValueFactory property="Close" />
                 </cellValueFactory>
             </TableColumn>
             <TableColumn minWidth="100.0" prefWidth="75.0" text="Volume">
                 <cellValueFactory>
                     <PropertyValueFactory property="Volume" />
                 </cellValueFactory>
             </TableColumn>
         </columns>
     </TableView>
 </children>
</HBox>

Les tableaux sont représentés par la classe javafx.scene.control.TableView. Dans le FXML, nous allons décrire la structure du tableau. En l’occurrence, trois colonnes : date, prix et volume de transaction.

Nous indiquons aussi un cellValueFactory par colonne. Il y a deux éléments importants dans les TableView :

  • La cellValueFactory qui indique à JavaFX quelle valeur afficher et comment l’afficher. Ici nous indiquons que nos valeurs sont des propriétés d’un objet (PropertyValueFactory) et elles seront affichées via un toString()
  • La cellFactory qui indique comment afficher la cellule. Par défaut du texte, mais on pourrait vouloir afficher un champ texte ou une image.

Notre tableau est maintenant structuré, mais comment le remplir ? Direction le Java.

Dans notre Controller, nous allons binder notre tableau :

@FXML
private TableView<HistoricQuote> tableView;

Une TableView est lié à un type d’objet, ici un HistoricQuote remonté par le service de Yahoo.

Ensuite dans notre méthode run :

public void run(ActionEvent event) {
 List<HistoricQuote> quotes = yahooService.getHistoric(code.getText(), (Integer) duration.getValue());
 final ObservableList<HistoricQuote> items = FXCollections.observableArrayList();
 quotes.stream().limit(5l).forEach(historic -> items.add(historic));
 tableView.setItems(items);
}

Nous faisons :

  • Un appel au service de Yahoo en récupérant les données saisies dans le formulaire
  • La création de notre FXCollections (avec le même type que la TableView)
  • L’ajout des cinq éléments voulus
  • L’ajout de la liste dans le tableau

Notre tableau est maintenant complété et affiché. Remarquez l’utilisation des lambdas de Java 8 qui simplifient ce code.

Pour terminer sur les tableaux et comme dit plus haut, PropertyValueFactory affiche nos valeurs via un toString(), ce qui, pour notre date, va donner quelque chose comme : « Tue Aug 19 00:00:00 CEST 2014 »

Heureusement, nous pouvons créer notre propre cellValueFactory pour afficher la date comme on le souhaite.

Commençons par binder notre colonne de date dans notre controller :

@FXML
private TableColumn columnDate;

Dans la méthode initialize() appelée à l’instanciation du controller, nous pouvons faire :

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
        columnDate.setCellValueFactory(value -> new SimpleStringProperty(
   new SimpleDateFormat("dd-MM-yyyy").format(((HistoricQuote) value.getValue()).getDate())));
}

La value passée en paramètre est de type TableColumn.CellDataFeatures qui nous permet de traiter la valeur de la colonne en cours. Ensuite un simple formatage de date suffit à afficher ce que l’on souhaite.

 

La création de graphique

Dernier élément manquant à notre application : le graphique.

JavaFX propose toute une série de graphiques prêt à l’emploi, ce qui rend leur utilisation relativement simple.

Comme pour tous les éléments JavaFX, il est possible de les créer directement en FXML. Malheureusement, l’axe des Y de notre graphique (les prix) changera dynamiquement, ce qui oblige à recréer entièrement le graphique à chaque fois (une fois les axes fixés, on ne peut plus les changer). Nous allons donc passer en Java.

Coté FXML, un seul ajout, une HBox permettant de binder le tout avec le controller :

<HBox fx:id="hboxGraph" visible="false"/>

Coté Java, voici le code complet que je vais expliquer par la suite :

private void fillGraph(List<HistoricQuote> quotes) {
        ObservableList<XYChart.Series<String, Float>> lineChartData = FXCollections
                .observableArrayList();
        final XYChart.Series<String, Float> series = createSerie(quotes);
        lineChartData.add(series);
        NumberAxis yAxis = createYAxis(quotes);
        final CategoryAxis xAxis = new CategoryAxis();
        xAxis.setLabel("Temps");
        LineChart chart = new LineChart(xAxis, yAxis, lineChartData);
        chart.setPrefWidth(1010);
        chart.setPrefHeight(400);
        hboxGraph.getChildren().clear();
        hboxGraph.getChildren().add(chart);
}

private XYChart.Series<String, Float> createSerie(List<HistoricQuote> quotes) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
        final ObservableList<XYChart.Data<String, Float>> observableList = FXCollections
                .observableArrayList();
        quotes.stream().forEach(historic -> {
            XYChart.Data<String, Float> data = new XYChart.Data<String, Float>(
                    dateFormat.format(historic.getDate()),
                    historic.getClose());
            observableList.add(data);
        });
        return new XYChart.Series<String, Float>(
                "Evolution du cours", observableList);
}
private NumberAxis createYAxis(List<HistoricQuote> quotes) {
        Optional<HistoricQuote> max = quotes.stream().max((h1, h2) -> {
            if (h1.getHigh() == h2.getHigh())
                return 0;
            return h1.getHigh() < h2.getHigh() ? -1 : 1;
        });
        Optional<HistoricQuote> min = quotes.stream().min((h1, h2) -> {
            if (h1.getLow() == h2.getLow())
                return 0;
            return h1.getHigh() < h2.getHigh() ? -1 : 1;
        });
        return new NumberAxis("Variation", min.get().getLow(), max.get().getHigh(), 0.2);
}

La méthode fillGraph() est appelé dans la méthode run() est prend en paramètre la liste des valeurs retournée par le service de Yahoo.

Voici comment créer le graphique :

  • 2 Création d’une FXCollections qui sera la liste des séries de notre graphique. Pour rappel, JavaFX ne travaille qu’avec des listes de ce type
  • 4 Création d’une série pour le graphique. Il est possible d’ajouter plusieurs série à notre graphique. Comme nous voulons une courbe, nous prenons une série de point (XY)
  • 6 Création de l’axe des Y
  • 7 Création de l’axe des X qui sera une simple suite de String; un point étant égal à une date
  • 8-10 Création du graphique en lui même
  • 11 On clean la HBox créé dans le FXML pour éviter l’empilement de graphique à chaque run
  • 12 Ajout du graphique à la HBox, et donc dans la fenêtre

La série, méthode createSerie(), est créée comme suit :

  • 18 Création d’une nouvelle FXCollections. Celle-ci va contenir la liste des points de la courbe
  • 20-25 Chaque point est créé avec la date en X et les prix de cloture en Y
  • 26 Création de la série elle même avec un titre et la liste des points

Enfin remarquez la création de l’axe des Y (méthode createYAxis()). C’est lui qui nous oblige à recréer le graphique à chaque clic sur le bouton run.

Cet axe est créé en lui spécifiant le point minimum et maximum du graphique ainsi que l’unité entre deux graduations.

Le prix d’une action étant complètement différent entre deux actions, on ne peut pas fixer un axe des Y identique pour chaque graphique. Malheureusement, il est impossible de changer cet axe de manière dynamique.

 

La concurrence

Le service de Yahoo rend de bons services mais parfois, il peut mettre du temps à répondre. En l’état actuel des choses, notre application donnera l’impression de planter si le service est lent à répondre.

Pour y remédier, nous allons ajouter une petite fenêtre de chargement le temps que le service nous réponde en utilisant les Task JavaFX. Les Tasks sont une implémentation des Futures et se rapprochent également des promesses Javascript. Il devient alors simple d’exécuter des traitements asynchrones et d’agir en fonction de la réponse.

Voici la nouvelle implémentation de la méthode run() en y ajoutant notre fenêtre de loading :

public void run(ActionEvent event) {
    final Stage progressBar = openLoadingWindow();
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Task<YahooResponse> task = new Task<YahooResponse>() {
        @Override
        protected YahooResponse call() throws Exception {
            return yahooService.getHistoric(code.getText(), (Integer) duration.getValue());
        }
    };
    task.setOnFailed(workerStateEvent -> progressBar.close());
    task.setOnSucceeded(workerStateEvent -> {
        YahooResponse yahooResponse = (YahooResponse) workerStateEvent.getSource().getValue();
  progressBar.close();
        if (yahooResponse != null && yahooResponse.getQuery().getCount() > 0) {
            List<HistoricQuote> quotes = yahooResponse.getQuery().getResults().getQuote();
            fillTableView(quotes);
            fillGraph(quotes);
        }
    );
    executorService.submit(task);
    executorService.shutdown();
}
 
private Stage openLoadingWindow() {
    final Stage progressBar = new Stage();
    progressBar.initModality(Modality.WINDOW_MODAL);
    progressBar.initOwner(code.getScene().getWindow());
    progressBar.setScene(new Scene(new Group(JfxUtils.loadFxml("/fr/xebia/blog/fxml/loading.fxml"))));
    progressBar.show();
    return progressBar;
}

Notre nouvelle fenêtre est un objet Stage comme pour notre fenêtre principale.

Une Task implémente Runnable, nous devons donc créer un objet implémentant la méthode call. C’est dans cette méthode que nous appelons le service Yahoo. Ensuite nous utilisons deux méthodes très utiles des Tasks :

  • setOnFailed() qui indique le comportement si la tâche échoue. Ici on ferme la fenêtre de loading
  • setOnSucceeded() qui indique le comportement si la tâche réussie. Ici on ferme la fenêtre de loading et on remplit le tableau et le graphique

La Task est exécutée dans un ExecutorService basique de Java.

Comme on le voit, il est très simple de faire des traitements asynchrones en JavaFX, ce qui est très pratique pour les longues tâches de calcul ou autres appels de services.

Pour information, voici le FXML de la fenêtre de loading qui utilise un nouvel objet : la ProgressBar :

<AnchorPane prefHeight="97.0" prefWidth="291.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <ProgressBar layoutX="46.0" layoutY="39.0" prefWidth="200.0" />
    </children>
</AnchorPane>

 

Conclusion

Notre application est maintenant terminée, voici un exemple d’écran avec l’action Ubisoft :

Vous pouvez retrouver l’intégralité du code source sur le github suivant : https://github.com/RNiveau/article-javafx8

Nous avons vu comment créer des écrans, créer des taches asynchrones, manipuler le FXML et les listes, soit les tâches les plus courantes dans une application. Mais JavaFX offre bien plus de possibilités dont voici une liste non exhaustive :

  • Animations d’éléments
  • Lecture Audio / Vidéo
  • Gestion de la 2D / 3D
  • Multitouch pour les écrans tactiles
  • Browser web intégré

Vous pouvez voir une démo de ces fonctionnalités via une application dédiée dans les samples du JDK (http://www.oracle.com/).

Il est donc possible de faire beaucoup de choses avec JavaFX et de manière relativement simple. L’apport du FXML par rapport au tout Java aide beaucoup à la réalisation des interfaces.

Toutefois, il est clair que JavaFX reste un marché de niche. Utiliser JavaFX dans un navigateur est à oublier, le plugin Java des navigateurs n’étant presque plus utilisé au profit des frameworks Javascript qui permettent de créer facilement des interfaces web complexes.

JavaFX est utilisé là où le besoin d’une application lourde est encore présent (applications en lien avec des drivers spécifiques de machines par exemple) ou sur des systèmes embarqués ne disposant pas forcément de navigateur web.

Le portage de JavaFX sur Android (déjà effectué) pourrait donner un nouveau souffle au framework. Le portage sur iOS également, mais il faudra pour cela qu’Apple accepte le déploiement d’applications contenant une JVM intégrée.

4 réflexions au sujet de « JavaFX 8 : La résistance des applications lourdes »

  1. Publié par Christophe L., Il y a 3 années

    En combinant JavaFX et JavaWebStart; on peut réaliser une application cliente pure Java sans la lourdeur d’un déploiement explicite. L’avantage sur javascript pour les interfaces complexes; donc code complexe; c’est qu’on reste sur du statiquement typé, plus fiable et plus facile à lire. A voir ensuite, par rapport à un AngularDart ou à du Ceylon qui compile en Javascript….

  2. Publié par [Java] JavaFX 8 et Java Swing - Le Texier, Il y a 2 années

    […] Je ne vais pas présenter le fonctionnement l’utilisation de JavaFX 8 dans cet article. Je vais présenter ce que j’ai fait en l’utilisant et les problèmes que je rencontrés. D’autres articles suivront dans lesquelles je présenterai les solutions de ces problèmes. Pour ceux qui n’ont jamais entendu parler du JavaFX 8 voici un article assez sympas qui le présente bien: La résistance des applications lourdes. […]

  3. Publié par Vansuypeene Jean-Marc, Il y a 2 années

    Je travaille avec Eclipse Mars 4.5 sous Win10. Je n’arrive pas à faire fonctionner la ligne :
    Node root = (Node) loader.load(Main.class.getResource(fxml).openStream());
    dans la classe JFxUtils.java et je ne comprends pas pourquoi?
    Si vous avez une idée je suis preneur.
    J’essaye depuis une semaine de trouver!!!
    merci d’avance.
    Cordialement.

  4. Publié par Romain Niveau, Il y a 2 années

    Bonjour,

    Qu’entendez vous par « Je n’arrive pas à faire fonctionner la ligne » ?

    Quelle exception avez vous ?

  5. Publié par Vansuypeene Jean-Marc, Il y a 2 années

    Bonjour,
    l’exception est la suivante:
    screen.fxml
    Exception in Application start method
    java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source)
    at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
    Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$156(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    Caused by: java.lang.IllegalStateException: ne peut lire le fichier screen fxml
    at application.JfxUtils.loadFxml(JfxUtils.java:19)
    at application.Main.start(Main.java:21)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$174(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$149(Unknown Source)
    … 1 more
    Caused by: javafx.fxml.LoadException:
    /C:/Users/Jean-marc/workspaceMars4.5_2/Article1/bin/application/screen.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
    at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
    at javafx.fxml.FXMLLoader.load(Unknown Source)
    at application.JfxUtils.loadFxml(JfxUtils.java:16)
    … 10 more
    Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.glassfish.jersey.client.JerseyClientBuilder
    at javax.ws.rs.client.ClientBuilder.newBuilder(ClientBuilder.java:103)
    at javax.ws.rs.client.ClientBuilder.newClient(ClientBuilder.java:114)
    at application.service.YahooService.(YahooService.java:22)
    at application.Controller.initialize(Controller.java:64)
    … 13 more
    Caused by: java.lang.ClassNotFoundException: org.glassfish.jersey.client.JerseyClientBuilder
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at javax.ws.rs.client.FactoryFinder.newInstance(FactoryFinder.java:113)
    at javax.ws.rs.client.FactoryFinder.find(FactoryFinder.java:206)
    at javax.ws.rs.client.ClientBuilder.newBuilder(ClientBuilder.java:86)
    … 16 more
    Exception running application application.Main

    Merci de m’avoir répondu.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *