Projet Informatique Éléments de programmation EIA-FR E2 J. BAPST 13.02.2013 INTRODUCTION Ce document rassemble différentes informations complémentaires qui peuvent s'avérer utiles lors du développement d'applications en Java. Ces informations sont accompagnées d'extraits de code qui illustrent le principe de fonctionnement et dont vous pouvez vous inspirer (en les adaptant au contexte de votre application). CONSULTATION DE LA DOCUMENTATION DE LA PLATE-FORME JAVA La documentation des API (Application Programming Interface) de la plate-forme Java peut être consultée de différentes manières : Dans Eclipse : de manière contextuelle en pressant sur Shift+F2 Par défaut Eclipse consulte la documentation disponible en ligne sur le site de Sun (une connexion internet est nécessaire dans ce cas) mais il est possible d'indiquer un autre emplacement, par exemple si la documentation a été préalablement installée localement. Consulter le document "Eclipse 4.2 : Installation et configuration" accessible depuis la page web du cours ou sur Cyberlearn pour configurer l'accès contextuel à la documentation de la plate-forme Java (API) et l'installation locale de cette documentation. Sur le Web : site de Sun (la référence) ou d'autres portails de documentation. Hyperliens disponibles sur la page web du cours ou sur la page des liens : jacques.bapst.home.hefr.ch/links Dans sa configuration standard, la version 4.2 d'Eclipse utilise la version 1.7 de la plate-forme Java. C'est donc la documentation de cette version qu'il faut consulter. Il est important d'être à l'aise avec la consultation de la documentation de la plate-forme Java de manière à trouver rapidement les informations nécessaires et à les exploiter efficacement. Les possibilités de navigation sont nombreuses : Le lien Frames affiche la liste de l'ensemble des packages et des classes dans deux cadres situés sur le bord gauche de l'écran (le mode No Frames permet de supprimer ces deux cadres de navigation pour ne garder que l'information principale). Le lien Overview affiche la liste de tous les packages (contenu identique à celui du cadre supérieur gauche du mode Frames). Le lien Tree affiche, dans le fenêtre principale, l'arborescence de tous les packages et de toutes les classes de la plate-forme Java. Le lien Index affiche une liste alphabétique dans laquelle il est possible de rechercher et d'accéder à tous les éléments (classes, interfaces, constructeurs, champs, constantes, méthodes, exceptions, …) de la plate-forme Java. Le lien Deprecated affiche la liste des éléments "dépréciés" / "réprouvés" (classes, interfaces, constructeurs, champs, constantes, méthodes, exceptions, …) c'est-à-dire les éléments qui ont été supprimés ou, plus généralement, remplacés par d'autres dans les versions successives de la plate-forme Java. Il est déconseillé d'utiliser ces éléments qui seront, un jour ou l'autre, supprimés définitivement de la plate-forme Java. La documentation indique généralement les éléments qui peuvent être utilisés en lieu et place. Le lien Help donne des informations générales concernant l'utilisation de la documentation. JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 1 SÉLECTION DU LOOK-AND-FEEL (L&F) Si l'on utilise la libraire Swing pour la gestion de l'interface utilisateur graphique, le Look-and-Feel (L&F) de l'application (la manière dont se présentent les composants visuels) peut être modifié sans changer l'application elle-même grâce à la notion de Pluggable Look-and-Feel. La méthode statique UIManager.setLookAndFeel() permet de modifier le L&F de l'application en lui passant en paramètre le nom d'une classe (de type LookAndFeel) qui peut être chargée dynamiquement. Des méthodes statiques (de UIManager) permettent de rechercher deux L&F particuliers : getSystemLookAndFeelClassName() retourne le nom de la classe du L&F natif de la plate-forme d'exécution (Windows dans notre cas). getCrossPlatformLookAndFeelClassName() retourne le nom de la classe d'un L&F indépendant de la plate-forme d'exécution (appelé Java ou Metal). D'autres classes de L&F peuvent également être disponibles. On trouve généralement la classe : com.sun.java.swing.plaf.motif.MotifLookAndFeel qui représente le L&F OSF/Motif utilisé sur certaines plates-formes UNIX. La méthode statique UIManager.getInstalledLookAndFeels() retourne un tableau d'informations (de type UIManager.LookAndFeelInfo) concernant les L&F qui sont à disposition sur la plate-forme d'exécution. Le L&F est généralement défini avant la création de l'interface utilisateur (dans la phase d'initialisation de l'application). Si le L&F est modifié alors que des composants Swing sont déjà affichés (changement dynamique), il faut forcer la mise à jour du L&F de tous les composants en invoquant la méthode statique : SwingUtilities.updateComponentTreeUI(RootContainer) RootContainer étant le conteneur qui est à la racine de l'arborescence qui doit être mise à jour (généralement la fenêtre principale de l'application). * * * * * A partir de la version 1.6 update 10, un nouveau L&F a été introduit. Ce nouveau L&F, nommé «Nimbus» comporte des caractéristiques intéressantes (qualité graphique, configurable, défini vectoriellement donc redimensionnable sans pixellisation, etc.). Exemple de code pour définir le L&F «Nimbus» en s'assurant qu'il soit disponible sur la plate-forme cible : //--- Try to Set the Nimbus Look&Feel for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()){ if ("Nimbus".equals(laf.getName())) { try { UIManager.setLookAndFeel(laf.getClassName()); } catch (Exception e) { try { System.out.println("*** Nimbus Look&Feel not available" + " (Metal used instead)"); UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (Exception e1) { e1.printStackTrace(); } } } } JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 2 VALEURS LITTÉRALES ET CONSTANTES D'une manière générale, il est recommandé que toutes les valeurs littérales (excepté les valeurs simples telles que 0, 1, -1) soient définies sous forme de constantes nommées et ne soient pas écrites "en dur" dans le code source. Pour une application donnée, il est conseillé de rassembler toutes les valeurs littérales (constantes numériques, noms de répertoires, de fichiers, couleurs, valeurs par défaut, etc.) dans une classe (ou éventuellement une interface) réservée exclusivement à cet usage (par exemple dans une classe nommée Constants). Dans les autres classes de l'application, l'importation statique permet d'utiliser ces constantes sans avoir à les préfixer avec le nom de la classe. public class Constants { public static final int NB_STEPS = 500; public static final double public static final double BASE_WIDTH BASE_HEIGHT = = 50.0; 120.5; IMAGE_PROJ = "\Resources\Images\Logo.jpg"; public static final String . . . } import static applic.Constants.*; ... //--- Utilisation des constantes System.out.println("Nombre de pas : " + NB_STEPS); ... DÉTERMINATION DU RÉPERTOIRE COURANT Il faut éviter de mettre, en dur dans le code, des chemins d'accès absolus vers les fichiers (par exemple "D:\Test\Applic\config\myConfig.cfg"). Il est préférable de travailler avec des chemins relatifs, généralement par rapport au répertoire courant, c'est-à-dire le répertoire dans lequel l'application est installée (emplacement où se trouve le fichier JAR). Pour connaître le répertoire courant (chemin d'accès complet enregistré dans une chaîne de caractères), on peut utiliser l'instruction suivante : //--- Répertoire courant String currentDir = System.getProperty("user.dir"); Il est ensuite possible de compléter de chemin d'accès avec des noms de sous-répertoires (à enregistrer de préférence sous forme de constantes). //--- Constantes ... public static final String CONFIG_SUBDIR = "config"; public static final String CONFIG_FILE = "myConfig.cfg"; ... //--- Ouverture du fichier en lecture String fSep = System.getProperty("file.separator"); // File path separator String fileName = currentDir + fSep + CONFIG_SUBDIR + fSep + CONFIG_FILE; try { BufferedReader r = new BufferedReader(new FileReader(fileName)); } catch (FileNotFoundException e) { System.out.println("ERROR : File " + fileName + "cannot be opened"); e.printStackTrace(); } JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 3 JFILECHOOSER - BOÎTE DE DIALOGUE POUR SÉLECTIONNER UN FICHIER Dans la librairie Swing, le composant JFileChooser permet de créer facilement une boîte de dialogue permettant à l'utilisateur de naviguer dans l'arborescence des disques et de sélectionner un fichier. La boîte de dialogue peut être créée pour ouvrir un fichier existant (showOpenDialog()) ou pour sauvegarder un fichier (showSaveDialog()). Le constructeur de la classe JFileChooser permet de donner un répertoire initial (point de départ de la navigation) plutôt que le répertoire par défaut du système d'exploitation qui n'est pas forcément idéal. Un filtre peut être associé au composant JFileChooser dans ce cas, seul les fichiers acceptés par le filtre sont présentés à l'utilisateur. Un filtre prédéfini existe pour filtrer les fichiers selon leurs extensions (FileNameExtensionFilter); une liste d'extension peut être mentionnée. L'exemple ci-dessous illustre le fonctionnement de ce composant (dans cet exemple, il n'y a pas de fenêtre principale, la référence est mise à null et la boîte de dialogue sera centrée sur l'écran). public class TestJFileChooser { public static void main(String[] args) { JFrame parentView = null; // Référence fenêtre principale (null=centré) String fileName; //--- Répertoire courant String currentDir = System.getProperty("user.dir"); //--- Création d'un filtre basé sur les extensions (.jpg et .jpeg acceptés) FileFilter filter = new FileNameExtensionFilter("JPEG file", "jpg", "jpeg"); //--- Création du JFileChooser avec répertoire courant comme point de départ JFileChooser fChooser = new JFileChooser(currentDir); //--- Ajout et activation du filtre fChooser.setFileFilter(filter); //--- Ouverture de la boîte de dialogue pour choisir un fichier int returnVal = fChooser.showOpenDialog(parentView); if(returnVal == JFileChooser.APPROVE_OPTION) { fileName = fChooser.getSelectedFile().getAbsolutePath(); System.out.println("Selected file : " + fileName); } //--- Ouverture de la boîte de dialogue pour enregistrer un fichier returnVal = fChooser.showSaveDialog(parentView); if(returnVal == JFileChooser.APPROVE_OPTION) { fileName = fChooser.getSelectedFile().getAbsolutePath(); System.out.println("Selected file : " + fileName); } } } JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 4 FORMATAGE DES NOMBRES EN VIRGULE FLOTTANTE Il existe plusieurs manières de formater les nombres en virgule flottante (float et double). On peut notamment utiliser la classe DecimalFormat ou la méthode format() de la classe String (disponible depuis la version 1.5 du SDK) ou utiliser la méthode printf() qui permet d'écrire (sur la console ou dans un fichier texte) en donnant les indications de formatage associées. Pattern DecimalFormat Syntaxe format() et printf() : java.sun.com/javase/7/docs/api/java/text/DecimalFormat.html : java.sun.com/javase/7/docs/api/java/util/Formatter.html#syntax Exemple d'utilisation de ces différentes techniques : public static void main(String[] args) { float v = 123.456789f; String s; //--- Utilisation de DecimalFormat DecimalFormat df = new DecimalFormat("0.0##"); s = df.format(v); System.out.println(s); // Max 3 ch. après la virg. //---- Utilisation de String.format() s = String.format("v with 2 digits %.2f", v); System.out.println(s); //--- Utilisation de printf() pour écriture sur la console System.out.printf("v with 3 digits %.3f %n", v); //--- Utilisation de printf() pour écriture dans un fichier String filename = "D:\\Temp\\Test_printf.txt"; // "En dur" pour le test try { PrintWriter p = new PrintWriter(new BufferedWriter( new FileWriter(filename))); p.printf("%.3f %n", v); p.close(); } catch (IOException e) { e.printStackTrace(); } } DATES ET HEURES Le formatage des dates (et heures) peut être effectué par la classe GregorianCalendar qui se base sur un modèle (pattern) dont la syntaxe est définie dans la documentation de cette classe (java.sun.com/javase/7/docs/api/java/text/SimpleDateFormat.html). L'exemple ci-dessous illustre le principe et les fonctions principales de ces classes. //--- Création d'un calendrier avec la date et l'heure courante GregorianCalendar cal = new GregorianCalendar(); //--- Extraction des différentes parties de la date et de l'heure int day = cal.get(GregorianCalendar.DAY_OF_MONTH); int month = cal.get(GregorianCalendar.MONTH) + 1; // January => 1 int year = cal.get(GregorianCalendar.YEAR); int int int int hour min sec ms = = = = cal.get(GregorianCalendar.HOUR_OF_DAY); cal.get(GregorianCalendar.MINUTE); cal.get(GregorianCalendar.SECOND); cal.get(GregorianCalendar.MILLISECOND); System.out.println(day+"."+month+"."+year+" "+hour+":"+min+":"+sec+"."+ms); //--- Utilisation de SimpleDateFormat pour formater la date String fmtPattern = "dd.MM.yyyy HH:mm:ss.SSS"; SimpleDateFormat formatter = new SimpleDateFormat(fmtPattern); String fmtDate = formatter.format(cal.getTime()); System.out.println(fmtDate); JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 5 LANCEMENT D'UNE APPLICATION EXTERNE OU D'UN FICHIER DE COMMANDES Depuis une application Java, il est possible de lancer une application externe, ou de lancer l'application associée à un fichier donné (par exemple lancer Word comme on le ferait en doublecliquant sur un fichier .doc) ou lancer un fichier de commandes (.bat ou .cmd). Le fichier de commandes peut-être prédéfini ou créé dynamiquement par l'application Java. Pour lancer une application externe ou un fichier de commandes, on utilisera : - La méthode exec() de l'environnement d'exécution avec la classe Runtime Pour lancer l'application associée à un fichier donné (l'équivalent du double-clic), on utilisera : - La méthode open() de la classe Desktop Exemple d'utilisation de ces deux techniques : package basic; import java.awt.Desktop; import java.io.File; import java.io.IOException; public class TestExecuteCmd { private private private private static static static static final final final final String String String String RUN_CMD CMD_FILE EXL_FILE IMG_FILE = = = = "cmd.exe /C start "; "/Resources/Test.cmd"; "/Resources/Worksheet.xlsx"; "/Resources/Orage.jpg"; public static void main(String[] args) { //--- Get Current Directory String currentDir = System.getProperty("user.dir"); //-------------------------------------------------------------------------// Execute command-file or application (using Runtime exec) //-------------------------------------------------------------------------Runtime rt = Runtime.getRuntime(); try { String cmd1 = RUN_CMD + currentDir + CMD_FILE; System.out.println("Executing " + cmd1); Process proc = rt.exec(cmd1); // Execute command file proc.waitFor(); String cmd2 = RUN_CMD + "Excel"; System.out.println("Executing " + cmd2); proc = rt.exec(cmd2); proc.waitFor(); // Start Excel } catch (IOException | InterruptedException e) { e.printStackTrace(); } //-------------------------------------------------------------------------// Open application associated to a file (using Desktop class) //-------------------------------------------------------------------------try { // Open Excel worksheet Desktop.getDesktop().open(new File(currentDir + EXL_FILE)); // Open image viewer Desktop.getDesktop().open(new File(currentDir + IMG_FILE)); } catch (IOException e) { e.printStackTrace(); } } } JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 6 UTILISATION D'UN TIMER DANS L'INTERFACE UTILISATEUR Si l'on souhaite exécuter une tâche après un certain délai ou répéter à intervalle périodique une activité liée à des éléments de l'interface-utilisateur, on peut utiliser la classe Timer (qui se trouve dans le package javax.swing). Ce timer fonctionne comme un composant visuel et génère des événements (ActionEvent) qui sont identiques à ceux des boutons (JButton). Leur traitement est donc le même (méthode actionPerformed()). Des informations supplémentaires figurent au chapitre 11 du cours IHM-1 (pages 6 à 9) : jacques.bapst.home.hefr.ch/ihm1/cours/ihm1_11.pdf Voir également la documentation de la classe Timer : java.sun.com/javase/7/docs/api/javax/swing/Timer.html DÉPLOIEMENT D'UNE APPLICATION SOUS FORME DE FICHIER JAR OU EXE Les applications Java sont généralement déployées sous forme de fichier JAR (Java Archive). Pour la création des fichiers JAR, consulter le document «Eclipse : Déploiement d'applications Java sous forme de fichiers JAR» disponible sur Cyberlearn. Il est également possible de déployer une application Java en utilisant un utilitaire créant un fichier natif exécutable (Java Executable Wrapper), comme par exemple Launch4J qui est téléchargeable sur SourceForge : http://launch4j.sourceforge.net/ Il en existe beaucoup d'autres qui sont, soit gratuits (JSmooth, JavaExe, ...), soit payants avec parfois des versions utilisables avec restrictions ou sur une durée limitée (JExeCreator, Exe4J, ...). CRÉATION D'UN INSTALLEUR Pour simplifier encore le déploiement d'une l'application Java (après avoir généré un exécutable), il est possible de créer un installeur en utilisant, par exemple, l'utilitaire gratuit Inno Setup qui est disponible sur http://www.jrsoftware.org/isinfo.php L'installeur ainsi créé s'exécutera sous la forme d'un assistant qui guidera pas à pas l'utilisateur lors de l'installation de l'application en lui laissant la liberté d'adapter certains éléments au contexte de sa machine. JBa EIA-FR Projet_IG3_Elements_Programmation.docx 13.02.2013 7