<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Forum du club des développeurs et IT Pro - Blogs - bouye</title>
		<link>https://www.developpez.net/forums/blogs/71025-bouye/</link>
		<description>Developpez.com, le Club des Développeurs et IT Pro</description>
		<language>fr</language>
		<lastBuildDate>Sat, 18 Apr 2026 23:56:48 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>15</ttl>
		<image>
			<url>https://forum.developpez.be/images/misc/rss.jpg</url>
			<title>Forum du club des développeurs et IT Pro - Blogs - bouye</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/</link>
		</image>
		<item>
			<title>Notes de mises à jour de JavaFX 24</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b10680/notes-mises-jour-javafx-24/</link>
			<pubDate>Sun, 16 Mar 2025 22:51:32 GMT</pubDate>
			<description>Alors que la sortie du JDK 24...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Alors que la sortie du JDK 24 est attendue pour demain 18 mars 2025 (heure américaine) et que JavaFX 24 suivra dans la foulée, les notes de mises à jour de l'OpenJFX 24 sont désormais <a href="https://github.com/openjdk/jfx/blob/master/doc-files/release-notes-24.md" target="_blank">disponibles sur GitHub</a>.<br />
<br />
Parmi les nouveautés importantes à signaler :<br />
<br />
<b>JDK 22 requis</b><br />
JavaFX 24 requiert au minimum le JDK 22 pour pouvoir être utilisé. <br />
<br />
<b>Confirmation d’accès natif</b><br />
Suite à des changements de sécurité dans le JDK 24, les méthodes qui font des accès natifs provoqueront désormais l'affichage de l'avertissement suivant dans la console : <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">WARNING: Restricted methods will be blocked in a future release unless native access is enabled</pre>
</div>Cela impactera l'utilisation pas mal de bibliothèques tierces faisant des appels natifs, dont JavaFX. Pour se prémunir d'un blocage de ces accès dans des versions futures du JDK, il faudra donc rajouter le flag suivant à l’interpréteur Java lors l’exécution : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">--enable-native-access=&lt;list-of-modules&gt;</span>. Pour JavaFX, la liste de ces modules inclut <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.graphics</span> qui fait partie des modules de base et, optionnellement, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.media</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.web</span> si vous les utilisez.<br />
<br />
Ce qui donne, par exemple :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">java --enable-native-access=javafx.graphics,javafx.media,javafx.web</pre>
</div><b>Liaison avec navigateur web intégré</b><br />
Le module <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jdk.jsobject</span> qui est utilisé pour fournir un pont entre le navigateur web <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">WebView</span> et le code Java est déprécié dans le JDK 24 et sera retiré dans une version future de Java. JavaFX 24 fournira désormais sa propre version de ce module qui devra donc être utilisé en lieu et place de la version du JDK.<br />
<br />
Lors du développement avec le JDK 24, le flag <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">--upgrade-module-path</span> devra être utilisé avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javac</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">java</span> pour permettre la compilation et l’exécution avec la nouvelle version du module :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">javac --upgrade-module-path=/path/to/javafx-sdk-24/lib
java --upgrade-module-path=/path/to/javafx-sdk-24/lib</pre></td></tr></table></pre>
</div>Cette méthode ne fonctionnera pas avec les JDK 22 ou 23. Pour ces JDK, il faudra alternativement utiliser le flag <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">--module-path</span>.<br />
<br />
Lors de la création d'applications natives avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jlink</span>, l'ordre dans lequel le chemin vers les fichiers jmods est liste est désormais important et, quand le JDK 24 est utilisé, le chemin d’accès des fichiers jmods de JavaFX doit être placés <b><u>avant</u></b> celui des fichiers du JDK :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">jlink --output jdk-with-javafx \
    --module-path /path/to/javafx-jmods-24:/path/to/jdk-24/jmods \
    --add-modules ALL-MODULE-PATH</pre></td></tr></table></pre>
</div>Cette méthode ne fonctionnera pas avec les JDK 22 ou 23. Pour ces JDK, il faudra mettre le chemin d’accès des fichiers jmods de JavaFX <b><u>après</u></b> celui des fichiers du JDK.<br />
<br />
<b>Extension des formats d'images pris en charge</b> <br />
Le chargement des images dans JavaFX 24 repose sur le module <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javax.imageio</span>. L'API de module permet d'utiliser des bibliothèques et pilotes tiers pour prendre en charge des formats d'images supplémentaires, par exemple des formats à densité variable tels que SVG. Lors du chargement d'image à densité variable, JavaFX générera une version rastérisée de l'image adaptée à la configuration de l'écran. <br />
<br />
Il est donc possible d'utiliser des bibliothèques et pilotes tiers fournis en tant qu’extension Image I/O ou en tant que services enregistrés auprès de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IIORegistry</span>. Voir la <a href="https://docs.oracle.com/en/java/javase/23/docs/api/java.desktop/javax/imageio/package-summary.html" target="_blank">documentation de Image I/O</a> pour plus d'information.<br />
<br />
<b>Conclusion</b><br />
Le JDK 24 force l’arrivée de quelques changements qui vont modifier un peules habitudes et la configuration des projets JavaFX qui était sensiblement les mêmes depuis la sortie du JDK 9 et le passage aux modules. L’arrivée du support de nouveaux formats d'image est toujours un plus bienvenu. Le reste du document détaille le lot habituel de correctifs ou de soucis connus.<br />
<br />
Sources : <a href="https://github.com/openjdk/jfx/blob/master/doc-files/release-notes-24.md" target="_blank">GitHub OpenJDK-OpenJFX</a></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b10680/notes-mises-jour-javafx-24/</guid>
		</item>
		<item>
			<title>Les transitions CSS en JavaFX (partie 1)</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b10642/transitions-css-javafx-partie-1/</link>
			<pubDate>Thu, 31 Oct 2024 04:31:55 GMT</pubDate>
			<description>Parmi les notes de mises a...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Parmi les notes de mises a jour de JavaFX 23 on peut voir l'info suivante qui s'y est glissée en catimini : <br />
<br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>https://gluonhq.com/products/javafx/openjfx-23-release-notes/#23</strong>
					
				</div>
				<div class="message"><font size="2"><b>List of New Features</b></font><br />
<div class="cms_table"><table width="500" class="cms_table"><tr valign="top" class="cms_table_tr"><td class="cms_table_td"><b>Issue key</b></td>
<td class="cms_table_td"><b>Summary</b></td>
<td class="cms_table_td"><b>Subcomponent</b></td>
</tr>
<tr valign="top" class="cms_table_tr"><td class="cms_table_td">[...]</td>
</tr>
<tr valign="top" class="cms_table_tr"><td class="cms_table_td">JDK-8311895</td>
<td class="cms_table_td">CSS Transitions</td>
<td class="cms_table_td">graphics</td>
</tr>
</table></div></div>
			
		</div>
	</div>
</div><div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>https://openjfx.io/highlights/23/</strong>
					
				</div>
				<div class="message"><ul><li style=""> CSS Transition support in JavaFX, making it easy to define animated transitions for creating rich and fluid user experiences</li></ul></div>
			
		</div>
	</div>
