Avant de commencer, je tiens à préciser que depuis le JDK 1.8.0_60, le contrôle WebView souffre d'un très gros bogue qui fait que le WebEngine n'est plus capable de charger des ressources (fichiers image, CSS, JavaScript) incluses dans un JAR lorsqu’on charge un fichier HTML inclus dans cette même archive. Ceci casse pas mal de solutions avec des navigateurs embarqués qui permettaient de charger, par exemple, des pages GoogleMap, etc. Voir [JDK-8134922] - Resource files are not loaded by the WebEngine when bundled in a jar file sur le JDK Bug System. Ces applications devraient toujours pouvoir fonctionner correctement avec le JDK 1.8.0_51. Ces derniers temps, pour vérifier les valeurs d'un objet paramètre dans une UI, je faisais une sortie texte en affichant un objet Text dans un TextFlow inclus dans un StackPane, lui-meme placé dans un ScrollPane. Comme l'objet paramètre n'est pas observable, j'ai mis en place un ScheduleService qui va régulièrement régénérer un rapport textuel et afficher le tout à l’écran :
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private final TextFlow textFlow = new TextFlow(); private final StackPane textStack = new StackPane(); private final ScrollPane scrollPane = new ScrollPane(); [...] textFlow.setId("textFlow"); // NOI18N. // textStack.setId("textStack"); // NOI18N. textStack.getChildren().setAll(textFlow); // scrollPane.setId("scrollPane"); // NOI18N.; scrollPane.setFitToWidth(true); scrollPane.setContent(textStack); getChildren().add(scrollPane); |
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | service.setOnSucceeded(workerStateEvent -> { final String result = (String) workerStateEvent.getSource().getValue(); // Ici le résultat est au format texte. if (!Objects.equals(oldResult, result)) { oldResult = result; final Text text = (result == null) ? null : new Text(result); textFlow.getChildren().clear(); if (text != null) { textFlow.getChildren().setAll(text); } } }); |
Étant donné que les paramètres se multiplient, j'ai décidé d'opter pour une version HTML du rapport ; ce qui permet de mettre un peu mieux les paramètres importants en évidences et de condenser l'affichage en jouant sur la taille de la police ou avec des <div> placés sur un flow layout.
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | private final WebView webView = new WebView(); [...] webView.setId("webView"); // NOI18N. webView.setContextMenuEnabled(false); getChildren().add(webView); |
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 | service.setOnSucceeded(workerStateEvent -> { final String result = (String) workerStateEvent.getSource().getValue(); // Ici le résultat est au format HTML. if (!Objects.equals(oldResult, result)) { oldResult = result; webView.getEngine().loadContent(result); } }); |
Or WebView est un composant complexe "opaque" (dans le sens où on ignore comment interagir avec ses sous-parties) qui n'offre aucune API permettant de manipuler ses barres de défilement. J'ai essayé de bidouiller un peu via la méthode lookup() en cherchant l'id ou la classe CSS des barres de défilement mais cela n'a rien donné, au final, de concret ou du moins qui fonctionne correctement.
Il existe cependant une manière bien plus simple et rapide de régler ce problème : invoquer via le WebEngine des bouts de code JavaScript qui permettent de connaitre le défilement actuel de la page et, une fois la nouvelle page chargée, restaurer cette valeur. Nous allons commencer par ajouter un écouteur :
| Code Java : | Sélectionner tout |
1 2 3 4 5 | private final ChangeListener<Worker.State> engineLoadWorkerListener = (observable, oldValue, newValue) -> { if (newValue == Worker.State.SUCCEEDED) { restoreScrollAmount(); } }; |
Et ces deux méthodes qui permettent de sauvegarder et de restaurer les valeurs de défilement de la page :
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private int xScroll = 0; private int yScroll = 0; // Sauvegarde le défilement de la page web. private void storeScrollAmount() { xScroll = (Integer) webView.getEngine().executeScript("window.pageXOffset"); // NOI18N. yScroll = (Integer) webView.getEngine().executeScript("window.pageYOffset"); // NOI18N. } // Restaure le défilement dans la page web. private void restoreScrollAmount() { final String command = String.format("window.scrollTo(%d, %d)", xScroll, yScroll); // NOI18N. webView.getEngine().executeScript(command); } |
| Code Java : | Sélectionner tout |
webView.getEngine().getLoadWorker().stateProperty().addListener(engineLoadWorkerListener);
| Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | service.setOnSucceeded(workerStateEvent -> { final String result = (String) workerStateEvent.getSource().getValue(); // Ici le résultat est au format HTML. if (!Objects.equals(oldResult, result)) { oldResult = result; storeScrollAmount(); // Sauvegarde des valeurs de défilement. webView.getEngine().loadContent(result); } }); |
Vous avez lu gratuitement 1 679 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.