</div>Bien que le <a href="https://bugs.openjdk.org/browse/JDK-8311895" target="_blank">ticket sur le JDK Bug System</a> date de 2023, on peut trouver des tickets plus anciens datant de 2010 et de 2014 qui demandent essentiellement la meme chose : permettre de définir des animations dans les feuilles de style. Autant dire que c’était une fonctionnalité simple (d'apparence) mais qui était attendue de longue date.<br />
<br />
Je ne vais pas m’étendre en long et en large sur les limitations de la syntaxe, des propriétés supportées, ni sur les capacités à capturer les événements d'animation CSS depuis le code, l'excellent article (en anglais) &quot;<a href="https://www.pragmaticcoding.ca/javafx/elements/css-transitions" target="_blank">CSS Transitions</a>&quot; disponible sur PragmaticCode fait tout cela beaucoup plus en détails. L'important est de savoir que, grosso modo, les transitions CSS JavaFX sont inspirées des transitions <a href="https://www.w3.org/TR/css-transitions-1/" target="_blank">CSS pour le web définies par par le W3.org</a>.<br />
<br />
Placer des transitions (animations) légères dans le fichier CSS permet d'enrichir la présentation visuelle sans devoir alourdir de code du composant. C'est une autre manière de séparer la vue (la presentation) des classes métier, tout comme le fait de placer le design des formulaires dans un fichier FXML externe et de se contenter de mettre le code permettant de faire fonctionner ce formulaire dans une classe contrôleur. Ceci dit rien n'oblige à utiliser un FXML pour mettre en oeuvre ces transitions, elle fonctionnent très bien en l’état sur des écrans définis dans du code Java pur (ou Kotlin ou autre) aussi.<br />
<br />
<b>Mise en place du projet</b><br />
Commençons donc par écrire un simple programme JavaFX qui contient juste une scène, contenant un gestionnaire de mise en page de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">BorderPane</span> (la mise en page peut se faire dans 5 emplacements : haut, bas, droite, gauche et centre) :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test.csstransition;
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application;
<span style="color: #0000ff;">import</span> javafx.scene.Scene;
<span style="color: #0000ff;">import</span> javafx.scene.layout.BorderPane;
<span style="color: #0000ff;">import</span> javafx.stage.Stage;
&nbsp;
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">class</span> Main <span style="color: #0000ff;">extends</span> Application <span class="br0">&#123;</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> String... args<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        launch<span class="br0">&#40;</span>args<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
&nbsp;
&nbsp;
    <span style="color: #339933;">@Override</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> start<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> Stage stage<span class="br0">&#41;</span> <span style="color: #0000ff;">throws</span> Exception <span class="br0">&#123;</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> root = <span style="color: #0000ff;">new</span> BorderPane<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> scene = <span style="color: #0000ff;">new</span> Scene<span class="br0">&#40;</span>root<span class="br0">&#41;</span>;
        stage.setTitle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Test&quot;</span><span class="br0">&#41;</span>;
        stage.setWidth<span class="br0">&#40;</span><span style="color: #cc66cc;">800</span><span class="br0">&#41;</span>;
        stage.setHeight<span class="br0">&#40;</span><span style="color: #cc66cc;">600</span><span class="br0">&#41;</span>;
        stage.setScene<span class="br0">&#40;</span>scene<span class="br0">&#41;</span>;
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Nous allons également en profiter pour ajouter quelques nœuds graphiques dans note scene : un contrôle, ici un bouton, plusieurs formes géométriques et une région. Je rappelle qu'une région est un nœud graphique représentant généralement une forme rectangulaire skinnable, et qui sert de base a la plupart des contrôles. <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> button = <span style="color: #0000ff;">new</span> Button<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Button&quot;</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> tooBar = <span style="color: #0000ff;">new</span> ToolBar<span class="br0">&#40;</span><span class="br0">&#41;</span>;
tooBar.getItems<span class="br0">&#40;</span><span class="br0">&#41;</span>.setAll<span class="br0">&#40;</span>button<span class="br0">&#41;</span>;
<span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> rectangle = <span style="color: #0000ff;">new</span> Rectangle<span class="br0">&#40;</span><span style="color: #cc66cc;">200</span>, <span style="color: #cc66cc;">200</span>, <span style="color: #cc66cc;">150</span>, <span style="color: #cc66cc;">100</span><span class="br0">&#41;</span>;
rectangle.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;rectangle&quot;</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> circle = <span style="color: #0000ff;">new</span> Circle<span class="br0">&#40;</span><span style="color: #cc66cc;">100</span><span class="br0">&#41;</span>;
circle.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;circle&quot;</span><span class="br0">&#41;</span>;
circle.setCenterX<span class="br0">&#40;</span><span style="color: #cc66cc;">150</span><span class="br0">&#41;</span>;
circle.setCenterY<span class="br0">&#40;</span><span style="color: #cc66cc;">150</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> region = <span style="color: #0000ff;">new</span> Region<span class="br0">&#40;</span><span class="br0">&#41;</span>;
region.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;region&quot;</span><span class="br0">&#41;</span>;
region.setLayoutX<span class="br0">&#40;</span><span style="color: #cc66cc;">300</span><span class="br0">&#41;</span>;
region.setLayoutY<span class="br0">&#40;</span><span style="color: #cc66cc;">275</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> center = <span style="color: #0000ff;">new</span> Pane<span class="br0">&#40;</span><span class="br0">&#41;</span>;
center.getChildren<span class="br0">&#40;</span><span class="br0">&#41;</span>.setAll<span class="br0">&#40;</span>rectangle, circle, region<span class="br0">&#41;</span>;
root.setTop<span class="br0">&#40;</span>tooBar<span class="br0">&#41;</span>;
root.setCenter<span class="br0">&#40;</span>center<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
Pour le moment rien de bien excitant : les 2 formes sont noires (initialisation avec les options par défaut) et la région est invisible car soit transparent, soit avec la la même couleur de fond que celle de notre conteneur parent.<br />
<br />
<img src="https://www.developpez.net/forums/attachments/p660851d1729568808/c-cpp/outils-c-cpp/cppbuilder/convertir-ansistring-hexadecimal/csstransition-1.jpg/" border="0" alt="Nom : csstransition-1.jpg
Affichages : 7196
Taille : 23,4 Ko"  style="float: CONFIG" /><br />
<br />
<b>Ajout de la feuille de style</b><br />
J’insère ensuite un fichier de feuille de style CSS vide dans le même package, et je charge ce fichier de la manière suivante :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">Optional.ofNullable<span class="br0">&#40;</span>getClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.getResource<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;test.css&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
     .map<span class="br0">&#40;</span>URL::toExternalForm<span class="br0">&#41;</span>
     .ifPresent<span class="br0">&#40;</span>scene.getStylesheets<span class="br0">&#40;</span><span class="br0">&#41;</span>::add<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
Et nous allons commencer à remplir le CSS en donnant une apparence un peu plus colorée à notre contenu en ajoutant les lignes suivantes dans le fichier CSS :<br />
* Le cercle sera bleu avec une bordure noire de 1 pixel d’épaisseur.<br />
* le rectangle sera rempli d'un gradient vertical allant du bleu au vert et avec une bordure affichant un gradient diagonal allant du jaune vers le rouge avec une épaisseur de 2 pixels.<br />
* la région sera dotée d'une taille minimale de 100 × 75 pixels, avec un fond rouge et une bordure grise, le tout semi-transparent.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span>, <span style="color: #800000;">blue</span>, <span style="color: #800000;">green</span><span class="br0">&#41;</span>;
    -fx-stroke: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span> <span style="color: #0080ff;">right</span>, <span style="color: #800000;">yellow</span>, <span style="color: #800000;">red</span><span class="br0">&#41;</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">2</span>px;
<span class="br0">&#125;</span>
<span style="color: #339933;">.circle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #800000;">blue</span>;
    -fx-stroke: <span style="color: #800000;">black</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">1</span>px;
<span class="br0">&#125;</span>
<span style="color: #339933;">.region</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">red</span>;
    -fx-background-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-border-color: <span style="color: #800000;">grey</span>;
    -fx-border-width: <span style="color: #cc66cc;">1</span>px;
    -fx-border-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-min-width: <span style="color: #cc66cc;">100</span>px;
    -fx-min-height: <span style="color: #cc66cc;">75</span>px;
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Ce qui nous donne désormais ceci :<br />
<br />
<img src="https://www.developpez.net/forums/attachments/p660852d1729569451/c-cpp/outils-c-cpp/cppbuilder/convertir-ansistring-hexadecimal/csstransition-2.jpg/" border="0" alt="Nom : csstransition-2.jpg
Affichages : 2103
Taille : 28,1 Ko"  style="float: CONFIG" /><br />
<br />
<b>Et les transitions ?</b><br />
Nous y arrivons ! Pour déclencher une animation, nous avons besoin de 2 choses : premièrement un état différent de l’état de base. Ceci se s'accomplit généralement en CSS grâce à une ou plusieurs pseudo classe. Ici nous allons utiliser la pseudo-classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">hover</span> qui dénote le fait que le curseur de la souris se trouve au-dessus du nœud ciblé. C'est un des pseudo-classe prédéfinies et qui se trouvent aussi dans les CSS web, mais ne vous inquiétez pas, les transitions CSS en JavaFX fonctionnent aussi avec des pseudo-classes personnalisées.<br />
<br />
Et la seconde chose dont nous avons besoin c'est une ou plusieurs propriétés que nous allons faire varier. Ici, nous allons prendre par exemple, la propriété <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-fx-rotate</span> de la classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Rectangle</span>. Cette propriété définit bien sûr l'angle de la rotation qui est appliquée sur le nœud. Notre CSS va donc devenir : <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span>, <span style="color: #800000;">blue</span>, <span style="color: #800000;">green</span><span class="br0">&#41;</span>;
    -fx-stroke: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span> <span style="color: #0080ff;">right</span>, <span style="color: #800000;">yellow</span>, <span style="color: #800000;">red</span><span class="br0">&#41;</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">2</span>px;
    -fx-rotate: <span style="color: #cc66cc;">0</span>;
<span class="br0">&#125;</span>
<span style="color: #339933;">.rectangle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-rotate: <span style="color: #cc66cc;">90</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Si on relance l'application, on peut voir que le rectangle tourne de 90° sur lui-même dès que le curseur entre dans sa boite englobante. <b>Attention</b> cependant, évitez de mettre votre curseur trop près du bord droit ou gauche du rectangle si vous souffrez épilepsie. En effet, dans ce cas le rectangle va basculer très rapidement sans arrêt d'entre son état par défaut et son état <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">hover</span> provoquant un clignotement assez désagréable à l'écran. Cela est dû au fait que, dès que le rectangle se trouve orienté à 90°, votre curseur est en dehors de la boite englobante, provoquant ainsi un retour à l’état initial, et ainsi de suite, <i>ad vitam</i>. <br />
<br />
Changeons maintenant la définition pour rajouter l'animation de la rotation : <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:156px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span>, <span style="color: #800000;">blue</span>, <span style="color: #800000;">green</span><span class="br0">&#41;</span>;
    -fx-stroke: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span> <span style="color: #0080ff;">right</span>, <span style="color: #800000;">yellow</span>, <span style="color: #800000;">red</span><span class="br0">&#41;</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">2</span>px;
    -fx-rotate: <span style="color: #cc66cc;">0</span>;
    <span style="color: #0000ff;">transition</span>: -fx-rotate <span style="color: #cc66cc;">2</span>s;
<span class="br0">&#125;</span>
<span style="color: #339933;">.rectangle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-rotate: <span style="color: #cc66cc;">90</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
La ligne <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition: -fx-rotate 2s;</span> qui est définie dans le sélecteur de base du rectangle permet de définir une animation d'une durée de 2 secondes sur la propriété <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-fx-rotate</span> permettant ainsi d'avoir une transition fluide entre l'état par défaut et l'état <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">hover</span>. Quand le curseur de la souris sort de la boite englobante du nœud, l'animation commence par se mettre en pause avant de s'inverser pour tenter de revenir à l’état initial. L'effet est quand même plus agréable que le clignotement précédent.<br />
<br />
Il est aussi possible d’écrire cette transition de la manière suivante :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:132px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span>, <span style="color: #800000;">blue</span>, <span style="color: #800000;">green</span><span class="br0">&#41;</span>;
    -fx-stroke: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span> <span style="color: #0080ff;">right</span>, <span style="color: #800000;">yellow</span>, <span style="color: #800000;">red</span><span class="br0">&#41;</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">2</span>px;
    -fx-rotate: <span style="color: #cc66cc;">0</span>;
    <span style="color: #0000ff;">transition-property</span>: -fx-rotate;
    <span style="color: #0000ff;">transition-duration</span>: <span style="color: #cc66cc;">2</span>s;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
La directive <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition</span> et les sous-directives associées permettent donc de spécifier une ou plusieurs propriété, un temps d'animation et également un interpolateur. Il est également possible de specifier un temps d'attente avant démarrage de l'animation. De multiples définitions d'animations doivent être séparées par des virgule.<br />
<br />
<ul><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition</span> - spécifie une ou plusieurs animation de manière condensée. Il est possible d'utiliser le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">all</span> pour signaler des transitions sur toutes les propriétés idoines ;</li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition-property</span> - spécifie une ou plusieurs propriétés à animer. Il est également possible d'utiliser le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">all</span> ici ;</li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition-duration</span> - spécifie une ou plusieurs durée d'animation. Le nombre de durées doit correspondre au nombre de propriétés définies ;</li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition-delay</span> - spécifie un ou plusieurs délais d'attente avant animation. Le nombre de délais doit correspondre au nombre de propriétés définies ;</li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">transition-timing-function</span> - spécifie un ou plusieurs interpolateurs à appliquer à l'animation. Voir <a href="https://openjfx.io/javadoc/23/javafx.graphics/javafx/scene/doc-files/cssref.html#typeeasingfunction" target="_blank">Guide de reference des CSS de JavaFX 23</a>. Le nombre d'interpolateurs doit correspondre au nombre de propriétés définies ;</li></ul><br />
<br />
Prenons maintenant notre cercle, je vais lancer une transition sur sa position, son opacité, l’épaisseur de sa bordure et ses couleurs de remplissages et de trait. Pour faire simple, je vais mettre toutes ses transitions à la même durée de 3 secondes. Pour la version de base non animée cela done :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.circle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #800000;">blue</span>;
    -fx-stroke: <span style="color: #800000;">black</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">1</span>px;
    -fx-opacity: <span style="color: #cc66cc;">1.0</span>;
    -fx-translate-x: <span style="color: #cc66cc;">0</span>;
    -fx-translate-y: <span style="color: #cc66cc;">0</span>;
<span class="br0">&#125;</span>
<span style="color: #339933;">.circle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #800000;">cyan</span>;
    -fx-stroke: <span style="color: #800000;">yellow</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">50</span>px;
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
    -fx-translate-x: <span style="color: #cc66cc;">50</span>;
    -fx-translate-y: <span style="color: #cc66cc;">50</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Et pour rajouter des transitions, n'importe laquelle de ces définitions qui sont équivalentes fera l'affaire :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">    <span style="color: #0000ff;">transition-property</span>: -fx-fill, -fx-stroke, -fx-stroke-width, -fx-translate-x, -fx-translate-y;
    <span style="color: #0000ff;">transition-duration</span>: <span style="color: #cc66cc;">3</span>s, <span style="color: #cc66cc;">3</span>s, <span style="color: #cc66cc;">3</span>s, <span style="color: #cc66cc;">3</span>s, <span style="color: #cc66cc;">3</span>s;</pre></td></tr></table></pre>
</div><br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">    <span style="color: #0000ff;">transition</span>: -fx-fill <span style="color: #cc66cc;">3</span>s, -fx-stroke <span style="color: #cc66cc;">3</span>s, -fx-stroke-width <span style="color: #cc66cc;">3</span>s, -fx-translate-x <span style="color: #cc66cc;">3</span>s, -fx-translate-y <span style="color: #cc66cc;">3</span>s;</pre>
</div><br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">    <span style="color: #0000ff;">transition</span>: <span style="color: #0080ff;">all</span> <span style="color: #cc66cc;">3</span>s;</pre>
</div><br />
<b>Limitations</b><br />
<b>Actuellement</b>, les transitions CSS en JavaFX fonctionnent avec toutes les propriétés qui utilisent des valeurs numériques ou qui implémentent l'interface <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"> javafx.animation.Interpolatable&lt;T&gt;</span>, ce qui inclut les implémentations JavaFX des couleurs (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.scene.paint.Color</span>), mais aussi les point 2D (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.geometry.Point2D</span>) et les points 3D (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.geometry.Point3D</span>). Les couleurs sont utilisées un peu partout dans les CSS fournies par défaut, mais je n'ai pas croisé d’occurrence d'utilisation de point 2D ou 3D. Sur le papier, il devrait être possible de créer des transition avec des propriétés customisées, voir des types interpolables customisés, mais il n'est pas dit que le moteur CSS de JavaFX soit capable d’inférer les bonnes classe lors de la lecture de la feuille de style. À noter que des améliorations sur le parsing des CSS sont en préparation pour les futures version de JavaFX permettant de mieux supporter des types de valeur autres.<br />
<br />
Il n'est pas possible de faire des transitions sur les couleurs prédéfinies. Dans les CSS par défaut de JavaFX, beaucoup de couleurs sont prédéfinies ; par exemple <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-fx-color</span> contient la couleur grise qui est appliquée dans la plupart des conteneurs. Et il est possible de redéfinir ces couleurs dans des CSS customs :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:120px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-color: <span style="color: #800000;">green</span>;
    -fx-fill: -fx-color;
<span class="br0">&#125;</span>
<span style="color: #339933;">.rectangle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-color: <span style="color: #800000;">blue</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
La couleur changera bien du vert au bleu lorsque le curseur entre dans la boite englobante du rectangle mais si on définie une transition CSS ciblant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-fx-color</span> (au lieu de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-fx-fill</span>), celle-ci ne fonctionnera pas et, à l’écran, on conservera la transition abrupte précédente.<br />
<br />
Et en ce qui concerne les contrôles ? En fait c'est là où le bas blesse : la plupart des propriétés stylables visuelles sur les contrôles sont définies dans la classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Region</span> et concernent des choses telles que la bordure et la surface interne du contrôle. Souvent ce sont des propriétés qui définissent un à plusieurs objets complexes qui ne sont pas interpolables. Donc, dans JavaFX 23, en gros, ce qu'on peut animer sur les contrôles via les transitions CSS ce sont surtout les mêmes propriétés d’opacité ou de taille, positionnement, angle, échelle, etc. que sur les formes géométriques ; et il reste impossible de faire des transitions sur les bordures, leurs épaisseurs et angles de coins arrondis ou encore sur la peinture de fond du contrôle.<br />
<br />
Par exemple, en appliquant la feuille de style suivante, tous les changements seront appliqués lorsque le curseur passera au-dessus de la région, mais la transition CSS impliquera uniquement l’opacité de la région :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.region</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">red</span>;
    -fx-background-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-border-color: <span style="color: #800000;">grey</span>;
    -fx-border-width: <span style="color: #cc66cc;">1</span>px;
    -fx-border-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
    -fx-min-width: <span style="color: #cc66cc;">100</span>px;
    -fx-min-height: <span style="color: #cc66cc;">75</span>px;
    <span style="color: #0000ff;">transition</span>: <span style="color: #0080ff;">all</span> <span style="color: #cc66cc;">2</span>s;
<span class="br0">&#125;</span>
<span style="color: #339933;">.region</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">purple</span>;
    -fx-background-radius: <span style="color: #cc66cc;">21</span>px;
    -fx-border-color: <span style="color: #800000;">black</span>;
    -fx-border-width: <span style="color: #cc66cc;">10</span>px;
    -fx-border-radius: <span style="color: #cc66cc;">20</span>px;
    -fx-opacity: <span style="color: #cc66cc;">1</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
<b>Conclusion</b><br />
Voici le code et la feuille de style finale pour ce bref aperçu de cette nouvelle fonctionnalité. Utilisée avec parcimonie et subtilité, elle peut permettre de rajouter une touche de zestes et de piments à vos interface graphiques JavaFX sans pour autant devoir se lancer dans de lourds travaux de codages d'animations en Java pur. Il suffira de quelques modifications de vos fichiers CSS !<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test.csstransition;
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application;
<span style="color: #0000ff;">import</span> javafx.scene.Scene;
<span style="color: #0000ff;">import</span> javafx.scene.control.Button;
<span style="color: #0000ff;">import</span> javafx.scene.control.ToolBar;
<span style="color: #0000ff;">import</span> javafx.scene.layout.BorderPane;
<span style="color: #0000ff;">import</span> javafx.scene.layout.Pane;
<span style="color: #0000ff;">import</span> javafx.scene.layout.Region;
<span style="color: #0000ff;">import</span> javafx.scene.shape.Circle;
<span style="color: #0000ff;">import</span> javafx.scene.shape.Rectangle;
<span style="color: #0000ff;">import</span> javafx.stage.Stage;
&nbsp;
<span style="color: #0000ff;">import</span> java.net.URL;
<span style="color: #0000ff;">import</span> java.util.Optional;
&nbsp;
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">class</span> Main <span style="color: #0000ff;">extends</span> Application <span class="br0">&#123;</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> String... args<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        launch<span class="br0">&#40;</span>args<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
&nbsp;
&nbsp;
    <span style="color: #339933;">@Override</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> start<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> Stage stage<span class="br0">&#41;</span> <span style="color: #0000ff;">throws</span> Exception <span class="br0">&#123;</span>
        <span style="color: #808080;">// Toolbar &amp; button.</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> button = <span style="color: #0000ff;">new</span> Button<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Button&quot;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> tooBar = <span style="color: #0000ff;">new</span> ToolBar<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        tooBar.getItems<span class="br0">&#40;</span><span class="br0">&#41;</span>.setAll<span class="br0">&#40;</span>button<span class="br0">&#41;</span>;
        <span style="color: #808080;">// Shapes &amp; region.</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> rectangle = <span style="color: #0000ff;">new</span> Rectangle<span class="br0">&#40;</span><span style="color: #cc66cc;">200</span>, <span style="color: #cc66cc;">200</span>, <span style="color: #cc66cc;">150</span>, <span style="color: #cc66cc;">100</span><span class="br0">&#41;</span>;
        rectangle.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;rectangle&quot;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> circle = <span style="color: #0000ff;">new</span> Circle<span class="br0">&#40;</span><span style="color: #cc66cc;">100</span><span class="br0">&#41;</span>;
        circle.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;circle&quot;</span><span class="br0">&#41;</span>;
        circle.setCenterX<span class="br0">&#40;</span><span style="color: #cc66cc;">150</span><span class="br0">&#41;</span>;
        circle.setCenterY<span class="br0">&#40;</span><span style="color: #cc66cc;">150</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> region = <span style="color: #0000ff;">new</span> Region<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        region.getStyleClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;region&quot;</span><span class="br0">&#41;</span>;
        region.setLayoutX<span class="br0">&#40;</span><span style="color: #cc66cc;">300</span><span class="br0">&#41;</span>;
        region.setLayoutY<span class="br0">&#40;</span><span style="color: #cc66cc;">275</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> center = <span style="color: #0000ff;">new</span> Pane<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        center.getChildren<span class="br0">&#40;</span><span class="br0">&#41;</span>.setAll<span class="br0">&#40;</span>rectangle, circle, region<span class="br0">&#41;</span>;
        <span style="color: #808080;">// Layout.</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> root = <span style="color: #0000ff;">new</span> BorderPane<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        root.setTop<span class="br0">&#40;</span>tooBar<span class="br0">&#41;</span>;
        root.setCenter<span class="br0">&#40;</span>center<span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> scene = <span style="color: #0000ff;">new</span> Scene<span class="br0">&#40;</span>root<span class="br0">&#41;</span>;
        <span style="color: #808080;">// load and apply CSS.</span>
        Optional.ofNullable<span class="br0">&#40;</span>getClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.getResource<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;test.css&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .map<span class="br0">&#40;</span>URL::toExternalForm<span class="br0">&#41;</span>
                .ifPresent<span class="br0">&#40;</span>scene.getStylesheets<span class="br0">&#40;</span><span class="br0">&#41;</span>::add<span class="br0">&#41;</span>;
        stage.setTitle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Test&quot;</span><span class="br0">&#41;</span>;
        stage.setWidth<span class="br0">&#40;</span><span style="color: #cc66cc;">800</span><span class="br0">&#41;</span>;
        stage.setHeight<span class="br0">&#40;</span><span style="color: #cc66cc;">600</span><span class="br0">&#41;</span>;
        stage.setScene<span class="br0">&#40;</span>scene<span class="br0">&#41;</span>;
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.button</span> <span class="br0">&#123;</span>
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
    <span style="color: #0000ff;">transition</span>: -fx-opacity <span style="color: #cc66cc;">1</span>s;
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #339933;">.button</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-opacity: <span style="color: #cc66cc;">1.0</span>;
<span class="br0">&#125;</span>
<span style="color: #339933;">.rectangle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span>, <span style="color: #800000;">blue</span>, <span style="color: #800000;">green</span><span class="br0">&#41;</span>;
    -fx-stroke: <span style="color: #0080ff;">linear-gradient</span><span class="br0">&#40;</span>to <span style="color: #0080ff;">bottom</span> <span style="color: #0080ff;">right</span>, <span style="color: #800000;">yellow</span>, <span style="color: #800000;">red</span><span class="br0">&#41;</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">2</span>px;
    -fx-rotate: <span style="color: #cc66cc;">0</span>;
    <span style="color: #0000ff;">transition</span>: -fx-rotate <span style="color: #cc66cc;">2</span>s;
<span style="color: #808080;">/*    transition-property: -fx-rotate;*/</span>
<span style="color: #808080;">/*    transition-duration: 2s;*/</span>
<span class="br0">&#125;</span>
<span style="color: #339933;">.rectangle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-rotate: <span style="color: #cc66cc;">90</span>;
<span class="br0">&#125;</span>
<span style="color: #339933;">.circle</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #800000;">blue</span>;
    -fx-stroke: <span style="color: #800000;">black</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">1</span>px;
    -fx-opacity: <span style="color: #cc66cc;">1.0</span>;
    -fx-translate-x: <span style="color: #cc66cc;">0</span>;
    -fx-translate-y: <span style="color: #cc66cc;">0</span>;
    <span style="color: #0000ff;">transition</span>: <span style="color: #0080ff;">all</span> <span style="color: #cc66cc;">3</span>s;
<span style="color: #808080;">/*    transition: -fx-fill 3s, -fx-stroke 3s, -fx-stroke-width 3s, -fx-translate-x 3s, -fx-translate-y 3s;*/</span>
<span style="color: #808080;">/*    transition-property: -fx-fill, -fx-stroke, -fx-stroke-width, -fx-translate-x, -fx-translate-y;*/</span>
<span style="color: #808080;">/*    transition-duration: 3s, 3s, 3s, 3s, 3s;*/</span>
<span class="br0">&#125;</span>
<span style="color: #339933;">.circle</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-fill: <span style="color: #800000;">cyan</span>;
    -fx-stroke: <span style="color: #800000;">yellow</span>;
    -fx-stroke-width: <span style="color: #cc66cc;">50</span>px;
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
    -fx-translate-x: <span style="color: #cc66cc;">50</span>;
    -fx-translate-y: <span style="color: #cc66cc;">50</span>;
<span class="br0">&#125;</span>
<span style="color: #339933;">.region</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">red</span>;
    -fx-background-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-border-color: <span style="color: #800000;">grey</span>;
    -fx-border-width: <span style="color: #cc66cc;">1</span>px;
    -fx-border-radius: <span style="color: #cc66cc;">0</span>px;
    -fx-opacity: <span style="color: #cc66cc;">0.5</span>;
    -fx-min-width: <span style="color: #cc66cc;">100</span>px;
    -fx-min-height: <span style="color: #cc66cc;">75</span>px;
    <span style="color: #0000ff;">transition</span>: <span style="color: #0080ff;">all</span> <span style="color: #cc66cc;">2</span>s;
<span class="br0">&#125;</span>
<span style="color: #339933;">.region</span><span style="color:#FF803A;">:hover</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">purple</span>;
    -fx-background-radius: <span style="color: #cc66cc;">21</span>px;
    -fx-border-color: <span style="color: #800000;">black</span>;
    -fx-border-width: <span style="color: #cc66cc;">10</span>px;
    -fx-border-radius: <span style="color: #cc66cc;">20</span>px;
    -fx-opacity: <span style="color: #cc66cc;">1</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
<img src="https://www.developpez.net/forums/attachments/p660899d1729636893/c-cpp/outils-c-cpp/cppbuilder/convertir-ansistring-hexadecimal/csstransition-4.gif/" border="0" alt="Nom : csstransition-4.gif
Affichages : 2100
Taille : 1,18 Mo"  style="float: CONFIG" /><br />
<br />
<b>Épilogue ?</b><br />
Vous avez pu remarquer que ce blog post est intitulé &quot;partie 1&quot;. En effet, comme nous avons pu le voir, bien que sympathiques sur des formes géométriques, les animations CSS ne fonctionnent autant qu'on le voudrait sur des régions ou des contrôles car les éléments CSS de ces nœuds sont plus complexes et ne sont pas interpolables. Cependant, des améliorations du support des animations CSS pour ce genre de propriétés sont annoncées pour le futur JavaFX 24 qui devrait pointer le bout de son nez en mars 2025.<br />
<br />
À suivre... ?</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b10642/transitions-css-javafx-partie-1/</guid>
		</item>
		<item>
			<title>Les abonnements en JavaFX</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b10640/abonnements-javafx/</link>
			<pubDate>Thu, 10 Oct 2024 04:47:42 GMT</pubDate>
			<description>Salut,  
de passage à nouveau...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Salut, <br />
de passage à nouveau après quelques temps d'absence (même si toujours présent sur la modération du forum). Je me suis penché ces derniers temps sur les nouveautés apportées dans Java et JavaFX 21 à 23. Parmi les choses qui méritent d’être relevées, on peut trouver :<br />
<ul><li style="">Le fait de ne plus avoir besoin de nommer les variables inutilisées dans les lambda (Java 22)</li><li style="">Le support des animations simples dans les CSS (JavaFX 23)</li><li style="">Les abonnements sur les propriétés (JavaFX 21)</li></ul><br />
C’est sur ce dernier point que je vais revenir aujourd’hui car il se trouve être un complément à ma série d’articles tournant autour des propriétés en JavaFX :<br />
<ul><li style=""><a href="https://fabrice-bouye.developpez.com/tutoriels/javafx/evenement-invalidation-modification-proprietes-expressions-javafx/" target="_blank">De l'art et de la manière de définir des propriétés dans vos objets JavaFX</a></li><li style=""><a href="https://fabrice-bouye.developpez.com/tutoriels/javafx/binding-bas-niveau-liaisons-proprietes-expressions-javafx/" target="_blank">Comprendre le binding de bas niveau en JavaFX</a></li><li style=""><a href="https://fabrice-bouye.developpez.com/tutoriels/javafx/binding-haut-niveau-liaisons-proprietes-expressions-javafx/" target="_blank">Comprendre le binding de haut niveau en JavaFX</a></li></ul><br />
Précédemment, pour connaitre les changements sur la valeur contenue dans une propriété, il fallait enregistrer des écouteurs de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">InvalidationListerner</span> ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ChangeListener</span> :<br />
<ul><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">InvalidationListener</span>  - un type d’évènement léger qui prévient que la valeur contenue dans la propriété n’est plus valide (invalidée), et ne fournit plus d’autre notification tant que la valeur n’est pas revalidée (ce qui se passe au premier accès direct à la propriété) ;<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span>observable -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span></pre>
</div></li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ChangeListener</span>  - un type d’évènement lourd (récurrent) qui prévient que la valeur dans la propriété a changé et fournit des références sur la propriété, l’ancienne valeur et la nouvelle valeur. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span><span class="br0">&#40;</span>observable, oldValue, newValue<span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span>;</pre>
</div></li></ul><br />
<br />
<b>Abonnement</b><br />
Les abonnements (<i>subscriptions</i>) se trouvent donc être un moyen de simplifier encore plus le code (et la gestion des écouteurs) lorsqu’on gère des propriétés observables. Chaque propriété se trouve désormais affublée d’une nouvelle méthode nommée <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">subscribe()</span> qui dispose de 3 surcharges :<br />
<br />
<b><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Runnable</span> (lambda sans paramètre)</b><br />
Cette méthode est définie dans l'interface <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.beans.Observable</span>, là où est défini le contrat de gestion des <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">InvalidationListener</span> . Elle sert exactement à faire la même chose : être prévenu que la valeur de la propriété est désormais invalide.  Le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Runnable</span> passé en argument sera exécuté une seule fois tant que la valeur n’est pas à nouveau revalidée ; donc des changements successifs de valeur passeront totalement inaperçus. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span>observable -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span></pre>
</div>Devient : <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span></pre>
</div><br />
Les 2 autres méthodes sont définies dans l'interface <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ObservableValue&lt;T&gt;</span>, là où est défini le contrat de gestion des <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ChangeListener</span>. De la même manière, ces 2 surcharges font exactement la même chose que des écouteurs de changement : être prévenu des variation de la valeur de la propriété.  <br />
<br />
<b><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Consumer</span> (lambda avec 1 paramètre)</b><br />
Le paramètre qui sera fourni au <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Consumer</span> correspond à la nouvelle valeur de la propriété. De plus, ce consommateur sera invoqué immédiatement après la mise en place de l’abonnement.<br />
En effet, les propriétés ont souvent déjà une valeur initiale quand on les manipule et, quand on monte une interface graphique, il est donc assez courant de devoir écrire :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span><span class="br0">&#40;</span>observable, oldValue, newValue<span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span>
  updateWithText <span class="br0">&#40;</span>newValue<span class="br0">&#41;</span>;
<span class="br0">&#125;</span><span class="br0">&#41;</span>;
<span style="color: #808080;">// Mettre &agrave; jour avec la valeur d&eacute;j&agrave; pr&eacute;sente.</span>
updateWithText<span class="br0">&#40;</span>newValue<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div>La présence de cette méthode permet donc de faire simplement :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span>newValue -&gt; updateWithText<span class="br0">&#40;</span>newValue<span class="br0">&#41;</span><span class="br0">&#41;</span>;
<span style="color: #808080;">// Ou</span>
myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span><span style="color: #0000ff;">this</span>::updateWithText<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
<b><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">BiConsumer</span> (lambda avec 2 paramètres)</b><br />
Les deux paramètres fournis au <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">BiConsumer</span> correspondent à l’ancienne et à la nouvelle valeur de la propriété.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span><span class="br0">&#40;</span>observable, oldValue, newValue<span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span>  <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span>;</pre>
</div>La présence de cette méthode permet donc de faire simplement :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span><span class="br0">&#40;</span>oldValue, newValue<span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span>;</pre>
</div>En revanche, ici le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">BiConsumer</span> n’est pas invoqué immédiatement après l’abonnement puisque la valeur de la propriété n’a pas encore été modifiée.<br />
<br />
<b>Désabonnement</b><br />
Un souci majeur de la gestion des évènements par écouteurs était qu'il fallait conserver des références sur ces derniers, et ce de manière à les désenregistrer et éviter des soucis tels que des propagations d'évènements non-souhaités même après que les composants ou dialogues aient été cachés ou encore pour pallier aux potentielles fuites mémoire. Il était donc assez courant devoir écrire :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">final</span> PropertyChangeListener&lt;String&gt; textChangeListener = <span class="br0">&#40;</span>observable, oldValue, newValue<span class="br0">&#41;</span> -&gt; <span class="br0">&#123;</span><span class="br0">&#125;</span>;
&nbsp;
<span style="color: #808080;">// Lors de la construction de l'interface graphique.</span>
myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span>textChangeListener<span class="br0">&#41;</span>;
&nbsp;
<span class="br0">&#91;</span>...<span class="br0">&#93;</span>
&nbsp;
<span style="color: #808080;">// Lors de la destruction de l'interface graphique.</span>
myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.removeListener<span class="br0">&#40;</span>textChangeListener<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
Et cela ne fonctionnait pas du tout d'ailleurs avec les références de méthode :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:192px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> reactToTextChange<span class="br0">&#40;</span>ObservableValue&lt;String&gt; observable, String oldValue, String newValue <span class="br0">&#123;</span>
  <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #808080;">// Lors de la construction de l'interface graphique.</span>
<span style="color: #808080;">// Fonctionne OK.</span>
myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.addListener<span class="br0">&#40;</span><span style="color: #0000ff;">this</span>::reactToTextChange<span class="br0">&#41;</span>;
&nbsp;
<span class="br0">&#91;</span>...<span class="br0">&#93;</span>
&nbsp;
<span style="color: #808080;">// Lors de la destruction de l'interface graphique.</span>
<span style="color: #808080;">// Pas OK car on a une autre r&eacute;f&eacute;rence diff&eacute;rente de la 1ere.</span>
myTextField.textProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.removeListener<span class="br0">&#40;</span><span style="color: #0000ff;">this</span>::reactToTextChange<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
Ici c'est plus facile car chacune des méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">subcribe()</span> renvoie un objet de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.util.Subscription</span> sur lequel il suffit d'invoquer la méthode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">unsubscribe()</span><div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">private</span> Subscription textSubscription;
<span style="color: #808080;">// Lors de la construction de l'interface graphique.</span>
textSubscription = myTextField.getProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span>newValue -&gt; <span class="br0">&#123;</span> <span class="br0">&#91;</span>&#133;<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span>;
<span style="color: #808080;">// Ou</span>
<span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> updateToNewText<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> String newValue<span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="br0">&#91;</span>...<span class="br0">&#93;</span>
<span class="br0">&#125;</span>;
&nbsp;
textSubscription = myTextField.getProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span><span style="color: #0000ff;">this</span>::updateToNewText<span class="br0">&#41;</span>;
&nbsp;
<span class="br0">&#91;</span>...<span class="br0">&#93;</span>
&nbsp;
<span style="color: #808080;">// Lors de la destruction de l'interface graphique.</span>
textSubscription.unsubscribe<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span style="color: #808080;">// Ou</span>
Optional.ofNullable<span class="br0">&#40;</span>textSubscription<span class="br0">&#41;</span>
    .ifPresent<span class="br0">&#40;</span>Subscription::unsubscribe<span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><b>Conclusion</b><br />
Nous en avons fini avec ce petit tour rapide des abonnements qui permettent de simplifier et d’unifier la gestion des invalidations et des changements de valeur des propriétés, ainsi que de gérer plus facilement les désabonnements.<br />
Grosso modo, dans un contrôle customisé, il devrait être suffisant de faire comme suit :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:156px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">private</span> List&lt;Subscription&gt; subscriptions = <span style="color: #0000ff;">new</span> LinkedList&lt;&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp;
<span style="color: #808080;">// Lors de la construction de l'interface graphique.</span>
subscriptions.add<span class="br0">&#40;</span>aSubControl.aProperty<span class="br0">&#40;</span><span class="br0">&#41;</span>.subscribe<span class="br0">&#40;</span>&#133;<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp;
<span class="br0">&#91;</span>...<span class="br0">&#93;</span>
&nbsp;
<span style="color: #808080;">// Lors de la destruction de l'interface graphique.</span>
subscriptions.forEach<span class="br0">&#40;</span>Subscription::unsubscribe<span class="br0">&#41;</span>;
subscriptions.clear<span class="br0">&#40;</span><span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b10640/abonnements-javafx/</guid>
		</item>
		<item>
			<title>Créer une application JavaFX avec Kotlin</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b10538/creer-application-javafx-kotlin/</link>
			<pubDate>Fri, 20 Oct 2023 04:59:19 GMT</pubDate>
			<description>Salut, ça faisait longtemps !...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Salut, ça faisait longtemps ! <br />
Il faut dire que le COVID, plusieurs confinements, et des changements de règles coté boulot ont fait que poster sur un blog était devenu peu pratique. De plus, ces dernières années, mon rôle se limite plutôt à faire de l’administration système que du développement. <br />
<br />
Il n'aura échappé à personne que, ces derniers temps, Java semble être, euh, au creux de la vague... et ce pour diverses raisons sur lesquelles nous ne nous étendrons pas. Bien que Kotlin de JetBrains existe depuis 2011, ce n'est que depuis 2019 qu'il a pris son essor quand Google a décidé d'en faire le langage de développement préféré pour Android. Outre le fait que AndroidStudio soit basé sur IntelliJ IDEA de JetBrains, sans doute auront-ils jugé le langage assez mature et suffisamment compatible avec la JVM au cœur de leur OS mobile. Bien que j'utilise IDEA depuis un peu plus de 10 ans déjà, je ne m’étais encore jamais penché jusqu'à présent sur Kotlin. J'ai vu qu'il existe un framework JavaFX pour Kotlin nommé <a href="https://github.com/edvin/tornadofx" target="_blank">TornadoFX</a> mais il ne semble plus être maintenu et je ne suis pas totalement sûr de l’intérêt de l'utiliser étant donné que, en théorie, on devrait pouvoir directement écrire une app JavaFX en Kotlin sans trop de difficulté.<br />
<br />
<b>Prérequis</b><br />
Vous avez besoin de :<br />
<ul><li style="">La dernière version de IntelliJ IDEA Community avec le support de Java et Kotlin ;</li><li style="">Une version récente de l'OpenJDK (20 ou 21 feront l'affaire) ;</li><li style="">Une version récente du SDK JavaFX (20 ou 21 feront l'affaire) pour votre OS à télécharger <a href="https://gluonhq.com/products/javafx/" target="_blank">chez Gluon</a> (ou un autre fournisseur) ;</li><li style="">Une version récente des fichiers JMOD de JavaFX (20 ou 21 feront l'affaire) pour votre OS à télécharger chez Gluon (ou un autre fournisseur) - cela sera utile pour la création d'une application native.</li></ul><br />
Optionnel et non couvert par ce blog:<br />
<ul><li style="">De quoi signer numériquement votre JAR ;</li><li style="">De quoi signer numériquement votre exécutable Windows ou macOS ;</li><li style="">Un créateur d'installeur pour Windows (cependant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span> peut directement créer des paquets RPM ou DEB pour Linux ou des images DMG pour macOS ainsi que des installeurs MSI pour Windows)</li><li style="">De quoi signer numériquement votre installeur Windows ou votre image macOS.</li></ul><br />
Désarchivez votre JDK et votre SDK JavaFX dans des emplacements vides. Personnellement, je place en général les fichiers JMOD de JavaFX dans un répertoire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jmods</span> dans la racine du SDK JavaFX mais vous pouvez les mettre où bon vous semble. <br />
<br />
Installez ensuite IntelliJ IDEA, puis lancez l'IDE. <br />
<br />
<b>Création du projet</b><br />
Sur l’écran d’accueil, optez pour la création d'un nouveau projet vide en faisant <b>New Project</b> mais ne choissisez pas un générateur prédéfini. Dans la configuration de ce projet vide, donnez-lui un nom, puis choisissez <u>Kotlin</u> au lieu de Java en tant que <b>Langage</b>. Si le JDK qui vous intéresse n'est pas disponible, allez dans le menu déroulant <b>JDK</b> et faites <b>Add SDK</b> puis naviguez vers la racine de votre copie du JDK avant de valider votre choix. Sélectionnez ce JDK à votre retour dans la configuration du projet. Vérifiez que tous vos réglages sont corrects et appuyez sur <b>Create</b>.<br />
<br />
Une fois, le projet généré, vous pouvez aller dans <b>File -&gt; Project Structure...</b> ou cliquez avec le bouton de droite sur le nœud racine du projet et choisissez <b>Open Module Settings</b>. Allez dans <b>Libraries</b>, et appuyez sur le bouton <b>+</b> en haut de la colonne listant les bibliothèques (ne pas appuyer sur le bouton <b>+</b> dans l’écran détaillant le contenu du runtime Kotlin pour Java, cela a pour effet d'ajouter des fichiers a la bibliothèque sélectionnée). Dans <b>Project Library</b>, choisissez <b>Java</b> et naviguez jusqu'au répertoire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">lib</span> contenu dans votre SDK JavaFX, puis sélectionnez tous les fichiers JAR avant d'appuyer sur <b>OK</b>. Lorsque Intellj IDEA vous demande d'ajouter la bibliothèque à votre projet, faite <b>Cancel</b>. Dans la colonne listant les bibliothèques, vous pouvez sans doute voir que IDEA vous a rajouté une bibliothèque nommée <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx-swt</span> ou quelque chose de similaire. Donnez-lui un nom correct, genre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx-21</span>, en éditant le champ <b>Name</b> sur l’écran détaillant le contenu de cette bibliothèque. Pensez à appuyer sur <b>Apply</b> en bas de boite de dialogue pour valider ce changement de nom.<br />
<br />
Au niveau du projet, basculez désormais sur les réglages <b>Modules</b>, puis dans l'onglet <b>Dependancies</b>. Appuyez sur le bouton <b>+</b> situes sous l’entrée <b>Module SDK</b>. Choisissez <b>Library...</b> et sélectionnez votre nouvelle bibliothèque JavaFX <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx-21</span> avant de faire <b>Add Selected</b>. Vous pouvez maintenant fermer les réglages du projet en appuyant sur le bouton <b>OK</b> en bas de la boite de dialogue. <br />
<br />
:!: Attention : il semble y avoir un bug de longue date dans IntelliJ qui fait que si vous n'avez pas appuyé sur <b>Apply</b> quand vous avez changé le nom de la bibliothèque, l'IDE va avoir tendance à réutiliser le nom précédent de la bibliothèque après fermeture des réglages du projet. Donc, si vous avez un soucis ultérieurs avec JavaFX qui n’est pas détecté par l'IDE, pensez à revenir sur l’écran  <b>Modules -&gt; Dependancies</b> et à vérifier que la bibliothèque incluse porte bien son nouveau nom <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx-21</span> et non pas son ancien nom <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx-swt</span>. Si le nom est incorrect, supprimez la bibliothèque en utilisant le bouton <b>-</b> et rajoutez-la à nouveau avec le bouton <b>+</b> comme décrit précédemment. Ceci devrait résoudre vos soucis.<br />
<br />
Une fois de retour dans la vue principale du projet, dépliez l'arborescence <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">src -&gt; main -&gt; kotlin</span> et cliquez avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">kotlin</span> et faites <b>New -&gt; Package</b>. Donnez le nom <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test</span> à ce package. Puis, cliquez une fois de plus avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">kotlin</span> et faites <b>New -&gt; module-info.java</b>. Cela créera un nouveau fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">module-info.java</span> sous le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">kotlin</span> dans lequel vous pouvez mettre l’ébauche de module suivante :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">module</span> test <span class="br0">&#123;</span>
    <span style="color: #0000ff;">exports</span> test;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
<b>Application basique</b><br />
Nous allons commencer par une application JavaFX très simple : afficher une fenêtre vide. Cliquez avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test</span> (celui qui correspond au package) et faites <b>New -&gt; Java Class</b>. Appelez cette nouvelle classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainFX</span> et validez. Vous pouvez saisir le code suivant dans votre classe :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test;
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application;
<span style="color: #0000ff;">import</span> javafx.stage.Stage;
&nbsp;
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">class</span> MainFX <span style="color: #0000ff;">extends</span> Application <span class="br0">&#123;</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> String... args<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        Application.launch<span class="br0">&#40;</span>args<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #339933;">@Override</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> start<span class="br0">&#40;</span><span style="color: #0000ff;">final</span> Stage stage<span class="br0">&#41;</span> <span style="color: #0000ff;">throws</span> Exception <span class="br0">&#123;</span>
        stage.setTitle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Test FX&quot;</span><span class="br0">&#41;</span>;
        stage.setWidth<span class="br0">&#40;</span><span style="color: #cc66cc;">800</span><span class="br0">&#41;</span>;
        stage.setHeight<span class="br0">&#40;</span><span style="color: #cc66cc;">600</span><span class="br0">&#41;</span>;
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Tout ce que fait ce code est d'initialiser une application, de configurer sa fenêtre en lui donnant un titre et des dimensions, puis de l'afficher.<br />
<br />
Si le SDK JavaFX est correctement installé et détecté par IntelliJ (voir plus haut), l'IDE vous indiquera des erreurs dans le code, et surtout soulignera une partie des lignes d'importation de classe en rouge. En passant votre curseur dessus, une infobulle vous indiquera que vous avez besoin de rajouter des modules manquants à l'appel. Cliquez sur une des lignes fautives et faites <b>ALT+ENTRÉE</b> au clavier, puis choisissez <b>Add required 'javafx.graphics' directive to module-info.java...</b>. Cela ajoutera la ligne <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">requires javafx.graphics;</span> dans votre fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">module-info.java</span> et devrait enlever toutes les erreurs présentes dans votre classe.<br />
<br />
Dans l'arborescence du projet, cliquez avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainFX</span> et choisissez <b>Run 'MainFX.main()'</b>. Une fois votre code compilé, la fenêtre vide de notre application de test de devrait apparaître sur l’écran. C'est bien, mais on veut faire la même chose en Kotlin, non ? Fermez votre fenêtre et cliquez avec le bouton de droite sur le nœud du package <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test</span>, puis choisissez <b>New -&gt; Kotlin Class/File</b>, et donnez le nom <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt</span> à cette nouvelle classe. Vous pouvez mettre le contenu suivant dans cette classe :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:192px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application
<span style="color: #0000ff;">import</span> javafx.stage.Stage
&nbsp;
<span style="color: #0000ff;">class</span> MainKt : Application<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">fun</span> start<span class="br0">&#40;</span>stage: Stage<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        stage.title = <span style="color: #FF0000;">&quot;Test Kt&quot;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
On peut voir que, bien que similaire, le code Kotlin est un peu moins verbeux que le code Java. La déclaration d’héritage permet directement l'invocation d'un constructeur de la classe parente pouvant prendre des paramètres. Outre l'absence de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">;</span> en fin de ligne (ils sont optionnels), je n'ai pas eut besoin d’invoquer un <i>setter</i> pour changer le titre de la fenêtre ou encore ses dimensions. Par contre j'ai du changer mes valeurs numériques entières en nombres flottants car Kotlin utilise un typage plus fort que Java. Également, dans la déclaration des paramètres de ma méthode (désormais une fonction), le nom de la variable vient avant son type. Reste un soucis, comment lancer cette application ? Contrairement à Java, Kotlin n'a pas le concept de membre ou de méthode statiques dans les classes. Or nous en utilisions 2 précédemment : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">main()</span> qui est le point de lancement habituel des programmes Java et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.launch()</span> qui permet d'initialiser une app JavaFX (en initialisant les <i>runtimes</i> au passage, en créant une instance de notre classe et en gérant automatiquement tout ce qui est création de la fenêtre native, avant d'invoquer la methode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">start()</span> de notre classe avec la fenêtre en paramètre). <br />
<br />
Le premier soucis est assez simple à gérer : il suffit de déclarer une fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">main()</span> globale qui servira à faire la même chose. Il vous suffit donc de placer la fonction suivante <u>en dehors du corps de la classe</u> : <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">fun</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    println<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;Hello World!&quot;</span><span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
IDEA soulignement immédiatement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">println()</span> en rouge en indiquant dans une infobulle que la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">println()</span> est définie dans le module <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">kotlin.stdlib</span> et que ce dernier est absent de notre projet. Vous pouvez corriger ce soucis en choisissant <b>Add required 'kotlin.stdlib' directive to module-info.java...</b> directement dans l'infobulle ou en faisant <b>ALT+ENTRÉE</b> sur la ligne incriminée. Cela rajoutera la ligne <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">requires kotlin.stdlib;</span> dans votre fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">module-info.java</span> et devrait enlever toutes les erreurs présentes dans votre classe. Désormais, notre fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">module-info.java</span> ressemble à cela :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">module</span> test <span class="br0">&#123;</span>
    <span style="color: #0000ff;">requires</span> javafx.graphics;
    <span style="color: #0000ff;">requires</span> kotlin.stdlib;
    <span style="color: #0000ff;">exports</span> test;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Dans l'arborescence du projet, cliquez avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt.kt</span> et choisissez <b>Run 'MainKt'</b> pour voir s'afficher &quot;Hello World!&quot; sur votre sortie. <br />
<br />
À noter que les variantes suivantes sont également valides pour décrire un point de lancement Kotlin :<br />
<ul><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">fun main(args: Array&lt;String&gt;)</span> - cette fonction accepte un tableau de chaînes de caractères qui sont les paramètres passés sur la ligne de commande.</li><li style=""><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">fun main(vararg args: String)</span> - cette fonction accepte un nombre variable de chaînes de caractères qui sont les paramètres passés sur la ligne de commande.</li></ul><br />
<br />
Le second soucis est un poil plus embêtant : il nous faut arriver à invoquer <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.launch()</span>. Kotlin nous permet de simuler des méthodes statiques en ajoutant un membre compagnon dans une classe. Par exemple en faisant :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application
<span style="color: #0000ff;">import</span> javafx.stage.Stage
&nbsp;
<span style="color: #0000ff;">class</span> MainKt : Application<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">companion</span> <span style="color: #0000ff;">object</span> <span class="br0">&#123;</span>
        <span style="color: #0000ff;">fun</span> launch<span class="br0">&#40;</span>args: Array&lt;<span style="color: #0080ff;">String</span>&gt;<span class="br0">&#41;</span> <span class="br0">&#123;</span>
            Application.launch<span class="br0">&#40;</span>args<span class="br0">&#41;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">fun</span> start<span class="br0">&#40;</span>stage: Stage<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        stage.title = <span style="color: #FF0000;">&quot;Test Kt&quot;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">fun</span> main<span class="br0">&#40;</span>args: Array&lt;<span style="color: #0080ff;">String</span>&gt;<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    MainKt.launch<span class="br0">&#40;</span>args<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Mais l'IDE va immédiatement souligner la ligne <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.launch(args)</span> en rouge en nous indiquant qu'elle ne peut pas trouver de surcharge de la méthode qui fonctionne avec les types des arguments que nous utilisons. Cela vient du fait que les <i>varargs</i> et tableaux en Kotlin ne sont pas tout à fait gérés de la même manière que leurs équivalents Java. On peut régler ce problème en utilisant le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">spread operator</span> de Kotlin pour permettre de passer les éléments contenus dans la variable individuellement. Cet opérateur s’écrit sous la forme d'une <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">*</span> placée devant la variable. La ligne devient donc : <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">        <span style="color: #0000ff;">fun</span> launch<span class="br0">&#40;</span>args: Array&lt;<span style="color: #0080ff;">String</span>&gt;<span class="br0">&#41;</span> <span class="br0">&#123;</span>
            Application.launch<span class="br0">&#40;</span>*args<span class="br0">&#41;</span>
        <span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Cependant, notre solution ne fonctionne toujours pas car l’exécution le programme va échouer avec l'erreur suivante :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code console :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">Exception in thread &quot;main&quot; java.lang.RuntimeException: Error: class test.MainKt$Companion is not a subclass of javafx.application.Application
	at javafx.graphics@21.0.1/javafx.application.Application.launch(Application.java:305)
	at test/test.MainKt$Companion.launch(MainKt.kt:9)
	at test/test.MainKtKt.main(MainKt.kt:20)
	at test/test.MainKtKt.main(MainKt.kt)</pre></td></tr></table></pre>
</div><br />
En effet, la méthode statique <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.lauch()</span> qui permet de démarrer une application JavaFX s'attend à ce que la classe dans laquelle elle est invoquée hérite de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application</span> Or, l'objet compagnon est compilé dans une classe interne (la trace mentionne <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt$Companion</span>) qui n’hérite pas de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application</span>. Heureusement, il existe une variante de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.lauch()</span> qui permet de spécifier quelle classe doit être utilisée pour initialiser l'app. On peut donc transformer le code en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Application.launch(MainKt::class.java, *args)</span> en utilisant la syntaxe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt::class.java</span> qui permet de récupérer la référence sur la classe Java. Ce qui nous donne :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application
<span style="color: #0000ff;">import</span> javafx.stage.Stage
&nbsp;
<span style="color: #0000ff;">class</span> MainKt : Application<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">companion</span> <span style="color: #0000ff;">object</span> <span class="br0">&#123;</span>
        <span style="color: #0000ff;">fun</span> launch<span class="br0">&#40;</span><span style="color: #0000ff;">vararg</span> args: <span style="color: #0080ff;">String</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
            Application.launch<span class="br0">&#40;</span>MainKt::<span style="color: #0000ff;">class</span>.java, *args<span class="br0">&#41;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">fun</span> start<span class="br0">&#40;</span>stage: Stage<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        stage.title = <span style="color: #FF0000;">&quot;Test Kt&quot;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">fun</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">vararg</span> args: <span style="color: #0080ff;">String</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    MainKt.launch<span class="br0">&#40;</span>*args<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
En observant ce code, on se rend compte que notre appel est finalement totalement détaché de la classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt</span> (plus rien de nous oblige à initialiser le <i>toolkit</i> depuis l’intérieur de la classe) , ce qui nous permet de nous affranchir de la classe compagnon et de simplifier le code en :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application
<span style="color: #0000ff;">import</span> javafx.stage.Stage
&nbsp;
<span style="color: #0000ff;">class</span> MainKt : Application<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">fun</span> start<span class="br0">&#40;</span>stage: Stage<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        stage.title = <span style="color: #FF0000;">&quot;Test Kt&quot;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">fun</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">vararg</span> args: <span style="color: #0080ff;">String</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    Application.launch<span class="br0">&#40;</span>MainKt::<span style="color: #0000ff;">class</span>.java, *args<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Vous pouvez à nouveau exécuter votre code Kotlin pour voir apparaître une fenêtre identique à celle produite par le code Java à l'exception du titre de la fenêtre. Félicitations !<br />
<br />
<b>Application avancée</b><br />
C'est sympa mais on a juste une fenêtre vide à l'ecran. Nous allons maintenant modifier notre app pour afficher des contrôles et la rendre plus intéressante avec avec un graphique en ligne. Une fois de plus je vais commencer par modifier l'application Java pour donner une référence de ce que doit être l'application finale avant de passer sur la version Kotlin. <br />
<br />
Dans l’arborescence de votre projet, cliquez avec le bouton de droite sur le nœud <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">src -&gt; resources</span> puis choisissez <b>New -&gt; Directory</b> et donnez à ce nouveau répertoire le même nom que notre package (ici <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test</span>). Faites un clic droit sur ce nouveau répertoire et choisissez <b>New -&gt; File</b>, puis nommez ce fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">strings.properties</span>. Éditez ce fichier et collez ce contenu dedans :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Properties :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">app.title.fx = Test FX
app.title.kt = Test Kt
xaxis.label = abscisses
yaxis.label = ordonnées
series.label = y = x²</pre></td></tr></table></pre>
</div><br />
Faites une seconde fois un clic droit sur ce nouveau répertoire et choisissez <b>New -&gt; File</b> et nommez ce fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">app.css</span>. Éditez ce fichier et collez ce contenu dedans :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CSS :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:72px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #339933;">.root</span> <span class="br0">&#123;</span>
    -fx-background-color: <span style="color: #800000;">white</span>;
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Vous allez maintenant modifier le contenu de la méthode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">start()</span> classe Java <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainFX</span> comme suit :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Java :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td valign="top"><pre style="margin: 0">        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> bundle = ResourceBundle.getBundle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;test/strings&quot;</span><span class="br0">&#41;</span>;
        <span style="color: #808080;">// Cr&eacute;ation du graphique.</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> series = <span style="color: #0000ff;">new</span> LineChart.Series&lt;Number, Number&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        series.setName<span class="br0">&#40;</span>bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;series.label&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
        IntStream.rangeClosed<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span><span class="br0">&#41;</span>
                .forEach<span class="br0">&#40;</span>x -&gt; <span class="br0">&#123;</span>
                    <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">double</span> y = Math.pow<span class="br0">&#40;</span>x, <span style="color: #cc66cc;">2</span><span class="br0">&#41;</span>;
                    <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> data = <span style="color: #0000ff;">new</span> XYChart.Data&lt;Number, Number&gt;<span class="br0">&#40;</span>x, y<span class="br0">&#41;</span>;
                    series.getData<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span>data<span class="br0">&#41;</span>;
                <span class="br0">&#125;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> xAxis = <span style="color: #0000ff;">new</span> NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span>, <span style="color: #cc66cc;">5</span><span class="br0">&#41;</span>;
        xAxis.setLabel<span class="br0">&#40;</span>bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;xaxis.label&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> yAxis = <span style="color: #0000ff;">new</span> NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">100</span>, <span style="color: #cc66cc;">10</span><span class="br0">&#41;</span>;
        yAxis.setLabel<span class="br0">&#40;</span>bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;yaxis.label&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> chart = <span style="color: #0000ff;">new</span> LineChart&lt;&gt;<span class="br0">&#40;</span>xAxis, yAxis<span class="br0">&#41;</span>;
        chart.getData<span class="br0">&#40;</span><span class="br0">&#41;</span>.add<span class="br0">&#40;</span>series<span class="br0">&#41;</span>;
        <span style="color: #808080;">// Mise en place de la sc&egrave;ne.</span>
        <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">var</span> root = <span style="color: #0000ff;">new</span> StackPane<span class="br0">&#40;</span><span class="br0">&#41;</span>;
        root.getChildren<span class="br0">&#40;</span><span class="br0">&#41;</span>.setAll<span class="br0">&#40;</span>chart<span class="br0">&#41;</span>;
        <span style="color: #0000ff;">var</span> scene = <span style="color: #0000ff;">new</span> Scene<span class="br0">&#40;</span>root<span class="br0">&#41;</span>;
        <span style="color: #808080;">// Gestion des CSS.</span>
        Optional.ofNullable<span class="br0">&#40;</span>getClass<span class="br0">&#40;</span><span class="br0">&#41;</span>.getResource<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.css&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .map<span class="br0">&#40;</span>URL::toExternalForm<span class="br0">&#41;</span>
                .ifPresent<span class="br0">&#40;</span>scene.getStylesheets<span class="br0">&#40;</span><span class="br0">&#41;</span>::add<span class="br0">&#41;</span>;
        <span style="color: #808080;">// Gestion de la fen&ecirc;tre.</span>
        stage.setTitle<span class="br0">&#40;</span>bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.title.fx&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
        stage.setWidth<span class="br0">&#40;</span><span style="color: #cc66cc;">800</span><span class="br0">&#41;</span>;
        stage.setHeight<span class="br0">&#40;</span><span style="color: #cc66cc;">600</span><span class="br0">&#41;</span>;
        stage.setScene<span class="br0">&#40;</span>scene<span class="br0">&#41;</span>;
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>;</pre></td></tr></table></pre>
</div><br />
IntelliJ va sans doute se plaindre que le module <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafx.controls</span> est absent. Placez votre curseur sur une des lignes d'importation incriminées et faites <b>ALT+ENTRÉE</b> au clavier pour procéder à cette correction. Désormais, notre fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">module-info.java</span> ressemble à cela :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">module test {
    requires javafx.graphics;
    requires javafx.controls;
    requires kotlin.stdlib;
    exports test;
}</pre></td></tr></table></pre>
</div>Vous pouvez changer la configuration de votre projet pour lancer la classe Java et vérifier que le graphique s'affiche correctement.<br />
<br />
Parmi les choses qui sont faites par ce code :<br />
<ul><li style="">On initialise un gestionnaire de ressources localisées qui va permettre d'extraire les chaînes de texte depuis le fichier <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">strings.properties</span> ;</li><li style="">On crée un graphique en ligne qui permet d'afficher les valeurs du carré des nombres entiers entre 0 et 10 (inclus) ;</li><li style="">On crée tous les composants et la scène nécessaire pour afficher ce graphique ;</li><li style="">On charge le fichier CSS <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">app.css</span> et on l'applique sur la scène ;</li><li style="">On place la scène dans notre fenêtre.</li></ul><br />
Le code bien que verbeux n'est pas très compliqué. <br />
<br />
Maintenant, vous allez copier ce code Java et... le coller dans le code de la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">start()</span> dans la classe Kotlin <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt</span> ! En effet, IntelliJ va détecter que ce code est en Java et va vous proposer de traduire automatiquement ce code Java en code Kotlin ce qui prend juste quelques secondes. Et il est plutôt efficace à cette tache : <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br /></div></td><td valign="top"><pre style="margin: 0">        <span style="color: #0000ff;">val</span> bundle = ResourceBundle.getBundle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;test/strings&quot;</span><span class="br0">&#41;</span>
        <span style="color: #808080;">// Cr&eacute;ation du graphique.</span>
        <span style="color: #808080;">// Cr&eacute;ation du graphique.</span>
        <span style="color: #0000ff;">val</span> series = Series&lt;Number, Number&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>
        series.name = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;series.label&quot;</span><span class="br0">&#41;</span>
        IntStream.rangeClosed<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span><span class="br0">&#41;</span>
            .forEach <span class="br0">&#123;</span> x: <span style="color: #0080ff;">Int</span> -&gt;
                <span style="color: #0000ff;">val</span> y: <span style="color: #0080ff;">Double</span> = x.pow<span class="br0">&#40;</span><span style="color: #cc66cc;">2.0</span><span class="br0">&#41;</span>
                <span style="color: #0000ff;">val</span> <span style="color: #0000ff;">data</span> = XYChart.Data&lt;Number, Number&gt;<span class="br0">&#40;</span>x, y<span class="br0">&#41;</span>
                series.<span style="color: #0000ff;">data</span>.add<span class="br0">&#40;</span><span style="color: #0000ff;">data</span><span class="br0">&#41;</span>
            <span class="br0">&#125;</span>
        <span style="color: #0000ff;">val</span> xAxis = NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0.0</span>, <span style="color: #cc66cc;">10.0</span>, <span style="color: #cc66cc;">5.0</span><span class="br0">&#41;</span>
        xAxis.label = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;xaxis.label&quot;</span><span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> yAxis = NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0.0</span>, <span style="color: #cc66cc;">100.0</span>, <span style="color: #cc66cc;">10.0</span><span class="br0">&#41;</span>
        yAxis.label = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;yaxis.label&quot;</span><span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> chart = LineChart<span class="br0">&#40;</span>xAxis, yAxis<span class="br0">&#41;</span>
        chart.<span style="color: #0000ff;">data</span>.add<span class="br0">&#40;</span>series<span class="br0">&#41;</span>
        <span style="color: #808080;">// Mise en place de la sc&egrave;ne.</span>
        <span style="color: #808080;">// Mise en place de la sc&egrave;ne.</span>
        <span style="color: #0000ff;">val</span> root = StackPane<span class="br0">&#40;</span><span class="br0">&#41;</span>
        root.children.setAll<span class="br0">&#40;</span>chart<span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> scene = Scene<span class="br0">&#40;</span>root<span class="br0">&#41;</span>
        <span style="color: #808080;">// Gestion des CSS.</span>
        <span style="color: #808080;">// Gestion des CSS.</span>
        Optional.ofNullable<span class="br0">&#40;</span>javaClass.getResource<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.css&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
            .map <span class="br0">&#123;</span> obj: URL -&gt; obj.toExternalForm<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>
            .ifPresent <span class="br0">&#123;</span> e: <span style="color: #0080ff;">String</span>? -&gt; scene.stylesheets.add<span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#125;</span>
        <span style="color: #808080;">// Gestion de la fen&ecirc;tre.</span>
        <span style="color: #808080;">// Gestion de la fen&ecirc;tre.</span>
        stage.title = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.title.fx&quot;</span><span class="br0">&#41;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.scene = scene
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span></pre></td></tr></table></pre>
</div><br />
Quelques soucis mineurs au final : tous mes commentaires ont été doublés et la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">pow()</span> semble être manquante. Pour les commentaires, c'est facilement corrigeable. Pour la fonction cela est du au fait que la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">pow()</span> est uniquement définie pour les nombres flottants et pas pour les nombres entiers. Il est possible de corriger le soucis en faisant : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">val y: Double = x.toDouble().pow(2.0)</span>. IntelliJ soulignera la ligne en rouge une dernière fois, il suffit de faire <b>ALT+ENTRÉE</b> au clavier sur cette ligne pour rajouter l'import manquant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">import kotlin.math.pow</span> en début de fichier. Profitez-en pour changer la clé de ressource du titre de la fenêtre de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">stage.title = bundle.getString(&quot;app.title.fx&quot;)</span> en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">stage.title = bundle.getString(&quot;app.title.kt&quot;)</span>. Ce qui nous donne après un très court nettoyage du code :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Kotlin :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">package</span> test
&nbsp;
<span style="color: #0000ff;">import</span> javafx.application.Application
<span style="color: #0000ff;">import</span> javafx.scene.Scene
<span style="color: #0000ff;">import</span> javafx.scene.chart.LineChart
<span style="color: #0000ff;">import</span> javafx.scene.chart.NumberAxis
<span style="color: #0000ff;">import</span> javafx.scene.chart.XYChart
<span style="color: #0000ff;">import</span> javafx.scene.chart.XYChart.Series
<span style="color: #0000ff;">import</span> javafx.scene.layout.StackPane
<span style="color: #0000ff;">import</span> javafx.stage.Stage
<span style="color: #0000ff;">import</span> java.net.URL
<span style="color: #0000ff;">import</span> java.util.*
<span style="color: #0000ff;">import</span> java.util.stream.IntStream
<span style="color: #0000ff;">import</span> kotlin.math.pow
&nbsp;
<span style="color: #0000ff;">class</span> MainKt : Application<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">fun</span> start<span class="br0">&#40;</span>stage: Stage<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span style="color: #0000ff;">val</span> bundle = ResourceBundle.getBundle<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;test/strings&quot;</span><span class="br0">&#41;</span>
        <span style="color: #808080;">// Cr&eacute;ation du graphique.</span>
        <span style="color: #0000ff;">val</span> series = Series&lt;Number, Number&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>
        series.name = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;series.label&quot;</span><span class="br0">&#41;</span>
        IntStream.rangeClosed<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>, <span style="color: #cc66cc;">10</span><span class="br0">&#41;</span>
            .forEach <span class="br0">&#123;</span> x: <span style="color: #0080ff;">Int</span> -&gt;
                <span style="color: #0000ff;">val</span> y: <span style="color: #0080ff;">Double</span> = x.toDouble<span class="br0">&#40;</span><span class="br0">&#41;</span>.pow<span class="br0">&#40;</span><span style="color: #cc66cc;">2.0</span><span class="br0">&#41;</span>
                <span style="color: #0000ff;">val</span> <span style="color: #0000ff;">data</span> = XYChart.Data&lt;Number, Number&gt;<span class="br0">&#40;</span>x, y<span class="br0">&#41;</span>
                series.<span style="color: #0000ff;">data</span>.add<span class="br0">&#40;</span><span style="color: #0000ff;">data</span><span class="br0">&#41;</span>
            <span class="br0">&#125;</span>
        <span style="color: #0000ff;">val</span> xAxis = NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0.0</span>, <span style="color: #cc66cc;">10.0</span>, <span style="color: #cc66cc;">5.0</span><span class="br0">&#41;</span>
        xAxis.label = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;xaxis.label&quot;</span><span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> yAxis = NumberAxis<span class="br0">&#40;</span><span style="color: #cc66cc;">0.0</span>, <span style="color: #cc66cc;">100.0</span>, <span style="color: #cc66cc;">10.0</span><span class="br0">&#41;</span>
        yAxis.label = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;yaxis.label&quot;</span><span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> chart = LineChart<span class="br0">&#40;</span>xAxis, yAxis<span class="br0">&#41;</span>
        chart.<span style="color: #0000ff;">data</span>.add<span class="br0">&#40;</span>series<span class="br0">&#41;</span>
        <span style="color: #808080;">// Mise en place de la sc&egrave;ne.</span>
        <span style="color: #0000ff;">val</span> root = StackPane<span class="br0">&#40;</span><span class="br0">&#41;</span>
        root.children.setAll<span class="br0">&#40;</span>chart<span class="br0">&#41;</span>
        <span style="color: #0000ff;">val</span> scene = Scene<span class="br0">&#40;</span>root<span class="br0">&#41;</span>
        <span style="color: #808080;">// Gestion des CSS.</span>
        Optional.ofNullable<span class="br0">&#40;</span>javaClass.getResource<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.css&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
            .map <span class="br0">&#123;</span> obj: URL -&gt; obj.toExternalForm<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>
            .ifPresent <span class="br0">&#123;</span> e: <span style="color: #0080ff;">String</span>? -&gt; scene.stylesheets.add<span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#125;</span>
        <span style="color: #808080;">// Gestion de la fen&ecirc;tre.</span>
        stage.title = bundle.getString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;app.title.kt&quot;</span><span class="br0">&#41;</span>
        stage.width = <span style="color: #cc66cc;">800.0</span>
        stage.height = <span style="color: #cc66cc;">600.0</span>
        stage.scene = scene
        stage.show<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">fun</span> main<span class="br0">&#40;</span><span style="color: #0000ff;">vararg</span> args: <span style="color: #0080ff;">String</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    Application.launch<span class="br0">&#40;</span>MainKt::<span style="color: #0000ff;">class</span>.java, *args<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></pre>
</div><br />
Parmi les choses qu'on peut remarquer : Kotlin utilise le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">val</span> qui est similaire à la combinaison <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">final var</span> en Java. Ces variables ne sont donc pas mutables après leur déclaration. Pour déclarer des variables mutables, il faut utiliser à la place le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">var</span>. D'ailleurs les paramètres des functions sont aussi non-mutables tant qu'on y est. De plus, Kotlin n'utilise pas le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">new</span> quand il faut créer de nouvelles instances. Le bloc lambda Kotlin ressemble à son ancêtre Java. Pour le reste, au niveau de la résolution des resources sur le CLASSPATH, et bien cela fonctionne exactement comme en Java basique et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">this.getClass()</span> est devenu <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javaClass</span>. <br />
<br />
Au lancement, notre application Kotlin + JavaFX se présente et se comporte exactement comme son équivalent 100% Java. Il y a probablement des choses qui pourraient être simplifiées en utilisant plus de fonctions ou d'idiomes de Kotlin (pour, entre autres, la gestion des valeurs potentiellement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">null</span>) mais c'est déjà un bon départ.<br />
<br />
<b>Fichier JAR</b><br />
Nous allons maintenant créer un JAR pour permettre de distribuer plus facilement notre application. Allez dans le menu <b>File -&gt; Project Structure...</b> ou cliquez avec le bouton de droite sur le nœud racine de votre projet et choisissez <b>Open Module Settings</b>. Déplacez-vous dans l'onglet <b>Artifact</b> et cliquez sur le bouton <b>+</b> et choisissez <b>JAR -&gt; From module with dependencies...</b>. Dans <b>Main Class</b>, vous allez spécifier la classe qui sert à lancer le programme, celle qui contient la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">main()</span>. Or, souvenez-vous que cette fonction est globale et ne fait pas partie de la classe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test.MainKt</span>. Si vous dépliez la boite déroulante, vous verrez qu'il existe dans votre projet une 3e classe nommée <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">test.MainKtKt</span> (un second &quot;Kt&quot; a été ajouté à son nom) qui a été générée à la compilation. C'est cette classe qui contient la fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">main()</span>. Sélectionnez-la et validez, puis créez votre artéfact sans changer d'autres options.<br />
<br />
L'onglet <b>Artifact</b> détaillle désormais le contenu de votre nouvel artéfact. Commencez par changer son nom en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt</span>. Puis sélectionnez le nœud racine qui correspond au fichier JAR et cliquez avec le bouton de droite puis choissiez l'action <b>Rename</b> et renommez-le en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MainKt.jar</span> et appuyez sur <b>ENTRÉE</b> pour valider. Dans la liste des JAR qui seront recopiés dans votre archive, suprimez tous les JAR de JavaFX (et uniquement ceux-ci). Conservez les autres JAR tierces comme les bibliothèques de Kotlin ou encore la bibliothèque des annotation Java. Validez en cliquant sur <b>OK</b>. En revenant vers votre projet, vous pouvez voir que l'IDE a ajouté un fichier manifeste dans vos ressources.<br />
<br />
Vous pouvez maintenant compiler votre fichier JAR en allant dans le menu <b>Build -&gt; Build Artifacts...</b> puis en choisissant <b>MainKT -&gt; Build</b>. Au bout de quelques secondes, la nouvelle archive créée devrait se trouver dans le répertoire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">out/artifacts/MainKt</span> de votre projet.<br />
<br />
Une fois votre JAR obtenu, c'est le bon moment pour le signer avec un certificat numérique avant de procéder à sa distribution.<br />
<br />
<b>Lanceur natif</b><br />
Il est temps maintenant de créer un lanceur natif pour votre programme. Cela permet d'éviter de devoir fournir des scripts de lancemnent a vos utilisateurs et ainsi eviter la presence parfois insolites de fenetres d'intepreteur de commande sur leur écran. Pour cela, nous allons utiliser l'outils <a href="https://docs.oracle.com/en/java/javase/21/docs/specs/man/jpackage.html" target="_blank"><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span></a> qui est fourni dans le JDK.<br />
<br />
Utilisez votre explorateur de fichier ou votre interpréteur de commandes favori suivant votre plateforme et déplacez-vous dans le répertoire racine de votre projet. Créez un sous-répertoire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">package</span> et placez-y le contenu suivant. Vous pouvez utiliser des services en lignes pour convertir une images PNG en icones Windows ICO ou macOS ICNS :<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:120px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td valign="top"><pre style="margin: 0">package
&#9500;&#9472;&#9472; linux
&#9474;   &#9492;&#9472;&#9472; MainKt.png
&#9500;&#9472;&#9472; macos
&#9474;   &#9492;&#9472;&#9472; MainKt.icns
&#9492;&#9472;&#9472; windows
    &#9492;&#9472;&#9472;  MainKt.ico</pre></td></tr></table></pre>
</div>Créez maintenant un répertoire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">bin</span> à la racine de votre projet et placez-y les fichiers suivants. Pensez à changer les permissions d'exécution si nécessaire suivant les spécificités de votre OS. Vous pouvez également modifier les chemins vers le JDK, le SDK JavaFX ou les fichiers JMODS de JavaFX suivant votre installation.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">bin
&#9500;&#9472;&#9472; package.bat
&#9500;&#9472;&#9472; package_linux.sh
&#9492;&#9472;&#9472; package_macos.sh</pre></td></tr></table></pre>
</div>Pour Windows : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">package.bat</span><div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code CMD :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td valign="top"><pre style="margin: 0">@echo off
set JAVA_HOME=&quot;C:\Program Files\java\jdk-21.0.1\&quot;
set PATH=%JAVA_HOME%\bin;%PATH%

java -version

set APP_NAME=MainKt
set APP_TYPE=app-image
set APP_ICON=./package/windows/%APP_NAME%.ico

set MAIN_JAR=%APP_NAME%.jar
set MODULES=javafx.graphics,javafx.controls

set INPUT_DIR=out\artifacts\%APP_NAME%
set OUTPUT_DIR=redist

set FX_HOME=E:\fabriceb\Devel\Java\lib\JavaFX\javafx-sdk-21.0.1
set FX_LIBS=%FX_HOME%\lib
set FX_JMODS=%FX_HOME%\jmods

if exist %OUTPUT_DIR%\%APP_NAME% rmdir /s /q %OUTPUT_DIR%\%APP_NAME%
if not exist %OUTPUT_DIR% mkdir %OUTPUT_DIR%
REM Test the app works.
REM java --module-path $FX_LIBS --add-modules $MODULES -jar $INPUT_DIR/$MAIN_JAR
REM Create native launcher.
jpackage --type %APP_TYPE% --input %INPUT_DIR% --name %APP_NAME% --main-jar %MAIN_JAR% --module-path %FX_JMODS% --add-modules %MODULES% --dest %OUTPUT_DIR% --icon %APP_ICON%</pre></td></tr></table></pre>
</div><br />
La version Windows génère directement un lanceur natif exécutable. Il est possible de générer un installeur MSI, consultez la documentation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span>.<br />
<br />
Pour Linux : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">package_linux.sh</span><div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code bash :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">#!/bin/sh</span>
<span style="color: #339933;">JAVA_HOME</span>=<span style="color: black">/</span>usr<span style="color: black">/</span>local<span style="color: black">/</span>java<span style="color: black">/</span>jdk-21.0.1
<span style="color: #339933;">PATH</span>=<span style="color: #339933;">$JAVA_HOME</span><span style="color: black">/</span>bin:<span style="color: #339933;">$PATH</span>
&nbsp;
java <span style="color: #339933;">-version</span>
&nbsp;
<span style="color: #339933;">APP_NAME</span>=TestKt
<span style="color: #339933;">APP_TYPE</span>=app-image
<span style="color: #339933;">APP_ICON</span>=
&nbsp;
<span style="color: #339933;">MAIN_JAR</span>=<span style="color: #339933;">$APP_NAME</span>.jar
<span style="color: #339933;">MODULES</span>=javafx.graphics,javafx.controls
&nbsp;
<span style="color: #339933;">INPUT_DIR</span>=.<span style="color: black">/</span>out<span style="color: black">/</span>artifacts<span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span>
<span style="color: #339933;">OUTPUT_DIR</span>=redist
&nbsp;
<span style="color: #339933;">FX_HOME</span>=<span style="color: black">/</span>home<span style="color: black">/</span>fabriceb<span style="color: black">/</span>devel<span style="color: black">/</span>java<span style="color: black">/</span>lib<span style="color: black">/</span>javafx<span style="color: black">/</span>javafx-sdk-21.0.1
<span style="color: #339933;">FX_LIBS</span>=<span style="color: #339933;">$FX_HOME</span><span style="color: black">/</span>lib
<span style="color: #339933;">FX_JMODS</span>=<span style="color: #339933;">$FX_HOME</span><span style="color: black">/</span>jmods
&nbsp;
<span style="color: #0000ff;">if</span> <span style="color: black">&#91;</span><span style="color: black">&#91;</span> <span style="color: #339933;">-d</span> <span style="color: #339933;">$OUTPUT_DIR</span><span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span> <span style="color: black">&#93;</span><span style="color: black">&#93;</span>; <span style="color: #0000ff;">then</span>
	<span style="color: #0080ff;">rm</span> <span style="color: #339933;">-rf</span> <span style="color: #339933;">$OUTPUT_DIR</span><span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span>
<span style="color: #0000ff;">fi</span>
<span style="color: #0080ff;">mkdir</span> <span style="color: #339933;">-p</span> <span style="color: #339933;">$OUTPUT_DIR</span>
<span style="color: #808080;"># Test the app works.</span>
<span style="color: #808080;">#java --module-path $FX_LIBS --add-modules $MODULES -jar $INPUT_DIR/$MAIN_JAR</span>
<span style="color: #808080;"># Create native launcher.</span>
jpackage <span style="color: #339933;">--type</span> <span style="color: #339933;">$APP_TYPE</span> <span style="color: #339933;">--input</span> <span style="color: #339933;">$INPUT_DIR</span> <span style="color: #339933;">--name</span> <span style="color: #339933;">$APP_NAME</span> <span style="color: #339933;">--main-jar</span> <span style="color: #339933;">$MAIN_JAR</span> <span style="color: #339933;">--module-path</span> <span style="color: #339933;">$FX_JMODS</span> <span style="color: #339933;">--add-modules</span> <span style="color: #339933;">$MODULES</span> <span style="color: #339933;">--dest</span> <span style="color: #339933;">$OUTPUT_DIR</span></pre></td></tr></table></pre>
</div><br />
La version Linux génère directement un lanceur natif exécutable ; cet exécutable ne prend pas d'icone mais il reste possible de fournir une image PNG pour personaliser un raccourci servant à lancer l'application dans votre interface graphique. Il est possible de générer des paquets RPM ou DEB pour votre distribution, consultez la documentation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span>.<br />
<br />
Pour macOS : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">package_macos.sh</span><div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code bash :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">#!/bin/sh</span>
<span style="color: #339933;">JAVA_HOME</span>=<span style="color: black">/</span>Library<span style="color: black">/</span>Java<span style="color: black">/</span>JavaVirtualMachines<span style="color: black">/</span>jdk-21.0.1.jdk<span style="color: black">/</span>Contents<span style="color: black">/</span>Home<span style="color: black">/</span>
<span style="color: #339933;">PATH</span>=<span style="color: #339933;">$PATH</span>:<span style="color: #339933;">$JAVA_HOME</span><span style="color: black">/</span>bin
&nbsp;
<span style="color: #339933;">APP_NAME</span>=MFCL-Viewer
<span style="color: #339933;">APP_TYPE</span>=app-image
<span style="color: #339933;">APP_ICON</span>=.<span style="color: black">/</span>package<span style="color: black">/</span>macosx<span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span>.icns
&nbsp;
<span style="color: #339933;">MAIN_JAR</span>=mfcl.viewer.jar
<span style="color: #339933;">MODULES</span>=javafx.graphics,javafx.controls
&nbsp;
<span style="color: #339933;">INPUT_DIR</span>=.<span style="color: black">/</span>out<span style="color: black">/</span>artifacts<span style="color: black">/</span>mfcl_viewer_jar
<span style="color: #339933;">OUTPUT_DIR</span>=redist
&nbsp;
<span style="color: #339933;">FX_HOME</span>=<span style="color: black">/</span>Users<span style="color: black">/</span>fabriceb<span style="color: black">/</span>devel<span style="color: black">/</span>lib<span style="color: black">/</span>javafx<span style="color: black">/</span>javafx-sdk-21.0.1
<span style="color: #339933;">FX_LIBS</span>=<span style="color: #339933;">$FX_HOME</span><span style="color: black">/</span>lib
<span style="color: #339933;">FX_JMODS</span>=<span style="color: #339933;">$FX_HOME</span><span style="color: black">/</span>jmods
&nbsp;
<span style="color: #0000ff;">if</span> <span style="color: black">&#91;</span><span style="color: black">&#91;</span> <span style="color: #339933;">-d</span> <span style="color: #339933;">$OUTPUT_DIR</span><span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span> <span style="color: black">&#93;</span><span style="color: black">&#93;</span>; <span style="color: #0000ff;">then</span>
	<span style="color: #0080ff;">rm</span> <span style="color: #339933;">-rf</span> <span style="color: #339933;">$OUTPUT_DIR</span><span style="color: black">/</span><span style="color: #339933;">$APP_NAME</span>
<span style="color: #0000ff;">fi</span>
<span style="color: #0080ff;">mkdir</span> <span style="color: #339933;">-p</span> <span style="color: #339933;">$OUTPUT_DIR</span>
<span style="color: #808080;"># Test the app works.</span>
<span style="color: #808080;">#java --module-path $FX_LIBS --add-modules $MODULES -jar $INPUT_DIR/$MAIN_JAR</span>
<span style="color: #808080;"># Create native launcher.</span>
jpackage <span style="color: #339933;">--type</span> <span style="color: #339933;">$APP_TYPE</span> <span style="color: #339933;">--input</span> <span style="color: #339933;">$INPUT_DIR</span> <span style="color: #339933;">--name</span> <span style="color: #339933;">$APP_NAME</span> <span style="color: #339933;">--main-jar</span> <span style="color: #339933;">$MAIN_JAR</span> <span style="color: #339933;">--module-path</span> <span style="color: #339933;">$FX_JMODS</span> <span style="color: #339933;">--add-modules</span> <span style="color: #339933;">$MODULES</span> <span style="color: #339933;">--dest</span> <span style="color: #339933;">$OUTPUT_DIR</span> <span style="color: #339933;">--icon</span> <span style="color: #339933;">$APP_ICON</span></pre></td></tr></table></pre>
</div><br />
La version macOS génère directement un répertoire d'application. Il est possible de générer un paquet PKG ou une image DMG si besoin, consultez la documentation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span>.<br />
<br />
Nous utilisons l'outil <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span> du JDK pour créer un lanceur natif pour votre applicaiton sur votre systeme d'exploitation. Si vous souhaitez porter votre app vers un système d'exploitation différent, vous n'avez pas besoin de recompiler specialement votre projet Kotlin pour ce nouvel OS. Tout ce que vous avez besoin de faire est d'installer un JDK sur le nouvel OS ainsi que de récupérer les fichiers JMODS de JavaFX pour cet OS. Vous pouvez ensuite copier le fichier JAR, les scripts de packaging et les icones d'applications existants aux endroits appropriés, puis de modificer, si nécessaire, les chemins d'accès dans le script correspondant à cet OS, avant d'executer ce script.<br />
<br />
<b>La suite ?</b><br />
Si vous êtes sous Windows, par exemple, c'est le bon moment de signer votre lanceur natif avec un certificat Microsoft Authenticode. Vous pouvez ensuite empaqueter tous les fichiers générés par <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span> avec un créateur d'installeur (InnoSetup, etc.).<br />
<br />
De même, si vous êtes sur macOS, c'est également une bonne étape pour signer votre application ou votre image avec un certificat de développeur Apple.<br />
<br />
<b>Conclusion</b><br />
Voila, vous avez créé une application JavaFX en Kotlin et vous pouvez désormais la distribuer à vos utilisateurs. Même si le code Kotlin prend moins de place et est un peu plus facile à lire que son equivalent Java, on peut se rendre compte qu'il ne sont pas si eloignés l'un de l'autre tant qu'on continue à utiliser des blibliothèques Java. Grace à la grande efficacité de la traduction automatique du code offerte par IntelliJ IDEA nous n'avons pas perdu énormément de temps en portant du code existant Java en code Kotlin. Le challenge serait maintenant de créer une application JavaFX dont le cœur de metier serait écrit en Kotlin pur. Cependant, concevoir et créer une nouvelle application JavaFX directement en Kotlin ne semble pas non-plus etre une tache totalement insurmontable une fois qu'on a appréhendé les bases du language et de son API.</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b10538/creer-application-javafx-kotlin/</guid>
		</item>
		<item>
			<title>Mise à jour de la feuille de route Java coté client</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b9366/mise-jour-feuille-route-java-cote-client/</link>
			<pubDate>Wed, 13 May 2020 22:36:09 GMT</pubDate>
			<description>Le 11 mai dernier, Oracle a...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Le 11 mai dernier, Oracle a mis à jour sa feuille de route pour Java coté client en ce qui concerne le déploiement (Applet et Java Web Start) ainsi que les technologies interface utilisateur (AWT, Swing et JavaFX).<br />
<br />
Parmi les choses annoncées :<br />
<ul><li style="">Le support commercial ainsi que les mises à jour de Java SE 8 sont prolongées de mars 2025 jusqu’en décembre 2030 ;</li><li style="">Les mises à jour de Java SE 8 sont disponibles indéfiniment pour un usage personnel non-commercial. Précédemment, la date limite de fin de disponibilité était décembre 2020.  Oracle s'engage a respecter un délai de 18 mois pour mettre à jour la feuille de route si une nouvelle date de fin de disponibilité est définie ;</li><li style="">Oracle continue de proposer un support commercial pour Java Web Start jusqu'en décembre 2030 via son offre legacy Java SE ou ou lorsque cette technologie est utilisée avec des produits Oracle.</li><li style="">Oracle s'engage à continuer de proposer Java Web Start dans Java SE 8 pour un usage personnel non-commercial tant que les mises à jour continuent à être distribuées pour un tel usage. Cependant, la compagnie encourage les développeurs a migrer qui utilisent cette technologie à migrer vers des solutions plus modernes ;</li><li style="">En 2015, il était annoncé que les Applets étaient supportées dans Java SE 8 jusqu'en mars 2019. De nos jours, les Applet ne sont plus supportées mais continuent de fonctionner sous Windows et reçoivent toujours des mise a jour. Il n'est pas dans les plans d'Oracle de retirer les composants nécessaires à leur fonctionnement dans Internet Explorer 11. Cependant, la compagnie pourra être amenée à le faire avec peu ou pas d'avertissements préliminaires ;</li><li style="">Le support de JavaFX dans JavaSE est prolongée de mars 2022 jusqu’à mars 2025. Oracle rappelle que JavaFX a été porté vers OpenJFX en tant que module indépendant du JDK depuis le JDK 11. La compagnie rappelle également qu'elle continue de piloter et de collaborer activement à l'initiative OpenSource ;</li><li style="">Oracle rappelle également que AWT et Swing sont toujours des technologies core Java pour toutes les versions clientes disponibles ainsi que leur calendrier de support respectif.</li></ul><br />
<br />
Sources :<br />
<ul><li style=""><a href="https://www.oracle.com/technetwork/java/javase/javaclientroadmapupdatev2020may-6548840.pdf" target="_blank">Java Client Roadmap Update</a> (PDF)</li><li style=""><a href="https://blogs.oracle.com/java-platform-group/java-client-roadmap-updates" target="_blank">Blog de Donald Smith</a> - Directeur senior de la gestion du produit</li></ul></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b9366/mise-jour-feuille-route-java-cote-client/</guid>
		</item>
		<item>
			<title><![CDATA[Microsoft rejoint l'OpenJDK]]></title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b8375/microsoft-rejoint-l-openjdk/</link>
			<pubDate>Wed, 30 Oct 2019 22:42:10 GMT</pubDate>
			<description>Dans un message envoyé sur la...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Dans un message envoyé sur la liste de distribution du comité de gouvernance de l'OpenJDK, Bruno Borges de la division de la gestion des produits Java chez Microsoft annonce l’arrivée du géant de Redmond en tant que contributeur du projet communautaire Java.<br />
<br />
Cela fait longtemps que Microsoft travaille en collaboration avec Oracle pour participer au développement de Java pour s'assurer que la JVM offre des performances adéquates sur ses OS Windows. Ces dernières années Microsoft a également lancé une vaste campagne de recrutements tous azimuts auprès d'anciens employés d'Oracle pour venir renforcer ses équipes de développements d'outils. Cela a conduit à la normalisation de kits de développements Java qui permettent aux acteurs du monde Java de s'interfacer avec ses services sur sa plateforme Cloud Azure. Mais c'est la première fois que le géant intègre l'OpenJDK pour contribuer directement au développement de Java.<br />
<br />
Bruno Borges indique que, dans un premier temps, l’équipe d’ingénierie Java chez Microsoft se chargera de travailler sur des correctifs de bugs mineurs et des <i>backports</i> tout en continuant d’étudier et d'observer les usages et politiques en court dans l'OpenJDK, par exemple discuter sur la liste de diffusion pour arriver à un consensus avant de chercher à publier un correctif.<br />
<br />
Source : <a href="https://mail.openjdk.java.net/pipermail/discuss/2019-October/005173.html" target="_blank">Microsoft’s Ready do Contribute to OpenJDK</a> sur la liste de diffusion du comité de gouvernance de l'OpenJDK.</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b8375/microsoft-rejoint-l-openjdk/</guid>
		</item>
		<item>
			<title>OpenJDK annonce la mise en disponibilité en accès anticipé de jpackage</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7997/openjdk-annonce-mise-disponibilite-acces-anticipe-jpackage/</link>
			<pubDate>Tue, 03 Sep 2019 22:41:04 GMT</pubDate>
			<description>*OpenJDK annonce la mise en...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><b><font size="4">OpenJDK annonce la mise en disponibilité en accès anticipé de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span>,</font></b> <br />
<b><font size="1">l'outil en ligne de commande de créations de lanceurs natifs pour Java</font></b><br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span> est défini dans la proposition d’amélioration <a href="https://openjdk.java.net/jeps/343" target="_blank">JEP 343: Packaging Tool</a> comme étant un ensemble d'outils pour créer des lanceurs natifs pour les applications Java pour les principaux systèmes d'exploitation supportés par Java coté client (Linux, macOS et Windows). Dans son concept, il reprend dans les grandes lignes les fonctionnalités de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javafxpackager</span>, un outil introduit par Oracle dans le JDK7 et destiné à créer des lanceurs natifs pour JavaFX. Cet outil était devenu par la suite <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javapackager</span> dans les JDK 8, 9 et 10 et permettait de créer des lanceurs pour n'importe quel type d'application Java (CLI, Swing). <br />
<br />
Les applications ainsi créées contenaient une JVM embarquée ainsi que des lanceurs, installeurs et désinstalleur natifs adaptés au système d'exploitation hôte  (exe, msi, pkg, dmg, deb ou encore rpm) et facilitaient l'expérience utilisateur de l'installation et de la désinstallation ou encore des icônes et descriptifs de l'application. Ces paquetages natifs permettaient la prise en charge des signatures numériques natives pour vérifier l’authenticité du paquetage par l'OS ou l'antivirus et facilitaient également la création d'une distribution de l'application compatible sur les magasins en ligne des éditeurs.<br />
<br />
Il avait cependant cessé d’évoluer et ne supportait pas les modules. Ne faisant de plus pas partie de l'OpenJDK, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">javapackager</span> avait été retiré des JDK 11 et 12 au profit de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jlink</span> un outil supportant les modules et capable de créer une distribution Java restreinte, mais sans support de lanceurs ou installeur natifs, ce qui avait créé un vide dans écosystème Java coté client.<br />
<br />
Bien que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">jpackage</span> fut initialement prévu pour le JDK 13, cette version anticipée est construite sur une version préliminaire du JDK 14. L'outil tiers <a href="https://wixtoolset.org/" target="_blank">Wix</a> est toujours requis pour construire des installeurs sous Windows.<br />
<br />
Source : <br />
<ul><li style=""><a href="https://twitter.com/OpenJDK/status/1168804664671920128" target="_blank">Twitter de l'OpenJDK</a></li><li style=""><a href="https://jdk.java.net/jpackage/" target="_blank">jpackage Packaging Tool</a></li><li style=""><a href="https://openjdk.java.net/jeps/343" target="_blank">JEP 343: Packaging Tool</a></li></ul></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7997/openjdk-annonce-mise-disponibilite-acces-anticipe-jpackage/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Jour 5 - Sur le Retour</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7620/pokemon-gofest-2019-chicago-jour-5-retour/</link>
			<pubDate>Sat, 27 Jul 2019 11:51:22 GMT</pubDate>
			<description><![CDATA[J'ai pris pas mal de retard...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">J'ai pris pas mal de retard hélas lors de la rédaction de cette dernière entrée car je me suis fait rattrapé par les activités du boulot et de la vie hors période de vacances ^^.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485537d1561155091/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 3337
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
Je dois bien avouer que j'ai eut un peu plus de mal à me lever ce samedi matin compte tenu des mes aventures des deux journées précédentes ; le temps franchement mauvais de cette nouvelle journée n'aidant pas à me forcer à sortir de mon lit douillet.<br />
<br />
<b>Shopping time!</b><br />
Après un rapide toilettage et petit déjeuner et avoir préparé nos bagages, nous avons repris le métro la ligne rose à Polk en direction de <i>the Loop</i> ; cependant, la ligne étant en maintenance pour le week-end, notre train a dévié de son trajet habituel pour nous déposer sur à la station Racine de la ligne Bleu. Cela nous a permis de reconnaître un peu les lieux puisque c'est de cette station que nous devrons prendre le métro dans l’après-midi pour aller jusqu’à O'Hare l’aéroport de la ville. Après quelques minutes d'attente nous avons embarqué dans la nouvelle rame de métro en direction du centre-ville. Alors que la ligne rose est constituée d'un métro aérien, la ligne bleue est quant à elle souterraine dans son tronçon du centre-ville et nous n'avons donc pas vu grand chose jusqu’à la station Washington située dans le sous-sol de la galerie commerciale <i>Block Thirty Seven</i> (bloc 37).<br />
<br />
Notre temps en ville étant limité, pour ma part je me suis dirigé vers <i>the Bean</i> pour y rencontrer mon dernier partenaire d’échanges planifiés pour ce séjour pendant que mes 2 compagnons de voyage sont partis en direction de <i>Navy Pier</i> pour aller a un magasin d'articles de sport des <b>Chicago Bulls</b> qu'ils y avaient vu le mercredi précédent. J'avais prévu d’échanger quelques <b>Relicanth</b> contre un <b>Zarbi B</b> et j'avais également promis à cette personne de lui donner un poisson de chaque sexe. En effet dans la série classique, le ratio mâle / femelle est de 87,5% contre 12, 5% et Pokémon GO suit cette valeur ce qui rend les femelles plus rares pour cette espèce. Cependant, compte tenu de notre départ proche et du fait que ma collection de Pokémon était passablement pleine après toutes les captures de la veille, je lui ai finalement donné tous les poissons pierre qu'il me restait ; autant pouvoir jouer un peu en capturant des chose sur le retour à Los Angeles et Auckland. <br />
<br />
<b>On the road again...</b><br />
Je suis ensuite retourné vers le <i>Block Thirty Seven</i>  pour y prendre un souvenir de la ville dans le petit <i>Disney Store</i> du <i>Block Thirty Seven</i> et j'y ai retrouvé mes compagnons qui avaient abandonné leur idée initiale, <i>Navy Pier</i> étant tout simplement trop éloigné pour le peu de temps qu'il nous restaient. En repartant, nous avons acheté des salades et sandwichs dans un Prêt-à-Manger du sous-sol de la galerie avant de reprendre la ligne bleue en direction de la station Racine. Cette station est coincée au beau milieu d'une <i>Highway </i>(autoroute) et est accessible par des passerelles qui partent de deux ponts qui enjambent l'autoroute. Ici aussi, comme à certains endroits en ville, certaines rampes et passerelles font un peu vétustes et on sent bien qu'on est dans la <i><a href="https://fr.wikipedia.org/wiki/Rust_Belt" target="_blank">Rust Bel</a></i>t (ceinture de la rouille) cette grande région industrielle du nord-est des États-Unis qui semble ne s’être jamais complètement remise de la tertiairisation de l’économie (passage à l’économie de service), du déclin industriel et des déplacements des usines automobiles vers d'autres contrées à partir des années 60 et a vu sa démographie chuter depuis.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p494045d1564227503/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/mickey-chicago.jpg/" border="0" alt="Nom : mickey chicago.jpg
Affichages : 579
Taille : 34,9 Ko"  style="float: CONFIG" /><br />
<font size="1">Mickey accroché à un réverbère ployé par le vent (ornement de Noël)... Comme quoi je n'ai pas fait que ramener des souvenirs Pokémon de ce voyage...</font></div><br />
C'est sous une pluie fine que nous avons rejoint notre AirBnB dans <i>Little Italy</i> et après un rapide déjeuner nous avons sorti les poubelles et avons procéder à un petit nettoyage tout en vérifiant que nous n'avions rien oublié. Notre avion décollant à 17h nous avions convenu d'un <i>late checkout</i> (rendre les clés tardivement sans surcoût) avec le propriétaire des lieux et c'est vers 13h que nous avons claqué définitivement la porte de notre logement. une quinzaine de minutes plus tard, nous montions à nouveau dans le métro cette fois-ci en direction du terminus nord de la ligne : O'Hare. Arrivés sur place nous avons dit au revoir à notre compagnon de voyage qui venait de France métropolitaine car il avait décidé de rester quelques jours de plus à Chicago pour visiter la ville avant de repartir vers l'Europe. Nous avons ensuite rapidement enregistré nos bagages en soute avant de passer les contrôles de sécurité. Tout comme à LAX, le terminal est principalement constitué de restaurants, cafétéria, snacks et <i>diners</i>, on y trouve peu de boutiques ou de possibilité d'y acheter des souvenirs de dernière minute de Chicago.<br />
<br />
<b>Pendant ce temps-là...</b><br />
Durant notre <i>trip</i> en métro vers l’aéroport les conditions météorologiques ont continué à se détériorer aux alentours de <i>the Loop</i>. Vers 13h00, la municipalité de Chicago a finalement émis un avis d'alerte aux orages violents et, vers 13h15, Niantic a fait évacuer la zone des festivités en enjoignant les joueurs à retourner à leur hôtel ou domicile. Puis la compagnie a complètement suspendu l’événement vers 13h25 en faisant disparaître les Pokéstops et en stoppant les apparitions de créatures. Du fait de l'annulation de la session d'autographes, de leur coté, les YouTubeurs ont préparé des posters signés dans leur chambre d’hôtel avant d'annoncer sur leurs <a href="https://twitter.com/trnrtips/status/1140297304064319489?s=20" target="_blank">chaînes Twitter respectives</a> un point de rendez-vous à 17h à <i>Navy Pier</i> pour ceux qui seraient encore présents dans les environs. L’événement a toutefois repris son cours vers 15h30 lorsque toutes les alertes eurent été levées. Par la suite, et pour s'excuser auprès des participants qui ont vu leur expérience de jeu altérée, Niantic a décidé d'offrir <a href="https://pokemongolive.com/fr/post/chicagoeventupdate/" target="_blank">un événement de remplacement</a> à tous les joueurs disposant d'un ticket valide pour le samedi 15 juin le samedi 22 juin de 9h à 19h (heure locale). Durant ces 10 heures, tous ces joueurs (et uniquement eux) ont pu voir apparaître les mêmes Pokémon que durant le GO Fest et ce où qu'ils soient dans le monde.<br />
<br />
<b>LA Noir</b><br />
Contrairement au vol aller, nous n'avons eut aucune difficulté avec notre vol retour vers Los Angeles ; notre avion American était à l'heure bien que bondé et il y a eut très peu de turbulences durant le trajet. Arrivés après le coucher du soleil, notre passage à LAX a été très bref, à peine le temps de sortir nos bagages du tapis et de passer du terminal 7 au terminal international Tom Bradley pour les y enregistrer à nouveau cette fois ci sur les bornes automatisées individuelles d'Air New Zealand. Hum...  d'ailleurs c'est la première fois que je vois une borne d'enregistrement me proposer une procédure spéciale si jamais je me me sens le besoin d'enregistrer une arme à feu en cabine... ... ... oui, décidément, nous somme toujours bien aux États-Unis... <br />
Le passage des formalités de sécurité pour le départ est vite expédié, et s’avère beaucoup plus rapide qu'à l’arrivée et nous nous retrouvons rapidement à nouveau en zone internationale avec juste le temps de faire quelques boutiques pour y prendre des souvenirs. <br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p492683d1563755371/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/galaxy-s-edge.jpg/" border="0" alt="Nom : galaxy's edge.jpg
Affichages : 180
Taille : 102,2 Ko"  style="float: CONFIG" /><br />
<font size="1">Une jolie pub pour <i>Star Wars Galaxy's Edge</i> qui vient d'ouvrir à Disneyland nous attendait en débarquant de l'avion à LAX.</font></div><br />
Finalement la zone de départ se trouve tout au bout du terminal, dans une nouvelle extension destinée aux vols <i>low cost</i> ; en fait comme à l’arrivée nous allons devoir prendre des bus pour aller jusqu’à un terminal d'embarquement spécial où se trouve notre avion. Autant dire que la procédure a pris un certains temps avant que tous les passagers soient à bord peu après 22h. De plus, Air New Zealand a du immobiliser son Boeing 737 Max suite à la crise actuelle autour de cet avion et a donc affrété un appareil de remplacement d'un autre type auprès d'une autre compagnie ; en fait ce dernier n'est qu'à moitié plein et, immédiatement après le décollage, l’équipage nous a invité à nous répartir dans les sièges encore libres dans la cabine pour que tout le monde puisse disposer de plus d'espace pour pouvoir s'allonger et espérer ainsi pouvoir passer un vol plus confortable. J'ai pour ma part passé quelques heures à regarder des animations Disney telles que La Bande à Picsou et quelques épisodes des nouveaux cartoon Mickey Mouse avant de m'endormir...<br />
<br />
<b>Pendant ce temps-là... (bis)</b><br />
Dimanche, le dernier jour du GO Fest s'est déroulé dans des conditions météo moyennes : du brouillard puis un plafond nuageux très bas cachant les gratte-ciels. Il n'y a pas eut de gros grain mais le terrain n'avait pas particulièrement eut le temps de sécher ce qui a obligé les joueurs à patauger dans la boue. Il n'y a pas eut d'autres alerte météo cependant donc l’événement n'a pas été interrompu comme cela avait pu être le cas pour l’après-midi du samedi. Les dresseurs presents rapportent que la boutique de souvenir Pokemon a rapidement été épuisée, il ne restait plus d'article à vendre après 4 jours de liesse.<br />
En fin de journée, Niantic a à nouveau réuni les jours près de l’arène PvP pour la photo de groupe et leur a offert une activité inattendue : un <i>stress test</i> de raid. 12 arènes temporaires ont été rajoutées durant une dizaine de minutes, ce qui a permet aux centaines de joueurs encore sur place de participer à des raids contre le Pokémon <b>Miaouss</b> pour rester sur la thematique de la Team Rocket... Cela a ainsi permi de mettre les serveurs à l’épreuve d'un grand nombre de dresseurs jouant ensemble dans une zone géographique très restreinte. Le même test a d'ailleurs été reproduit lors du GO Fest de Dortmund ce qui laisse à penser que les futurs GO Fest offriront des raids en plus des autres activités de la zone.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p492685d1563756015/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/raid-test.jpg/" border="0" alt="Nom : Raid-test.jpg
Affichages : 293
Taille : 45,6 Ko"  style="float: CONFIG" /><br />
<font size="1">Les arènes temporaires créées pour les tests sur <i>Buttler Field</i>. Source de l'image: Reddit.</font></div><br />
<b>Jour 7</b><br />
Oui il n'y a pas eut de jour 6 ; à nouveau la magie du franchissement de la ligne de changement de date mais dans l'autre sens... pour nous la journée de dimanche est passé totalement inaperçue : nous sommes partis le samedi au soir de Los Angeles et c'est lundi matin que nous sommes arrivés à Auckland après presque 13h et des poussières de vol. Malheureusement l'avion a pris du retard au décollage et nous accusons désormais 40 minutes de retard ce qui met en péril notre correspondance vers Nouméa. Comme à l'arrivée, nous passons rapidement les formalités d'immigration ; puis tandis que mon compagnon de voyage reste à la livraison des bagages pour récupérer nos valises, je fonce vers l'enregistrement après avoir passé les contrôles douaniers et phytosanitaires pour voir si la procédure est encore ouverte et s'il y a moyen de demander au personnel d'attendre quelques instants supplémentaires.  Aucun soucis, l'enregistrement pour notre vol est toujours en cours mais, comme souvent avec Air New Zealand, il se déroule sur des bornes automatiques sans personne autour... mais bon les valises finissent par arriver et nous repassons la police de l'air et des frontières après avoir obtenus nos cartes d'embarquement. Mauvaise nouvelle pour moi : mon sac à dos déclenche une alarme et je me retrouve 15 minutes à poireauter derrière un couple avec 3 enfants en bas âge qui est en train de dépiauter ses bagages... je n'avais jamais vu une aussi grande quantité de trucs interdits entassés dans des sac de cabine (pack de congélation, bouteilles d'eau, ...)... pendant ce temps là la queue derrière moi s'allonge avec d'autres personnes qui doivent passer également au contrôle pour faire vérifier leurs affaires. Finalement, on me rend mon sac sans que j'ai à l'ouvrir, il s'agissait d'une alarme aléatoire, destinée a tester la vigilance des agents... super...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p492681d1563755230/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/noumea.jpg/" border="0" alt="Nom : noumea.jpg
Affichages : 289
Taille : 35,4 Ko"  style="float: CONFIG" /><br />
<font size="1"><i>Home, sweet home!</i> La presqu’île de Nouméa vue du ciel...</font></div><br />
Le temps d’ingérer rapidement une boite de sushis (j'aime bien les sushis au petit déj), et de dévaliser le vendeur de <a href="https://www.whittakers.co.nz/" target="_blank">Whittaker's</a> histoire de finir la réserver de dollars néo-zélandais qu'il me restait d'un voyage en févier dernier, nous voici à nouveau dans l'avion, direction la maison cette fois ! Notre second passage à Auckland aura été très rapide et nous avons hâte de rentrer après cette semaine de folie. Après un vol sans encombre, nous nous posons avec 20 minutes d'avance à la Tontouta, l’aéroport international de Nouvelle-Calédonie. Ici aussi le passage des formalités et de la douane est rapide (pour une fois) et nous reprenons ensuite rapidement chacun de notre coté le chemin vers la ville ; ça tombe bien... à 13h nous avons une invitation pour un raid EX contre le boss <b>Deoxys forme Défense</b>... nous pensions ne pas pouvoir arriver à temps pour pouvoir le faire mais désormais nous sommes largement en avance ! <br />
<br />
Et oui, le GO Fest est bien terminé mais il nous faut encore continuer à tous les attraper pour devenir le meilleur dresseur ! <i>To be continued...</i><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p492686d1563764757/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/pokeball.png/" border="0" alt="Nom : pokeball.png
Affichages : 316
Taille : 3,7 Ko"  style="float: CONFIG" /></div><br />
<b>Épilogue - Expecto Patronum</b><br />
La fin de semaine suivante a vu également <a href="https://jeux.developpez.com/actu/267028/Niantic-lance-Harry-Potter-Wizards-Unite-un-jeu-video-de-role-en-RA-qui-reprend-la-formule-de-Pokemon-Go-Un-racketiciel-pour-les-enfants/" target="_blank">le lancement de <b>Harry Potter: Wizards Unite</b></a> tout d'abord aux États-Unis et au Royaume Uni puis 2 jours plus tard dans d'autres régions du monde, France comprise. À part quelques rééquilibrages et l'ajout des langues supplémentaires le jeu est sommes toutes identique à ce qu'il était durant la bêta. D'ailleurs les comptes des testeurs n'ont pas été réinitialisés à la sortie du jeu et ils ont pu continuer de jouer aux niveaux d'avancement qu'ils avaient acquis. <br />
<br />
Globalement, le client, développé par WB Games San Francisco, semble être plus stable et moins bogué que Pokémon GO, son aîné ; cependant il s’avère gourmand en bande passante pour télécharger les modèles 3D et leurs sons et textures, une options dans les réglages permet d'ailleurs de télécharger en amont les 3,3Go de ressources du jeu quand on est sur réseau Wi-Fi. De plus, les soucis que j'avais détectés durant ma courte phase de test à Auckland sont toujours présents : les animations sont jolies mais trop lentes et longues, les sorts échouent bien trop souvent ce qui laisse rapidement un sentiment de frustration et l’énergie est un facteur bien trop limitant. Niantic a d'ailleurs rapidement procédé à un rééquilibrage en urgence lors du week-end de lancement en augmentant la quantité d’énergie retournée par les auberges et en offrant un pack de démarrage gratuit dans la boutique du jeu. Faire pousser des plantes en serres s’avère toujours pénible compte tenu du besoin de repasser sur place à heure fixe pour récupérer sa récolte et les limitations de l’inventaire toujours aussi frustrantes ; sans parler des nombres incitations à dépenser son argent dans le magasin du jeu pour augmenter cette limite. L’expérience en forteresse s’avère cependant différent du reste du jeu et est assez sympa à plusieurs s'apparentant plus à ce qu'on peut trouver dans un MMORPG classique ou chaque profession peut briller ; d’ailleurs il est nécessaire d'avoir un groupe plutôt hétéroclite pour pouvoir avancer là où un groupe de 5 personnes de la même profession pourra avoir du mal à compléter le niveau de la forteresse.<br />
<br />
Depuis, profitant de l'infrastructure mise en place pour Pokémon GO, Niantic a lancé toute une pléthore d’événements en jeu dans les semaines qui ont suivi la sortie. La compagnie vient d'ailleurs d'annoncer la tenue d'un <a href="https://www.harrypotterwizardsunite.com/post/fanfestival-071919/" target="_blank">Fan Festival</a> (l’équivalent du GO Fest) dès la fin du mois d’Août <a href="https://harrypotterwizardsunite.com/events/2019/fanfestival/" target="_blank">à Indianapolis</a>. Les modalités d'inscriptions et de participations sont similaires à celles des GO Fest : inscription en jeu, tirage au sort avec notification en jeu et par mél, temps limité pour prendre sa décision et valider sa participation,  payer (ici car c'est à nouveau un événement payant) tout en invitant potentiellement des amis. Niantic annonce d'ailleurs la tenue d'un événement exclusif durant ce festival avec l’arrivée des Retrouvables dragons en jeu ; dragons qui deviendront par la suite des Retrouvables régionaux pour inciter les joueurs à voyager. Cependant par certains coté le jeu semble avoir du mal à décoller et on est très loin de la liesse qui s’était emparée des rues à la sortie de Pokémon GO. Cela s'en ressent d'ailleurs sur les bénéfices engrangés... bien que Harry Potter: Wizards Unite soit le 2nd meilleur jeu mobile en RA devant Jurassic World Alive et Walking Dead Our World, il a dégagé sur son premier mois <b>30 fois moins</b> (!) de bénéfices que Pokémon GO ! Le Roi ne semble pas encore être prêt à être détrôné...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p492677d1563754051/applications/developpement-2d-3d-jeux/api-graphiques/directx/declaration-survie-jeu-video-france/harry-potter-wizards-unite-first-month-revenue.jpg/" border="0" alt="Nom : harry-potter-wizards-unite-first-month-revenue.jpg
Affichages : 556
Taille : 112,2 Ko"  style="float: CONFIG" /><br />
<font size="1">Les revenus des jeux RA mobiles lors de leur premier mois d'exploitation après leur lancement. Source : <a href="https://sensortower.com/blog/harry-potter-wizards-first-month" target="_blank">SensorTower</a>.</font></div><br />
<b><font color="#FF0000">R</font></b><br />
<br />
<div style="text-align: center;">
<div class="video-container"><iframe class="restrain" title="YouTube video player" width="560" height="315" allowfullscreen src="//www.youtube.com/embed/JelZpnkEcPM?wmode=transparent&amp;fs=1" frameborder="0"></iframe></div>
</div></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7620/pokemon-gofest-2019-chicago-jour-5-retour/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Jour 4 - GoFest Part 2</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7616/pokemon-gofest-2019-chicago-jour-4-gofest-part-2/</link>
			<pubDate>Fri, 05 Jul 2019 05:11:51 GMT</pubDate>
			<description>*Note :* le GO Fest de...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><b>Note :</b> le GO Fest de Dortmund a commencé hier. Comme prévu les habitats et les espèces présentes sur site sont différents de ceux de Chicago mais globalement un visiteur aura une expérience de jeu similaire au GO Fest de Chicago en visitant l'événement allemand.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485535d1561155051/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 2778
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
L'animé Pokémon, de même que plusieurs des principaux jeux vidéo de la série commencent par un chercheur spécialisé dans l’étude des Pokémon qui vient demander à un gamin de choisir un Pokémon pour d'aller ensuite explorer le monde pour tenter de remplir son Pokédex. Le plus connu d'entre eux est le <b>Professeur Chen</b> bien sur qui a envoyé Sasha, Red, Green ainsi Régis et Blue faire la toute première aventure (et ses remakes plus récents). Dans Pokémon GO, c'est le <b>Professeur Willow</b> (Saule en 2016 et 2017, mais la version française du jeu a adopté le nom anglais depuis), entouré de ses assistants <b>Blanche</b> (cheffe de l’équipe Sagesse - bleu), <b>Candella</b> (cheffe de l’équipe Bravoure - rouge) et <b>Spark</b> (chef de l’équipe Intuition - jaune), qui envoie les joueurs explorer le monde.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488958d1562282656/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/willow.jpg/" border="0" alt="Nom : willow.jpg
Affichages : 241
Taille : 53,3 Ko"  style="float: CONFIG" /><br />
<font size="1">Une nouvelle recherche attend les assistants du professeur Willow.</font></div><br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>Professeur Willow</strong>
					
				</div>
				<div class="message">Dresseur, j'ai relevé une activité inhabituelle chez les Pokémon de la région... peux-tu commencer à enquêter sur le terrain tandis que je regarde si mes livres mentionnent quelque chose ?</div>
			
		</div>
	</div>
</div><b>Votre mission si vous l'acceptez...</b><br />
Initialement Pokémon GO a été lancé sans aucun arc narratif, se contentant d'être un jeu de collectionneur avec quelques aspects de combats et de contrôle territorial hérités d'Ingress. Il en fut ainsi en 2016 et tout 2017 jusqu'à ce que Niantic rajoute des &quot;recherches&quot; courant 2018. Si les &quot;recherches de terrain&quot; données par les Pokéstops sont juste une couverture pour des tâches et quêtes journalières destinées à garder le joueur occupé en lui demandant d'aider le professeur Willow dans son travail, les &quot;recherches spéciales&quot; quant à elles apportent un arc narratif léger tournant autour du professeur qui enquête sur des phénomènes mystérieux ou tente de comprendre comment les Pokémon vivent dans la nature. Durant ces recherches le professeur contacte directement le joueur par son communicateur et à travers un semblant d'histoire le lance, le plus souvent, à la découverte de Pokémon ultra-rares, les Pokémon fabuleux. Niantic a également réutilisé le concept pour offrir aux joueurs une paire de quêtes exclusives durant des événements. <br />
<br />
On retrouve exactement le même concept dans Harry Potter: Wizards Unite mais en beaucoup plus développé avec une série de &quot;missions du Code du Secret Magique&quot; qui donnent lieu à des discussions entre personnages non-joueurs expliquant un peu mieux l'état du monde des sorciers dans le contexte du jeu. Des discussions supplémentaires sont également disponibles dans le Registre quand on examine certains Retrouvables récupérés et qui sont destinées à dévoiler quelques éléments d'intrigue sur les cause de la Calamite qui frappe le monde des sorciers. Le récent événement &quot;Brillant&quot;qui vient de démarrer a peine 1 semaine après le lancement de ce nouveau jeu reprend d'ailleurs également ce concept de narration légère de manière à faire que le joueur se sente un peu plus implique dans le monde du jeu.<br />
<br />
Et c'est d'autant plus étrange que dans Pokémon GO l'idée mériterait d'être mieux exploitée en offrant plus d'histoire aux joueurs. En effet, bien qu'intéressant le principe est encore assez peu utilisé dans Pokémon GO : il n'y a en tout et pour tout actuellement que :<br />
<ul><li style="">3 recherches spéciales permanentes (pour chacun des Pokémon fabuleux <b>Mew</b>, <b>Celebi</b> et <b>Meltan</b>) ; une quatrième sera sans doute rajoutée peu après le GO Fest de Yokohama.</li><li style="">2 temporaires : 1 pour obtenir le Pokémon fantôme <b>Spiritomb</b> durant Halloween 2018 (on en sait pas si elle reviendra cette année) et une toute nouvelle qui vient d’être ajoutée pour l’été 2019 destinée à récompenser les joueurs sur le retour.</li><li style="">et 2 exclusives à des événement : 1 pour le GO Fest de 2018 à Chicago qui permettait aux participants d'obtenir Celebi en avant-première, et 1 à Safari Zone de Yokosuka au Japon en Août 2018 (qui ne donnait rien de particulier).</li></ul><br />
On aimerai en avoir bien plus (avec peut-être moins d'exclusives ou de temporaires) !<br />
<br />
Mais passons, ce GO Fest 2019 à Chicago étant l'occasion d'une nouvelle recherche spécial exclusive inédite... quels nouveaux mystères allons-nous découvrir, Professeur ? <br />
<br />
<b>1/5 - Se faire de nouveaux amis</b><br />
Cette fois-ci j'ai retenu les leçons de la veille : à chaque fois que je passais devant la boutique de souvenirs Pokémon, j'abandonnais tout espoir d'y accéder rien qu'en voyant la longueur de la file d'attente des joueurs. Ce matin, je suis arrivé plus d'une heure à l'avance. il y a déjà la queue certes, mais elle n'est pas encore très très longue (elle le sera BEAUCOUP plus à 9h au lancement anticipé de l’événement). Une fois mes quelques achats effectués, c'est donc rapidement que je me mets à la tache pour profiter de ma journée de jeu et pour répondre aux questions existentielles du professeur et tenter de découvrir le mystère caché dans ce parc : Willow a en effet découvert un Pokémon rare profondément endormi qu'il n'arrive pas à réveiller.<br />
<br />
Mais ne mettons pas la charrue avant les bœufs, pour cette première étape, le professeur me demande de récolter des ressources et de réunir d'assistants pour l'aider pendant qu'il se replonge dans ses livres à la recherche de réponses à se questions. Il nous faut donc faire tourner 7 Pokéstops ce qui est une bonne occasion pour commencer à activer les Pokéstops de l'événement histoire de gagner des objets et de découvrir quels sont les recherches de terrain de l'événement. Celles-ci sont des plus classiques (capturer un certain nombre de Pokémon, faire des lancers, utiliser des baies, etc.) mais donnent toutes en récompense 3 bonbons rares. Ces bonbons peuvent être donnés à n'importe quel Pokémon ce qui permet, quand le joueur en a accumulé suffisamment, de faire monter la créature de poche de niveau de manière à la rendre plus efficace en combat pour les arènes ou les raids. En général, ces bonbons sont donnés en quantités variables en récompenses de raids et parfois dans des recherches de terrain plus longues ou compliquées que la moyenne. Autant dire qu'avec 83 Pokéstops dans la zone de jeu, qui donnent chacun potentiellement 3 bonbons, c'est l'abondance ! En avant dresseur et courage car il va falloir faire toutes ces quêtes durant les 10 prochaines heures ! En parallèle les Pokéstops du parc peuvent aussi donner des œufs de 2km (il faut marcher 2km pour les faire éclore) qui contiennent une sélection des Pokémon présents durant l'événement, Pokémon qui sont en temps normal disponibles dans des œufs de plus grande distance. De plus, ils sont également potentiellement chromatiques, ce qui ne gâche rien !<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p487275d1561724917/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/parc-1.jpg/" border="0" alt="Nom : parc 1.jpg
Affichages : 378
Taille : 67,3 Ko"  style="float: CONFIG" /><br />
<font size="1">Faire tourner un Pokéstop, certes,  mais par lequel commencer ?? <i>Hutchinson Field</i> en est rempli. Au loin des arènes et raids hors de la zone de l'événement. </font></div><br />
Les joueurs amis sont une fonctionnalité rajoutée courant 2018 : un dresseur peut envoyer un code numérique ou encore scanner un QR code pour être rajouté dans liste de contacts d'un autre joueur. Bien que Pokémon GO ne supporte pas la discussion directe en jeu contrairement à Ingress, être amis apporte plusieurs avantages : les joueurs peuvent se renforcer mutuellement les dégâts qu'ils occasionnent lors des raids, ce qui permet de battre plus facilement un boss qui a pris possession d'une arène. Il est aussi possible de faire des échanges de Pokémon avec ses amis et espérer avoir de meilleurs Pokémon, voir même des Pokémon chanceux. À haut niveau d'amitié il est aussi possible de faire des combats entre joueurs depuis n'importe quel endroit de la planète. Et enfin les joueurs peuvent s'envoyer des cadeaux qu'il ramassent sur des Pokéstops ; ces cadeaux pouvant contenir des objets utiles en jeu ou même des œufs de 7km pouvant donner des Pokémon rares. <br />
<br />
Cette étape de la recherche spéciale demandant d'ajouter 3 amis et d'envoyer 3 cadeaux, autant dire qu'immédiatement chacun se tourne vers son voisin le plus proche pour donner son code ou scanner le QR code d'autrui, ce qui permet de brièvement faire connaissance et découvrir d'où viennent les autres joueurs. Même si les joueurs présents sont principalement des américains provenant de tous les états (Alaska et Hawaï compris), il y a des joueurs provenant de tous les coins de la planète ! De quoi offrir plein d’opportunités de discussions et d’échanges...<br />
<br />
<b>2/5 - Explorer les habitats</b><br />
Ayant réussi avec bio la première étape de la recherche, voici que le professeur nous contacte à nouveau. Ses instruments étant désormais calibrés et, avec l'aide des ressources et assistants supplémentaires que nous avons réunis, nous allons pouvoir explorer plus en avant les zones du parc et tenter de catégoriser toutes les espèces de Pokémon réunis dans cet endroit. Ici à l’entrée sud nous nous trouvons sur la bordure de la zone désertique, plusieurs espèce de type roche ou de sol peuplent cet endroit : <b>Embrylex</b>, <b>Racaillou</b>, <b>Rapion</b>, <b>Sabelette</b> (version Kanto) et <b>Archéomire</b> même si on trouve également quelques <b>Hypotrempe</b>. L'avant-poste d’échange plus au sud est principalement peuplé de Racaillou, <b>Abra</b> et <b>Machoc</b>. Même si leurs mécaniques d’évolution sont différentes dans Pokémon GO, on peut remarquer que Niantic a mis autour du <i>trading post</i> des espèces de Pokémon qui évoluaient uniquement lors des échanges entre joueurs dans les jeu Game Boy d'origine Pokémon Rouge et Pokémon Bleu.<br />
<br />
En remontant vers le jardin des Fées on peut croiser des <b>Pikachu </b>et <b>Évoli </b>qui portent encore les couronnes de fleur de l’événement du printemps dernier ; des <b>Cheniti</b> à cape plante (Cheniti vert donc) pendouillent des arbres. Les roseraient des jardin offrent un habitat reposant pour les Pokémon fée mais hébergent également pas mal de Pokémon plante ou insecte ; ainsi au détour d'un massif il n'est pas rare de croiser des <b>Mélodelfe </b>mais aussi des <b>Chenipan </b>ou des <b>Granivol</b> tandis que des <b>Snubulls </b>gambadent dans les parterres de fleur. Parfois un <b>Mysdibule</b> sauvage montre les crocs de sa coiffure ce qui semble faire fuir quelques <b>Blizzi </b>qui trainent dans le coin, étonnant quand on sait que ce Mysdibule est généralement uniquement disponible en tant que boss de raid ou depuis peu dans des œufs de 7 et 10km ; personne n'en avait encore jamais vu de sauvage ! Toute une foultitude de Pokémon de type eau s’ébattent autour de la fontaine Buckingham au centre du parc : des <b>Wailme</b>r, <b>Barpau</b>, <b>Cociperl</b>, <b>Krabby</b>, <b>Minidraco</b>, <b>Nenupiot</b>, <b>Écaillon</b> et j'en passe, même si quelques <b>Fantominus</b> traînent également dans le coin...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488962d1562284594/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/parc.jpg/" border="0" alt="Nom : parc.jpg
Affichages : 383
Taille : 75,1 Ko"  style="float: CONFIG" /><br />
<font size="1">Les souvenirs d'une journée d'exploration bien remplie !</font></div><br />
le temps se rafraîchit lorsqu'on pénètre dans la forêt gelée et la neige commence même à tomber en flocons à certains endroits, et on peut entendre le cri du <b>Lohklass</b> solitaire qui cherche toujours un compagnon ou une compagne ; des <b>Farfuret</b> se cachent derrière les tronc d'arbre et des <b>Pomedepic</b> essaient de tendre des pièges depuis les branches pour tenter d'attraper des <b>Marcacrin</b>. Ici et là des <b>Sabelette</b> d'Alola et des <b>Goupix</b> d'Alola s'amusent dans des tas de neige. Isolées sur les montagnes enneigées de leur archipel tropical d'origine, ces deux espèces de Pokémon ont en effet adopté le type glace et jusqu’à présent les dresseurs n'en avaient obtenu que dans les œufs de 7km envoyés par leurs amis du bout du monde ; c'est la toute première fois que j'en vois dans la nature ! Quelques <b>Tarsal</b> semblent s’être perdus dans la zone. La bordure nord de la forêt est une nouvelle occasion de rencontrer des Pikachu et Évoli à couronne de fleur et ici aussi des Cheniti sont accrochés au branchés.<br />
<br />
Au nord, les vois deviennent bien plus dense et bien plus sombre et prennent même des aspects menaçants. Des toiles d’araignées pendent entre les arbres, de la fumée sort d'un puits ; l’ambiance en devient carrément lugubre quand on s'avance trop dans les ombres. En effet des Pokémon spectre rodent dans le coin : <b>Polichombre</b>, <b>Skelenox</b>, <b>Tenefix</b> mais aussi <b>Baudrive</b> semblent être porteurs de malheur. Ils ont même attiré des <b>Malosse</b> et des <b>Medhyena</b> qui hurlent comme aux heures sombres de la nuit. Plusieurs <b>Absol</b> les ont d’ailleurs rejoint, pourtant je n'en avais jamais rencontré qu'en boss de raid et dans des œufs de 7 et 10km ; c'est le professeur qui va être surpris. Non loin de là quelques <b>Hippopotas </b>continuent de ruminer tranquillement dans un coin en ne semblant pas faire attention à l'agitation macabre qui nous entoure.<br />
<br />
Les dresseurs avertis ont vite remarqué que de petits écureuils blancs et bleu se retrouvent également un peu partout dans le parc : <b>Pachirisu</b>, qui est un régional uniquement disponible dans les zones arctiques (nord du Canada, Alaska et Sibérie) est venu nous dire bonjour. De plus, des Zarbi (ces Pokémon étranges et antiques en forme de lettres) A, E, K, P, U et ! font également leur apparition de temps à autres et, une fois toutes les lettres rassemblées, semblent vouloir former la phrase &quot;<i>WAKE UP!</i>&quot; (&quot;Réveille toi !&quot; en anglais), mais qu'est ce que cela peut bien vouloir dire ?<br />
<br />
<b>3/5 - Cacophonie photographique</b><br />
De manière générale, pour le moment, l’événement se déroule  sans trop d'accros par rapport à la veille : dans le monde réel les machines à bulle, neige, vent ou fumée sont désormais bien rodées et ne demandaient pas de nouvel entretient de la part du staff. Les boutiques semblent être mieux achalandées et il y a beaucoup moins de soucis de connexion dans les jardins des fées également. Côté monde virtuel, cette journée n'aura pas vu l'apparition inattendue et boguée de Pokémon chromatiques non prévus sur le planning. Cependant, vers 12h30 et pendant près de 30 minutes les rouages du jeu se grippent temporairement : impossible d'activer des Pokéstops ou de capturer des Pokémon ; certains dresseurs autour de moi se plaignent d'avoir du laisser partir des Évoli à couronne de fleur chromatique faute d'avoir pu les capturer. D’après un ami de France avec qui j’étais en train de discuter via Messenger, cette fois-ci le soucis était mondial et non pas confiné à la zone du GO Fest ; une fois le problème corrigé tout repart comme sur des roulettes ; certains repartent vite en arrière au cas ou leur Évoli serait encore là, on ne sait jamais...<br />
<br />
Mon rapport sur les espèces disponible dans le parc à interloqué le professeur : les espèce de Pokémon semblent être correctement reparties dans des habitats qui leur sont propres et dans lesquels elles prospèrent. Toutes, sauf une poignée d’espèces qui semblent s’être égarées et qui ne se trouve pas au bon endroit. Je repars donc en mission pour récupérer des spécimens et les déplacer dans leur habitat d'origine en espérant pouvoir trouver la source de ce déplacement inattendu. En effet, les espèces suivantes ne se trouvent pas au bon endroit du parc :<br />
<ul><li style=""><b>Hypotrempe</b> ne devrait pas se trouver dans le désert mais autour de la fontaine où il y a de l'eau à ne plus savoir quoi en faire ;</li><li style=""><b>Blizzi</b> n'a rien à faire dans le jardin des fées tout ensoleillé et sera sans doute heureux de regagner la froide forêt gelée ;</li><li style=""><b>Tarsal </b>doit être complètement givré sous les chutes de neige et s'épanouira bien mieux dans les roseraies avec les autres fées ;</li><li style=""><b>Hippopotas</b> supporte les climat chaud et sec du désert et donc n'a pas vraiment sa place au milieu des fantômes ;</li><li style="">Et enfin il faudrait faire cesser les troubles causés par <b>Fantominus</b> et le ramener auprès de ses congénères spectres.</li></ul><br />
<br />
Willow me demande d'ailleurs d'en profiter pour tester les nouvelles fonctions avancées de mon appareil photo intégré histoire de document le processus de réintroduction. Nos camera embarquées ont en effet reçu des mises à jour il y a quelques mois pour nous permettre de prendre des nouvelles photos via un mécanisme nommé Cliché GO. Désormais en mode AR+ et en utilisant les bibliothèques <a href="https://developers.google.com/ar/" target="_blank">ARCore</a> de Google ou <a href="https://developer.apple.com/augmented-reality/" target="_blank">ARKit</a> d'Apple, le téléphone est capable de détecter les plans horizontaux et peut ainsi placer les créatures de poche de manière plus réaliste lorsqu'on est en mode réalité augmentée ce qui permet, par exemple, de les approcher par derrière pour les surprendre lors de la capture et, depuis cette année, permet également de prendre des photos bien plus immersives. Il reste bien sûr possible de prendre des photos en mode AR normal mais elles sont souvent bien moins réussies que celles en mode AR+. Cette nouvelle fonctionnalité a d’ailleurs attiré l'attention du Pokémon <b>Queulorior</b> qui était resté jusque là caché aux yeux de tous. Depuis, il affectionne parfois s’immiscer sur les photos que prennent les dresseurs dans un acte que Spark a qualifié de &quot;photobomb&quot; ; plusieurs Pikachu ont également suivit le mouvement en imitant son mauvais exemple lors de récents événements...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488946d1562280783/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/habitats.jpg/" border="0" alt="Nom : habitats.jpg
Affichages : 377
Taille : 98,5 Ko"  style="float: CONFIG" /><br />
<font size="1">Ramener les Pokémon dans leur habitat respectif révèle des Pokémon musicaux !</font></div><br />
Capturer les spécimen et les ramener dans leur habitat d'origine a été l'occasion d'un nouveau périple à travers les zones du parc, ce qui m'a permis de récupérer quelques nouveaux chromatiques dont certains que je ne possédais pas auparavant. J'en ai profité également pour avancer quelques médailles en collectant des Zarbi ou en prenant des clichés. Cependant, ce n'est pas Queulorior qui a été attiré par mes photographies cette fois-ci mais toute une palanquée de Pokémon musicaux. Je pense pouvoir expliquer au professeur la raison de la migration de certaines créatures hors de leur habitat. Ainsi un <b>Ramboum</b> se cachait dans les bois hantés tandis qu'un <b>Eoko</b> carillonnait dans le vent et les bourrasques de neige de la forêt gelée. À la fontaine Buckingham, un <b>Archéodong</b> faisant tant de bruit qu'on entendait plus l'eau s’écouler et dans les roseraies, un <b>Rondoudou</b> endormait tout le monde de voix cajoleuse. Enfin, les bruit stridents d'un <b>Mélokrick</b> retentissait dans la zone désertique d'habitude si calme. Bref, en quelques coup d'appareil photo (et de Pokéball) je me suis retrouvé chef d'orchestre d'un ensemble orchestral de poche miniature !<br />
<br />
<b>4/5 - Le dormeur doit se réveiller</b><br />
La nouvelle de mes découvertes a été très favorablement accueillie par le professeur : d'une part car cela permettait aux choses d'enfin rentrer dans l'ordre dans le parc désormais que tous les Pokémon étaient retournés dans leur habitat d'origine. Mais, de plus, Willow avait fini par découvrir la description du dormeur mystérieux dans ses ouvrages de référence : il s'agissait pas moins que du Pokémon fabuleux <b>Jirachi</b> ! Ce Pokémon de type acier et psychique est endormi dans un sommeil de 1000 ans et seul une mélodie des plus pures peut le réveiller et le sortir de sa torpeur ! Je crois qu'il est tant de mettre à contribution mon orchestre de poche !<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488957d1562281921/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/jirachi.jpg/" border="0" alt="Nom : jirachi.jpg
Affichages : 350
Taille : 53,6 Ko"  style="float: CONFIG" /><br />
<font size="1">Lorsqu'ils sont tous réunis, les Pokémon musicaux peuvent réveiller Jirachi. Source du sprite : Bulbapedia.</font></div><br />
Les captures des Pokémon fabuleux précédemment obtenus par des recherches spéciales avaient été l'occasion de moments amusants et sortants de l'ordinaire. Presque à chaque fois, sauf bug imprévu (...), le téléphone passe automatiquement en mode AR pour rendre la séquence de capture un peu plus spéciale que pour celle des Pokémon normaux. Pour Mew, la créature de poche devenait presque totalement invisible et il fallait arriver à le deviner dans le décor. Pour Célébi, ce dernier se téléportait d'un bout à l'autre de l’écran et il fallait arriver à anticiper un peu ses mouvements. Seul Meltan n'avait pas eut droit, hélas, à quelques chose de spécial.<br />
Ici, pour Jirachi, c'est tout l'orchestre miniature qui se retrouve en train de chanter autour du Pokémon endormi jusqu'à son réveil avant de partir pour laisser la capture s'effectuer. Comme pour les fabuleux de 1<sup>ère</sup> et 2<sup>ème</sup> génération, on utilise un nombre infini de Pokéball normales et le Pokémon se laisse capturer uniquement à la 3<sup>ème</sup>  tentative.<br />
<br />
<b>5/5 - Ce n'est qu’un au-revoir</b><br />
En tout cas le professeur est très heureux : la journée de ses assistants de terrain a été bien remplie avec des tribulations et explorations en tous genre, et il a pu faire de nouvelles découvertes fascinante sur l’écologie et le comportement des Pokémon ; et il y a bien sûr eut une nouvelle créature de poche très rare ! Avant de prendre congé, il nous conseille entre autres de profiter des dernières heures de festivité dans le parc avant sa clôture pour faire éclore quelques œufs ou encore contacter quelques uns des nombreux dresseurs encore sur place pour voir si certains d'entre eux sont intéressés pour faire des échanges. Oh oui et également en profiter pour prendre quelques Clichés GO de notre nouvel ami, Jirachi le Pokémon qui peut exhausser nos souhaits. Je dois bien avouer que j'ai suivi son conseil et que j'en ai profité pour compléter un peu ma collection de Zarbi en récupérant des lettres que je ne possédais pas, allez plus que 2 lettres et ma collection est complète ! De leur coté, ces dresseurs sont repartis avec quelques <b>Relicanth</b> provenant de Nouméa. En tout cas le professeur nous recontactera sous peu car il sait qu'il peut sans soucis compter sur nous !<br />
<br />
Une seul soucis majeur vient à nouveau gripper le déroulement de l’évènement : 30 minutes avant la fin, les Pokéstops perdent soudainement tous leurs leurres sans qu'il soit possible de les réactiver. Ce qui a pour effet immédiat de réduire drastiquement les apparitions de Pokémon et d'énerver considérablement les dresseurs qui étaient encore en train de chasser leurs derniers chromatiques de la journée. 15 minutes avant la fin, soudainement, les leurres se remettent en route et les joueurs peuvent repartir dans ces derniers instants de <i>farming </i>intense. À nouveau, pour la seconde fois, à 19h tout s’arrête, la seconde journée du GO Fest est terminée.<br />
 <br />
<b>Nous sommes de retour...</b><br />
l’événement est fini, les joueurs partent du parc ou pour certains se réunissent près de l’arène de combat pour une photo de groupe de cette seconde journée. Las, fatigués et avec les pieds fortement endoloris, nous décidons de rester prendre un peu le frais sur le pourtour de la fontaine Buckingham ; la journée a été ensoleillée  et nous avons pris quelques nouveaux coup de soleil. Pour cet événement Niantic a augmenté la limite des Clichés GO qui peuvent faire l'objet de <i>photobomb</i> à 100 par jour (en temps normal c'est 1 seul par jour), c'est donc là une occasion unique de prendre quelques derniers clichés souvenirs de Jirachi ou des chromatiques capturé durant la journée et de finaliser la médaille idoine. Tout se passe bien quand... 30 minutes après la fin du GO Fest...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488944d1562279364/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/team-rocket.jpg/" border="0" alt="Nom : team rocket.jpg
Affichages : 476
Taille : 56,6 Ko"  style="float: CONFIG" /><br />
<font size="1">Des individus suspects ont été repérés dans la zone du GO Fest après sa fermeture. Partout où ils sont passés ils étaient suivis d'un <b>Miaouss</b>.</font></div><br />
Des gens louches, voire peut-être même des criminels qui semblent être attirés par des Pokémon rares... un chat retord... hum, j'ai l'impression d'avoir déjà vu cela quelques part.... Et si tout ceci n’était que le signe annonciateur d'autres trépidantes aventures* à venir ???? <br />
<br />
<div style="border: 1px solid #7192A8; border-radius: 5px; padding: 5px">
    <div style="text-align: right">
      <input type="button" value="Montrer" style="width:80px; font-size:10px; margin:0; padding:0;" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = '';this.value = 'Cacher'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.value = 'Montrer';}">
    </div>
    <div>
        <div style="display: none;"><br />
*j'ai depuis entendu des messages déroutants provenant de Dortmund et indiquant qu'une montgolfière noire frappée d'un sigle <b><font color="#FF0000">R</font></b> survolait le parc en fin de journée..<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p488972d1562300832/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/concerne-graphes/r-balloon.jpg/" border="0" alt="Nom : R balloon.jpg
Affichages : 510
Taille : 23,8 Ko"  style="float: CONFIG" /><br />
<font size="1">un mystérieux objet volant non-identifité sème la zizanie a Dortmund. D’après les premiers rapports, se trouveraient à bord une femme, un homme et un chat... Source : <a href="https://twitter.com/_ZoeTwoDots/status/1146825739817365504?s=20" target="_blank">Twitter</a></font></div></div>
    </div>
</div><br />
<br />
En attendant, le départ approche, et les nuages reviennent avec le coucher du soleil ; les prévisions ne sont guère encourageantes pour le lendemain. Cette fois-ci nous rentrons directement vers <i>Little Italy</i> car nous sommes fatigués par ces 3 jours de marche intense dans les environs du parc et des berges du lac Michigan. Plutôt que de dîner en ville, nous nous rendons dans un des bistro italiens qui se trouvent encore dans le quartier pour prendre des sandwich saucisse frite (saucisse italienne, pas des hot-dogs), c’était bien gras mais aussi bien bon ma foi. <br />
<br />
Allez, il est temps de se coucher !</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7616/pokemon-gofest-2019-chicago-jour-4-gofest-part-2/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Jour 3 - GOFest Part 1</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7612/pokemon-gofest-2019-chicago-jour-3-gofest-part-1/</link>
			<pubDate>Fri, 28 Jun 2019 01:09:58 GMT</pubDate>
			<description>Pièce jointe 485539...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485539d1561156226/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 1725
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
<b>Remarque :</b> on sait déjà que les modalités d’entrée dans le parc Wetfallen pour le GO Fest de Dortmund, les habitats et espèces de Pokémon présents (et donc la recherche spéciale), les activités, les YouTubeurs présents ou encore les moyens de paiement acceptés dans les boutiques de souvenir Niantic et Polémon sont différents de ceux du GO Fest de Chicago décrits ici.<br />
<br />
C'est par une nouvelle matinée pluvieuse que s'est ouvert le premier des 4 jours de festivités.<br />
<br />
<b>De bon matin</b><br />
Nous nous sommes levés peu après 7h et après un bref déjeuner et une séance de toilette, nous somme repartis vers la station de métro de Polk en direction du <i>Loop</i> aux alentours de 8h. Ce matin, notre petit bout de <i>Little Italy</i> situé près de l’université médicale de l'Illinois étaient remplies d’étudiants en médecine courant dans tous les sens en se dirigeant vers leurs bâtiments universitaires et autres hôpitaux. Étant donné notre heure de départ tardive de la veille, nous n'avions pas eut de soucis dans le métro, mais ce jeudi matin les rames étaient bondées de personnes se rendant au centre-ville pour démarrer leur journée de travail. Nous avons décidé de descendre à la station Adam/Wabbash plus proche de la fontaine centrale pour accéder à l’entrée sud de l’événement. De nombreux joueurs convergeaient également vers la zone, leur téléphone en main, habillés de t-shirts et casquettes arborant Pikachu ou leur Pokémon favori, des Pokéball, des slogan destinés à motiver l’équipe à laquelle ils étaient affiliés (ou d'autres moins flatteurs envers les 2 autres équipes) ou encore leur communauté locale de joueurs, adresses Discord ou Telegram à l'appui. Ici et là on pouvait également retrouver quelques personnes déguisées en Sacha, Red, Ondine ou d'autres personne de l'animé ou des jeux vidéo ou même en Pokémon.<br />
<br />
Dès la publication de l’annonce du GO Fest de Chicago, Niantic avait édicté une liste d'articles autorisés ou interdits dans le parc, répondant ainsi aux exigences de sécurités dictées par la ville : comme dans nombre d’écoles nord-américaines ou durant des événement rassemblant des foules (match, concert), seuls les sac à dos complètement transparents ou laissant entrevoir leur contenu (sac à mailles) étaient autorisés dans l'enceinte du parc. En 2017, lors du premier GO Fest qui s'était tenu dans <i>Buttler Field</i>, l'enceinte des festivités avait été entièrement clôturée et des contrôles de sécurité incluant des fouilles avaient été établis provoquant de longues queues et pas mal de délais pour les participants souhaitant entrer dans le parc et participer à l'événement ce qui était venu se rajouter à la longue liste des soucis rencontrés par les joueurs cette année-là. En 2018, lors du GO Fest 2018, Niantic avait émis la même liste d'interdictions mais, au final, <i>Lincoln Park</i> avait été laissé grand ouvert aux visiteurs et aux touristes sans aucun <i>check-point</i> de sécurité. Pour cette année 2019, le retour à <i>Grant Park</i>, certes sur un terrain presque 4 fois plus grand, laissait planer le doute sur la présence de clôture et de points de contrôles puisque la zone est bien plus facile à encercler de barrières contrairement au grand parc du nord de la ville. Au final, point de contrôles et même si la police municipale était bien présente en effectifs renforcés et même si des barrières avait été entassées le long de <i>Balbo Drive</i>, le parc était complètement en libre accès pour tous les visiteurs tandis que la circulation était coupée sur <i>Jackson Drive</i> et <i>Balbo Drive</i> permettant aussi aux joueurs de naviguer sans risque dans toute la surface de jeu du parc.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485847d1561349293/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/89a6c08.jpg/" border="0" alt="Nom : 89a6c08.jpg
Affichages : 202
Taille : 108,8 Ko"  style="float: CONFIG" /><br />
<font size="1">Vue aérienne du site du GO Fest quelques jours avant le GO Fest sous une météo plus clémente. À cette date, toutes les structures ne sont pas encore en place, il manque notamment les points d'information, toilettes de chantier ou encore les stations de recharge. Au premier plan, <i>Maggie Daley Park</i> et un bout de <i>Millenium Park</i>. Source : Reddit.</font></div><br />
À notre arrivée la météo étant toujours pluvieuse avec quelques goutte tombant de temps à autres ; je me faisais du soucis pour les batteries et autre câbles logés dans mon sac à doc, ayant opté pour un sac à mailles ouvertes, autrement plus confortable qu'un sac en vinyle transparent certes, mais qui laissait son contenu totalement exposé à la pluie. J'ai pu me rassurer cependant car je n’étais pas le seul dans ce cas, pas mal de participants ayant opté pour des sacs à dos similaires qui répondaient aux exigences de la municipalité de Chicago. Coup de chance pour nous, bien que le temps soit resté maussade juste que vers 14h, il n'a jamais eut de gros grains et donc mes batteries sont restées relativement au sec toute la journée. Il n'en pas été de même pour nos chaussures ; si les zones pavées de briques autour de la fontaine Buckingham étaient parfaitement praticables, tant <i>Bulter Field</i> que <i>Hutchinson Field</i> sont principalement constituées de zones gazonnées ou de terre battue (les 12 terrains de Baseball sur <i>Hutchinson Field</i>). Or ces zones n'avaient pas encore eut le temps de sécher suites aux fortes pluies de la veille, et nous avons passé une bonne partie de la journée à patauger dans la boue à chaque fois que nous nous rendions dans un de ces endroits.<br />
<br />
<b>La foule des grands jours</b><br />
Cette année, tous les tickets étant numériques et directement attachés au compte, aucun besoin de faire tourner un Pokéstop spécial ou de scanner un QR code : à partir de l'heure d'activation (9h pour les accès anticipés, 11h pour les accès régulier), le joueur a juste besoin d’être dans le parc pour que sa participation s'active. Ainsi à 9h précises, dans le jeu des dresseurs disposant d'un ticket avec accès anticipé, le parc prend soudainement vie et plus de 80 Pokéstops font leur apparition, immédiatement placés sous leurres par les joueurs présents, et une petite infobulle apparaît dans le coin inférieur droit de l’écran annonçant quel le Professeur Willow a une nouvelle recherche spéciale pour laquelle il demande l'aide du joueur... mais nous en reparlerons plus tard... Point d'arène dans tout le parc cependant, durant cette journee les joueurs ne doivent pas être distrait par les combats pour reprendre les arènes et il n'est pas sûr et certain que les serveurs tiendraient la route si plus de 10 000 joueurs se lançaient en même temps dans un raid (souvenez-vous des performances exécrables de la veille).<br />
<br />
Point de QR code donc ; pour les Safari Zone, les joueurs le recevaient par mél et devaient les imprimer, pour les GO Fest précédents à Chicago, ils étaient fournis sous la forme de bracelets en papier à porter autour du poignet qui étaient envoyés par voie postale dans les jours précédents l’événement. Tous les smartphone n'ayant pas forcément d'appareil photo, ou du moins d'appareil photo en état de marche, et l'utilisateur pouvant également retirer les permission d'accès à l'application, ces QR codes étaient également accompagnés d'un code alpha-numérique que le joueur pouvait saisir en replacement du scan de sa feuille ou de son bracelet. En 2018, les aléas de la poste américaine avait fait qu'un nombre important de joueurs était arrivés à Chicago sans avoir reçu leur code ; en particulier les joueurs étrangers dont le code était arrivé à leur domicile après leur départ pour les USA. Niantic avait du installer des comptoirs où les joueurs lésés pouvaient venir demander un bracelet de remplacement en fournissant une preuve de l'achat des tickets du GO Fest. Outre les soucis de revente au marché noir déjà mentionnés et inhérent à un support physique, cela avait également conduit à ce que certains joueurs profitent du système en jouant plusieurs jours d’affilée : un premier jour avec un QR code de remplacement et un second jour en jouant avec leur bracelet d'origine ce qui est normalement impossible et interdit par le règlement de l’événement.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p486524d1561520755/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/bultler-field-comparaison.jpg/" border="0" alt="Nom : Bultler Field-comparaison.jpg
Affichages : 233
Taille : 83,4 Ko"  style="float: CONFIG" /><br />
<font size="1">Les zones de jeu de <i>Butler Field</i> et la fontaine Buckingham vus par un joueur avec ticket (à gauche) et un joueur sans ticket (à droite). Niantic avait décidé de rajouter un Pokéstop publiquement accessible durant les heures d'ouverture à coté de la fontaine pour soutenir une œuvre caritative.</font></div><br />
9h... Tout s'active comme par magie... Ça y est l’événement a enfin commencé et les joueurs commencent à s’éparpiller dans le parc en faisant la chasse aux Pokémon rares qui apparaissent ici et là, poussés en avant dans leur chasse par les demandes du professeur. Comme à leur habitude, Les américains commencent à pousser de grands cris et a gesticuler dans tous les sens : l’événement n'a pas débuté depuis 5 minutes que plusieurs personnes ont déjà réussi à capture de nouveaux Pokémon chromatiques. L’enthousiasme est au plus haut malgré les gouttes de pluie qui s’écrasent de temps en temps sur les écrans, malgré la boue aussi. Des pistes musicales tirées de Pokémon GO et du récent Pokémon Let's GO sorti en Novembre dernier sur Nintendo Switch commencent à retentir dans les divers habitats ; il faudra faire avec et arriver à les supporter toute la journée. Cette première journée sert de rodage pour les autres, ainsi le staff et divers techniciens continueront à passer dans le parc régulièrement pour vérifier si ventilateurs, les machines à bulle de savon, flocons de neige ou à fumée fonctionnent correctement et à remplir leurs réservoirs si besoin. Dans les aires de jeu des divers habitats et les tentes des équipes, les animateurs s’échauffent la voix en vue d'une longue journée. Pour les joueurs n'ayant pas de tickets, tout reste désespérément vide par contre ; les apparitions de Pokémon (tous ceux de l'événement hormis les Pokémon exclusif de la fête comme les <b>Zarbi</b> et le Pokémon régional attitré) ont été augmentées en ville de même que les chances d'avoir des chromatiques . Chicago leur est offerte mais la zone du GO Fest n'est faite pas pour eux.<br />
<br />
<b>Compétition et célébrités</b><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p486532d1561523194/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/pvp1.jpg/" border="0" alt="Nom : pvp1.jpg
Affichages : 254
Taille : 49,9 Ko"  style="float: CONFIG" /> <img src="https://www.developpez.net/forums/attachments/p486534d1561523215/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/pvp2.jpg/" border="0" alt="Nom : pvp2.jpg
Affichages : 223
Taille : 49,0 Ko"  style="float: CONFIG" /><br />
<font size="1">L’arène PvP à <i>Bulter Field</i> en fin d’après-midi alors que la météo était passée au beau fixe.</font></div><br />
Bien que la plupart des joueurs soient amenés assez souvent à passer d'une zone à une autre du parc pour les besoins de leur recherche ou leur chasse aux Pokémon rares ou chromatiques, certains verront leur journée organisée par thématique en fonction de leurs buts dans cet événement. Tout au nord, <i>Bultler Field</i> était la zone réservée aux compétions mais également aussi dédiée aux sessions d'autographes. Dès leur entrée dans le parc, les joueurs disposant d'un ticket actif pour la journée et intéressés par le PvP (<i>Player vs. Player</i> - joueur contre joueur) étaient invités à se rendre à l’arène située à l'estrade Petrillo pour obtenir un coupon de participation et ensuite s'inscrire dans le planning des combats de la journée.  Pour les retardataires, il était toujours possible de faire la queue et espérer obtenir une participation plus tardive en fonction des éliminatoires et désistements. Les combats étaient organisés en poules de 16 joueurs qui devaient s’affronter 2 à 2 placés sur une petite arène verte et dirigés par un juge. Tandis que retentissaient les musiques de combat de Pokémon Let's GO, le joueur devait progresser au fil de ses victoires jusqu’à l’arène finale au centre de la zone. Les gagnants de chaque tournoi recevaient un lot contenant une médaille exclusive, le t-shirt du GO Fest 2019 en version noire, un porte-clés a l’effigie du logo de son équipe et des écouteurs intra-auriculaires offerts par un sponsor. Hormis la médaille et les écouteurs, il était également possible de gagner ces objets en participant aux défis des animateurs dans les tentes des équipes et dans les divers habitats.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p486542d1561525090/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/pvp-3.jpg/" border="0" alt="Nom : pvp 3.jpg
Affichages : 266
Taille : 49,8 Ko"  style="float: CONFIG" /><br />
<font size="1">Le lot de récompenses pour les gagnants du tournoi PvP. Source : Reddit</font></div><br />
Niantic avait également invité 5 YouTubeurs / influenceurs connus du jeu qu'il était possible de rencontrer lors d'une session d'autographes, pour discuter quelques minutes avec eux et bien sur prendre des photos souvenir. Les joueurs intéressés devaient venir à 11h sur <i>Butler Field</i> pour faire la queue près de petites tentes blanches placées au nord de la zone de manière à obtenir des tickets nominatifs  (1 ticket par YouTubeur) et uniquement valides pour la journée. Les joueurs devaient ensuite revenir avant 13h pour entrer dans la file d'attente de leur personnalité favorite et espérer la rencontrer et obtenir un poster signé de l'événement avant 15h, la fin de la session. Autant dire qu'il fallait s'armer de patience, surtout pour ceux désirant des autographes de plus d'une personne. À noter que cette attraction de la journée n’était pas restreinte aux personnes disposant d'un ticket actif et n'importe qui pouvait venir réclamer des tickets pour rencontrer les influenceurs. Les personnes invitées étaient :<br />
<br />
<ul><li style=""><a href="https://www.youtube.com/channel/UCrtyNMe3xtv3CLg5QR78HzQ" target="_blank">TrainerTips</a> - un YouTubeur de la region de Los Angeles. Pour une raison qui m’échappe encore Nick était venu déguisé avec un béret, une fausse barbe et une fausse moustache ce premier jour. Il n’était pas déguisé le jour suivant ;</li><li style=""><a href="https://www.youtube.com/channel/UC-10uJUkzxSXa9sEtV67YcA" target="_blank">ZoëTwoDots</a> - une YouTubeuse originaire d'Australie ;</li><li style=""><a href="https://www.youtube.com/user/ReversalKnD" target="_blank">Reversal</a> - un YouTubeur venant des Pays-Bas ;</li><li style=""><a href="https://www.youtube.com/channel/UC7MKIIrXba8AjaRrgyfX3mQ" target="_blank">PkmnMasterHolly</a> - une YouTubeuse de la région de Las Vegas ;</li><li style=""><a href="https://www.youtube.com/user/MYSTlC7" target="_blank">Mystic7</a> - un YouTubeur de la région de Los Angeles.</li></ul><br />
<br />
<b>Détente autour de la fontaine</b><br />
<i>Jackson Drive</i> et <i>Balbo Drive</i> étant bloquées à la circulation, ces 2 rues devenues pétitionnes de part et d'autre de la fontaine étaient réservées aux <i>food trucs</i> qui sont restés actifs toute la journée avec de longues queues aux heures de pointe, les américains passant énormément de temps à se sustenter. Les bancs des zones ombragées de part et d'autres de ces runes ont été assaillis par les joueurs tout au long de la journée. Les joueurs squattaient également les bancs de la boutique Niantic située dans le petit bois de la zone immédiatement au nord de la fontaine. La boutique était en effet peu visitée, la plupart des dresseurs lui préférant la boutique Pokémon située sur la bordure de <i>Hutchinson Field</i>. Sur présentation du jeu montrant les Pokéstops actifs ou du badge de l'événement du jour il était possible d'acheter un des 3 articles qu'elle proposait :  un sac en toile, une gourde disponible en 2 coloris différents et une casquette qui soit n’était pas livrée soit en rupture à chaque fois que j'y suis passé. À noter que la boutique Niantic acceptait uniquement les cartes de crédit comme moyen de paiement.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p486530d1561522678/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/evoli.jpg/" border="0" alt="Nom : evoli.jpg
Affichages : 293
Taille : 35,7 Ko"  style="float: CONFIG" /><br />
<font size="1">Séance photo avec Évoli (et Pikachu qui alternait toutes les demi-heures) près de la fontaine Buckingham</font></div><br />
La zone étant toujours ouverte aux visiteurs extérieurs, il n’était pas rare de croiser des touristes venus prendre la fontaine Buckingham en photo ou flâner dans les jardins de roses tout en se demandant pourquoi diable il y avait autant de gens présents sur place avec leur téléphone à la main... Une file d'attente au sud de la fontaine permettait de se faire prendre en photo avec une des mascotte du jeu, Pikachu et Évoli alternaient toutes les heures pour le bonheur des jeunes... et des moins jeunes... Il ne faut pas se leurrer non plus, malgré la présence d'enfant, la moyenne d'âge des joueurs de Pokemon GO oscille entre 25 et 50 ans. Ce sont principalement des joueurs fans de la première vague de jeux console /animé/ jeu de carte à fin des années 90 ou des adultes ayant choppé la Pokémania lors de sa resurgence à la sortie de Pokemon GO (CF : bibi). Seul bémol de la zone : une mauvaise connectivité en milieu de journée dans le Jardin des Fées située entre la fontaine et <i>Balbo Drive</i>. Vers midi, l'affluence des joueurs était telle qu'il n’était pas rare de voir le jeu lutter pour interagir avec les Pokéstops ou pour capturer des Pokémon. <br />
<br />
Vouloir accéder au Pokémon Store situé en bordure de <i>Hutchinson Field</i> était une toute autre gageure que pour la boutique de souvenirs de Niantic. En milieu de journée il n’était ainsi pas rare que la queue soit de 40 minutes à 1h30 en moyenne, dépassant au coin de <i>Balbo Drive</i> et continuant sur une longue distance sur <i>Colombus Drive</i>. Accessible uniquement aux joueurs disposant d'un ticket actif pour la journée, il fallait montrer le jeu montrant les Pokéstops actifs ou le badge de l'événement du jour, la boutique proposait à la vente une version grise du t-shirt du GO Fest (le noir étant réservé aux récompenses de tournois et de défis) ainsi que divers <i>goodies</i> Pokémon tels que des peluches, casquettes et figurines mais en quantité limitées ; il valait donc mieux faire partie des premiers à accéder à la boutique en debut de journée. Une fois entré, chaque joueur pouvait prendre jusqu’à 2 t-shirt avant de se voir tendre une petite fiche cartonnée et un crayon pour noter ses commandes de <i>googies</i>. Il fallait ensuite passer devant plusieurs vitrines montrant le merchandising disponible et reporter les objets désirés et leurs quantités sur la carte. Enfin, il fallait patienter une nouvelle fois le temps qu'un accompagnateur se libère pour venir prendre votre carton de commande et vous escorte ensuite jusqu’à la caisse tout en récupérant au passage le contenu de votre commande. Votre commande était ensuite rangée dans un grand sac en papier estampillé GO Fest tandis que vous procédiez au paiement par carte de crédit uniquement tout comme pour la boutique Niantic.<br />
<br />
<b>H 40ans Relicanth-Créhelf cherche F/H 15-75ans Lumivole-Créfadet et plus si affinité</b><br />
<br />
<div style="text-align: center;"><div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p487103d1561676400/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/sandy-desert.jpg/" border="0" alt="Nom : sandy desert.jpg
Affichages : 278
Taille : 49,0 Ko"  style="float: CONFIG" /><br />
<font size="1">Des joueurs convergent vers <i>Hutchinson Field</i>. L'avant-poste d’échanges se trouve au-delà des tentes des équipes tout au fond de la zone.</font></div><br />
Bien que le nord du parc soit rempli de joueurs cherchant la compétition ou à rencontrer des célébrités, c'est dans la grande zone ouverte de <i>Hutchinson Field</i> au sud qu'on trouve le plus de monde. Malgré la boue et les flaques d'eau, ce grand <i>open space</i> est idéal pour parcourir de longues distance de manière à faire éclore des œufs dans le jeu. L'ambiance dans les tentes et les habitats y est également un peu plus festive que dans leurs équivalents de <i>Bultler Field</i> tant les hôtes sont survoltés et mettent une ambiance du tonnerre grâce aux divers mini-jeux destinés à rendre l’événement encore plus convivial. Ouverts uniquement aux participants de la journée et de nature diverses, ils consistent en savoir qui dans l'audience a capturé le plus de tel Pokémon ou de tel type dans son Pokédex, qui a le plus gros ou le plus grand, qui a réussi à faire un échange sur la plus longue distance, comment débloquer telle ou telle récompense en jeu, ou encore des questions plus généraliste sur l'univers de Pokémon. Les gagnants se voient remettre des coupons qu'ils doivent apporter à un kiosque centralisé pour se voir distribuer leur récompense : t-shirt du GO Fest en version noire, porte-clés, etc. Ici et là des staffs de Niantic distribuent également des planches d'autocollants et d'autres goodies aux dresseurs visiteurs de passage dans la tente.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p487105d1561676418/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/trading-post.jpg/" border="0" alt="Nom : trading post.jpg
Affichages : 183
Taille : 59,8 Ko"  style="float: CONFIG" /></div><font size="1">Le <i>trading post</i> est bondé durant la seconde moitié de l’après-midi ; au fond des stands de grillade s'affairent à vendre de la nourriture aux joueurs qui cherchent des opportunités d’échanges tout en se reposant sur des bottes de paille.</font></div><br />
En ce premier jours l'avant-poste d’échanges est très populaire auprès des joueurs pour plusieurs raisons : l'endroit dispose des tonneaux faisant office de tables pour se tenir debout, des petits cubes et des bottes de paille pour s’asseoir permettant ainsi de se reposer un peu les pieds ; il y a également quelques parasols pour se mettre à l'ombre car le soleil a fait son apparition après 15h et commence à taper dur. Des petits stands à grillades sont également disponible en fond de zone, ce qui permet aux joueurs américains d'acheter de la nourriture et de se sustenter tout en discutant ou en cherchant une opportunité d'échange. Niantic distribue d'ailleurs à l’entrée de l'avant-poste des feutres et des petites pancartes qui permettent de noter sur une face les Pokémon qu'un joueur recherche et sur l'autre ceux qu'il peut céder ; les dresseurs dans l'avant-poste qui ne sont pas occupés à manger circulent d'ailleurs en les agitant régulièrement tandis que ceux qui sont dans les autres zones du parc les ont fixées sur leur sacs ou chapeau de manière à attirer des partenaires d’échanges potentiels. Tous les dresseurs présents continuent de s'amuser en discutant joyeusement et en capturant des Pokémon bien sûr. D'ailleurs Niantic a passé le nombre maximal d’échange spécial* de 1 a 5 et a réduit les coûts d’échange de 50% pour l'occasion ! Cependant, dans l'enceinte du parc, il est impossible de procéder à un échange avec un joueur sans ticket actif, une autre manière de leur faire comprendre que, en cette journée, ils ne sont pas les bienvenus dans la zone.<br />
<br />
<font size="1">* Les échanges spéciaux sont le fait d'obtenir un Pokémon absent du Pokédex d'un des deux joueurs ou un Pokémon légendaire ou encore chromatique.</font><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p487117d1561678902/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/trade.jpg/" border="0" alt="Nom : trade.jpg
Affichages : 189
Taille : 31,5 Ko"  style="float: CONFIG" /><br />
<font size="1">De gauche à droite, la fiche de commande d'articles pour la boutique de souvenirs Pokémon, la pancarte d'échange du <i>trading post</i> et divers petites fiches que nous avions préparées en amont de cet évènement.</font></div><br />
Mais l'autre raison du nombre important de joueurs sur place c'est que la rumeur circule sur le fait qu'un Pokémon rare serait capturable dans la zone. En effet, le Pokémon <b>Abra</b> apparaît régulièrement dans cette partie du parc ; or durant les 20 premières minutes de la matinée durant l'accès anticipé, suite à un bug informatique, quelques joueurs chanceux qui s’était dirigés vers la zone d'échanges dès l'ouverture ont pu capturer la version chromatique d'Abra. Évidement l'information, une fois vérifiée, s'est très vite répandue parmi les joueurs via les réseaux sociaux mais malheureusement le bogue a très vite été corrigé par Niantic et plus aucun Abra chromatique n'a montré le bout de son museau de tout le reste de l'événement. D'ailleurs ce n'est pas le seul bug de ce type de ce premier jour, presque au même moment dans la Jardin des Fées, un joueur chanceux a pu capturer un <b>Mélofée</b> chromatique sauvage, chose qui n'est normalement pas possible dans Pokémon GO, ici aussi le bogue sera vite corrigé... <i>Why can't we have fun??</i><br />
<br />
<b>Fin de soirée</b><br />
En fin de journée les jambes sont lourdes et les pieds endolories, il n'est donc pas rare de voir les joueurs assis en groupes dans les quelques zones herbeuses sèches des divers parcs ou sous les arbres en bordure, préférant rester près des endroits où apparaissent certaines espèces plus que d'autres. Tout le monde étant affairé à tenter de trouver des derniers Pokémon rare ou chromatiques avant la fin de l'événement. La météo s’étant nettement améliorée, il faut de plus faire attention à ne pas attraper de coup de soleil. Peu à peu les divers <i>food trucks</i> et stands de vente de grillades s’arrêtent de servir les convives faute de ressources suffisantes mais aussi car l'heure de la clôture s'approche.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485849d1561349487/bases-donnees/postgresql/requetes/postgresql-pb-lors-d-insertion-donnees/img_2816.jpg/" border="0" alt="Nom : IMG_2816.jpg
Affichages : 256
Taille : 143,1 Ko"  style="float: CONFIG" /><br />
<font size="1">Vue aérienne du site du GO Fest jeudi 13 juin 2019 vers 16h. Il y avait déjà beaucoup de monde ce jeudi mais le vendredi sera encore plus fourni. Source : Reddit.</font></div><br />
À 19h précise les Pokéstops disparaissent soudainement tandis que la musique qui jouait non-stop depuis l'ouverture s’arrête. Les hôtes des différentes tentes et habitat souhaitent une bonne soirée aux joueurs tout en les invitant à se diriger vers l'estrade Petrillo sur <i>Bultler Field</i> ; c'est devant l’arène de combat PvP que Niantic a en effet décidé de faire les photos de groupes destinées à célébrer événement. Le pic de visiteurs a sans doute été atteint vers midi mais il y avait encore un grand nombre de personnes sur place à cette heure tardive se reposant sur les bancs et flânant autour de la fontaine. Cependant, les touristes et simple visiteurs reprennent peu à peu possession de la place et, ici et là, des jeunes gens en tenue de gala viennent prendre des photos devant la fontaine pour un mariage ou une soirée de fin d’année. Les derniers staffs présents sur place couvrent ou rangent les infrastructures qui seront a nouveau utilisée des le lendemain matin.<br />
<br />
Nous nous sommes repliés vers <i>the Bean</i> où je devais procéder à un échange planifié en vue d'obtenir le Pokémon légendaire nord-américain <b>Créfadet</b> contre le <b>Créhelf</b> natif de Nouméa, mes compagnons faisant un bref détour en chemin pour aller capturer un <b>Lumivole</b> qui apparaissait dans le radar de leur jeu (je l'avais déjà obtenu lors d'un échange précédent et donc il n'apparaissait pas pour moi). J'ai également pu capturer un <b>Wailmer</b> chromatique dans un leurre glacial placé sur le Pokéstop le plus proche en attendant l'arrivée de mon partenaire d'échange. Mon contact m'avait également demandé de lui fournir quelques douzaines de <b>Relicanth</b> qu'il espérait obtenir en version chanceuse* ce que nous avons pu faire dès les tous premiers échanges :D.  Sur la fin, fatigués et fourbus nous avons lentement pris le chemin du centre-ville pour y dîner avant de prendre à nouveau la ligne rose du métro en direction de <i>Little Italy</i> de manière à nous préparer à la longue journée du lendemain... notre journée de jeu à nous ; après tout la plupart d'entre nous n’avions été que des spectateurs extérieurs de cette première journée du GO Fest sans pouvoir y participer directement.<br />
<br />
<font size="1">* Les Pokémon chanceux ont un fond doré et sont moins coûteux à améliorer.</font><br />
<br />
<div style="border: 1px solid #7192A8; border-radius: 5px; padding: 5px">
    <div style="text-align: right">
      <input type="button" value="Montrer" style="width:80px; font-size:10px; margin:0; padding:0;" onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = '';this.value = 'Cacher'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.value = 'Montrer';}">
    </div>
    <div>
        <div style="display: none;"><div style="text-align: center;">Des gens malhonnêtes se tapissent dans l'ombre...<br />
<font color="#FF0000"><b><font size="7">R</font></b></font></div></div>
    </div>
</div></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7612/pokemon-gofest-2019-chicago-jour-3-gofest-part-1/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Jour 2 - La Cité du Vent</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7608/pokemon-gofest-2019-chicago-jour-2-cite-vent/</link>
			<pubDate>Fri, 21 Jun 2019 04:21:38 GMT</pubDate>
			<description>Pièce jointe 484643...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484643d1560881101/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 1976
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
...du vent et aussi de la pluie... <br />
<br />
<b>E.T. cellphone home</b><br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>Homer Simpson</strong>
					
				</div>
				<div class="message"><div style="text-align: center;">Hmmmm des donuts.... gaaaaaah</div></div>
			
		</div>
	</div>
</div>Après une arrivée aussi tardive et un si long vol pour parvenir à Chicago, je me suis réveillé vers 10h. La météo était grisâtre et les prévisions pour la journée peu engageantes ; j'avais espéré que le fait de passer dans l’hémisphère nord nous permettrait d'avoir des températures de fin de printemps ou même d'été, mais non, les prévisions annoncées se sont avérées exactes : nous avons eut droit à exactement le même temps qu'à Auckland : 12 à 16°C, nuageux... une pluie froide en plus. J'avoue que ça augurait bien pour un événement sensé se dérouler en plein air durant 10 heures d'affilée. Durant notre sommeil notre compagnon de voyage venant de Métropole était allé faire les courses et nous avait ramené un petit déjeuner typiquement américain : une grosse boite de donuts... bien gras et couvert de glaçage au chocolat ou a la vanille...  oui décidément nous sommes bien aux États-Unis :D. Enfin... la boite nous aura tenu plusieurs jours.<br />
<br />
Il avait de plus fait un peu de reconnaissance dans le centre commercial le plus proche et avait pu localiser une boutique d’opérateur mobile. Une fois bien rassasiés et réveillés nous sommes donc sortis rapidement nous fournir en cartes SIM en optant pour le plan touriste à 35 USD chez T-Mobile. À noter qu'il est possible d’opter pour un plan groupé lorsqu'on est suffisamment nombreux. Ainsi armés et Pokémon GO à nouveau pleinement autonome et fonctionnel, nous nous sommes dirigés vers la station Polk sur la ligne rose où nous avons pris le métro aérien qui allait nous mener à <i>the Loop</i>, le surnom du centre-ville de Chicago. À la station, nous avons obtenu une carte VENTRA, gérée par l’autorité des transports de Chicago, auprès d'un distributeur que nous avons ensuite chargée avec un passe de 3 jours.<br />
<br />
Nous sommes ensuite descendu au <i>Loop</i> à la station Washington/Wabbash située près de la bordure nord de <b>Grant Park</b>. Au centre-ville, de part son aspect vieillot et semi-délabré, la ligne de métro aérien qui passe par dessus les artères routières dessine un décor qu'on reconnaît aisément si on a vu des épisodes d'<b>Urgences</b> ou encore de la trilogie <b>Batman </b>de Christopher Nolan. Mais le clou de cette visite reste quand meme le parc dans lequel va se dérouler l'événement durant 4 jours. Nommé en l'honneur du 18ème président des Etats-Unis qui fut général dans l'armée nordiste durant la Guerre de Session, <i>Grant Park</i> est un ensemble de plusieurs petits parcs dédiés à des activités culturelles ou en plein air situés entre <i>the Loop</i> et la rive du lac Michigan. On y trouve plusieurs musées et monuments ainsi que le conservatoire de musique. Le parc dispose aussi de 16 terrains de baseball (dont 12 sur le site du GO Fest) et de 12 cours de tennis qui sont ouverts au public et de plus de 6km de voie piétonnes.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485296d1561087534/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/the-bean.jpg/" border="0" alt="Nom : The bean.jpg
Affichages : 404
Taille : 74,2 Ko"  style="float: CONFIG" /><br />
<font size="1"><i>The Cloud Gate AKA The Bean</i></font></div><br />
Nous sommes tout d'abord allés à <i>Millenium Park</i> où la pluie nous a surpris alors que nous approchions de <i>the Cloud Gate</i> (la porte des nuages), surnommée <i>the Bean</i>, une grosse structure chromée en forme de haricot, ce qui nous a forcé à nous réfugier dans une boutique de souvenirs le temps que le grain passe. Près de là des répétitions de musique classique étaient en cour au théâtre Harris ; en effet ce parc hébergeait également un festival de musique, dont l’entrée était gratuite, sur plusieurs jours ce qui nous a donné droit à un vrai <i>melting pot</i> musical d'une journée à une autre (classique, rock, jazz...) chaque fois que nous passions dans ce secteur. Alors que la pluie s’était légèrement calmée nous nous sommes alors dirigés vers le lieu où le GO Fest devait se tenir dès le lendemain, le cœur de <i>Grant Park</i>.<br />
<br />
<b>Avant la bataille</b><br />
Cette année, Niantic vu les choses en grand et a réservé toute la zone adjacente à la fontaine Buckingham. Les joueurs ont donc accès à une zone jouable qui s'étale sur un grand rectangle de 1.3km x 250m, ce qui est plus que nécessaire pour permettre à plus de 12 000 personnes de jouer dans la même journée :<br />
<ul><li style="">Au nord <b>Butler Field</b> dispose d'une estrade dédiée aux concerts et spectacles, la zone est entourée de bois et dispose de plusieurs chemins de promenade. C'est dans cette seule zone, entièrement clôturée à l’époque, qu'avait eut lieu le GO Fest de 2017.</li><li style="">Au centre <b>Buckingham Fountain</b> est une zones pavée de brique bordée par des jardins de roses dans un style à la française au sud au nord.</li><li style="">Au sud <b>Hutchinson Field</b> est une grande zone herbeuse sur la quelle se trouvent 12 petits terrains d’entraînement au baseball. D'ailleurs elle contient aucun POI puisque les règles d'Ingress spécifient que seules les constructions, fabrications ou réalisations artistiques humaines font des POIs acceptables.</li></ul><br />
Cette année, tout comme en 2018 au <i>Licoln Park</i>, la zone de jeu n'est pas clôturée et reste ouverte aux passants, touristes et autres visiteurs curieux. Les rues situées entre les 3 aires de jeux seront par contre fermées à la circulation pour permettre aux joueurs de passer de l'une à l'autre sans encombre.<br />
<br />
Contrairement à Pokémon GO, Ingress dispose d'un <a href="https://www.ingress.com/intel" target="_blank">carte officielle</a>, disponible pour tout agent (les joueurs d'Ingress), qui permet de visualiser l'état du jeu en temps réel sur l'ensemble de la planète. Outre ses usages directs dans son jeu d'origine (ex : planifier ses liens de création de voile ou tenter d'anticiper les actions de la faction ennemie), cette carte s'avère fort utile pour aller vérifier en avance si votre destination dispose d'une couverture suffisante de Pokéstops ou d'arènes pour rendre le jeu intéressant dans Pokémon GO puisque les deux jeux partagent la même base de POIs.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485284d1561075964/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/map.jpg/" border="0" alt="Nom : map.jpg
Affichages : 667
Taille : 385,0 Ko"  style="float: CONFIG" /><br />
<font size="1">Plan de situation de la zone de jeu d'après Ingress et Google Maps. La zone jouable est encadrée en rouge. <i>Millenium Park</i> est en haut à droite au dessus de l'institut des arts.</font></div><br />
De toutes manières, Niantic avait complètement nettoyé la zone en prévision du GOFest. Si les POIs étaient toujours bien présents en ouvrant Scanner [REDACTED] ou Ingress Prime, dans Pokémon GO on en voyait désormais plus rien, uniquement un grand espace vert complètement vide ! Et c'est ainsi que le parc allait apparaître dans le monde numérique pour les joueurs : durant l’événement les joueurs avec des tickets valident verraient une foultitude de Pokéstop ainsi que les Pokémon promis, les autres n'ayant pas de ticket valides pour cette journée donnée, absolument rien. Coté monde réel, de nombreuses installations patientaient sous la pluie en attendant les visiteurs à venir.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485297d1561088562/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/event-map.jpg/" border="0" alt="Nom : event map.jpg
Affichages : 545
Taille : 110,2 Ko"  style="float: CONFIG" /><br />
<font size="1">La carte de l’événement distribuée par Niantic.</font></div><br />
La veille, pendant que nous attendions notre avion à Los Angeles, Niantic avait fini par enfin publier la carte des festivités et le plan d'organisation du parc pour ces 4 jours : sur <i>Bultler Field</i> 3 grandes tentes pour été érigées, chacune dédiée à une des 3 équipes ; des tentes similaires ont été placées au sud sur <i>Hutchinson Field</i>. Elles permettent à un dresseur de venir se reposer à l'ombre ou de recharger son téléphone tout en discutant avec les autres membres de son équipe. Ces tentes seront également les lieux ou des animateurs proposeront des défis aux joueurs pour gagner des <i>goodies </i>(tshirt exclusif, porte-clés, etc.) en repondant a des questions sur l'univers Pokémon en général ou sur Pokémon GO en particulier ou encore savoir qui a capturé le plus de telle ou telle créature et divers autres challenges amicaux. Les joueurs pourront également participer à ces défis près des estrades placées dans les différents habitats tels que les bois effrayants, la forêt gelée, le jardin des fée ou encore le désert de sable. Ces zones dédiées à un ou deux types d'espèce de Pokémon particuliers ont eut droit à des décoration avec des toiles d’araignées, et des lanceur de fumée, de &quot;neige&quot; (des flocons de mousse de savon) et de bulles de savon. La forêt gelée héberge également la boutique à souvenirs de Niantic tandis que la boutique à souvenirs Pokemon jouxte la zone désertique. Au centre du parc la fontaine Buckingham est une zone dédiée aux Pokémon de type eau.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485289d1561085496/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/bultler-field.jpg/" border="0" alt="Nom : Bultler Field.jpg
Affichages : 429
Taille : 67,9 Ko"  style="float: CONFIG" /><br />
<font size="1">Les tentes des équipes Intuition, Sagesse et Bravoure sur <i>Butler Field</i>.</font></div><br />
L'estrade de <i>Butler Field</i> servira de lieu d'affrontement pour une compétition de combats entre joueurs tandis que la zone toute au sud de <i>Hutchinson Field</i> est désignée point de rencontre pour faire des échanges entres joueurs. Des petites tentes blanches au nord de <i>Butler Field</i> sont dédiées à 5 YouTuber / influenceurs qui viendront participer chaque jour à des sessions d'autographes. Ici et là une douzaine de point de chargement rapide pour mobiles et batterie sont habillement déguisés en Pokéstops. Le tout est complète par plusieurs dizaines de toilettes chimiques de chantier et plusieurs points de réapprovisionnement en eau potable connectés au réseau du parc, ce qui permettra aux joueurs de se désaltérer et de remplir à nouveaux leurs bouteilles d'eau. Quelques points d'aide (<i>helpdesk</i>) sont également présents pour orienter les joueurs qui auraient des difficultés à se retrouver dans l'organisation du le parc.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485293d1561085720/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/niantic-store.jpg/" border="0" alt="Nom : Niantic Store.jpg
Affichages : 836
Taille : 112,3 Ko"  style="float: CONFIG" /><br />
<font size="1">Le boutique Niantic dans la foret gelée... elle ne verra pas beaucoup plus d'action durant tout le GO Fest :aie:...</font></div><br />
Enfin pour le moment tout est bien calme avec seulement quelques ouvriers qui s'affairent à mettre en place les dernières touches et faire les derniers branchements (sous la pluie) pendant que quelques joueurs, touristes intrigues ou encore sportifs en train de courir ou de faire du vélo traversent rapidement  la zone avant de se mettre à l'abri. La météo s’étant calmée nous décidons de partir vers <i>Navy Pier</i>, a 15-20 minutes de marche en suivant la rive du lac Michigan vers le nord. <i>Navy Pier</i> est un très grand ponton sur lequel se trouve une grand roue, un <i>food court</i>, un arboretum et plusieurs hôtels et ainsi que divers autres attractions destinées à la famille et aux enfants. L’extrémité de <i>Navy Pier</i> qui s'avance dans le lac Michigan est également un lieu de spawn important de Pokémon.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485301d1561089642/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/navy-pier.jpg/" border="0" alt="Nom : Navy Pier.jpg
Affichages : 403
Taille : 79,7 Ko"  style="float: CONFIG" /><br />
<font size="1">Tout au bout de <i>Navy Pier</i>. À noter que c'est toujours le <i>Pride Month</i> aux USA.</font></div><br />
<b>Échanges en vue</b><br />
<b>Note :</b> le <b>Pokédex</b> est, en jeu, une encyclopédie des Pokémon rencontrés et capturés par le dresseur. Un des buts du joueur dans un jeu Pokémon est de compléter intégralement son Pokédex d’où le slogan &quot;Attrapez les tous !&quot;.<br />
<br />
Depuis le début du jeu Niantic a fait que certains Pokémon sont disponibles uniquement dans des régions bien spécifiques du monde ; le but étant d'inciter les joueurs à voyager mais aussi plus tard à s’échanger des créatures régionales quand cette fonctionnalité est devenue disponible en jeu. On ne va cependant pas se voiler la face, ça encourage aussi les tricheurs à contrefaire leurs coordonnées GPS pour aller les capturer sans devoir prendre la route ou se payer un billet d'avion. <br />
<br />
Ce sont en tout désormais une bonne vingtaine de Pokémon qu'un joueur ne pourra jamais trouver de part chez lui s'il ne part pas visiter la planète ou fait l'effort de trouver un autre joueur les possédant et qui serait susceptible de les échanger ; les échanges étant, au même titre, que les combats une des composantes fondamentales d'un jeu Pokémon. Ainsi dans les jeux normaux sur console (pas dans Pokémon GO) certains Pokémon peuvent évoluer uniquement si leur dresseur les donne à un autre joueur qui le renverra ensuite à son possesseur initial. Point d’échange, point de Pokédex complet possible.<br />
<br />
Ainsi, <b>M. Mine</b> que certains ont pu voir dans le récent film <b>Détective Pikachu</b> est exclusif à la plupart des pays européens tandis que <b>Tauros</b>, un taureau a 3 queues, est présent sur presque tout le territoire des USA. <b>Tropius</b>, une espèce de Diplodocus volant croisé avec un bananier, se trouve uniquement en Afrique tandis que <b>Canarticho</b> un canard tenant un poireau se trouve en Extrême-Orient... Même ici à Nouméa nous en avons quelques uns comme <b>Relicanth </b>un poisson pierre fossile commun à plusieurs îles du Pacifique Sud ou encore <b>Pijako</b> un oiseau chanteur qu'on trouve dans tout l’hémisphère Sud. <br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p485283d1561074914/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/lake_guardians_dp.png/" border="0" alt="Nom : Lake_guardians_DP.png
Affichages : 424
Taille : 32,6 Ko"  style="float: CONFIG" /><br />
<font size="1">Les gardiens du lac Créhelf, Créfollet et Créfadet, image provenant de <a href="https://bulbapedia.bulbagarden.net/" target="_blank">Bulbapedia</a>.</font></div><br />
Plus récemment, les Pokémon légendaires gardiens du lac <b>Créhelf</b>, <b>Créfollet</b> et <b>Créfadet</b> de 4ème génération, ont aussi été introduits en jeu en tant que régionaux :<br />
<ul><li style="">Créhelf est disponible en Asie (Extrême-Orient) Pacifique. C'est la fée que j'ai pu récupérer ici à Nouméa quand nous faisions nos raids le mois dernier.</li><li style="">Créfollet est disponible en Europe, Afrique, Moyen-Orient et Inde.</li><li style="">Créfadet est disponible en Amérique du Nord et du Sud.</li></ul><br />
Nous avons eut quelques semaines de raid pour en capturer plusieurs, mais et, c'est une première, ils sont aussi (extrêmement rarement) trouvables dans la nature près des lacs et étendues d'eau dans leurs régions respectives. Ces Pokémon sont donc très fortement recherchés par les joueurs et peuvent fortement peser dans une négociation quand on recherche quelque chose de rare pour compléter son Pokédex. Or les échanges de Pokémon légendaires entre joueurs sont assez coûteux pour des joueurs qui ne les possèdent pas encore. Pour réduire ces coûts, il faut prendre le temps de monter son niveau d’amitié en jeu sur une durée d'au minimum 1 mois (la réduction maximale arrive au bout de 3 mois). Donc à partir du moment où nous savions que nous allions à Chicago, j'ai pris des contacts sur le<b> Discord Silph Road Summer Tour</b> pour planifier certains échanges en avance et monter notre niveau d’amitié pour que ces derniers ne me coûtent pas trop cher. <br />
<br />
Nommée d’après la compagnie qui conçoit les Pokéball dans l'univers du jeu, <b><a href="https://thesilphroad.com/" target="_blank">the Silph Road</a></b> (<a href="https://www.reddit.com/r/TheSilphRoad/" target="_blank">Reddit</a>) a initialement été créée pour entretenir un réseau de voyageurs internationaux susceptibles de transférer des Pokémon rares d'un dresseur à un autre en traversant les continents et océans. Après tout les échanges n’étant pas disponibles au lancement du jeu, l'association a depuis étendu ses activités à bien d'autres domaines tels que la recherche de la compréhension des mécaniques de géolocalisation du jeu notamment ses liens entre  <a href="http://s2geometry.io/devguide/s2cell_hierarchy" target="_blank">le découpage géographique en cellules S2</a> et <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> pour les <a href="https://fr.wikipedia.org/wiki/Biome" target="_blank">biomes</a> et autres nids, les taux de chance d'avoir tel ou tel Pokémon dans des œufs ou encore faire des regroupement et activités sociales entre joueurs. Dernièrement <i>Silph Road</i> organise également un tournoi PvP officieux, la <i>Silph League</i>. Depuis que les échanges sont possibles, les restrictions anti-triche imposées* aux joueurs de GO ont fait qu'il était devenu impossible de mener à bien le but initial de l'organisation (faire transiter des Pokémon par un tiers) et donc elle a décidé de faciliter les prises de contact directes entre joueurs qui veulent s’échanger des monstres de poche en organisant des espaces de rencontre virtuel dédiés, chaque grand événement étant l'occasion pour les joueurs de s’échanger masse de créatures compte tenu du nombre croissant de visiteurs qui traversent les océans pour aller assister à ces rencontres et festivités. <br />
<br />
*Un Pokémon peut être échangé <u>une seule et unique fois</u> entre joueurs et ses statistiques de combat sont régénérées lors de l’échange ce qui empêche le trafic de Pokémon avec des stats parfaites.<br />
<br />
<b>Clair de Lune</b><br />
Depuis quelques semaines Niantic a décidé d'organiser chaque mercredi de 18 à 19 heures une heure de raid hebdomadaire durant laquelle plus de raids de niveau 5 apparaissent plus souvent sur les arènes, ce qui permet aux joueurs s'organiser plus facilement pour combattre le ou les Pokémon légendaire(s) du moment et essayer de le capturer. Durant notre journée d'exploration de la ville, le groupe Discord DTC (DownTown Chicago) que j'avais rejoins en préparation du voyage a appelé les joueurs locaux et les visiteurs à se réunir au pied du gratte-ciel <i>Blue Cross and Blue Shield of Illinois</i> pour se préparer à affronter Cresselia, le Pokémon qui représente le croissant de lune.<br />
<br />
Nous sommes tranquillement revenus de Navy Pier en passant par le petit parc <i>Lake Shore East Park</i> qui est coincé entre des tours de toutes parts. À cette heure de la journée, les habitants de Chicago sortaient promener leur chien ou faire leur jogging. Peu avant 18 heures c’était plusieurs dizaines de joueurs qui étaient en attente des éclosions des œufs de raids. J'avais donné rendez-vous sur place également à un joueur franco-américain avec qui je devais échanger un <b>Créhelf</b> contre un <b>Vortente</b>. Pokémon de 4ème génération en forme de plante carnivore, Vortente a récemment été introduit en jeu en tant que régional dans le sud des États-Unis où se trouvent des plantes d'allure similaire dans la vie réelle ; autant dire que c’était là une bonne occasion pour moi de l'obtenir. J'ai rapidement rencontré mon contact et nous avons pu procéder à notre échange comme prévu avant de nous préparer aux raids à venir.<br />
<br />
Malheureusement, comme d'habitude autant de joueurs concentrés au même endroit fait que les réseaux mobiles des divers opérateur saturent rapidement. Après avoir expérimenté pas mal de soucis réseau sur le premier raid, nous avons finalement décidé de laisser partir le gros des joueurs pour ensuite avancer à notre rythme. En cours de route nous avons rencontré quelques autres joueurs retardataires qui arrivaient sur le point de rendez-vous et, au final, nous avons enchaîné sur les 3 raids suivant les plus proches de manière un peu informelle mais toujours dans la bonne humeur que seul un début de pluie est venue entacher. J'ai également pu décrocher un Cresselia chromatique ce qui me fera un bon souvenir de Chigago. Les chromatiques sont des Pokémon qui sont colorés différemment et sont plus rares à trouver. Pendant ce temps là les passants autour de nous se demandaient ce qui causait une telle agitation et pourquoi il y avait autant de gens dans les rues... jusqu’à ce que quelqu'un finisse par sortir un &quot;<i>Bah it must be some Pokémon GO players, there might be some kind of event going on...</i>&quot; :ptdr:<br />
<br />
Nous sommes ensuite revenus vers <i>Cloud Gate</i> et tandis que nous terminions nos 3 dernier raids sur <i>Millenium Park</i> la pluie s'est faite plus pressente. Nous sommes repartis vers le centre-ville faire un peu de shopping pour des câbles USB et des adaptateurs secteurs avant de dîner dans un Viapiano du <i>Loop </i>puis de rentrer par la ligne rose du métro avant que la pluie ne devienne trop menaçante... et c'est fatigué et trempés de la tête aux pieds mais contents de notre journée que nous sommes finalement rentrés à notre AirBnB.</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7608/pokemon-gofest-2019-chicago-jour-2-cite-vent/</guid>
		</item>
		<item>
			<title>Gluon annonce ses outils pour créer des applications Java natives pour macOS et iOS</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7657/gluon-annonce-outils-creer-applications-java-natives-macos-ios/</link>
			<pubDate>Wed, 19 Jun 2019 00:05:47 GMT</pubDate>
			<description>Gluon (https://gluonhq.com/)...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><a href="https://gluonhq.com/" target="_blank">Gluon</a> annonce une refonte de ses outils Java, autour de l'<a href="http://openjdk.java.net/" target="_blank">OpenJDK</a> et de l'<a href="http://openjfx.io/" target="_blank">OpenJFX</a> sous le nom de <b>Gluon Client plugin</b> qui est disponible en version bêta. Désormais, grâce au support fourni par <a href="http://graalvm.org/" target="_blank">GraalVM</a>, cet outil permet de compiler des applications natives pour macOS et surtout pour iOS ainsi que le simulateur iOS fourni dans XCode, l'outil de développement d'Apple.<br />
<br />
La pile précédente d'outils Gluon nommée <b>javafxmobile</b> permettant le port de JavaFX vers des plateformes mobiles (iOS, Android et ARM) était construite dans sa version iOS sur la version Open source de RoboVM, mais ce <i>middleware</i> n’était plus maintenu depuis le rachat de RoboVM par Xamarin suivi de l’arrêt du projet par Microsoft quelque temps plus tard. Gluon espère donc que sa nouvelle pile d'outils remplacera à terme son ancien plugin et proposera des plans de migration lorsque son nouvel outil sera suffisamment mature.<br />
<br />
De plus, les derniers développements de l'OpenJFX font que le port mobile de JavaFX est au même niveau que le port <i>desktop</i>. Auparavant la version mobile de JavaFX était rendue disponible plusieurs mois après la version <i>desktop</i> et faisait office de citoyen de seconde classe. Ce n'est désormais plus le cas et la dernière version de l'OpenJFX compile sur toutes les plateformes supportées. Cela permet donc de proposer une unique plateforme de développement dans laquelle les dernières fonctionnalités sont d’ores et déjà disponibles sur mobile.<br />
<br />
Enfin, Gluon annonce que sa pile d'outils mobiles supporte désormais l’utilisation du JDK11.<br />
<br />
Oh et il semble que la nouvelle ait intéressé <a href="https://twitter.com/errcraft/status/1141120445028028418?s=20" target="_blank">quelqu'un qui passait par là</a>...<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484703d1560901914/java/edi-outils-java/environnement-developpement-integre-edi/jbuilder/jbuilder7-jtable-colonne-alignement/gosling.jpg/" border="0" alt="Nom : gosling.jpg
Affichages : 6008
Taille : 34,4 Ko"  style="float: CONFIG" /></div><br />
Source : <a href="https://gluonhq.com/java-on-ios-for-real/" target="_blank">Java on iOs, for real.</a> sur le blog de Gluon</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7657/gluon-annonce-outils-creer-applications-java-natives-macos-ios/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Jour 1 - le Jour sans Fin</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7627/pokemon-gofest-2019-chicago-jour-1-jour-fin/</link>
			<pubDate>Tue, 18 Jun 2019 04:37:55 GMT</pubDate>
			<description>Pièce jointe 484387...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484387d1560831540/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 1350
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
<b>Note :</b> la majorité du contenu de ce billet a été rédigée dans l'avion entre Los Angeles et Chicago mais, par la suite, j'ai eut assez peu de temps à accorder à la rédaction (et c'est pas facile de rédiger sur un téléphone), donc les billets suivants ont tous été écrits après mon retour de voyage.<br />
<br />
Non, il ne s'agit pas du <b>Jour de la Marmotte</b> avec Bill Murray. La nuit fut un peu courte entre l'excitation du voyage à venir et le passage de la navette assez tôt, j'ai du dormir à tout casser à peine 2 heures et demi.<br />
<br />
<b>Surprise du matin</b><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484365d1560815631/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/badge-small.png/" border="0" alt="Nom : Badge-small.png
Affichages : 267
Taille : 40,1 Ko"  style="float: CONFIG" /></div><br />
Que ce soit un bug ou fait exprès, la bonne surprise du matin fut que Niantic a attribué en avance les badges de participation à cet événement. En effet, une partie des principaux événements spéciaux depuis 2017 permettent aux joueurs d'obtenir des badges exclusifs.<br />
<br />
Pour obtenir un tel badge, lors des événement précédents, il fallait le plus souvent activer un Pokéstop spécial qui demandait ensuite de scanner un QR code obtenu en s'inscrivant à l'événement en question. Si les premières <i>Safari Zones</i> fonctionnaient généralement sur le principe du &quot;premier arrivé, premier servi&quot; menant rapidement à une congestion des sites web d'inscription, les festivités les plus récentes ont opté pour le principe de la tombola : les joueurs s'inscrivent durant une période désignée pour espérer obtenir des tickets d'entrée qui sont tirés au sort. Chaque ticket permettant d'inviter 2 à 3 autres personnes à venir jouer durant 1 seule journée bien spécifique. La période d'inscription de plusieurs jours permet en général d'éviter que les serveurs entrent en surcharge tandis que l'étalement de l'événement sur plusieurs jour évite les soucis mentionnés tantôt quand une trop grosse concentration de joueurs se forment et déclenche une congestion des réseaux mobiles. Par contre, cela ne réglait pas un autre soucis majeur : la vente de tickets au marché noir ; des gens peu scrupuleux créant des tonnes d’adresse mél pour ensuite obtenir des QR code et les revendre. <br />
<br />
Pour les GOFest de 2019, Niantic a opté pour une nouvelle solution plus élégante même si sans doute pas à toute épreuve : désormais l'inscription à la tombola se fait directement via le jeu sur une période de 48h. Les joueurs sont ensuite tirés au sort par vague successives sur plusieurs jours ou semaines jusqu'à épuisement des tickets. S'il est sélectionné, le joueur a ensuite 48h pour acheter (Chicago et Dortmund sont payants) ou valider (Yokohama est gratuit) son inscription et inviter d'autres personnes. S'il décide de ne pas venir, son ticket d'inscription est remis en jeu dans la tombola. De plus, seconde sécurité, un joueur ne peut inviter que ses contacts en jeu et uniquement ceux de ses contacts avec qui il est ami depuis 1 semaine ou plus. Espérons que ce système minimisera fortement le marché noir de la revente, à défaut de réduire la présence de <i>fly</i> / <i>spoofs</i> (les joueurs qui trichent en contrefaisant leurs coordonnées GPS.<br />
<br />
Tout n'est pas parfait cependant : <br />
<ul><li style="">Quelque soit le système d'inscription utilisé, les joueurs locaux se sentent toujours lésés et exclus quand ils ne peuvent obtenir un ticket pour des festivités majeures se déroulant dans leur propre ville.</li><li style="">Le coté aléatoire de la tombola est également assez frustrant pour les joueurs étrangers ; ainsi nous avions espéré pouvoir aller à la <i>Safari Zone</i> de Sentosa à Singapour plus tôt dans l’année et finalement aucun d'entre nous n'avait été choisi dans cette tombola et c'est bien dommage car le voyage aurait été beaucoup plus court tout en étant beaucoup moins coûteux.</li><li style="">Pour les deux premiers GO Fest de 2019, Niantic a uniquement pris en charge le support du paiement de l'inscription par carte de crédit. Or il se trouve que dans certains pays d'autres moyens de paiement (ex : PayPal) sont plus couramment utilisés pour les achats sur Internet, par exemple en Allemagne. Le GO Fest de Chicago a rapidement distribué tous ses tickets et clôturé sa tombola, chaque jour étant complet en nombre de joueurs ; rendant ainsi impossible tout achat de ticket sur place durant l'événement. Ça n'a pas été le cas pour celui de Dortmund : beaucoup de joueurs allemands ayant confirmé avoir été tirés au sort mais être ensuite incapables d'acheter leur ticket. Niantic a donc du ré-ouvrir non seulement la tombola mais aussi les inscriptions et à ce jour, les tirage ne sont toujours pas terminés et on ne sait pas encore si un système de billetterie sera mis en place ou pas aux entrée du parc aux jours de l'événement. </li></ul><br />
<br />
<b>La cité des voiles</b><br />
Le vol d'un peu plus de 3h entre la Tontouta (l’aéroport de Nouméa) et Auckland s'est passé sans encombre. La sortie de l'aéroport international est toujours extrêmement rapide et il est possible d'obtenir une carte SIM avant même d'avoir passé les contrôles de la la police de l'air et des frontières ou même d'avoir récupéré ses bagages. En effet, l’aéroport a placé stratégiquement un dernier <i>duty free</i> avant les premiers contrôles de sortie et 2 opérateurs kiwi y proposent des SIM destinées aux touristes (Vodafone NZ et Sparks). Pour le moment il est extrêmement aisé d'obtenir un visa de touriste à l’arrivée pour peu qu'on soit en possession d'un billet d'avion retour pour quitter la Nouvelle Zélande. Le pays mettra cependant en place un visa électronique nommée <a href="https://www.immigration.govt.nz/about-us/what-we-do/our-strategies-and-projects/eta-new-requirements" target="_blank">NZeTA</a> similaire à l'<a href="https://fr.wikipedia.org/wiki/Syst%C3%A8me_%C3%A9lectronique_d%27autorisation_de_voyage" target="_blank">ESTA américaine</a> et à l'ETIAS européenne plus tard dans l’année qui sera désormais obligatoire.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484394d1560832508/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/aucklandskytower.jpg/" border="0" alt="Nom : AucklandSkyTower.jpg
Affichages : 275
Taille : 26,2 Ko"  style="float: CONFIG" /><br />
<font size="1">La <b>Sky Tower </b>d'Auckland est la plus grande tour de l’hémisphère sud.</font></div><br />
Nous avions un escale de 7h avant de repartir vers Los Angeles et nous avons donc décidé de nous rendre en ville après avoir trouvé un garde bagage (<i>Smart Gate</i>). Le <i>SkyBus</i> met environ 40m pour rallier l'aéroport au hub de transport de <i>Britomart</i> sur les quais d'Auckland. Malgré le fait d’être à la fin de l'automne austral, les températures et la météo sont plutôt habituelle pour la ville : entre 12 et 16°C et un temps nuageux, limite pluvieux. Nous avons décidé d’éviter la très populaire <i>Queen Street</i> et la tour d'Auckland pour rester près du terminal des ferry. Il est toujours plaisant de se balader de <i>Britomart</i> puis <i>Viaduc</i> jusqu'à <i>Wynyard</i> sur l'ancien port de pêche et industriel reconverti en zone où il fait bon vivre. Cependant la zone est en travaux car la ville se prépare doucement à l'arrivée de la coupe de l'America en 2021 en rénovant une fois de plus son front de mer. <br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484385d1560820456/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/teamnewzealandbase.jpeg/" border="0" alt="Nom : TeamNewZealandBase.jpeg
Affichages : 237
Taille : 42,7 Ko"  style="float: CONFIG" /><br />
<font size="1">Le QG de<i> Team New Zealand</i> lors de la future <i>America's Cup</i> à Auckland.</font></div><br />
<b>Wingardium leviosa</b><br />
Le passage à Auckland aura aussi été l'occasion de tester <b>Harry Potter: Wizards Unite</b>. En effet, le jeu de Niantic y est disponible en bêta ouverte sur Android depuis la mi-avril 2019 ; bêta qui fut ensuite étendue à l'Australie quelques semaines plus tard. S'il est facile de trouver et télécharger le fichier APK du jeu, une fois passé le didacticiel (et les bugs), le joueur se trouvera devant un monde désespérément vide, le jeu étant géo-restreint aux zones de la bêta. Dans la zone couverte, le jeu prend vie par contre et la carte se couvre de nombreuses auberges, serres et autres forteresses qui correspondent aux POIs fournis par la plateforme AR de Niantic. Ainsi le joueur averti reconnaîtra les emplacements des portails d'Ingress et des Pokéstops et arènes de Pokémon GO. Les deux jeux les plus récents ont des règles différentes d'Ingress en ce qui concerne la distance minimale entre 2 POIs, c'est donc Scanner [REDACTED] et Ingress Prime qui affichent le plus de lieux de jeu.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p484382d1560817058/general-developpement/algorithme-mathematiques/algorithmes-structures-donnees/procedure-recursives/nianctic-games.png/" border="0" alt="Nom : Nianctic games.png
Affichages : 835
Taille : 351,9 Ko"  style="float: CONFIG" /><br />
<font size="1">Comparaison des cartes de <b>Scanner [REDACTED]</b>, <b>Ingress Prime</b>, <b>Pokémon GO</b> et <b>Harry Potter: Wizards Unite</b> dans le quartier de Viaduc à Auckland.</font></div><br />
Dans ce jeu, une &quot;Calamité&quot; a frappé le Ministère de la Magie britannique éparpillant de part le monde nombre d'artefacts, animaux et mais aussi magiciens. Le joueur qui, est un jeune magicien affilié à une des maison d’étudiant de Poudlard, est chargé par Harry Potter, désormais Auror de son état, de retrouver tous ces objets et entité tout en essayant de découvrir la source du problème et surtout en évitant que le monde normal des Moldus (gens normaux qui ne connaissaient ni n'utilisent la magie) ne découvre le monde magique caché. Souvent un objet est gardé par des créatures magiques hostiles ou les magiciens enlevés sont plus ou moins prisonniers de sorts de restriction et donc le joueur est sensé former des sorts en suivant des lignes sur son écran (mais pas en agitant son téléphone devant lui comme un maboul tout seul dans la rue, ouf...). Le jeu puise son bestiaire dans tout le monde magique de J. K. Rowling, de la franchise Harry Potter mais aussi de sa franchise compagnonne les Animaux Fantastiques.<br />
<br />
Vous pouvez vous en faire une idée en regardant les vidéo postées par les bêta-testeurs sur YouTube mais j'avoue ne pas être fan du <i>gameplay</i> de <b>Wizard Unite</b> car ce dernier est particulièrement lent et long. Ainsi chaque changement de niveau ou acquisition d'un nouveau <b>Retrouvable</b> (le nom des objets, créatures ou personnes magiques volées au Ministère de la Magie et que le joueur est sensé retrouver), donne lieu à une jolie mais très lente animation d'un <i>Patronus </i>(esprit gardien) descendant sur plusieurs écrans pour révéler un score, ce qui se révèle assez pénible sur la longueur. Accéder à une auberge, l’équivalent de hacker un portail dans Ingress ou de faire tourner un Pokéstop ou une arène dans Pokémon GO s’avère également très lent, probablement pour empêcher les gens de jouer en conduisant (pas une mauvaise idée en soit) mais donne une sensation de lourdeur et viendra aussi impacter encore plus négativement les joueurs qui se trouvent dans les transports en commun (qui déjà ne peuvent plus jouer dès que le bus roule trop vite). Le Registre qui, à la manière d'un cahier Panini, permet de placer les autocollants des objets récupérés manque de vie par rapport au Pokédex. C'est d'autant plus étonnant que les films Harry Potter nous ont habitués à nous montrer tableaux vivants ou encore des journaux et autres magazines avec des photos animées. Enfin le jeu est bourré de micro-transaction en tout genre, bien plus que ses deux aînés.<br />
<br />
Cependant, le jeu connaîtra sans doute un franc succès au moins lors de sa sortie initiale, entres autres à cause de la large base de <i>Potterheads </i>(les fans de l’univers de Harry Potter) qui forment toutes et tous de potentiels futurs joueurs. Warner Bros Games est sensé faire un communiqué dans les jours qui viennent, probablement pour annoncer une date de sortie aux US. À noter que, dans la bêta, le jeu est uniquement disponible en Anglais (textes mais aussi voix) pour le moment.<br />
<br />
<b>La cité des anges</b><br />
De retour à l'aéroport nous avons rapidement récupéré nos bagages pour les enregistrer sur notre vol pour à destination des US. Nous avons ensuite décollé vers 19h30 pour ce qui devait être la fin de ce mardi déjà bien rempli... et c'est mardi vers 11h15 que nous avons atterri à Los Angeles... Ah les joies de traverser la ligne de changement de date dans ce sens-là... Si le long vol de plus de 12h s'est passé sans aucun soucis, l’arrivée à Los Angeles a été d'un autre acabit ; l’aéroport de LAX est régulièrement encombré par un trop plein d'avions sur ses pistes et ne dispose pas d'infrastructures suffisantes pour permettre à tous d’accéder aux bras du terminal international Tom Bradley pour procéder au débarquement. Notre vol <i>Air New Zealand</i> a donc accosté un terminal dédié... à une gare de bus qui nous ont ensuite conduits jusqu'au bâtiment principal où nous avons passé les formalités d'immigration. Entrer aux États-Unis s’avère toujours aussi compliqué et j'ai été séparé de mon compagnon de voyage pendant plus de 40min puisqu'il a du faire toutes les séries de saisies d'empreintes étant donné qu'il s'agissait là de son premier voyage aux USA (pour moi c'est le 4ème, donc je suis passé plutôt rapidement).<br />
<br />
Il ne faut pas compter sur l’opérateur en téléphonie calédonien pour proposer des plans de <i>roaming</i> internationaux (qui seraient de toute façon hors de prix s'ils existaient), donc une fois réunis et nos bagages récupérés, nous nous sommes ensuite lancés à la recherche d'un point de vente de carte SIM ; en effet : une fois sortie de la zone WiFi gratuite de l’aéroport point de connexion mobile signifie point de Pokémon GO... ou de services de messagerie, ou de recherche sur Google, ou de GMail, ou de................. bref, rien. Il y a bien un minuscule point de vente mobile à coté des arrivées mais il était dédié à l’opérateur <b>Sprint</b> ;  or cet opérateur américain, tout comme <b>Verizon</b> utilise toujours <a href="https://fr.wikipedia.org/wiki/Code_division_multiple_access" target="_blank">CDMA</a> tandis que <b>AT&amp;T</b> et <b>T-Mobile</b> utilisent quant à eux <a href="https://fr.wikipedia.org/wiki/Global_System_for_Mobile_Communications" target="_blank">GSM</a> qui est plus adapté aux besoins d'une bonne partie des voyageurs internationaux. Nous sommes ensuite allés jusqu'au terminal 2 dédié à Delta Airlines où un de nos plan indiquait une boutique mobile (hélas derrière les contrôles de sécurité). Ah LAX, la magie de ses embouteillages, de ses bruits de klaxon et autres invectives furieuses provenant de conducteurs énervés, de ses gaz d’échappement qui viennent vous polluer les poumons lorsqu'on marche d'un terminal à un autre.... euh, mais je m’égare. Les boutiques d’opérateurs les plus proches étant situées hors de LAX et notre temps de passage à Los Angeles initialement très réduit, nous avons donc du nous résoudre à abandonner notre quête et à devoir aller acheter des cartes SIM à Chicago dès le lendemain.<br />
<br />
C'est en revenant au terminal 4 d’où nous devions partir vers Chicago que nous avons commencé à recevoir en cascade de mél la vraie mauvaise nouvelle de cette très longue journée : American (le nouveau nom d'American Airlines) a repoussé notre vol vers Chicago initialement prévu pour 17h à 18h, puis à 19h et enfin à 19h30... Une fois nos bagages enregistrés et de nouvelles formalités de sécurité passées, nous sommes entrés dans le terminal pour patienter le temps du départ ; l’occasion d'une longue marche aller-retour jusqu'au terminal international, les zones d'attente du terminal 4 et du terminal international etant connectées. Même si AA s'est fendu d'une collation gratuite à destination de tous les passagers de ce vol, nous n'avons jamais vraiment su ou compris quelle était la raison exacte de ce retard. Nous avons fini par décoller et, dans la lumière du coucher du soleil, il était facile de voir combien la Californie est sèche au-delà des collines qui jouxtent Los Angeles. Bien que les parcours de golf accompagnés de petits lacs et les jardins individuels soient foison, le paysage est très sec et aride ; presque tous les cours d'eau sont à sec, et le peu d'eau que l'agriculture ne capte pas ne résiste pas très longtemps aux besoins humains ou à leurs jardins.<br />
<br />
Après plus de 4h de vol accompagnés de turbulences lors du passage au dessus des Rocheuses puis des Grandes Plaines, nous avons atterri à O'Hare l’aéroport de Chicago vers 1h15 du matin. Après une brève queue pour obtenir un taxi et un trajet sur des autoroute désertes, nous avons finalement rejoin, après 2h du mat, notre AirBnB dans <i>Little Italy</i> où nous attendait le 3eme comparse de notre voyage qui lui était arrivé de France métropolitaine plus tôt dans l’après-midi. Il était grand temps que cette journée se termine...</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7627/pokemon-gofest-2019-chicago-jour-1-jour-fin/</guid>
		</item>
		<item>
			<title>Pokémon GOFest 2019 Chicago : Prélude</title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7602/pokemon-gofest-2019-chicago-prelude/</link>
			<pubDate>Mon, 10 Jun 2019 10:06:16 GMT</pubDate>
			<description>Pièce jointe 482238...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p482238d1560158406/bases-donnees/ms-sql-server/administration/postgresql-probleme-connexion-pgaccess/unnamed.png/" border="0" alt="Nom : unnamed.png
Affichages : 1432
Taille : 15,4 Ko"  style="float: CONFIG" /></div><br />
<b>Avertissement :</b> je tiens à préciser que je ne suis affilié ni à Niantic, ni à The Pokémon Company, ni à Nintendo, Gamefreak ou Creatures. Tous les noms, marques et logos cités ou montrés appartiennent à leurs ayant-droits respectifs. Ah oui et si vous ne comprenez rien au vocabulaire Pokémon utilisé ici... tant pis pour vous :ptdr:.<br />
<br />
Un grand merci à <a href="https://www.developpez.net/forums/u69211/mickael-baron/" target="_blank">Mickael</a>, le responsable de la section Java, qui a eut l'idée de cette chronique.<br />
<br />
<b>Pika ?</b><br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				Dans l'univers de Pokémon, vers l'âge de 10 ans, les jeunes filles et garçons partent explorer le monde, seuls ou avec d'autres enfants de leur âge, pour capturer des créature sauvages et les entraîner pour les faire participer à des combats contre d'autres dresseurs dans l'espoir de devenir le meilleur Maître Pokémon.
			
		</div>
	</div>
</div>Oui, dit comme ça c'est très étrange et c'est un concept très japonais. Pokémon est un une approche multimédia centrée autour de cet univers qui est décliné en de multiples jeux vidéo sortis sur consoles portables Nintendo (mais pas que) depuis la fin des années 90 mais aussi en un jeu de cartes et bien sûr un animé de très longue durée (euh... on en est à la 22<sup>ème</sup> saison je crois) ainsi que plusieurs films animés d'origine japonaise. Plus récemment Hollywood s'est aussi lancé dedans avec la sortie du film Détective Pikachu avec Ryan Reynolds dans le rôle titre (voix et capture faciale). Des tournois mondiaux sont régulièrement organisés autour du jeu de carte et des jeux vidéo principaux de la série. Vous avez dû bien entendre le slogan &quot;<b>Attrapez-les tous !</b>&quot; à un moment où à un autre ?<br />
<br />
<b>Pokémon... GO ?</b><br />
<a href="https://pokemongolive.com/fr/" target="_blank"><b>Pokémon GO</b></a> le jeu mobile AR (<i>augmented reality</i> - réalité augmentée) géo-localisé pour iOS et Android développé et maintenu par Niantic a déferlé sur le monde en juillet 2016, prenant une bonne partie des pays occidentaux par surprise devant l'ampleur de la vague et la masse de joueurs qui déambulaient dans les rues <i>tels des zombies</i> (dixit nos amis politiciens) les yeux rivés sur leur téléphone à la recherche de créatures numériques invisible au yeux du commun des mortels. Nos chers concitoyens et eux ont dû s'y faire : la Pokémania, cette vague d’engouement pour les jeux vidéo, le jeu de cartes à collectionner et l'animé Pokémon qui avaient bousculé les cours de récrée au début des années 2000 était de retour et cette fois-ci elles touchaient toutes les générations via l'omniprésence des <i>Smartphones</i>. À tel point qu'on a rapidement vu fleurir des propositions de lois visant à réguler et ou interdire toute activité de regroupement des joueurs dans certains lieux (ex : écoles mais aussi bases militaires ou lieux <i>sensibles</i>), voir carrément l'interdiction du jeu dans certains pays sous prétexte d'espionage potentiel car le jeu géolocalisé aurait des liens cachés avec la CIA...<br />
<br />
<div style="text-align: center;">
<div class="video-container"><iframe class="restrain" title="YouTube video player" width="560" height="315" allowfullscreen src="//www.youtube.com/embed/4YMD6xELI_k?wmode=transparent&amp;fs=1" frameborder="0"></iframe></div>
</div><br />
Google avait initié l'idée d'un univers augmenté habité de Pokémon au 1<sup>er</sup> avril 2014 en lançant un jeu sur Google Maps doublé d'une vidéo dans laquelle la firme annonçait vouloir recruter un Maître Pokémon. Et c'est tout naturellement qu'en Septembre 2015 The Pokémon Company (TPC) et Niantic avaient dévoilé une bande annonce suggérant la sortie future du jeu mobile qui sera finalement publié en juillet de l'année suivante... dans les conditions que l'on connait... joueurs en folie... et serveurs en berne...<br />
<br />
<div style="text-align: center;">
<div class="video-container"><iframe class="restrain" title="YouTube video player" width="560" height="315" allowfullscreen src="//www.youtube.com/embed/2sj2iQyBTQs?wmode=transparent&amp;fs=1" frameborder="0"></iframe></div>
 </div><br />
Niantic n'en était pourtant pas à son premier essai. L'ex-filiale née dans les incubateurs de Google, créée par <a href="https://fr.wikipedia.org/wiki/John_Hanke" target="_blank">John Hanke</a> initiateur de Google Maps, Google Earth et de KML, avait déjà en effet lancé quelques années plus tôt <a href="https://ingress.com/" target="_blank"><b>Ingress</b></a>, un jeu géo-localisé dans lequel 2 équipes s’affrontent pour le contrôle de zones triangulaire dans une sorte de mélange entre RISK et un jeu d'espionage à l'échelle mondiale mâtiné d'une ambiance cyberpunk et de science-fiction (il est question de créatures provenant d'une autre dimension qui veulent influer sur l'espèce humaine avec une faction pro-évolution et une autre anti-évolution) ; à noter que Ingress a fait récemment l'objet d'un animé diffusé sur Netflix. Cependant, étant donné qu'Ingress était resté un jeu sommes toutes confidentiel à la base de joueurs restreintes, rien n'avait probablement préparé Niantic à l'ampleur que prendrait Pokémon GO à son lancement, ni à ses serveurs à résister à la charge du nombre de joueurs connectés.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p482239d1560158439/bases-donnees/ms-sql-server/administration/postgresql-probleme-connexion-pgaccess/895px-ingress_logo_vector.svg.png/" border="0" alt="Nom : 895px-Ingress_Logo_vector.svg.png
Affichages : 246
Taille : 3,3 Ko"  style="float: CONFIG" /></div><br />
<b>Et maintenant ?</b><br />
Avance rapide vers 2019, la folie est certes retombée et désormais les joueurs sont bien plus discrets dans les rues car moins nombreux. L'effet de mode est passé et certains ont abandonné le jeu car après tout sortir et faire de la marche peut s'avérer chronophage et épuisant à la longue (l'humain aime les activités qui rapportent facilement et  demandent des dépenses moindre en effort ou en énergie personnelle). D'autres ont abandonné suite aux problèmes initiaux de surcharge des serveurs, les bugs toujours présents dans le client du jeu ou encore le manque de fonctionnalités présentes au lancement ou tout simplement faute d'attrait face aux nouveaux Pokémon une fois leur Pokédex de 1ère génération presque complété. Cependant, et ce malgré une triche rampante, les joueurs sont toujours bien là, principalement dans les grandes villes; le jeu étant bien plus adapté aux environnements urbains qu'à ceux de la campagne. <br />
<br />
En l'espace de 3 ans Niantic a introduit pas mal de fonctionnalités attendues qui étaient absentes lors du lancement initial, tels les raids demandant aux membres des 3 équipes de coopérer un minium ou encore les journées communautaires favorisant le regroupement des joueurs (et diminuant de fait l'animosité latente entre joueurs d'équipes différentes) ou encore les échanges et les combats directs entres joueurs. Quelques quêtes scénarisés permettant d'obtenir des Pokémon fabuleux ou encore un mode photo permettant de faire poser ses créatures sont venus compléter le tableau entre temps. Ainsi, que cela soit dans les métropoles américaines, européennes, ou japonaises, au heures de pointe ou lors des journées communautaires, il n'est pas rare de voir des bandes de joueurs allant de parents entourés de leurs enfants, d'étudiant ou encore de <i>salary men</i> tout frais sortis de leur bureau se réunir pour faire des raids ou chasser des Pokémon chromatique. Et c'est aussi valable pour d'autres régions du globe telles que l'Amérique Latine ou encore l'Inde qui voient des records d'affluence de joueurs. Même si des jeux concurrents sont sortis entre temps (<a href="https://www.thewalkingdeadourworld.com/" target="_blank"><b>The Walking Dead: Our World</b></a> de Next Games ou encore <a href="https://www.jurassicworldalive.com/" target="_blank"><b>Jurassic World Alive</b></a> de Ludia, tous deux construits sur une API Google Maps fournie par Google) et même si d'autres sont annoncés (Square Enix a récemment annoncé <b>Dragon Quest Walk</b>) pour le moment aucun ne semble arriver à détrôner Pokémon GO auprès des joueurs.<br />
<br />
Pendant ce temps-là Niantic a continué à rationaliser <a href="https://nianticlabs.com/blog/nrwp-update/" target="_blank">sa plateforme AR</a> avec sa partie mobile cliente (basée sur le moteur 3D <a href="https://fr.wikipedia.org/wiki/Unity_(moteur_de_jeu)" target="_blank">Unity</a> en C#), sa partie serveur mais aussi sa base de donnée POI (<i>points of interest</i> - point d’intérêt ou encore sites remarquables) héritée d'Ingress et créée par les joueurs qui nourrit ses jeux existants ou futur. Ainsi le futur jeu mobile <a href="https://harrypotterwizardsunite.com/fr/" target="_blank"><b>Harry Potter: Wizards Unite</b></a> développé par Niantic pour Portkey Games et Warner Bros repose sur la même plateforme. Niantic est également en train d'abandonner LibGDX qui était utilisé pour développer la première version Ingress (désormais rebaptisée <b>Scanner [REDACTED]</b>) pour sortir une nouvelle version du jeu sous Unity nommée <b>Ingress Prime</b> (qui est elle-même sujet à controverse auprès des joueurs de ce jeu qui lui préfèrent la précédente version).<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p482250d1560159673/bases-donnees/ms-sql-server/administration/postgresql-probleme-connexion-pgaccess/titre.png/" border="0" alt="Nom : Sans titre.png
Affichages : 282
Taille : 18,5 Ko"  style="float: CONFIG" /></div><br />
<b>GOFest !</b><br />
Ingress le faisant déjà avec ses anomalies (événement majeur) ou ses <i>mission day</i> ou encore <i>first saturday</i> (événement moindre à l'échelle d'une ville et permettant l'initiation de nouveaux joueurs) c'est donc naturellement que Niantic a commencé à organiser, avec ses partenaires commerciaux mais aussi le support des administrations locales, <a href="https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_GO#Local_events" target="_blank">des événements localisés autour de Pokémon GO</a> ; les <b>Safari Zone</b> (événement mineur) mais aussi le <b>GOFest</b> (événement majeur, souvent payant).  En effet, rien de tel pour booster le tourisme que d'avoir plusieurs milliers de joueurs qui déferlent soudainement sur une ville pour quelques jours... quoi que cela ne se passe pas forcément toujours comme prévu...<br />
<br />
Initié le 22 juillet 2017, le premier GOFest qui se tenait au Parc Grant au cœur de Chicago (USA) n'aura pas vraiment marqué les esprits... enfin si, celui d'un flop monstrueux. Tout le monde présent aura blâmé Niantic sur le moment mais en fait le soucis était dû à la sous-évaluation des infrastructures 4G des principaux opérateurs mobiles américains qui ont largement sous-estimé le nombre de joueurs présents sur place. Bref, face à un manque chronique d'équipement et autre tours mobiles pour répéter et amplifier le signal 4G, l'événement a été un fiasco monstrueux ; à tel point que certains joueurs ont même lancé une <i>class action</i> contre Niantic (qui avait pourtant annoncé le remboursement intégral des frais d'inscription dès la fin de l'événement). Ce qui devait marquer dans les mémoires le 1<sup>er</sup> anniversaire du jeu et marquer l'arrivée des raids de niveau 5 permettant d'obtenir des Pokémon légendaires via les raids (les raids de niveau 1 à 4 avaient été ajouté en jeu le mois précédent) est plutôt un événement que tout le monde veut oublier...<br />
<br />
En comparaison le GOFest 2018 qui se tenait toujours à Chicago mais cette fois-ci au Parc Lincoln du 14 au 15 juillet 2018 est passé presque comme une lettre à la poste. Tout au plus les joueurs abonnés chez l'opérateur Verizon auront expérimenté une brève coupure de 30 minutes vite corrigée par le déploiement rapide de zones sous WiFi pour pallier à la coupure de la 4G. Niantic ayant appris de ses erreurs, cette fois-ci l'événement se déroulait sur plusieurs jours  (deux) et sur une plus grande surface. En effet, 2 semaines plus tôt la Safari Zone de Dortmund en Allemagne qui se tenait les 30 juin et 1er juillet 2018 au parc Westfalen avait subit les mêmes affres que le 1er GOFest : trop de joueurs concentrés en un espace trop restreint avec pas assez de répétiteur fournis par les opérateurs mobiles. Si le samedi avait fait pâle figure, le dimanche s'en était bien sortir car Niantic avait immédiatement réagi en élargissant la zone de jeu à toute la ville (avec le support de la municipalité de Dortmund). Donc, ici à Chicago, tout c'est plutôt bien passé, ce qui était de bonne augure pour la suite. Depuis, s'en est suivi tout une kyrielles de <i>Safari Zones</i> sur les 5 continents, qui se sont plus plutôt bien déroulées et qui ont permis à plusieurs milliers de joueurs de se rencontrer et de jouer ensemble pour chasser ou s'échanger des Pokémon. <br />
<br />
En 2019, pour la 3<sup>ème</sup> année du jeu, Niantic et TPC ont vu les choses en grand : pas moins de 3 GOFest sont prévus durant les mois d'été de l'hémisphère nord : Chicago (USA) du 13 au 16 juin 2019, Dortmund (Allemagne; une évolution de la <i>Safari Zone</i> de l'an dernier) du 4 au 7 juillet 2019 et enfin Yokohama (Japon, en conjonction avec la Municipalité de la ville qui y organise chaque année l'événement <i>Pikachu Outbreak</i>) du 6 au 12 Août 2019. Et encore une fois un nombre impressionnant de joueurs sont attendus : le permis de Niantic déposé auprès de la municipalité pour le GOFest de Chicago table sur 15 000 visiteurs par jours tandis que celui de Dortmund planche sur 25 000 visiteur par jour (mais nous y reviendrons).<br />
<br />
C'est donc du voyage vers le <a href="https://pokemongolive.com/events/fest/chicago/" target="_blank">GOFest 2019 de Chicago</a> dont nous allons parler dans les entrées suivantes :D<br />
Mais il est temps pour moi d'aller me coucher, la navette passe me récupérer tôt demain ^^<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p482246d1560159526/bases-donnees/ms-sql-server/administration/postgresql-probleme-connexion-pgaccess/gofest-chicago.jpg/" border="0" alt="Nom : GOFest Chicago.jpg
Affichages : 322
Taille : 60,7 Ko"  style="float: CONFIG" /></div><br />
<b>Note :</b> contrairement à mes voyages de 2012 où j'étais équipé d'une tablette et d'un ordinateur portable, ici je ne disposerai que d'un téléphone portable donc soyez indulgents face à divers fautes et erreurs de rédactions qui seront corrigées ultérieurement. De plus compte tenu du décalage horaire et de la fatigue, il est possible que toutes les entrées ne soient pas publiées immédiatement. Même chose pour les potentielles photos accompagnant les articles.</blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7602/pokemon-gofest-2019-chicago-prelude/</guid>
		</item>
		<item>
			<title><![CDATA[Problème d'utilisation de la marque Java au sein d'Eclipse Jakarta EE : analyse des conséquences futures]]></title>
			<link>https://www.developpez.net/forums/blogs/71025-bouye/b7432/probleme-d-utilisation-marque-java-sein-d-eclipse-jakarta-ee-analyse-consequences-futures/</link>
			<pubDate>Sun, 05 May 2019 22:49:27 GMT</pubDate>
			<description>Pour rappel Java EE (Java...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Pour rappel Java EE (<i>Java Enterprise Edition</i>) est un ensemble de spécifications qui définissent des API permettant de créer des fonctionnalités orientées entreprises ainsi que des applications distribuées ou encore des web services et microservices. Java EE 8, la dernière version de Java EE est basée sur Java SE 8.<br />
<br />
En septembre 2017, Oracle se défaisait de Java EE et cédait l’intégralité du projet à la Fondation Eclipse sous le nom &quot;<i>Eclipse Enterprise for Java</i>&quot; ou EE4J. En février 2018, La Fondation Eclipse indiquait que Java EE prendrait désormais le nouveau nom de Jakarta EE étant donné qu'Oracle possède la marque déposée &quot;Java&quot;. Jakarta EE est un projet communautaire guidé par les membres du comité EE4J.<br />
<br />
Le 3 mai dernier, Mike Milinkovich, directeur exécutif de la Fondation Eclipse, postait une mise à jour de la migration de Java EE vers le nouveau Jakarta EE. Un des soucis de la migration concerne la négociation avec Oracle sur l'utilisation du package &quot;<i>javax</i>&quot; et de ses sous-packages ainsi que sur l'utilisation commerciale du mot &quot;Java&quot;. Malgré plusieurs mois de négociations en bons termes entre les deux parties, le dialogue entre Oracle et la Fondation Apache a échoué et il en ressort que la Fondation Eclipse ne peut transposer ce package dans Jakarta EE puisque Oracle possède toujours la marque déposée Java. La Fondation Eclipse ne peut pas non plus utiliser le mot ou le logo Java dans les produits et dénominations commerciales tournant autours de Jakarta EE.<br />
<br />
Les implications de cette décision sont multiples au niveau de Jakarta EE&nbsp;:<br />
<ul><li style="">Jakarta EE 8 se doit de conserver ces espaces de nommage pour rester compatible avec Java EE 8&nbsp;;</li><li style="">cependant, aucune nouvelle modification de ces espaces de nommage et de leur contenu ne peut intervenir&nbsp;;</li><li style="">les ajouts et modifications à venir devront se faire dans un nouvel espace de nommage qui est encore à définir ; par exemple &quot;jakarta&quot; même si le choix n'a pas encore été fait&nbsp;;</li><li style="">les versions ultérieures de Jakarta EE pourront être amenées à abandonner des packages &quot;javax&quot; au fur et à mesure qu'ils sont remplacés par de nouvelles spécifications et API. Les versions futures de Jakarta EE seront donc amenées à s’éloigner de plus en plus de Java EE jusqu’à s'en détacher complètement&nbsp;;</li><li style="">toute évocation de Java EE, de même que les références à EJB (<i>Enterprise Java Beans</i>), JPA (<i>Java Persistence API</i>) ou JAX-RS (<i>Java API for RESTful Web Services</i>) devront être modifiées de par leur usage de la marque déposée &quot;Java&quot;&nbsp;;</li><li style="">le projet EE4J devrait être renommé pour la même raison. Les noms et logos associés restent encore à être déterminés par la communauté impliquée dans ce projet.</li></ul><br />
<br />
Les implications seront encore plus importantes pour les milliers d'applications et web-services construits sur Java EE. La Fondation Eclipse a comme ligne directrice de rendre le futur Jakarta EE 9 pleinement compatible avec Jakarta EE 8 (et donc Java EE 8) en introduisant un système permettant la rétrocompatibilité. Cependant les migrations vers les versions ultérieures de Jakarta EE pourront ne pas s’avérer évidentes sans modification importante du code pour se détacher complètement de la vieille couche Java EE. <br />
<br />
Sources&nbsp;: <br />
<ul><li style=""><a href="https://eclipse-foundation.blog/2019/05/03/jakarta-ee-java-trademarks/" target="_blank">blog de Mike Milinkovich</a>, directeur exécutif de la Fondation Eclipse&nbsp;;</li><li style=""><a href="https://dmitrykornilov.net/2019/05/03/thoughts-about-jakarta-ee-future-without-javax/" target="_blank">Blog de Dmitry Kornilov</a>, manager senior du développement logiciel chez Oracle et membre du comité Eclipse EE4J.</li></ul></blockquote>

]]></content:encoded>
			<dc:creator>bouye</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/71025-bouye/b7432/probleme-d-utilisation-marque-java-sein-d-eclipse-jakarta-ee-analyse-consequences-futures/</guid>
		</item>
	</channel>
</rss>
