Welcome to Bukkit France

Inscrivez-vous maintenant pour profiter d'un accès total à tout le contenu offert par la meilleur communauté Bukkit française ! Une fois inscrit et connecté, vous pourrez contribuez à la communauté en postant vos propres sujets et questions ou en répondant à ceux existants. Vous pourrez aussi customiser votre profil, recevoir des points de réputations, communiquer avec les autres membres via le chat, et plus encore! 

  • Annonces

    • Pskyco

      Bukkit France passe sous Discord !   20/02/2016

      Bukkit France est désormais passé sur Discord, au revoir donc notre vieux Teamspeak ! Téléchargez le client et venez nous rejoindre sur notre salon en suivant les instructions suivantes.
      M-à-j du 25/02/2017 : Désormais, seuls les comptes actifs sur le forum se verront donner l'accès au Discord, ce dernier n'est pas une plateforme d'aide de la même manière que le chat.
  • billets
    47
  • commentaires
    40
  • vues
    29 742

À propos de ce blog

Cours de Java

Billets dans ce blog

SystemGlitch

Prologue

blog-0426494001431880602.png

Bonjour chers/chères Bukkitiens/Bukkitiennes !

 

Bienvenue dans le cours de développement Java! Que pensez-vous de commencer par l'introduction? :lol:

 

 

 

Java32324.png

 

 

Java, non, on ne parle pas de la danse ridicule des années 1920!

 

Le Java est un langage de programmation apparu en 1995, et oui! 1995! :o Mais il était alors bien différent de celui que nous connaissons aujourd'hui! Il fut développé par l'entreprise Sun MicroSystems qui fut rachetée par Oracle Corporation en 2009. Il n'y pas si longtemps que ça finalement!

 

Java est un langage orienté objet robuste, puissant et surtout, très portable car il est multi-plateforme.

Sa grande portabilité réside dans un concept utilisé auparavant par le Pascal, il utilise une machine virtuelle que l'on nomme Java Runtime Environment (JRE), qui va faire l'intermédiaire entre le bytecode (écrit par le compilateur grâce au code de l'utilisateur), et va le transformer en langage compréhensible par la machine concernée. Il y a un autre aspect de sa "portabilité", se fût à sa création, sa syntaxe ressemble beaucoup à celle du C++ et ce n'est pas une coïncidence, les ingénieurs de l'époque travaillaient essentiellement en C, reprendre cette syntaxe permettait à une large communauté de pouvoir utiliser leur langage très rapidement, et c'est en grande partie grâce à cela que le Java est devenu vite populaire.

Sa puissante API permet de gérer un grand nombre de domaines comme les interfaces graphiques, la gestion des fichiers, que ce soit en local ou sur une base de données, et bien plus encore!

 

Ses possibilités sont très diversifiées. Les bases sont faciles à intégrer mais maîtriser les différents domaines demande plusieurs années de pratique... Mais ne vous inquiétez pas, nous irons pas-à-pas.

 

Contrairement à d'autres cours sur Internet, nous ne nous contenterons pas de dresser une liste exhaustive des possibilités du Java et de Bukkit car ce serait trop long et inutile! Nous ne somme pas là pour faire du bourrage de crane! Nous voulons vous fournir les outils nécessaires pour que vous sachiez vous débrouiller tout seul, sans être un assisté qui se contente de recopier un tutoriel!

Et plus important encore, vous comprendrez cette superbe vidéo!

 

 

 

 

 

 

 

Ne plongez pas la tête la première!

 

Afin de développer avec ce merveilleux langage, il vous faut d'abord installer Java, mais pas une simple JRE, la version Java SE Development Kit (JDK).

Nous tenons aussi à signaler que rien ne vous empêche d'installer plusieurs JDK et de choisir celle que vous voulez pour votre projet, via votre IDE.

 

Il est évidemment possible de développer à l'aide d'un simple éditeur de texte, mais avouez que l'idée même en est repoussante! Pour développer, il vous faudra des couleurs, de l'ordre et un environnement agréable, afin de mieux s'y retrouver au sein de son code. On appelle ces logiciels IDE (Integrated development environment). Nous allons explorer le monde du Java avec un IDE répondant au nom d'Eclipse. Vous pouvez télécharger la version dont nous aurons besoin ici!

 

Vous voila prêt à commencer me direz-vous! Et bien désolé de vous décevoir, mais non, il y a encore des choses à savoir avant de débuter. Vous vous doutez que ce genre d'outil n'est pas ce qu'il y a de plus simple à utiliser. :mellow:

 

Je pense que vous n'aurez pas trop de difficultés à apprendre les différents raccourcis clavier, ceux-ci sont spécifiés dans les menus.

Ceux-ci sont les plus importants:

  • Ctrl + Shift + O : Il vous permet de rapidement générer les imports dont vous aurez besoin pour faire fonctionner votre code.
  • Ctrl + S : Il permet de sauvegarder la classe sur laquelle vous travaillez actuellement.
  • Ctrl + Shift + S : Il permet de tout sauvegarder. Toutes les classes modifiées depuis la dernière sauvegarde seront sauvegardées !

 

Jetez un œil à cette rapide visite guidée de votre IDE :

 

Se8dlHS.png

 

 

Vous pourrez trouver plus d'informations à propos de votre IDE en consultant la documentation officielle d'Eclipse. Nous apprendrons tout de même quelques unes de ses fonctionnalités ensemble!

 

Lancez Eclipse. Une boite de dialogue apparaîtra. Spécifiez le dossier dans lequel vous voulez que tous vos projets soient sauvegardés. On appelle ce dossier "Workspace".

 

Faites un clic droit dans l'explorateur de packages et créez un nouveau projet :

 

LGske6A.png

 

Une boite de dialogue s'ouvrira pour vous demander de définir les paramètres de votre projet. Assurez-vous que ces derniers soient bien les mêmes que sur l'image suivante :

 

Akv3Wo5.png

 

Cliquez sur "Finish". Votre projet est créé! Nous le remplirons plus tard! Maintenant, passons aux choses sérieuses!

 

 

JeremGamer et JackBlue

 

tNIpRtq.png

SystemGlitch

Maintenant que vous avez un certain nombre de compétences en matière d'interfaces graphiques, vous serez en mesure de créer des logiciels bien plus "user-friendly" que de vulgaires consoles. Vous savez déjà plus ou moins ce qui vous attend dans ce TP, alors sans plus tarder, voici votre cahier des charges ! Lisez-le attentivement et surtout, dans son intégralité !

 

Nous voulons réaliser une petite interface graphique permettant de personnaliser un personnage de jeu de rôle. De nombreux champs de formulaires devront être utilisés afin de pouvoir paramétrer les caractéristiques suivantes :

  • Nom du personnage
  • Sexe du personnage
  • Tranche d'âge du personnage
  • Taille du personnage
  • Couleur de peau
  • Couleur de cheveux
  • Couleur des yeux


Vous pouvez ajouter des caractéristiques si vous le souhaitez.
En option, vous pouvez rajouter une image sur le côté, pour représenter le personnage, et mieux encore, vous pouvez la faire réagir avec les caractéristiques telles que le sexe ou la couleur de peau.
Ensuite nous souhaitons également que l'interface soit la plus claire possible, tout en étant bien structurée et organisée. Pour cela il vous faudra combiner de nombreux panneaux ayant des layout différents.

 

Histoire de ne pas perdre son travail, nous souhaitons également que toutes les caractéristiques soient sauvegardées et rechargées au lancement du programme. Le fichier de sauvegarde sera localisé dans le même dossier que le logiciel, histoire de s'y retrouver pendant les tests. On pourra éventuellement changer ça plus tard. Je dois vous obliger à une chose cependant: je souhaite que vous sauvegardiez toutes ces données à l'aide d'un ObjectOutputStream ! Les données devront être rechargées dans tous les champs de formulaire au lancement du logiciel si un fichier existe.

 

Lors de la fermeture de la fenêtre, les données doivent être sauvegardées. Voici une petite astuce pour effectuer quelques instructions lors de différents événements liés à une fenêtre :

this.addWindowListener(new WindowAdapter() {

	@Override
	public void windowClosing(WindowEvent e) {
		//Effectué juste avant que la fenêtre se ferme et que le processus se termine	
	}

	@Override
	public void windowDeiconified(WindowEvent e) {
		//Lorsque la fenêtre est restaurée après réduction
	}

	@Override
	public void windowIconified(WindowEvent e) {
		//Lorsque la fenêtre est réduite
	}
			
});


Comme d'habitude la documentation peut vous servir pour savoir quelles autres méthode proposent les WindowListener. ;)

 


Vous savez tout ! Maintenant fini de rêvasser, au travail ! J'apprécierais voir vos travaux une fois terminés alors n'hésitez pas à me les envoyer par message privé ;) Si vous avez besoin d'aide, je suis là également pour vous aiguiller !
N'oubliez pas ce que je vous ai dis pendant les deux autres TPs : prenez votre temps, réfléchissez bien avant de vous jeter la tête la première dans le code, etc... Cela s'applique pour tous vos projets ! Il y a cependant une petite différence : vous travaillez maintenant sur GUI, alors pensez bien à la forme qu'elle prendra. N'hésitez pas à vous faire un petit dessin si ça peut vous aider à bien visualiser. De plus, choisissez judicieusement les composants que vous allez utiliser; ça n'aurait aucun sens d'utiliser un champ de saisie pour choisir le sexe du personnage. ^_^

 

Je vous souhaite bonne chance !

 

Correction :

Spoiler

Cette correction ne comprend pas les petits extras que je vous ai proposé comme l'image sur le côté, je sais que vous savez le faire par vous-même! ;) Prenez bien le temps de la lire, et faites-le attentivement! Je quasiment certain que vous n'avez pas procédé ainsi. ^_^ Mais si c'est le cas alors je vous félicite allègrement! Je vous félicite quand même si vous avez réussi l'exercice par votre propres moyens sans regarder la correction!

 

Class de la fenêtre :


package fr.bukkit.jeremgamer.cours;

import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class MainFrame extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5897453038271365972L;

	public MainFrame() {
		this.setSize(300 , 250);		
		this.setTitle("Personnage");		
		this.setLocationRelativeTo(null);		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		ContentPanel content = new ContentPanel();
		this.setContentPane(content);		
		this.pack();
		
		this.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				content.save();
			}

		});
		
		this.setVisible(true);
		
		this.setMinimumSize(getSize());
		this.setMaximumSize(new Dimension(500 , 500)); //Ne fonctionne pas à cause d'un bug connu de l'API Java
	}

}


Class du panneau principal : (Accrochez-vous bien ^_^ )


package fr.bukkit.jeremgamer.cours;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ContentPanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7311158212818984619L;

	private RPCharacter rpc; 

	private ObjectInputStream ois;
	private BufferedInputStream bis;
	private FileInputStream fis;

	private ObjectOutputStream oos;
	private BufferedOutputStream bos;
	private FileOutputStream fos;

	private JTextField nameField = new JTextField();
	private JSpinner ageSpinner = new JSpinner(new SpinnerNumberModel(25 , 10 , 80 , 1));
	private	JComboBox<String> sexCombo = new JComboBox<String>();
	private JSlider sizeSlider = new JSlider();

	private int selectedEye;
	private int selectedSkin;
	private int selectedHair;
	
	public ContentPanel() {	

		try {
			initCharacter();
		} catch (IOException | ClassNotFoundException e) {
			System.err.println("Erreur lors de la lecture du fichier de sauvegarde.");
			System.out.println("Une sauvegarde vierge sera utilisée.");
			rpc = new RPCharacter();
		}

		BorderLayout bl = new BorderLayout();
		bl.setHgap(5);
		this.setLayout(bl);


		//------------------------------
		//Création des composants pour les caractérisitques
		//------------------------------


		//----------------

		JLabel nameLabel = new JLabel("Nom : ");

		//----------------		

		JLabel sexLabel = new JLabel("Sexe : ");
		sexCombo.addItem("Homme");
		sexCombo.addItem("Femme");
		sexCombo.addItem("Autre");

		//----------------

		JLabel ageLabel = new JLabel("Âge : ");

		//----------------

		JLabel sizeLabel = new JLabel("Taille : ");				
		JLabel sizeDisplay = new JLabel("175" , JLabel.RIGHT);

		sizeSlider.setMinimum(100);
		sizeSlider.setMaximum(250);
		sizeSlider.setValue(175);
		sizeSlider.setPaintTicks(true);
		sizeSlider.setPaintLabels(true);
		sizeSlider.setMinorTickSpacing(25);
		sizeSlider.setMajorTickSpacing(50);
		sizeSlider.addChangeListener(new ChangeListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				sizeDisplay.setText(String.valueOf(sizeSlider.getValue()));
			}

		});

		//----------------

		JPanel eyeColor = new JPanel();
		eyeColor.setLayout(new BoxLayout(eyeColor , BoxLayout.PAGE_AXIS));

		JLabel eyeColorLabel = new JLabel("Yeux");
		JRadioButton brown = new JRadioButton("Bruns");
		JRadioButton blue = new JRadioButton("Bleus");
		JRadioButton green = new JRadioButton("Verts");
		JRadioButton yellow = new JRadioButton("Jaunes");
		JRadioButton grey = new JRadioButton("Gris");
		JRadioButton hazel = new JRadioButton("Noisette");
		JRadioButton amber = new JRadioButton("Ambre");

		ArrayList<JRadioButton> eyeList = new ArrayList<JRadioButton>();
		eyeList.add(brown);
		eyeList.add(blue);
		eyeList.add(green);
		eyeList.add(yellow);
		eyeList.add(grey);
		eyeList.add(hazel);
		eyeList.add(amber);

		ButtonGroup grp = new ButtonGroup();
		int i = 0;
		for(JRadioButton b : eyeList) {
			grp.add(b);
			b.addActionListener(new TraitListener(i , TraitListener.EYE_GROUP));
			i++;
		}


		eyeColor.add(eyeColorLabel);
		for(JRadioButton b : eyeList)
			eyeColor.add(b);

		//----------------

		JPanel hairColor = new JPanel();
		hairColor.setLayout(new BoxLayout(hairColor , BoxLayout.PAGE_AXIS));

		JLabel hairColorLabel = new JLabel("Cheveux");
		JRadioButton brown2 = new JRadioButton("Bruns");
		JRadioButton blond = new JRadioButton("Blonds");
		JRadioButton red = new JRadioButton("Roux");

		ArrayList<JRadioButton> hairList = new ArrayList<JRadioButton>();
		hairList.add(brown2);
		hairList.add(blond);
		hairList.add(red);

		ButtonGroup grp2 = new ButtonGroup();
		i = 0;
		for(JRadioButton b : hairList) {
			grp2.add(b);
			b.addActionListener(new TraitListener(i , TraitListener.HAIR_GROUP));
			i++;
		}

		hairColor.add(hairColorLabel);
		for(JRadioButton b : hairList)
			hairColor.add(b);

		//----------------

		JPanel skinColor = new JPanel();
		skinColor.setLayout(new BoxLayout(skinColor , BoxLayout.PAGE_AXIS));

		JLabel skinColorLabel = new JLabel("Peau");
		JRadioButton light = new JRadioButton("Blanche");
		JRadioButton dark = new JRadioButton("Noire");
		JRadioButton yellow2 = new JRadioButton("Jaune");

		ArrayList<JRadioButton> skinList = new ArrayList<JRadioButton>();
		skinList.add(light);
		skinList.add(dark);
		skinList.add(yellow2);

		ButtonGroup grp3 = new ButtonGroup();
		i = 0;
		for(JRadioButton b : skinList) {
			grp3.add(b);
			b.addActionListener(new TraitListener(i , TraitListener.SKIN_GROUP));
			i++;
		}

		skinColor.add(skinColorLabel);
		skinColor.add(Box.createRigidArea(new Dimension(1, 3))); //Pour ajouster un tout petit écart
		for(JRadioButton b : skinList)
			skinColor.add(b);

		//------------------------------





		//------------------------------
		//Assemblage des composants de caractéristiques
		//------------------------------

		JPanel traitsContainer = new JPanel(new GridBagLayout());

		GridBagConstraints gbc = new GridBagConstraints(); 
		gbc.insets = new Insets(3 , 3 , 3 , 3);

		gbc.weightx = 1;
		gbc.weighty = 1;
		gbc.fill = GridBagConstraints.BOTH;

		gbc.gridx = 0;
		gbc.gridy = 0;

		gbc.gridwidth = 1;
		gbc.gridheight = 1;

		traitsContainer.add(nameLabel , gbc);

		gbc.gridwidth = GridBagConstraints.HORIZONTAL;
		gbc.gridx = 1;
		traitsContainer.add(nameField, gbc);

		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.gridx = 0;
		gbc.gridy = 1;
		traitsContainer.add(sexLabel , gbc);

		gbc.gridx = 1;
		traitsContainer.add(sexCombo, gbc);

		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.gridx = 0;
		gbc.gridy = 2;
		traitsContainer.add(ageLabel , gbc);

		gbc.gridx = 1;
		traitsContainer.add(ageSpinner , gbc);

		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.gridx = 0;
		gbc.gridy = 3;
		traitsContainer.add(sizeLabel , gbc);

		gbc.gridx = 1;
		traitsContainer.add(sizeDisplay , gbc);

		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.gridx = 0;
		gbc.gridy = 4;
		traitsContainer.add(sizeSlider , gbc);

		gbc.gridx = 2;
		gbc.gridy = 5;
		traitsContainer.add(hairColor , gbc);

		gbc.gridy = 6;
		traitsContainer.add(skinColor , gbc);

		gbc.gridheight = GridBagConstraints.VERTICAL;
		gbc.gridwidth = 2;
		gbc.gridx = 0;
		gbc.gridy = 5;
		traitsContainer.add(eyeColor , gbc);

		//------------------------------



		//------------------------------
		//Chargement des paramètres sauvegardés
		//------------------------------
		nameField.setText(rpc.name);
		sexCombo.setSelectedItem(rpc.sex);
		ageSpinner.setValue(rpc.age);
		sizeSlider.setValue(rpc.size);
		sizeDisplay.setText(String.valueOf(sizeSlider.getValue()));
		eyeList.get(rpc.eyes).setSelected(true);
		selectedEye = rpc.eyes;
		hairList.get(rpc.hair).setSelected(true);
		selectedHair = rpc.hair;
		skinList.get(rpc.skin).setSelected(true);
		selectedSkin = rpc.skin;
		//------------------------------


		this.add(traitsContainer , BorderLayout.CENTER);

	}
	
	private void initCharacter() throws IOException, ClassNotFoundException {
		File save = new File("character.save");
		if(save.exists()) {
			fis = new FileInputStream(save);
			bis = new BufferedInputStream(fis);
			ois = new ObjectInputStream(bis);

			rpc = (RPCharacter) ois.readObject();
			ois.close();
		} else
			rpc = new RPCharacter();
	}

	public void save() {
		rpc.name = nameField.getText();
		rpc.sex = (String) sexCombo.getSelectedItem();
		rpc.age = (int) ageSpinner.getValue();
		rpc.size = sizeSlider.getValue();
		rpc.eyes = selectedEye;
		rpc.hair = selectedHair;
		rpc.skin = selectedSkin;
				
		try {
			File file = new File("character.save");
			if(!file.exists())
				file.createNewFile();
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			oos = new ObjectOutputStream(bos);

			oos.writeObject(rpc);
			oos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class TraitListener implements ActionListener {

		private int i;
		private int group;

		public final static byte EYE_GROUP = 0;
		public final static byte HAIR_GROUP = 1;
		public final static byte SKIN_GROUP = 2;

		TraitListener(int i , byte group) {
			this.i = i;
			this.group = group;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if(group == EYE_GROUP)
				selectedEye = i;
			else if(group == HAIR_GROUP)
				selectedHair = i;
			else if(group == SKIN_GROUP)
				selectedSkin = i;
		}

	}
}


Class de l'objet de sauvegarde :


package fr.bukkit.jeremgamer.cours;

import java.io.Serializable;

public class RPCharacter implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 592864057290681719L;
	
	public String name;
	public String sex;
	public int age;
	public int size;
	public int eyes;
	public int hair;
	public int skin;
	
	public RPCharacter() {
		name = "";
		sex = "Homme";
		age = 25;
		size = 175;
		eyes = 0;
		hair = 0;
		skin = 0;
	}
	
}


Le résultat donne le rendu suivant :


LZxzrc9.png

 

Percevez-vous maintenant la puissance du GridBagLayout? Et ce n'est pas grand chose, il peut faire bien mieux !
Alors qu'avez-vous pensé de ce TP? N'hésitez pas à m'envoyer vos avis ou à les poster en commentaire ! ;)

 

Vous pouvez télécharger le JAR exécutable ici si vous voulez tester. Le fichier de sauvegarde sera localisé dans le dossier courant. (Le même dossier où se situe le JAR)

 

 

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

Beaucoup de temps s'est écoulé depuis votre dernier véritable TP. Alors prenez bien votre temps, repensez à tout ce que vous avez appris, relisez les cours si besoin et n'hésitez pas à me demander de l'aide! En effet je vais vous en demander beaucoup pour ce TP. Il va falloir vous investir, car il n'y a que comme ça que l'on progresse !

 

Vous allez avoir besoin des notions suivantes:

  • Les boucles
  • La communication avec l'utilisateur
  • Les méthodes
  • L'utilisation de plusieurs classes et packages
  • L'héritage et l'abstraction
  • Les exceptions
  • Les autres notions déjà connues pour le premier TP


Oui, c'est presque tout ce que nous avons vu depuis le dernier TP, je vous avais prévenu! ^_^
Ne vous découragez pas, vous vous passerez peut-être de certaines de ces notions, mais si vous voulez faire du mieux possible, ce que je souhaite le plus, il faudra tout utiliser !
 

Sans plus tarder, voici votre cahier des charges :
 
Votre programme est une application console (et oui je ne vais pas vous demander de me sortir une interface graphique alors que je ne vous ai pas encore appris à en faire! :P ). Cette application sera un logiciel de gestion de zoo. Elle devra être capable de:

  • Consulter la liste des espèces d'animaux présents dans le zoo, par catégorie (Félin, reptile, amphibien, etc...), ou indifféremment.
  • Consulter la fiche de chaque espèce d'animal (ne vous embêtez pas à mettre plein d'animaux, contentez-vous de 5 ou 6 ce sera déjà très bien!)
  • Ces fiches devront recenser les informations suivantes:
    • Régime de l'animal
    • Cri de l'animal
    • Le mode de déplacement de l'animal
    • Le type de reproduction
    • La taille approximative de l'animal
    • La durée de vie approximative de l'animal
    • (Ces valeurs ne doivent pas obligatoirement être exacte, ce serait aussi un travail de recherche documentaire que je vous demanderais sinon! ^_^ Mettez des valeurs au hasard, ça fonctionnera de la même façon!)
  • Point de vue technique maintenant, votre programme devra être hiérarchisé à l'aide de l'héritage et organisé à l'aide de packages.
  • Il devra gérer les exceptions, en renvoyant à l'utilisateur un message d'erreur plus commode qu'une stacktrace. Si le cœur vous en dit, vous pouvez même ajouter vos propres exceptions ! ;)


Pour un tel projet, il ne faut surtout pas se jeter la tête la première! Propulsez-vous à un mètre de votre clavier et réfléchissez à comment vous allez vous y prendre. Notez vos idées sur un papier, prenez en compte tous les éléments donnés. Si vous le souhaitez, je vous invite même à faire des diagrammes UML de votre projet! Pour cela, vous pouvez utiliser le logiciel ArgoUML, qui est très bon en la matière, et en plus de ça, il est entièrement codé en Java !

 


Sur ce, je vous souhaite bonne chance! Travaillez bien! ;)

 

Je vous propose une correction à télécharger. Vous pouvez importer le projet dans Eclipse et tester. ;)

 

 

JeremGamer

 


2cp1ED5.pngtNIpRtq.png

SystemGlitch

Nous y voila! Votre premier TP! Il faudra rassembler vos connaissances pour y parvenir, à savoir :

  • Les variables et types primitifs,
  • Les conditions et les opérateurs,
  • Les tableaux.


Votre programme devra savoir faire les choses suivantes :

  1. Un client entre dans le restaurant avec un budget aléatoire compris entre 10€ et 50€.
  2. On lui propose un plat approprié par rapport à son budget et par rapport à la "Carte du Chef".
  3. Cette carte devra comporter deux catégories. Le plat et son prix associé.
  4. Au moins quatre plats devront être proposés. Ne cherchez pas à faire de la haute gastronomie non plus et ne cherchez pas un bon rapport qualité/prix car nous ne sommes pas là pour ça ! Si l'envie vous chante, vous pouvez mettre un steak haché frites à 50€ !


Ne vous inquiétez pas, je vous guiderais un peu !

 


Tout d'abord, quelques petites choses plutôt utiles sont à savoir:

 

Premièrement, pour générer un nombre aléatoire, il vous faudra faire comme suit :

Random rand = new Random();
int budget = rand.nextInt((Max - Min) + 1) + Min;
//Ici Max sera 50 et Min sera 10.


Deuxièmement, nous sommes dans le milieu du business ! Nous allons donc faire en sorte de prendre le prix du plat en prenant le prix le plus proche du budget du client, le plus élevé si possible. Il faut bien que les affaires tournent n'est-ce-pas?

 


Pour finir, il faut toujours penser avant d'agir! Réfléchissez bien à comment vous allez vous y prendre. Notez vos idées sur un papier ou un fichier texte et une fois que vous vous sentez prêt, allez-y ! Prenez votre temps, vous n'êtes pas chronométrés! Essayez de bien vous souvenir de toutes les petites astuces que l'on vous a donné jusque là.

 

Une dernière chose, sachez que ce TP repose en quasi totalité sur votre réflexion. Le code à effectuer est assez simple, il suffit juste de trouver le concept ! Encore une fois, prenez bien le temps de réfléchir, c'est la clef du succès de n'importe quel projet ! Si vous avez des questions pertinentes, de grosses difficultés ou bien fini votre TP, nous vous encourageons à nous contacter par message privé! Nous vous aiderons si besoin.

 

Maintenant, fini de rigoler, préparez vos neurones et vos claviers, c'est parti !

 

 

 

 

 

 

 

 

__________________________

 

 

 

 

 

Correction

 

 


Quand vous aurez terminé, prenez bien le temps de tester votre programme et de voir s'il est fonctionnel. Si c'est le cas, félicitations ! Vous êtes sur une excellente voie pour l'apprentissage de ce langage ! Cependant, si vous avez abandonné, ce n'est pas grave! On apprend de ses échecs. La correction est là pour ça ! Jetez-y donc un œil ! ;)

 

 

Spoiler

Le code vous sera directement donné à chaque correction de TP. Essayez de le comprendre et ensuite, lisez les informations se trouvant en dessous. Elles détaillerons ce que nous faisons et comment nous le faisons.

 

import java.util.Random;
 
public class Main {
	
	public static void main(String args[]) {
		
		final int PLAT_1 = 8;
		final int PLAT_2 = 15;
		final int PLAT_3 = 25;
		final int PLAT_4 = 45;

		String menu[] = {"Steak haché frites" ,
				 "Cordon bleu et petits poids" ,
				 "Poulet rôti et haricots verts" ,
				 "Magret de canard et écrasé de pommes de terre"
		};
		
		Random rand = new Random();
		int budget = rand.nextInt((50 - 10) + 1) + 10;
		
		System.out.println("Un client rentre dans le restaurant.");
		System.out.println("Il possède " + budget + "€.");
		
		if (budget < PLAT_2) {
			System.out.println("Le serveur lui propose le " + menu[0] + ".");
		} else if (budget < PLAT_3) {
			System.out.println("Le serveur lui propose le " + menu[1] + ".");
		} else if (budget < PLAT_4) {
			System.out.println("Le serveur lui propose le " + menu[2] + ".");
		} else if (budget >= PLAT_4) {
			System.out.println("Le serveur lui propose le " + menu[3] + ".");
		}
		
	}
 
}


Que faisons-nous?

  1. On défini les prix des différents plats à l'aide de constantes.
  2. On écrit le menu grâce à un tableau à une dimension.
  3. On génère aléatoirement la budget du client.
  4. On écrit dans la console que le client entre avec tel montant d'argent.
  5. On teste dans quelle tranche de prix se trouve le budget du client.
  6. On en déduit le plat à proposer et on l'écrit dans la console.


Alors c'était difficile pour un premier TP? ^_^

 

 


JeremGamer

 


2cp1ED5.pngtNIpRtq.png

SystemGlitch

Bonjour à toutes et tous,

 

Lors du passage à la dernière version d'IPBoard il y a quelques mois, il y a eu un problème avec les balises codes et le format en général dans les blogs. Parmi ces problèmes, on peut retrouver la perte de police, ou les retours à la ligne dans les balises code. Cela rendait les cours parfaitement illisibles.

 

J'ai récemment reformaté l'intégralité des cours, des TPs et des Hors-série pour qu'ils soient de nouveau lisibles ! :) Cela a pris beaucoup de temps mais je pense que cela en vaut la peine.

 

Si vous n'avez pas encore commencé votre aventure dans le monde de Java, c'est le moment !

 

Votre prof de Java préféré,

JeremGamer

SystemGlitch

blog-0469592001437294857.png

Vous possédez un Raspberry Pi et vous souhaitez en faire un peu plus qu'un simple media-center? Il est tant de s'amuser un peu! Nous allons programmer notre Raspberry Pi en Java et le faire interagir avec le monde réel à l'aide de capteurs et de dipôles.

Notre projet sera le suivant: nous souhaitons allumer une LED lorsqu'un capteur détecte un mouvement, en passant par le logiciel afin de pouvoir étendre les perspectives d'évolution du prototype. :)

 

Cette vidéo que j'ai réalisée illustre le résultat final :

 

 

Je tiens à préciser que je considèrerai que vous disposez de connaissances basiques en électricité ainsi que de tout ce que je vous ai appris sur le Java jusque là. ;)

 

Matériel :

 

  • Un Raspberry Pi, de n'importe quel modèle. Ici j'utilise le modèle 2 B, le plus récent.
  • Tout ce qu'il vous faut pour le faire fonctionner pour une utilisation basique, à savoir:
    • Un câble d'alimentation 5V 2A
    • Un écran
    • Un clavier
    • Une souris
    • Un dongle Wifi (ou un câble Ethernet, nous aurons besoin d'une connexion internet)
    • Une carte Micro-SD avec Raspbian installé dessus
  • 3 câbles de montage femelle/femelle

  • 2 câbles de montage mâle/femelle

  • 1 câble de montage mâle/mâle

  • Une résistance 270Ω

  • Une LED

  • Un capteur PIR (de mouvement)

  • Une breadboard pour tout assembler

 

 

Vous pourrez trouver tout ce matériel sur le site ModMyPi pour des prix raisonnables et une livraison rapide. ;) Même si vous ne faites pas le montage de vos mains, rien ne vous empêche de quand même suivre ce chapitre. :lol:

 

Pour commencer, nous allons installer Java sur la machine. Ouvrez un terminal depuis votre Raspberry Pi (en considérant que vous le faites tourner sous Raspbian) et tapez la commande suivante, en vous assurant au préalable de bien être connecté à internet :

sudo apt-get update && sudo apt-get install oracle-java7-jdk

 

En attendant que tout cela s'installe, lancez Eclipse, nous allons préparer notre projet.

Nous aurons besoin de l'API Pi4J. Créer un nouveau projet et ajoutez l'API fraichement téléchargée au Build Path. Tout est prêt, passons désormais à la partie qui vous est la plus étrangère: le montage.

 

Tout d'abord, il faut savoir quelques petites choses. Le Raspberry Pi 2 B est doté de 40 broches dont 26 GPIOs (General Purpose Input/Output). Nous utiliserons ces broches pour connecter nos capteurs et dipôles. Nous ne pourrons pas utiliser certaines de ces broches, ces dernières sont prévues pour d'autres utilisations. Cependant attention, il faut brancher les choses là où il faut! Certaines broches ne sont pas des GPIOs comme je l'ai dis juste au dessus. Certaines délivreront simplement une tension (3.3V ou 5V), d'autres ne délivreront rien (on les appelle Ground, pour fermer le circuit électrique). Chaque GPIO peut être utilisé soit en entrée, soit en sortie, comme son nom l'indique. Le principe est simple, comme dans un ordinateur classique, le Raspberry interprètera la tension qui se trouve dans les câbles quand il s'agit d'une entrée, et la fera changer lorsqu'il s'agit d'une sortie. Tout cela sera géré par votre code! N'est-ce pas fabuleux? ^_^

Comment savoir quelle broche porte quel numéro? Encore une fois, la documentation est là pour nous sauver la vie !

ZxTsV62.png

Nous voila mieux renseignés ! Cependant il reste un problème en suspens... Comment savoir de quel côté commencer à compter? Cette fois c'est le site du constructeur qui nous sauve ! Il faut avoir les bons réflexes quand on ne sait pas quelque chose! ;) Mais vu que je le sais, je vous le dis, ce serait égoïste sinon. :lol:

La broche n°1 (délivrant du 3.3V, le carré orange sur l'image ci-dessus) est la broche la plus proche du port pour carte Micro-SD sur le Raspberry. C'est à dire la broche à l'extrême opposé des ports USB et vers l'intérieur de la carte. Vous voyez de laquelle il s'agit? Très bien, passons à la suite ! :P

 

Le montage de la LED sera effectué sur la breadboard. J'imagine que vous ne savez pas de quoi il s'agit, et encore moins comment ça fonctionne ! C'est normal, pas de panique, c'est vraiment très simple. ;)

 

Voici une illustration qui devrait beaucoup vous aider à comprendre le principe. (Source: sparkfun.com)

a3ahdje.jpg

A gauche, la breadboard telle que vous la voyez, et à droite, on lui a retiré son cache en plastique. Vous pouvez donc facilement voir les zones conductrices et celles qui sont reliées entre elles ou non. Les flèches rouges pointes les rails d'alimentation. Vous brancherez les câbles directement reliés à l'alimentation (les broches 1, 2, 4 et 17) sur le rail + et le câble fermant le circuit sur le rail -, pour ensuite relier ce rail vers une broche Ground sur le Raspberry. Au centre, on a donc toutes les lignes, pas besoin de vous expliquer comment circule le courant électrique! Cependant je tiens quand même à préciser que les branchements devront donc s'effectuer d'une certain manière afin de ne pas générer de court-circuit! Cette image l'illustre très bien: (Source: pbworks.com)

NqU2Ldo.gif

Dernière chose: ces planches sont extrêmement pratiques car elles nous permettent de faire des montages sans avoir de faire quelque soudure que ce soit! De plus, on peut facilement revenir en arrière si on s'est trompé, ou si on veut rajouter quelque chose. :D

 

Voila vous savez désormais vous servir d'une breadboard ! ;)

Intéressons-nous maintenant à notre montage! Voici à quoi il devrait ressembler :

2k1O67e.jpg

cWA1exT.jpg

BqVSDY5.jpg

 

Nous connectons le capteur (à droite) directement sur les broches sans passer par la breadboard; cela ne servirait à rien à part utiliser des câbles supplémentaires. De plus, vu la taille du montage, nous ne sommes pas restreints en broches. ^_^ J'ai soigneusement choisi la couleur des câbles afin de bien s'y retrouver.

En noir, il s'agit des câbles reliés aux broches Ground; en rouge, il s'agit des câbles reliés à l'alimentation; le câble jaune est le câble à connecter sur un GPIO afin que le capteur puisse communiquer avec le Raspberry; et le câble bleu est la fermeture du circuit sur le rail - de la breadboard.

 

Histoire de rende ça plus lisible pour vous, voici une version schématisée du montage : ;)

 

BsD9J8h.png

 

La broche 2 fournira une tension de 5V au capteur PIR, on refermera ce premier petit circuit sur la broche 6 Ground. Le câble jaune pour communiquer avec le Raspberry sera branché sur le GPIO 22, qui se trouve être la broche 31! Attention à cela! Pour bien effectuer le branchement de votre capteur, voici une photo qui devrait vous aider. Il serait dommage de griller votre capteur tout neuf... -_-

 

vJG06xC.jpg

 

Occupons nous désormais du second circuit: celui de la LED. Branchons un câble femelle/mâle sur le GPIO 26, sur la broche 32, juste en face du câble jaune. De l'autre côté, on le branchera sur la breadboard dans la colonne 'a'. Sur la même ligne, branchez la résistance. Cette dernière protège la LED, qui sera régulièrement allumée puis éteinte. Cela risquerait de la griller assez rapidement si l'on ne mettait pas de résistance. Le deuxième pôle de la résistance ira se brancher dans la même colonne mais quatre lignes plus loin. Place à LED désormais. La patte la plus longue (pôle +) ira se brancher sur la même ligne que le pôle - de la résistance. Quand à l'autre, on le branchera sur la ligne juste à côté comme montré sur le schéma. Finissons avec un câble mâle/mâle qui reliera cette dernière ligne au rail -. Plus qu'à ajouter le câble qui refermera le circuit sur le Raspberry sur la broche 6 Ground. Le montage est prêt ! :D

 

Le code :

 

Vous attendiez surement ce moment. Cela vous paraitra d'une simplicité déconcertante vous verrez. ;)

Pour commencer, il faut initialiser et paramétrer tout ça. Créons trois variables d'instance que nous initialiserons dans une méthode :

 
private GpioController gpio;
private GpioPinDigitalInput sensor;
private GpioPinDigitalOutput led;

private void initGPIOs() {
	System.out.println("Initializing GPIOs...");
	gpio = GpioFactory.getInstance();
	led = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_26); //La led est branchée en sortie sur le GPIO 26 (câble rouge de gauche)		

	sensor = gpio.provisionDigitalInputPin(RaspiPin.GPIO_22 , PinPullResistance.PULL_DOWN); //Le capteur est branché en entrée sur le GPIO 22 (câble jaune)
}

 

Voila qui est fait ! ^_^ Mais il manque quelque chose. Comment récupérer les informations venant du capteur? :lol:

Figurez-vous que c'est bien fait! On a tout à notre disposition dans cette formidable API ! :P Nous allons utiliser un event.

sensor.addListener(new GpioPinListenerDigital() { //On utilise un event plutôt qu'une boucle while, c'est bien plus optimisé
 
	@Override
	public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent e) {
		//...
	}
});

 

Nous sommes presque prêts. Créons une petite méthode supplémentaire afin de gérer cela. Il faut savoir que le capteur peut également envoyer un signal pour dire qu'il ne voit pas de mouvement ! Ce qui nous permettra d'éteindre la LED. En réalité, le capteur scanne périodiquement son champ de vision et augmente la tension dans le câble lorsqu'il voit quelque chose. L'event sera alors déclenché assez régulièrement.

private void handleSensorInput(final GpioPinDigitalOutput led, final GpioPinDigitalStateChangeEvent event) {
	if(event.getState().isHigh()) { //Si la tension dans le câble jaune est élevée -> Mouvement détecté par le capteur
		System.out.println("Motion detected");
		led.high(); //On allume la LED en augmentant la tension dans le câble
	} else { //Si la tension dans le câble jaune est faible -> Pas de mouvement
		led.low(); //On éteint la LED en retirant la tension dans le câble
	}
}

 

Je pense qu'il n'y a pas besoin de vous expliquer d'avantage ce code d'un simplicité enfantine. ;)

 

Dernière chose, il faut penser à tout bien faire correctement. Alors pensez à appeler cette méthode lorsque votre logiciel se termine afin de libérer les GPIOs. ^_^

public void shutdown() {
	led.low(); //Au cas où le logiciel soit terminé alors qu'un mouvement est détecté, la LED resterait allumée à l'infini sinon
	gpio.shutdown();
}

 

Le code complet nous donnera quelque chose qui ressemble à cela :

 
private GpioController gpio;
private GpioPinDigitalInput sensor;
private GpioPinDigitalOutput led;
	
private void initGPIOs() {
	System.out.println("Initializing GPIOs...");
	gpio = GpioFactory.getInstance();
	led = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_26); //La led est branchée en sortie sur le pin 26 (câble rouge de gauche sur la vidéo)		
 
	sensor = gpio.provisionDigitalInputPin(RaspiPin.GPIO_22 , PinPullResistance.PULL_DOWN); //Le capteur est branché en entrée sur le pin 22 (câble jaune sur la vidéo)
	sensor.addListener(new GpioPinListenerDigital() { //On utilise un event plutôt qu'une boucle while, c'est bien plus optimisé

		@Override
		public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent e) {
			handleSensorInput(led, e);
		}

	});
}
 
private void handleSensorInput(final GpioPinDigitalOutput led, final GpioPinDigitalStateChangeEvent event) {
	if(event.getState().isHigh()) { //Si la tension dans le câble jaune est élevée -> Mouvement détecté par le capteur
		System.out.println("Motion detected");
		led.high(); //On allume la LED en augmentant la tension dans le câble
	} else { //Si la tension dans le câble jaune est faible -> Pas de mouvement
		led.low(); //On éteint la LED en retirant la tension dans le câble
	}
}
	
public void shutdown() {
	led.low(); //Au cas où le logiciel soit terminé alors qu'un mouvement est détecté, la LED resterait allumée à l'infini sinon
	gpio.shutdown();
}

 

Exportez votre projet dans un Runnable Jar file et stockez-le dans votre Raspberry.

Ouvrez un terminal depuis ce dernier et tapez la commande suivante, en adaptant le nom du Jar ainsi que son chemin :

java -jar /home/pi/Desktop/BukkitPi.jar

 

Cela lancera votre programme! Vous pourrez commencer à tester !

Hum le plaisir aura été de courte durée... <_< Le capteur ne semble pas très bien fonctionner... -_-

Il n'est pas calibré. Vous avez vraiment de la chance de m'avoir ! :lol: Moi qui ai passé bien une heure à la calibrer...

 

Bref, vous avez sans doute remarqué deux petites bornes oranges sur votre capteur. A l'aide d'un petit tournevis, vous pouvez les tourner afin de calibrer le capteur par rapport à vos besoins. L'un modifie la sensibilité, l'autre le délai entre chaque balayage. Terminez votre programme avant de modifier cela, il semblerait que cela fonctionne mieux, pour une raison que je ne saurais expliquer. :lol: Voici mes réglages (faites bien attentions aux repères, il serait dommage d'inverser les deux bornes ^_^ ) :

 

OZpzeoA.jpg

 

Et voila ! Vous pouvez relancer votre programme ! Vous avez réalisé votre premier capteur de mouvement intelligent avec votre Raspberry Pi ! B)

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0205500001431879071.png

Ce hors-série sera dédié à l'utilisation de votre IDE, mais aussi d'un autre logiciel. Nous allons voir comment exporter votre projet et le rendre utilisable par n'importe qui, qui aurait Java installé sur sa machine.

 

Vous allez me dire que ce chapitre sera extrêmement court. Certes, mais je ne vais pas simplement vous expliquer qu'en trois clics votre programme sera compilé et utilisable! Nous verrons également comment générer des fichiers exécutable (".exe") pour Windows.

 

Commençons par l'export "classique". Nous allons compiler notre code, ainsi il ne sera plus lisible par l'humain mais par la machine. Avec Eclipse, rien de plus simple! Cliquez-droit sur votre projet et choisissez "Export". Dans la boite de dialogue qui s'ouvrira, ouvrez "Java", sélectionnez "Runnable Jar File" et cliquez sur "Next".

 

1JbA6nO.png

 

Vérifiez bien que "Launch Configuration" est bien réglé sur la configuration de votre programme, puis choisissez l'emplacement pour l'export. Dans "Library handling", je vous conseille de cocher "Extract required librairies into generated JAR". Cliquez sur "Finish". Voila! Votre programme est compilé!

Si votre programme a une interface graphique, rien d'autre à faire, cependant nous n'avons pas encore vu comment faire, mais n'ayez crainte, ça ne saurait tarder ;)

Cependant, si votre programme tourne sur console, comme nous le faisons jusque là, il y a une étape en plus.

Rendez-vous dans le dossier où se trouve le jar que vous venez d'exporter.

Si vous tentez de lancer votre programme, vous constaterez que rien ne se passe. Nous allons devoir l'ouvrir grâce à un petit script variant en fonction de votre système d'exploitation.

 

Windows :

 

Créez un fichier texte dans le même dossier que votre jar et modifiez l'extension de telle sorte à ce que votre fichier soit un fichier "bat" tel que "Run.bat".

Éditez ensuite ce fichier et écrivez-y les lignes suivantes :

@echo off
java -jar NomDuJar.jar
PAUSE

 

Linux :

 

Procédez de la même manière, mais avec un fichier en ".sh". Écrivez-y ceci :

#!/bin/bash
cd -P $(dirname $0)
java -jar ./NomDuJar.jar

 

Puis dans un terminal, tapez la commande suivante pour lancer votre programme :

cd 'chemin du dossier'

//puis

chmod +x NomDuJar.jar run.sh

 

MacOS X :

 

Créez également un fichier tel que son extension soit ".command" et autorisez son script à se lancer.

Insérez-y ceci :

cd "$( dirname "$0" )"
java -jar ./NomDuJar.jar

 

Ouvrez L'application Terminal et tapez "chmod +x " (n'oubliez pas l'espace à la fin) puis glissez le fichier que vous venez de créer dans le Terminal. Appuyez sur "Entrée" et fermez le Terminal. Vous n'avez plus qu'a double-cliquer sur votre fichier en ".command" pour lancer votre programme!

 

Voyons désormais comment créer des fichier exécutables pour Windows! Cela vous plaira surement! Sachez tout de même que cela ne fonctionnera qu'avec des programmes dotés d'une interface graphique. Commencez par compiler votre programme comme expliqué ci-dessus.

Nous aurons ensuite besoin du logiciel Launch4J que vous pouvez télécharger ici. Une fois le logiciel installé, lancez-le.

 

V8gDnru.png

 

De nombreuses options s'offrent à vous. Nous allons voir pas-à-pas les plus importantes.

 

Tout d'abord, à la première ligne, sélectionnez le chemin où sera créé votre fichier exécutable. A la seconde ligne, spécifiez l'emplacement du jar de votre programme.

La prochaine ligne qui nous intéressera sera la ligne "Icon" qui nous permettra de définir une icône pour notre fichier. Votre icône devra obligatoirement être un fichier ".ico" d'une taille de 64 par 64 pixels.

 

Rendez-vous maintenant dans l'onglet "Version Info". Je pense que vous n'avez pas besoin de mon aide pour remplir les champs proposés. Cette partie n'est pas obligatoire mais il est préférable de la remplir afin de renseigner au mieux les futurs utilisateurs.

 

Je vous laisse explorer par vous-même les autres options. ;)

 

Cliquez sur la disquette dans la barre en haut de la fenêtre pour sauvegarder votre configuration puis cliquez sur l'engrenage situé juste à côté afin de générer votre exécutable. Vérifiez que tout c'est bien passé dans la console en bas de la fenêtre.

Si tout c'est bien passé, alors vous aurez créé votre premier ".exe" !

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0250611001431874385.png

Aujourd'hui, au lieu continuer sur notre lancée sur les classes, nous allons nous arrêter un moment et nous intéresser aux Strings. Ces chaines de caractères ne sont pas si simple que ça à manipuler! Alors voici quelques astuces! ;)

 

Nous allons donc faire un petit tour de ce que l'API Java nous propose.

 

Commençons par la recherche dans un String. Vous souhaitez trouver un caractère en particulier (le récupérer sous forme de char). Si vous savez à quel index vous devez chercher, alors on utilisera la méthode "charAt(int)". L'index, c'est le numéro de caractère, au même titre qu'un index dans les tableaux. Attention le premier caractère est à l'index 0! (Vous pouvez récupérer le nombre total d'index à l'aide de la méthode "length()" qui retournera un int)

String s = "Une chaine de caractères";
char c = s.charAt(5);
System.out.println(c);

 

Votre programme vous affichera 'h' ! Si vous essayez de récupérer l'index 3, vous constaterez que rien ne s'affiche dans la console. C'est parce que vous avez récupéré un espace.

 

Maintenant vous voulez savoir à quels index se trouvent tous les 'e'.

Nous allons tout d'abord lire le String caractère par caractère puis ajouter les index auxquels nous avons trouvé des 'e'. Pour finir nous afficherons tous les index que l'on cherchait dans la console.

String s = "Une chaine de caractères";
ArrayList<Integer> index = new ArrayList<Integer>();
for(int i = 0 ; i < s.length() ; i++) {
	if(s.charAt(i) == 'e') {
		index.add(i);
	}
}
System.out.println("Les \'e\' dans ce String se trouvent aux index suivants:");
for(int i : index) {
	System.out.println(i);
}

 

Le résultat donne la figure suivante :

Les 'e' dans ce String se trouvent aux index suivants:
2
9
12
22

 

Il est également possible, d'une manière plus simple, de trouver l'index du premier caractère correspondant trouvé.

Cette méthode fonctionne aussi avec une chaine de caractères.

System.out.println( s.indexOf("ne") );

 

Il est possible de donner un index comme point de départ. Ajoutez un argument de type int, il représentera l'index à partir duquel votre programme commencera les recherches.

System.out.println( s.indexOf("ne" , 4) ); //Le programme commencera à chercher à l'index 4

 

Grâce à la méthode "lastIndexOf(char/String)", vous pouvez également récupérer l'index du dernier caractère ou de la dernière chaine de caractère correspondante.

 

 

Vous souhaitez savoir si un String contient ou non un caractère ou une suite de caractères précise.

Rien de plus simple !

 
System.out.println( s.contains("bla") );

 

La méthode "contains(CharSequence)" vous retournera un boolean.

 

Vous pouvez également tester si un String commence ou termine par une certaine chaine de caractère avec les méthodes "startsWith(CharSequence)" et "endsWith(CharSequence)". Ces deux méthodes vous retournerons également des boolean.

System.out.println( s.startsWith("Une") );
System.out.println( s.endsWith("ères") );

 

Vous pouvez également définir un point de départ pour la recherche avec la méthode "startsWith(CharSequence)" comme pour la méthode "indexOf(int)"!

 

Enfin pour tester une égalité, n'utilisez pas l'opérateur "==" mais la méthode "equals(String)". La méthode "equalsIgnoreCase(String)" propose la même fonctionnalité mais ne prend pas en compte les majuscules.

s.equalsIgnoreCase("UNE CHAINE de caractèRES") //retournera true

 

Vous savez désormais fouiller dans un String. Maintenant voyons comment les modifier.

 

Avant de commencer à faire le tour des méthodes disponibles à ce sujet, j'aimerais insister sur un point: Certains caractères ne sont pas acceptés dans les Strings: " , ' , \ , les retours à la ligne et les tabulations.

Alors voici comment faire :

String s = "pour écrire \" il faut mettre un antislash";
String s2 = "pour écrire \' il faut mettre un antislash qui s'écrit ainsi: \\";
String s3 = "une tabulation ---> \t";
String s4 = "retour à la ligne \n et voila!";

 

A l'aide des antislash vous pouvez aussi utiliser les caractères ASCII en unicode :

String s = "un accent grave: \u00e8";

 

Pour tous les connaître vous pouvez vous référer à ce site. ;)

 

Passons aux choses sérieuses! Pensez à une chose, utiliser la méthode sans assigner son retour à une autre variable ou à la variable source, c'est perdre les modifications! (Voir l'exemple juste en dessous)

Il est possible de facilement mettre tous les caractères en majuscule ou en minuscule :

 
String up = s.toUpperCase(); //Met tout en majuscules
String low = s.toLowerCase(); //Met tout en minuscules

 

Remplaçons une partie de ce String par une autre.

Nous utiliserons la méthode "replaceAll(String , String)" ou "replace(String , String)". Le premier argument sera ce que l'on cherche à remplacer et le second sera par quoi on le remplacera. (Fonctionne aussi avec des char)

String replaced = s.replaceAll("e" , "beuh"); //On remplacera ici tous les "e" par des "beuh"

 

Il est possible de juste remplacer la première correspondance :

String replaced = s.replaceFirst("e" , "beuh");

 

Nous allons maintenant "découper" un String en plusieurs afin d'avoir un tableau. Dans l'exemple qui suit nous récupérerons tous les mots.

String[] mots = s.split(" ");

 

Votre String est découpée et votre tableau comporte chacune de ses parties, sans les espaces. Sachez qu'en utilisant cette méthode, les caractères coupés ne seront pas comptés. Dans votre tableau, il n'y aura aucun espace!

 

Il nous reste une méthode à voir, la plus compliquée à comprendre, j'ai nommé "substring(int , int) / substring(int)"!

Cette méthode vous permet de récupérer une partie d'un String. Le premier argument définit l'index auquel on commencera à couper et le second l'index on on s’arrêtera.

 
String sub = s.substring(4 , 8); //Ici on récupère le contenu à partir de l'index 4 jusqu'a l'index 8. Ce qui donnera "chai".

 

Si vous ne mettez qu'un seul argument, alors votre programme récupérera le bout de String depuis l'index spécifié jusqu’à là fin.

String s = "Une chaine de caractères";
String sub = s.substring(4 , 8);
String sub2 = s.substring(4); //revient au même que s.substring(4 , s.length());
System.out.println(sub);
System.out.println(sub2);

 

Ce code donnera le résultat suivant :

chai
chaine de caractères

 

Une dernière chose, il est possible d'appeler une méthode de la classe String sans avoir besoin d'initialiser une variable !

"Une chaine de caractères".toLowerCase();

 

Voila vous savez l'essentiel sur les Strings! Je vous propose donc un petit TP sur la manipulation de String. Votre programme doit être capable de trouver la chaine de caractères contenu entre les balises ":SEARCH:" dans cette page web.

Voici quand même une petite aide. ^_^

 

Pour récupérer le code source d'une page web, vous devrez faire ceci :

 
URL u = new URL(ADRESSE); 
InputStream is = u.openStream();
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
String s;

 

Ensuite vous pourrez lire une à une les lignes de la page avec une boucle while :

while ((s = dis.readLine()) != null) {...}

 

Voila voila ! Bonne chance à tous ! ;) N'oubliez pas de me joindre si vous avez besoin d'aide ! :) Je vous invite aussi à m'envoyer en MP vos travaux une fois finis !

 

Correction :

 

Spoiler

 

 

public static void main(String[] args) {
	try {
		URL u = new URL("https://github.com/JeremGamer/FRBukkitTutorials/blob/master/README.md");
		InputStream is = u.openStream();
		DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
		String s;
		String toFind;

		while ((s = dis.readLine()) != null) {
			if (s.contains(":SEARCH:")) {
				toFind = s.substring(s.indexOf(":SEARCH:") , s.lastIndexOf(":SEARCH:"));
				toFind = toFind.substring(":SEARCH:".length());
				System.out.println("Trouvé: " + toFind);
				break;
			}
		}
	} catch (IOException e) {
		e.printStackTrace();
	}		
}

 

 

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

Jackblue

blog-0778262001447837675.png

Salut,

 

J'ai vu que certains était intéressé par Forge dernièrement, ayant pas mal bossé avec, je ne pense pas faire une série de tutoriel car ça serai plutôt long et l’intérêt serai assez faible, vu le nombre de ressource déjà disponible mais peu exploité, et c'est avant tout du modding, donc un certains investissement et une qualité de recherche est nécessaire, bien que quelques bons tuyaux est appréciable c'est pourquoi je fais ce post aujourd'hui :)

 

Et cela resssemble plus à un recueil de sites/blog vraiment intéressant pour ceux qui veulent s'y mettre et comprendre un peu mieux le fonctionnement global de Minecraft, c'est assez riche en enseignement cependant il vous faut vraiment connaître le Java, se lancer dans le modding sans rien connaître du Java est une énorme perte de temps ;)

 

Vous pouvez déjà faire un tour sur la page de Download en cliquant sur le logo ci-dessous, afin de télécharger le package universal afin de développer votre mod.

 

 

ptiy1lQ.png?1

 

Et faire un petit tour sur les tutos de bases du wiki :

http://www.minecraftforge.net/wiki/Category:Generic_Mod

 

On continue avec le blog de wuppy29, qui est un modder qui tient depuis déjà un bon moment un blog avec les bases du modding sous Forge: http://www.wuppy29.com/minecraft/modding-tutorials/forge-modding/

 

Ensuite il y'a le site français minecraftforgefrance.fr qui peut vous apportez des informations sur ce que vous recherchez, leur tutoriel ne sont pas encore mis à jour en 1.8 mais ça reste intéressant de jeter un coup d'oeil:

http://www.minecraftforgefrance.fr/showthread.php?tid=16

 

Le blog de TheGreyGhost est pour moi une référence, car il traite de façon abstraite (peu de code, mais pas mal d'explication) les concept de Minecraft et c'est une vraie mine d'or si vous prenez le temps de lire et de comprendre ses articles: http://greyminecraftcoder.blogspot.fr/p/list-of-topics.html

 

Le blog de Jabelar, lui proposera des articles avec des cas concrets et du code complet, peut être plus rassurant pour les débutants, lui aussi très riche en enseignement : http://jabelarminecraft.blogspot.fr/

 

Le blog de CoolAlias propose des tutos un peu plus avancé, peut être plus vraiment à jour, surement quelques nom de méthode à changer ou d'objet différent mais l'esprit est là: http://www.minecraftforge.net/wiki/CoolAliasTutorials

 

Il y'a deux autres blogs intéressants mais que je n'ai personnellement pas utilisé mais qui peuvent être intéressant de faire un tour:

- Bedrockminer : http://bedrockminer.jimdo.com/modding-tutorials/

- TheXFactor117 : http://www.minecraftforum.net/forums/mapping-and-modding/mapping-and-modding-tutorials/2282788-1-7-1-8-thexfactor117s-forge-modding-tutorials-20

 

Voilà pour la liste exhaustive des blogs incontournables si vous voulez vous lancez dans le modding sous Forge, avec en plus l'arrivé prochaine de Sponge. Je rajouterai que Forge permet de faire des mods assez facilement si vous vous contentez des bases mais demandera un bien meilleur niveau dés que vous voudrez changé certains éléments de Minecraft, et donc tout comme le NMS vous serrez amenez à utilisé de la reflection, ou les Access transformer (aussi appelé ASM byte manipulation) utilisé par Forge pour changer l'accessibilité de certaines variables.

 

C'est tout pour ce petit hors-série sur Forge afin de bien débuté avec, et Vendredi nouveau chapitre sur la série Spigot !

 

Jackblue

SystemGlitch

blog-0724736001431873040.png

Jusque là vous travaillez sur une classe sans vraiment savoir ce que c'est. Nous allons y remédier !

Ce chapitre sera chargé en vocabulaire ! Il faudra bien le connaître !

 

Tout d'abord, désolé de me répéter, vous avez travaillé jusque là avec une seule classe, or en programmation orientée objet, vous allez en utiliser une multitude! Les perspicaces auront alors deviné ce qu'est un objet, terme que j'utilise déjà depuis un certain temps.

 

Grossièrement, un objet est une variable non primitive telle les String. Et oui les String sont des objets, bien qu'ils soient un peu à part, vous allez voir pourquoi.

Les objets sont donc des classes que nous avons instancié. Nous reviendrons là-dessus dans quelques instants. Avant ça décrivons un peu la structure d'une classe.

 
class Main { //Déclaration de la classe avec le mot-clef "class"

     //Variables de classe et d'instance

     Main() { //Constructeur
          //Instructions lors de l'instanciation
     }

     void methode() {
          //Instructions
     }

} //Fin de la classe

 

N'ayez pas peur tout ce vocabulaire va vous être expliqué sous peu ! ^_^

 

Je sais que maintenant vous ne devriez plus avoir trop de difficultés avec les accolades donc je vais passer cette partie.

 

Commençons par les variables de classe.

Les variables de classe sont des variables déclarées en dehors de toute méthode et dont on défini directement la valeur. Ainsi leur valeurs seront initialement les mêmes pour tout objet de cette classe instancié. Ces variables doivent être déclarées static.

 

Les variables d'instance sont déclarées sans valeurs, on les définira dans le constructeur. Ainsi les valeurs de ces variables pourront être différentes pour chaque objet de cette classe instancié.

 

Vous remarquerez que le constructeur est en quelque sorte une méthode mais sans type, il n'est même pas un void ! Le constructeur est la méthode appelée lors de l'instanciation de la classe grâce à l'opérateur new.

 

Avant que tout cela ressorte par vos oreilles, assemblons toutes ces notions car elles sont toutes liées !

Voici un petit exemple de classe :

class Main {

     static int nombre = 5; //Une variable de classe

     int nombre2; //Une variable d'instance

     Main(int n) { //Constructeur
          System.out.println("Instanciation de la classe Main");
          this.nombre2 = n;
     }

     void methode() {
          //Instructions
     }

} //Fin de la classe

 

On instancie donc cette classe de la manière suivante :

Main obj = new Main(2); //La valeur mise en argument peut-être n'importe quel int

 

Quand cette ligne sera lue par l'ordinateur, vous pourrez constater que "Instanciation de la classe Main" s'est écrit dans la console! Le contenu du constructeur s'est bien exécuté lors de l'instanciation de notre objet obj.

 

Vous avez surement remarqué un nouveau mot-clef : this. Il fait référence à l'objet courant. C'est à dire qu'avec lui, on peut accéder à toutes les variables et méthodes de la classe dans laquelle il se trouve à l'aide de l'opérateur ".". Ici on récupère nombre2. Il n'était pas nécessaire de mettre this cette fois-ci car le paramètre porte un autre nom. Imaginez la situation suivante :

     int n;

     Main(int n) { 
          n = n;
     }

 

Comment votre programme sait à quelle variable vous faites référence? C'est là que this devient intéressant ! On rajoute this devant le premier n dans le constructeur et là on sait alors que l'on fait référence à la variable d'instance n et non au paramètre !

 

Ça va vous suivez? :lol: Je sais bien que ce n'est pas évident alors je le rappelle, vous pouvez m'envoyer des MP pour plus d'explications si vous le souhaitez !

 

Petite parenthèse : Les variables internes au constructeur ou aux méthodes sont appelées variables locales.

     Main(int n) { 
          this.n = n;
          int i = 6; //Une variable locale
     }

 

Le ou les constructeurs d'une classe doivent porter le même nom que la classe.

 

Oui j'ai bien dit "les" constructeurs ! De la même manière que les méthodes, il est possible d'avoir plusieurs constructeurs, du moment qu'ils ont des paramètres différents !

class Main {

     Main() {
          System.out.println("Instanciation de la classe Main sans argument");
     }

     Main(int n) {
          System.out.println("Instanciation de la classe Main avec l'argument " + n);
     }

     Main(int n , int j) {
          System.out.println("Instanciation de la classe Main avec les arguments " + n + " et " + j);
     }

}

 

Une telle classe pourrait donc s'instancier de trois manières différentes :

Main obj = new Main();
Main obj2 = new Main(5);
Main obj3 = new Main(7 , 42);

 

Une classe à un constructeur par défaut, qui ne fait rien et qui ne requiert aucun argument. C'est pour cela que faire ceci est inutile :

class Main {

     Main() {}

}

 

Si vous décidez de ne pas mettre de constructeur sans argument, alors il sera impossible d'instancier la classe sans argument.

class Main {

     Main(int i) {
           //Instructions
     }

}

 

Avec une telle classe, il sera impossible de faire ceci :

Main obj = new Main();

 

La seule manière d'instancier cette classe sera alors de spécifier un int en argument.

 

Une classe est aussi un "casier" à méthodes. Les méthodes contenues dans une classe lui sont spécifiques. Il est donc impossible qu'une autre classe les utilise, à moins qu'elle dispose d'une instance de cette classe !

class Main {

     int i = 5;

     void methode() {
          System.out.println("Plop!")
     }

}

 

Notre classe Main ressemble à ça. Pour qu'une autre classe puisse l'utiliser, il faudra instancier la classe Main puis appeler la méthode en passant par l'objet et en utilisant l'opérateur ".". On peut aussi récupérer les variables de cette même classe.

Main obj = new Main();

obj.methode();
int j = obj.i;

 

Il existe un moyen d'utiliser des méthodes issues d'une autre classe sans l'instancier, mais pour cela, il faut que cette méthode soit statique, désignée par le mot-clef static. Ces méthodes ne doivent en aucun cas utiliser des variables d'instances ! Tout simplement car on n'est pas certain que la classe qui la contient à été instanciée !

static void methode() {
      //Instructions
}

 

Cette méthode pourra être appelée de n'importe où à n'importe quel moment !

Attention cependant, l'utilisation des méthodes statiques peut-être dangereuse. Il faut les utiliser que dans des cas précis et ne pas en abuser car ils peuvent énormément fragiliser votre code, ce qui peut causer de nombreuses erreurs et bugs! Il faut donc être bien prudent quand à leur utilisation.

 

Ces méthodes sont essentiellement utilisées pour des actions simples ne faisant pas entrer de facteurs modifiant le fonctionnement du logiciel. Des utilitaires en général. Par exemple on souhaite faire une classe qui permet d'effectuer tout un tas d'actions concernant une liste. (Cette classe est déjà existante dans l'API Java) Toutes ses méthodes seront alors statiques !

 

Les méthodes statiques s'appellent différemment. On met d'abord le nom de la classe d'où elle provient, l'opérateur "." puis le nom de la méthode suivie des arguments.

//Méthode existante, justement pour trier une liste grâce à l'API Java
Collections.sort(list); //La méthode sort est statique et issue de la classe Collections

 

J'allais oublier ! Vous l'avez sûrement déjà oublié donc je vous le rappelle : voici comment créer une classe avec Eclipse :

 

Commencez par faire un clic droit dans l'explorateur à gauche à l'endroit où vous souhaitez créer la classe, puis "New -> Class".

 

E046LwC.png

 

Vous ne savez pas encore tout sur les classes mais je pense que vous avez eu votre dose pour aujourd'hui ! ^_^

 

Nous ferons alors une petite pause avec les classes avant d'entamer des notions complexes qui y sont liées.

Vous pouvez être fiers de vous! Vous en savez beaucoup plus sur le jargon du développeur désormais ! :P

 

Résumé:

 

  • Un objet est une instance d'une classe.
  • On utilise donc une multitude de classes dans la programmation orientée objet.
  • Les variables de classes sont déclarées et définies en dehors de toute méthode.
  • Les variables d'instances sont déclarées en dehors de toute méthode et définies dans le constructeur lors de l'instanciation de la classe.
  • Le constructeur est la méthode exécutée lors de l'instanciation de la classe.
  • Il peut y avoir plusieurs constructeurs du moment qu'ils ont des paramètres différents.
  • Une classe s'instancie à l'aide du mot-clef new.
  • Pour pouvoir utiliser les méthodes d'une classe depuis une autre, on doit utiliser une instance de celle-ci.
  • Les méthodes statiques peuvent être appelées depuis n'importe où et n'importe quand, sans avoir besoin d'instancier la classe qui la contient.
  • Elles sont à utiliser avec précaution !

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0549339001431871409.png

Vous connaissez désormais pas mal de choses à propos du langage et vous êtes de plus en plus autonomes. Vous pouvez déjà faire vos propres programmes console tout seul comme des grands! Alors ce que je vous propose aujourd'hui, c'est d'apprendre à utiliser votre merveilleux IDE afin d'en retirer le meilleur et de parfaire vos projets ainsi que de documenter votre code en le commentant et en l'annotant!

 

Au programme, des astuces en tout genre, des fonctionnalités expliquées en détails et des explications à propos de ces commentaires et annotations! C'est parti!

 

Commençons par les commentaires. C'est tout simplement du texte qui sera ignoré par le compilateur. Il aura alors pour utilité de s'y retrouver dans son code. Au lieu de le relire intégralement et recomprendre ce qu'il fait, il suffit de lire son commentaire! Voici comment ajouter un commentaire:

 
//Un commentaire!

 

Sur Eclispe, les commentaires tels que celui-ci sont affichés en vert. Attention cependant, les commentaires écrits de cette manière ne peuvent prendre qu'une seule ligne! Il existe donc un moyen d'écrire des commentaires sur plusieurs lignes! C'est bien fait n'est-ce pas? ^_^

 
/*votre commentaire
pouvant se trouver sur
plusieurs lignes*/

 

/* et */ agissent comme des "balises". Tout ce qui se trouve entre elles seront mises en commentaire.

 

Maintenant documentons un peu notre code! Késako allez-vous me dire! La documentation, c'est le fait de renseigner ce que fait une méthode, une variable ou une classe ou tout simplement d'y ajouter des informations complémentaires comme la licence qui les accompagne. La documentation est très importante quand votre code devient imposant ou lorsqu'il est utilisé par d'autres personnes que vous. C'est le cas de l'API Java, qui est très bien documentée! Je vous apprendrais bientôt à lire la Javadoc officielle afin de pouvoir vous débrouiller avec n'importe quelle classe de cette vaste API! La syntaxe est la suivante:

 
/**
 * Votre documentation, sur plusieurs lignes 
 * Chaque ligne doit commencer par une astérisque
 * La documentation est au format HTML c'est à dire que ce <b>mot</b> sera en gras!
 */

 

Dans la documentation, il y a ce que l'on appelle les attributs qui renseignent sur de nombreuses choses comme les paramètres s'il s'agit d'une méthode, le type qu'elle retourne, etc... Les attributs commencent par @ et doivent porter un nom bien précis en fonction de ce qu'ils renseignent!

 

Attention il y a un ordre à respecter! Commencez par la description (au format HTML) puis les attributs!

 

Voici un tableau des différents attributs:

 

aHSD36F.png

 

Exemple avec la classe de calculatrice fournie en cadeau dans le chapitre précédent :

 
/**
 * Programme de calculatrice console.
 * @author JeremGamer
 * @version 1.0
 * @see http://www.bukkit.fr/index.php/topic/14174-jeremjacks-javaschool/
 */
public class Main {
	
	private static final String CALCULS[] = { "Additionner: 1",
			"Soustraire: 2", "Multiplier: 3", "Diviser: 4", "Racine: 5",
			"Cosinus: 6", "Sinus: 7", "Tangente: 8" };

	private static Scanner sc = new Scanner(System.in);
	private static double[] list;
	
	/**
	 * char permettant de relancer la boucle si l'utilisateur veut faire un autre calcul.
	 */
	private static char ch = 'O';

	public static void main(String args[]) {
		double i;
		while (ch == 'O') { //Lancement de la boucle globale
			System.out.println("Quel calcul voulez-vous effectuer?");
			for (String s : CALCULS) //On affiche les différents calculs possible et comment les choisir.
				System.out.println(s); 

			int c = sc.nextInt(); //On récupère la réponse de l'utilisateur

			switch (c) { //En fonction de sa réponse, on lui demande un ou deux chiffres et on effectue le calcul.
			case 1:
				list = ask();
				System.out.println("Résultat: " + additionner(list[0], list[1]));
				break;
			case 2:
				list = ask();
				System.out.println("Résultat: " + soustraire(list[0], list[1]));
				break;
			case 3:
				list = ask();
				System.out.println("Résultat: " + multiplier(list[0], list[1]));
				break;
			case 4:
				list = ask();
				System.out.println("Résultat: " + diviser(list[0], list[1]));
				break;
			case 5:
				System.out.println("Veuillez insérer le nombre:");
				i = sc.nextDouble();
				System.out.println("Résultat: " + racine(i));
				break;
			case 6:
				System.out.println("Veuillez insérer le nombre:");
				i = sc.nextDouble();
				System.out.println("Résultat: " + cosinus(i));
				break;
			case 7:
				System.out.println("Veuillez insérer le nombre:");
				i = sc.nextDouble();
				System.out.println("Résultat: " + sinus(i));
				break;
			case 8:
				System.out.println("Veuillez insérer le nombre:");
				i = sc.nextDouble();
				System.out.println("Résultat: " + tangente(i));
				break;
			default:
				System.out.println("Ce nombre n'est pas valable! Veuillez en entrer un compris entre 0 et 9");
				continue;
			}
			System.out.println("Voulez-vous effectuer un autre calcul? (O/N)");
			sc = new Scanner(System.in); 
			String carac = sc.nextLine(); //On récupère la réponse de l'utilisateur pour fermer le programme ou relancer la boucle.
			ch = carac.charAt(0);
			if (ch != 'O') {
				System.out.println("Merci d'avoir utilisé ma calculatrice! Au revoir!");
				sc.close();
				System.exit(1);
			}
		}
		sc.close();
	}

	/**
	 * Permet d'<b>additionner<b> deux valeurs décimales et de récupérer le resultat.
	 * @param i un nombre décimal.
	 * @param j un nombre décimal.
	 * @return la valeur de la somme des deux nombres spécifiés.
	 */
	private static double additionner(double i, double j) {
		return i + j;
	}

	/**
	 * Permet de <b>soustraire<b> deux valeurs décimales et de récupérer le resultat.
	 * @param i un nombre décimal.
	 * @param j un nombre décimal.
	 * @return la valeur de la différence des deux nombres spécifiés.
	 */
	private static double soustraire(double i, double j) {
		return i - j;
	}

	/**
	 * Permet de <b>mutliplier<b> deux valeurs décimales et de récupérer le resultat.
	 * @param i un nombre décimal.
	 * @param j un nombre décimal.
	 * @return la valeur du produit des deux nombres spécifiés.
	 */
	private static double multiplier(double i, double j) {
		return i * j;
	}

	/**
	 * Permet de <b>diviser<b> deux valeurs décimales et de récupérer le resultat.
	 * @param i un nombre décimal.
	 * @param j un nombre décimal.
	 * @return la valeur du quotient des deux nombres spécifiés.
	 */
	private static double diviser(double i, double j) {
		return i / j;
	}

	/**
	 * Permet de récupérer la <b>racine</b> d'un nombre.
	 * @param i un nombre décimal.
	 * @return la valeur de la racine du nombre spécifié.
	 */
	private static double racine(double i) {
		return Math.sqrt(i);
	}

	/**
	 * Permet de récupérer le <b>sinus</b> d'un nombre.
	 * @param i un nombre décimal.
	 * @return la valeur du sinus du nombre spécifié.
	 */
	private static double sinus(double i) {
		return Math.sin(i);
	}

	/**
	 * Permet de récupérer le <b>cosinus</b> d'un nombre.
	 * @param i un nombre décimal.
	 * @return la valeur du cosinus du nombre spécifié.
	 */
	private static double cosinus(double i) {
		return Math.cos(i);
	}

	/**
	 * Permet de récupérer la <b>tangente</b> d'un nombre.
	 * @param i un nombre décimal.
	 * @return la valeur de la tangente du nombre spécifié.
	 */
	private static double tangente(double i) {
		return Math.tan(i);
	}

	/**
	 * <b>Demande</b> à l'utilisateur d'entrer les deux nombres requis pour effectuer le calcul.
	 * @return les deux nombres décimaux requis pour le calcul.
	 */
	private static double[] ask() {
		double i;
		double j;
		System.out.println("Veuillez insérer le premier nombre:");
		i = sc.nextDouble();
		System.out.println("Veuillez insérer le deuxième nombre:");
		j = sc.nextDouble();
		return new double[] {i , j};

	}
}

 

Et voila du code bien commenté et documenté! Certes c'est long, mais ça en vaut la peine! Comme ça vous économisez du temps à rechercher de nombreuses informations dans votre code. De plus, tout le monde pourra le lire aisément!

 

Les attributs sont à ne pas confondre avec les annotations, qui commencent également avec @. Les annotations précèdent une classe, une interface, une méthode ou un champ et contiennent des méta-données, c'est à dire des données supplémentaires mais n'affectant pas le fonctionnement de l'entité concernée. Nous allons passer très rapidement dessus.

 
@Author( name = "JeremGamer", date = "05/11/2014" )
class MaClasse() { }

 

Cette annotation donne des informations concernant l'auteur et la date de création.

 

-----> Mais alors, quelle est la différence avec les commentaire de documentation? :huh:

 

La différence est que l'on peut utiliser dans le code les annotations et que le compilateur (Eclipse par la même occasion) en prend compte! Par exemple si on veut récupérer les annotations de la classe Main de notre calculatrice, on fera :

 
Class clas = Main.class;
Annotation[] annotations = clas.getAnnotations();

 

Ceux qui auront essayé de copier-coller l'annotation @Author plus haut se rendrons compte qu'il y a une erreur! En effet elle n'existe pas! Il faut d'abord la créer ainsi, puis suivre les instructions :

 

aIwq6U3.png

 

Choisissez le nom de votre annotation, ici on utilisera "Author", puis cliquez sur "Finish".

 

Il faudra ensuite donner les valeurs requises et votre annotation Author devrais ressembler à ça :

 
public @interface Author {
    String auteur();
    String date();
/*il est possible d'ajouter une valeur par défaut avec le mot-clef default
int version() default 1;
*/
}

 

Pour récupérer les valeurs il suffira donc de faire comme suit :

 
for (Annotation annotation : annotations) {
    if (annotation instanceof Author)  {
        Author info = (Author) annotation;
        System.out.println("auteur : " + info.auteur());
        System.out.println("date : " + info.date());
    }
}

 

Il existe déjà trois annotations dans Java:

  • @Deprecated qui indique l'obsolescence. Un avertissement sera donné par Eclipse et le compilateur en cas d'utilisation d'une entité dépréciée.
  • @Override redéfini une méthode. Si une méthode issue de la super-classe porte le même nom et les mêmes paramètres, il faut alors utiliser cette annotation pour redéfinir cette méthode. (Pas d'inquiétude, ces notions viendront dans le chapitre juste après celui-ci!)
  • @SuppressWarnings indique au compilateur et à Eclipse d'ignorer les avertissements concernant l'entité annotée. Pour ajouter le bon argument utilisez votre IDE: passez le curseur sur la ligne soulignée en jaune et sélectionnez "Add SuppressWarnings '<argument>' to <entité>".

 

1KlOXYY.png

 

Sans plus tarder, passons à autre chose! Vous aurez toujours une liste de choses à faire, à corriger, etc... Toutes ces choses sont des TODO. (littéralement "à faire") Vous pouvez les ajouter en commentaire directement comme suit :

 
//TODO: Chose à faire

 

Eclipse se chargera alors de mettre le mot TODO en bleu-vert gras. Et vous pourrez voir apparaitre un rectangle bleu dans la barre juste à droite de votre code! Comme ça on voit facilement où sont les choses à faire! Mieux encore, il suffit de cliquer dessus pour aller directement à la ligne concernée! C'est le même principe pour les erreurs et les avertissements, sauf que les rectangles seront respectivement rouge et jaune !

 

zSK1IXC.png

 

Eclipse propose aussi une liste de choses à faire plus avancée. Jetons-y un œil! Faites donc un clic droit dans le carré blanc en haut à droite de votre zone de travail et choisissez "New -> Task" puis "Local".

 

98tB7ae.png

 

Et là tout plein de paramètres peuvent être définis comme l'heure limite, le nom et la description précise. Remplissez ça rigoureusement de manière à bien comprendre votre tâche à la prochaine visite! S'il s'agit d'un bug pensez à ajouter le message d'erreur! ;) Vous pouvez toujours modifier rapidement certains de ces paramètres en faisant un clic droit dessus dans la liste. Ici on la marque comme terminée en cliquant sur le bouton "Complete" :

 

ZgAMLQn.png

 

Vous n'avez pas la motivation pour mettre votre code en forme et de faire un bel indent? Ou alors vous n'avez pas respecté les conventions et vous souhaitez y remédier rapidement? Rien de plus simple avec votre IDE! Faites une sélection dans votre code ou sélectionner la/les classe(s) à mettre en forme dans l'explorateur de package et faites un clic droit puis "Source -> Format".

 

R8FxAsv.png

 

Pour corriger l'indent uniquement, vous pouvez aussi utiliser Ctrl + I. ;)

 

C'est lourd de devoir relancer son programme à chaque modification? Encore une fois, bonne nouvelle! Nous allons utiliser le debug mode! Les modifications effectuées dans le code durant l'exécution sont prises en compte et le programme peut continuer à tourner! Il agit donc presque pareil que la flèche dans un rond vert pour lancer votre programme.

 

tCWGar4.png

 

Il existe bien sûr plein d'autres fonctionnalités mais celles-ci sont les plus importantes et cela prendrait vraiment beaucoup trop de temps de toutes les détailler !

 

Résumé:

 

  • Les commentaires sont importants pour se retrouver dans son code, surtout quand il commencer à prendre une certaines taille. De plus il sera plus lisible pour les autres.
  • La documentation permet de renseigner un maximum d'informations à propos d'une classe, une interface, une méthode, un champ ou un constructeur. Elle est essentielle quand le code devient imposant, quand vous travaillez à plusieurs ou quand quelqu'un d'autre est susceptible d'utiliser votre code. (Exemple de l'API Java)
  • Les attributs sont des informations contenues dans les commentaires de documentation.
  • Une annotation est aussi une sorte de documentation ses informations sont utilisables par du code.
  • Il ne faut pas confondre les attributs et les annotations car tous deux commencent par @.
  • La balise TODO est à connaître.
  • Pensez à remplir votre liste de choses à faire grâce à votre IDE!
  • Utilisez le debug mode afin de gagner du temps et ainsi ne pas avoir à redémarrer le logiciel à chaque modification.

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0419999001431871091.png

Comme promis, je commence dès aujourd'hui à éclaircir les points noirs du chapitre précédent.

Nous allons parler aujourd'hui d'une notion extrêmement importante si ce n'est qu'un fondement même de la programmation orientée objet: Les méthodes.

 

Tout d'abord, une méthode est une série de commandes et d'actions étant effectuées lors de l'appel de cette dernière.

Tout cela peut vous paraître abstrait alors ne nous attardons pas plus, voici un exemple :

 
void direBonjour() {
     System.out.println("Bonjour!");
     System.out.println("Belle matinée n'est-ce pas?");
}

 

Important: une méthode est un bloc à part ! C'est à dire que chaque méthode est comprise entre les accolades du bloc de la classe mais pas dans le bloc de la méthode principale !

public class Main {	
	
	public static void main(String args[]) {		
		//Instructions
	}
	
	void direBonjour() {
		System.out.println("Bonjour!");
		System.out.println("Belle matinée n'est-ce pas?");
	}
}

 

J'insiste bien sur ce point: les instructions contenues dans une méthode s'effectuent uniquement lors de l'appel de celle-ci ! C'est à dire que dans le code ci-dessus, le programme n'écrira pas "Bonjour!" ni "Belle journée n'est-ce pas?". Alors comment fait-on?

 

C'est très simple: il suffit d'écrire son nom !

 

Maintenant allons plus loin et créons nos propres méthodes !

Pour se faire, il faut d'abord que je vous explique un autre élément. Les méthodes retournent une valeur ou non. Cette valeur est comme une autre, d'un certain type et peut-être stockée dans une variable du même type. Ce type est donc spécifié lors de la déclaration de la méthode. Ici nous avons une méthode void, c'est une exception car elle ne retourne rien! Elle se contente juste d'effectuer les actions demandées.

 

Voici donc la déclaration d'une méthode retournant un int :

int getInt() {
     //...
}

 

On commence donc par le type, puis le nom de la méthode, que l'on utilisera alors pour l'appeler.

 

 

L'instant Convention

 

  • Le nom des méthodes doit commencer par une minuscule, et comme pour les classes et variables peut comporter des majuscules et nombres ou même des underscores ("_") pour remplacer les espaces.
  • Comme toujours, utilisez des noms simples et descriptifs.
  • Le nom des méthodes définissant quelque chose doivent commencer par "set".
  • Le nom des méthodes retournant une valeur doivent commencer par "get".
  • Si la valeur retournée est un boolean, alors le nom de la méthode doit commencer par "is".
  • Quand il s'agit de:
  • Ajouter quelque chose, alors le nom doit commencer par "add".
  • Retirer quelque chose, alors le nom doit commencer par "remove".
  • Convertir un type en un autre (on appelle cela un Cast), alors le nom doit commencer par "to".

 

-----> Une méthode retourne une valeur, alors le mot-clef return évoqué dans le chapitre sur les boucles doit servir à cela non? ^_^

 

En effet, vous avez déjà rencontré le mot-clef qui entre ici en jeux! Il s'agit bien de return ! Commençons par le plus simple, les méthodes void. Dans ces méthodes, return n'est pas obligatoire. Cependant, si vous voulez arrêter la méthode à un certain endroit suivant une condition, vous pouvez l'utiliser au même titre que break !

 

Maintenant, voyons pour les méthodes retournant une valeur. Il est strictement obligatoire ! De la même manière que break, il stoppe la méthode, les instructions qui le suivent ne seront pas exécutées.

int getInt() {
     return 1;
}

 

Cette méthode est vraiment inutile mais elle est un bon exemple pour le point où nous en sommes. Cette méthode retournera 1 à chaque appel.

Petite précision: il est possible de mettre une variable à la place d'une valeur directe comme 1 ici, du moment qu'elle est du même type que celui spécifié dans la déclaration de la méthode.

 

Ainsi on peut stocker le retour de notre méthode dans une variable :

int i = getInt(); //i sera alors égal à 1 car getInt() retourne 1.

 

Sachez que les méthodes retournant une valeur peuvent être appelées comme les void, mais la valeur retournée sera perdue.

int getInt() {
     System.out.println("Bonjour!");
     return 1;
}

 

Une telle méthode pourra à la fois donner une valeur à une variable et écrire "Bonjour!" dans la console si elle est appelée de la même manière que juste au dessus! Cependant si on l'appelle "dans le vide", la valeur 1 sera perdue mais "Bonjour!" sera quand même écrit dans la console.

public static void main(String args[]) {
	getInt();
}
//Ce programme sera parfaitement fonctionnel!

 

Cependant s'il n'y a aucune utilité à ce que la méthode retourne une valeur, optez plutôt pour un void.

 

Afin qu'une méthode soit plus "modulable" et fonctionnelle pour plusieurs valeurs, nous ajouterons des paramètres en arguments. Un paramètre est une valeur à donner à la méthode lors de son appel. Cette dernière s'en servira alors pour effectuer ce qu'on lui demande. Exemple :

int multiplier(int nombre1 , int nombre2) {
	return nombre1 * nombre2;
}

 

La méthode multiplier contient ici deux paramètres. Lors de son appel, on pourra alors multiplier n'importe quels nombres entre eux !

int produit = multiplier( 5 , 2 ); //produit sera égal à 10

 

Nous prenons ici l'exemple des int mais sachez qu'une méthode peut être d'absolument n'importe quel type, qu'il soit primitif ou non !

 

Note: Deux méthodes (ou plus) peuvent porter le même nom à condition qu'elles aient des paramètres différents. On appelle cela la surcharge de méthode.

int methode(int nombre1 , int nombre2) {
	return nombre1 * nombre2;
}

double methode(int nombre1 , int nombre2) { //Cette méthode ne sera pas valable!
	return nombre1 * nombre2;           //Même si elle a un type différent, ses paramètres sont les mêmes
}                                           //que la méthode juste au dessus!

void methode() {
	System.out.println("Une méthode");
}

void methode(String message) {
	System.out.println(message);
}

 

L'utilisation des méthodes est très utile par exemple pour de longues suites d'actions répétées régulièrement et afin d’optimiser et de clarifier son code. Ainsi une simple ligne suffit à en exécuter de nombreuses autres !

 

Pour revenir aux points noirs du chapitre précédent: vous savez donc ce que vous avez fait en appelant la méthode nextLine() de votre variable sc de type Scanner !

 

Je vous offre en cadeau cette semaine un "pack" de méthodes permettant de coder une calculatrice ! ;)

double additionner(double i , double j) {
	return i + j;
}
	
double soustraire(double i , double j) {
	return i - j;
}
	
double multiplier(double i , double j) {
	return i * j;
}
	
double diviser(double i , double j) {
	return i / j;
}
	
double racine(double i) {
	return Math.sqrt(i);
}
	
double sinus(double i) {
	return Math.sin(i);
}
	
double cosinus(double i) {
	return Math.cos(i);
}
	
double tangente(double i) {
	return Math.tan(i);
}

 

Spoiler

Je suis de bonne humeur donc je vous ai concocté un petit (enfin gros) code cadeau supplémentaire! Voici une calculatrice pleinement fonctionnelle! ;) Je vous invite à tester ce code sur votre IDE. :)

 

import java.util.Scanner;

public class Main {
    
    private static final String CALCULS[] = { "Additionner: 1",
            "Soustraire: 2", "Multiplier: 3", "Diviser: 4", "Racine: 5",
            "Cosinus: 6", "Sinus: 7", "Tangente: 8" };

    private static Scanner sc = new Scanner(System.in);
    private static double[] list;
    private static char ch = 'O';

    public static void main(String args[]) {
        double i;
        while (ch == 'O') {
            System.out.println("Quel calcul voulez-vous effectuer?");
            for (String s : CALCULS)
                System.out.println(s);

            int c = sc.nextInt();

            switch (c) {
            case 1:
                list = ask();
                System.out.println("Résultat: " + additionner(list[0], list[1]));
                break;
            case 2:
                list = ask();
                System.out.println("Résultat: " + soustraire(list[0], list[1]));
                break;
            case 3:
                list = ask();
                System.out.println("Résultat: " + multiplier(list[0], list[1]));
                break;
            case 4:
                list = ask();
                System.out.println("Résultat: " + diviser(list[0], list[1]));
                break;
            case 5:
                System.out.println("Veuillez insérer le nombre:");
                i = sc.nextDouble();
                System.out.println("Résultat: " + racine(i));
                break;
            case 6:
                System.out.println("Veuillez insérer le nombre:");
                i = sc.nextDouble();
                System.out.println("Résultat: " + cosinus(i));
                break;
            case 7:
                System.out.println("Veuillez insérer le nombre:");
                i = sc.nextDouble();
                System.out.println("Résultat: " + sinus(i));
                break;
            case 8:
                System.out.println("Veuillez insérer le nombre:");
                i = sc.nextDouble();
                System.out.println("Résultat: " + tangente(i));
                break;
            default:
                System.out.println("Ce nombre n'est pas valable! Veuillez en entrer un compris entre 0 et 9");
                continue;
            }
            System.out.println("Voulez(vous effectuer un autre calcul? (O/N)");
            sc = new Scanner(System.in);
            String carac = sc.nextLine();
            ch = carac.charAt(0);
            if (ch != 'O') {
                System.out.println("Merci d'avoir utilisé ma calculatrice! Au revoir!");
                sc.close();
                System.exit(1);
            }
        }
        sc.close();
    }

    private static double additionner(double i, double j) {
        return i + j;
    }

    private static double soustraire(double i, double j) {
        return i - j;
    }

    private static double multiplier(double i, double j) {
        return i * j;
    }

    private static double diviser(double i, double j) {
        return i / j;
    }

    private static double racine(double i) {
        return Math.sqrt(i);
    }

    private static double sinus(double i) {
        return Math.sin(i);
    }

    private static double cosinus(double i) {
        return Math.cos(i);
    }

    private static double tangente(double i) {
        return Math.tan(i);
    }

    private static double[] ask() {
        double i;
        double j;
        System.out.println("Veuillez insérer le premier nombre:");
        i = sc.nextDouble();
        System.out.println("Veuillez insérer le deuxième nombre:");
        j = sc.nextDouble();
        return new double[] {i , j};

    }
}

 

 

Résumé:

 

  • Une méthode est une série d'actions s'effectuant lors de l'appel de cette dernière.
  • Une méthode retourne une valeur du type spécifié dans sa déclaration.
  • Cette valeur est retournée à l'aide du mot-clef return (obligatoire!).
  • Les méthodes de type void ne retournent rien.
  • Les valeurs retournées par une méthode peuvent être stockées dans une variable directement lors de l'appel de cette méthode.
  • Une méthode peut avoir des paramètres. Ce sont des valeurs requises à l'exécution de la méthode.
  • Plusieurs méthodes peuvent porter le même nom à condition qu'elles aient des paramètres différents.
  • De nombreuses conventions sont appliquées aux méthodes. Veillez à vous en souvenir!
  • Les méthodes optimisent et clarifient votre code.

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0867624001431870718.png

Jusque là, vos programmes n'étaient pas interactifs, et donc sans grand intérêt... Réjouissez-vous, nous abordons enfin la communication avec l'utilisateur !

 

Comme nous ne travaillons que sur console pour l'instant, je vous apprendrais à communiquer via du texte, tel un analyseur syntaxique.

 

Sachez que c'est très simple ! Il n'y a que quelques petites choses qui vous seront inconnues mais qui ne tarderons pas à être expliquées dans les chapitres à venir.

 

Nous allons utiliser une classe de l'API Java qui nous permet donc "d'établir la communication": la classe Scanner!

Je vous invite donc dès maintenant à ajouter ceci à votre méthode principale :

Scanner sc = new Scanner(System.in);

 

Vous venez de déclarer une variable de type Scanner. Nous ne somme plus dans les types primitifs! Cette variable est ce que l'on appelle un Objet.

 

Remarque : C'est la première fois que nous utilisons une classe, et c'est un autre développeur qui l'a concoctée pour nous ! :)Nous allons devoir donc importer les ressources nécessaires dans notre code. Déclarez votre variable puis utilisez le raccourci clavier CTRL+SHIFT+O pour qu'Eclipse s'occupe de gérer automatiquement les imports. ;) Sinon passez votre curseur sur le mot Scanner qui devrait être indiqué comme une erreur et votre IDE devrait vous proposer "Import 'Scanner' (java.util)".

 

Et maintenant, commençons à parler un peu avec notre utilisateur :

public static void main(String args[]) {
		
	Scanner sc = new Scanner(System.in);
	
	System.out.println("Comment vous appelez-vous?");
		
	String nom = sc.nextLine();
	System.out.println("Bonjour " + nom + "!");
	sc.close();
		
}

 

Ce programme va donc demander son nom à l'utilisateur puis le lui retransmettre. Le résultat Devrait ressembler à ça :

Comment vous appelez-vous?
Robert <-------------- Entrée de l'utilisateur
Bonjour Robert!

 

Il y a plusieurs choses sur lesquelles il faut insister. Tout d'abord, notre objet sc est un flux. Cela signifie que comme un robinet, il faut le fermer après utilisation! C'est la dernière ligne: sc.close();

Tous les flux se ferment de la même manière, avec la méthode close().

 

Ensuite, vous remarquerez que le programme se fige temps que l'utilisateur n'a pas répondu à la question. Cela provient de la ligne sc.nextLine();. C'est elle qui s'occupe de récupérer la réponse de l'utilisateur, que l'on stocke alors dans une variable String. Une fois que l'utilisateur aura validé son entrée, le programme se poursuivra.

 

Ici nous utilisons une méthode permettant de récupérer une String. Sachez qu'il existe aussi des méthodes pour récupérer des types primitifs !

Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
short s = sc.nextShort();
double d = sc.nextDouble();
long l = sc.nextLong();
byte b = sc.nextByte();
float f = sc.nextFloat();
boolean bl = sc.nextBoolean();
//Attention il n'existe pas de méthode pour récupérer les char. Utilisez alors la méthode nextLine().

 

Voila il n'y a rien d'autre à savoir pour l'instant sur l'utilisation de cette classe. Cependant il y a un conseil que j'aimerais vous donner par rapport à la communication avec l'utilisateur:

  • Règle d'or: Ne JAMAIS faire confiance à ce dernier! Effectuez toujours des tests pour voir ce qu'il fait! Par exemple s'il rentre une lettre au lieu d'un chiffre dans une calculatrice, ça ne risque pas de bien fonctionner!

 

En application , soit vous fermez le logiciel, l'utilisateur n'avait qu'a répondre correctement, soit vous utilisez une boucle !

 

Si vous avez bien suivi au cours précédent, je pense que vous saurez quelle boucle utiliser !

 

Ajoutons quelques petites choses à notre programme. Maintenant que nous connaissons le nom de l'utilisateur, nous allons lui redemander et vérifier s'il se paie notre tête ou non.

public static void main(String args[]) {
	
	Scanner sc = new Scanner(System.in);
	
	System.out.println("Comment vous appelez-vous?");
	
	String nom = sc.nextLine();
	System.out.println("Bonjour " + nom + "!");
		
	System.out.println("Pouvez-vous me répéter votre nom s'il vous plait?");
	String confirmation = sc.nextLine();
		
	while(!confirmation.equals(nom)) {
		System.out.println("Vous mentez! Répondez sérieusement!");
		confirmation = sc.nextLine();
	}
		
	System.out.println("Merci! Votre nom est bien " + confirmation + ".");
			
	sc.close();
		
}

 

Vous pouvez tester! N'est-ce pas génial? Si cela vous amuse vous pouvez même ajouter des comportements différents en fonction du nombre de fois que l'utilisateur ne répond pas correctement !

 

Concentrons nous sur la boucle. On y teste si la variable confirmation est différente de nom récupéré juste avant.

Donc tant qu'elles ne seront pas égales, le programme redemandera à l'utilisateur de "répondre sérieusement" !

La boucle se termine enfin quand l'utilisateur réécrit exactement son nom, on peut alors lui dire merci et terminer le programme tout en pensant à bien fermer le flux de sc.

 

 

Résumé :

  • La classe Scanner permet de lire les entrées clavier.
  • Il existe de nombreuses méthodes permettant de récupérer les différents types primitifs et les String.
  • Les Scanners sont des flux, il faut les fermer après utilisation.
  • Ne jamais faire confiance à l'utilisateur !
  • L'utilisation des boucles dans les programmes console est très importante.

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0114930001431870700.png

Vous rencontrerez très souvent un cas de figure: Vous voulez effectuer la même action, ou des actions se ressemblant beaucoup un grand nombre de fois. Pour cela, il existe ce que l'on appelle les boucles ! C'est tout simplement une structure dont le contenu se répétera un nombre de fois donné ou indéterminé.

Je m'explique: Imaginez-vous dans une situation concrète. Votre programme permet de lister tous les patients enregistrés dans les fichiers d'un médecin. Vous ne savez donc pas combien de fois la boucle devra tourner. De plus, le nombre de patients pourra varier, on aura donc un nombre de tours indéterminé. On utilisera une boucle while.

Maintenant, imaginez que votre programme doit effectuer dix fois la même action par patient, à peu de chose près. Le nombre de tours est déterminé et ne changera pas au cours de l'exécution du programme. On utilisera donc une boucle for.

Commençons par la plus simple: la boucle while.

Il n'y a qu'a traduire depuis l'anglais pour comprendre son utilité: "Tant que" l'expression donnée en argument est vraie (une expression booléenne donc), les commandes spécifiées dans son bloc (accolades) seront exécutées en boucle.

Un exemple vaut mieux que de longues phrases :

 
int i = 5;
int j = 10;
while( i < j ) {
      System.out.println(i  + " < " + j);
}
//Bien sûr, de la même manière que les conditions, on peut ne pas utiliser les accolades s'il n'y a qu'une instruction à répéter.

 

Ici, votre boucle écrira que i est inférieur à j tant que ce sera vrai.

Les plus malins auront repéré un gros problème.

En effet, ici, cette boucle tournera indéfiniment! Et oui! i et j ne changent pas de valeur donc i sera toujours inférieur à j et votre console sera remplie à jamais de texte! On appelle cela une boucle infinie. Il faut donc y faire très attention !

Pour éviter ce problème, nous incrémenterons i et constaterons le résultat. La boucle ne tournera que i - j fois soit 10 - 5 fois donc 5 fois. Essayez vous-même !

int i = 5;
int j = 10;
while( i < j ) {
     System.out.println(i  + " < " + j);
     i++;
}

 

Le résultat donnera la figure suivante :

5 < 10
6 < 10
7 < 10
8 < 10
9 < 10

 

Il existe une autre syntaxe pour cette boucle. Son fonctionnement est le même sauf que les instructions à exécuter se trouveront dans un bloc do. Cette forme porte le nom de "do-while".

int i = 5;
int j = 10;

do {
     //Instructions
} while (i < j); //Notez bien qu'il y a un point virgule à la fin!

 

Il y a cependant une petite différence avec sa sœur, la boucle while : la do-while s'exécutera au moins une fois, même si la condition n'est pas remplie !

Passons maintenant à la boucle for. Celle-ci vous donne la possibilité de lui spécifier combien de fois elle devra tourner. En plus de cela, elle a d'autres applications très intéressantes dont nous parlerons très, très bientôt !

Elle se syntaxe ainsi :

for(int i = 0 ; i < 10 ; i++) {
     //Instructions
}

 

Elle est un peu complexe par rapport à ce que nous avons vu jusque là, mais n'ayez crainte, elle est finalement simple d'utilisation. Il suffit de la connaître!

Lisons pas-à-pas cette ligne:

  • Le mot-clef for appelle une boucle.
  • On ouvre les parenthèses pour ajouter les arguments.
  • On déclare une variable avec la valeur choisie. Il est possible de lui assigner la valeur d'une variable déjà existante.
  • Un point virgule? :wacko: C'est là la particularité de cette boucle; les arguments sont séparés par des ";".
  • Un test. Il revient exactement au même que pour la boucle while. Vous pouvez mettre une variable déjà existante en deuxième nombre: i < j par exemple.
  • Et pour finir, l'actualisation. Ici c'est une incrémentation, mais il peut très bien s'agir d'une décrémentation ou d'un calcul classique comme i+=5. Attention cependant, vous ne pouvez utiliser que des opérations puis assignation dans ce champ !

 

-----> Mais alors, cette boucle fait la même chose qu'une boucle while avec une incrémentation de la valeur testée? :huh:

 

On peut dire ça, cependant, elle reste plus pratique et optimisée !

int i = 0;

while( i < 10 ) {
     System.out.println(i);
     i++;
}

//Revient au même que:

for(int i = 0 ; i < 10 ; i++)
     System.out.println(i);

 

La boucle for a une variante: la boucle for each. Elle permet d'utiliser l'intégralité des variables d'un tableau ou d'une collection.

C'est simple, "pour chaque valeur du tableau, effectuer telle action". Elle se syntaxe de la manière suivante :

int t[] = { 1 , 5 , 7 , 9 };

for(int i : t) {
     //Instructions
}

 

Je vais illustrer un peu cette notion plus compliquée à comprendre. Imaginez que chaque valeur du tableau est un client attendant à la caisse d'un supermarché. Chacun passe tour à tour et la caissière ré-exécute le passage des articles à chaque client. Quand il n'y aura plus de client, donc que le tableau aura déjà donné toutes ses valeurs, la caissière cessera de passer les articles.

Essayez quelque chose de très simple :

int t[] = { 1 , 5 , 7 , 9 };

for(int i : t) {
     System.out.println(i);
}

 

Vous constaterez que votre programme s'est contenté d'écrire un par un les nombres faisant partie de votre tableau puis, n'ayant plus rien à écrire, a stoppé la boucle.

Il est possible à tout moment d'utiliser break pour stopper la boucle. Cependant, les instructions qui suivent ce mot-clef dans le bloc ne pourront être effectuées !

while(i < j) {
     System.out.println(i);
     break; //La boucle ne s'exécutera qu'une seule fois car on la "casse" dès le premier tour!
     System.out.println("La boucle est stoppée"); //Erreur! Cette ligne se trouve après le break!
}

 

Vous pouvez utiliser un test :

while(i < j) {
     System.out.println(i);
     if(i == 8)
          break;
     System.out.println("Relancement de la boucle");
}
//Ici on teste si i est égal à 8. Si c'est le cas, on stoppe la boucle sans dire qu'elle se relance!

 

Maintenant, je vais vous expliquer une notion plus complexe.

Il est possible de mettre une boucle dans une boucle, elle-même dans une boucle. Comment gérer toutes ces boucles? :wacko:

Tout d'abord, illustrons la situation :

 

 

tEEq33A.png

 

Nous avons donc trois boucles, les unes dans les autres. Si vous ne souhaitez pas interrompre l'une d'entre elles depuis une autre, aucun souci à se faire. Sinon il va falloir s'accrocher !

Comme vous l'avez vu ici, j'ai identifié chaque boucle par une couleur. On peut faire à peu près la même chose en Java avec ce que l'on appelle les labels ! Il est donc possible de nommer une boucle au même titre qu'une variable !

label: while(i < j) {
     //Instructions
}

 

Dans notre situation, le code ressemblerait à cela (si on utilisait que des boucles for) :

vert : for(int i = 0 ; i < 10 ; i++) {
	//Instructions
	bleu: for(int j = 0 ; j < 10 ; j++) {
		//Instructions
		orange: for(int k = 0 ; k < 10 ; k++) {
			//Instructions
		}
		//Instructions après la boucle orange, dans la boucle bleu
	}
	//Instructions après la boucle bleu, dans la boucle verte
}
//C'est un bel exercice de compréhension des accolades n'est-ce pas?^^

 

A l'intérieur de chacune de ces boucles sera alors possible de stopper sa boucle enfant ou sa boucle parent ! Il suffit d'utiliser le mot-clef break et le label de la boucle à stopper !

break vert;

 

Et cela fonctionne également pour le mot-clef que nous allons voir dès maintenant !

continue permet de passer le reste des instructions de la boucle dans laquelle il se trouve puis de la relancer si le test renvoie toujours vrai, à condition qu'il ne précède aucun label. Par exemple, retournons à notre cabinet de médecine. Vous voulez déterminer combien il y a de femmes dans le total de vos patients. Nous utiliserons un tableau recensant vos patients, faire une boucle for pour tous les vérifier et déclarer une variable que l'on incrémentera si le patient est une femme.

int nombreDeFemmes = 0;
String patients[] = {"homme" , "homme" , "femme" , "homme" , "femme" , "femme" , "femme" , "homme"};
int tours = patients.length;

for(int i = 0 ; i < tours ; i++) {
	if(patients[i].equals("homme"))
		continue;
	nombreDeFemmes++;
}
System.out.println(nombreDeFemmes + " femmes consultent dans votre cabinet.");

 

Votre programme vous retournera alors que 4 femmes consultent dans votre cabinet! On constate donc que l'incrémentation de nombreDeFemmes est passée si le patient est un homme !

Au passage, vous remarquerez que j'ai utilisé la méthode equals et non l'opérateur == pour tester la valeur du String. Je détaillerais ce qu'est une méthode plus tard, mais sachez qu'il est bien plus fiable de faire ceci pour le type String !

Si ce mot-clef est suivi d'un label, il s'occupera alors de passer les instructions de la boucle spécifiée, mais pas de la boucle dans laquelle il est inscrit !

vert: for(int i = 0 ; i < 10 ; i++) {
	while(/*un test*/) {
		if(i == 5)
			continue vert;
	}
	System.out.println(i);
}

 

Ici, notre boucle for aura pour objectif d'écrire la valeur de i à chaque tour. Nous faisons une autre boucle, peu importe le test, dans laquelle nous vérifions si i est égal à 5. Si c'est le cas, on empêchera la boucle "vert" d'écrire sa valeur.

Enfin, le mot-clef return stoppe lui aussi les boucles, mais ce dernier effectuant une action que nous détaillerons plus tard, je ne l'expliquerais pas tout de suite. Pour l'instant, pensez juste qu'il est l'équivalent de break. ^_^

Le code cadeau de cette semaine vous permet de compter le nombre de "p" dans une phrase ! Bien sûr, il est facilement modifiable afin que d'autres lettres puissent être vérifiées !

String phrase = "pourquoi, n'arrêtait pas de pester sa promise, pascal, "
		+ "pourtant propriétaire depuis plusieurs années, partit dès la première"
      		+ " opportunité pour partager sa passion naissante avec son autre petite"
      		+ " copine, un pucelle de perpignan à la plastique parfaite, elle aurait"
      		+ " préféré le stopper plus tôt mais persuadée qu'il ne la planterait pas,"
      		+ " elle n'eut plus que ses yeux pour pleurer, emprisonnée à perpétuité dans ses larmes.";
	      
int max = phrase.length();
int nombreDeP = 0;

for (int i = 0; i < max; i++) {
     if (phrase.charAt(i) != 'p')
          continue;
	            
     nombreDeP++;
}
System.out.println("Il y a " + nombreDeP + " \"p\" dans cette phrase.");

 

Résumé :

  • Les boucles permettent d'effectuer plusieurs fois les mêmes actions, ou des actions quasiment identiques.
  • Les boucles while tournent un nombre de fois indéterminé, tant que leur test retourne vrai, et peuvent aussi s'écrire en do-while.
  • Il faut bien faire attention de ne pas écrire de boucle infinie! Sinon les actions se répéterons à l'infini, jusqu'à l’arrêt forcé du programme.
  • Les boucles for tournent un nombre de fois déterminé et prennent en compte une variable dédiée, un test et une actualisation.
  • Les boucles for each enregistrent dans une variable temporaire les valeurs d'un tableau ou d'une collection, une par une et tournent tant que ce tableau ou cette collection à d'autres éléments à proposer.
  • Le mot-clef break est utilisé pour stopper les boucles, même si le test renvoie toujours vrai.
  • Le mot-clef continue est utilisé pour passer les instructions qui restent avant que la boucle recommence. Il est quasi-identique à break, sauf qu'il relance la boucle.
  • Les labels permettent de nommer ses boucles et de les gérer depuis d'autres boucles avec les mots-clef cités précédemment.
  • Pour vérifier si une String est égal à une autre, utiliser la méthode equals(String).

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0476194001431870684.png

Il est sûr et certain que vous rencontrerez le cas suivant: vous avez un grand nombre de variables du même type à utiliser. Vous allez donc très certainement n'avoir qu'une idée en tête :

 
int nombre0 = 0;
int nombre1 = 1;
int nombre2 = 2;
int nombre3 = 3;
int nombre4 = 4;
int nombre5 = 5;

 

Vous conviendrez que ça ne semble pas très optimisé, et encore moins pratique. Il existe justement un outil pour faire cela ! C'est bien fait hein? ^_^

 

Cet outil, il s'agit des tableaux. Il permet, à l'aide d'une seule variable, de stocker une grand nombre d'éléments du même type. Nous prendrons ici int pour nos exemple. Mais sachez que les tableaux peuvent contenir absolument n'importe quel type, autant des types primitifs que des Objets (notion que vous verrez plus tard).

 

Vous savez ce qu'est un tableau en général, une multitude de cases alignées en lignes et en colonnes. Et bien ici, c'est pareil ! Dans chaque case, on aura une valeur. Pensez à toujours vous représenter vos tableaux dans votre tête lors de la création de vos programmes. ;)

 

Voyons désormais quelle forme cela prend en Java :

int tableau[];

 

La variable est déclarée mais pas initialisée pour l'instant, vous pouvez cependant le faire directement, nous verrons comment juste après.

Ici vous découvrez de nouveaux signes que sont les crochets. Ils caractérisent un tableau, leur utilité sera développée dans un instant.

 

Un tableau contient un certain nombre de cases, alors pour initialiser un tableau, soit on spécifie le nombre de cases (ces dernières seront alors vides et on pourra les remplir ensuite), soit on rempli directement à l'aide des valeurs choisies, et le nombre de cases sera alors adapté au nombre de valeurs entrées.

int tableau[] = new int[7]; //Tableau de 7 entiers, les cases sont vides pour l'instant

int tableau2[] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 }; //Aussi un tableau de 7 entiers, mais on rempli directement les cases

 

Notez l'utilisation d'un nouvel opérateur: new. Vous en aurez besoin sans arrêt plus tard, ne l'oubliez pas ! ;)

 

Rien de bien compliqué pour la première manière de faire. Pour la seconde, notez bien la syntaxe, le point virgule à la fin à ne pas oublier comme d'habitude, mais surtout les accolades: c'est entre ces dernières que se trouvera le contenu du tableau, chaque case étant séparée par une virgule.

 

La déclaration des valeurs se fait de la même manière que pour des variables classiques :

double tableau[] = { 0.0 , 0.7 , 1.5 , 4.2 };

char tableau2[] = { 'a' , 'b' , 'c' , 'd' };

String tableau3[] = { "BlaBla" , "Toto" , "Tata" , "Titi" };

 

Voici donc la forme de notre tableau dans notre tête :

 

REfdv3y.png

 

Vous allez me dire qu'il n'y a qu'une seule ligne ! Ce n'est pas vraiment un tableau alors! Et bien vous avez demandé à votre programme qu'il n'y ai qu'une seule ligne! En effet, le nombre de dimensions du tableau est définie par le nombre de crochets que l'on met! Ainsi, si vous voulez un tableau avec plusieurs lignes, rien de plus simple :

int tableau[][];

 

On aura désormais deux dimensions! En réalité, il s'agit d'un tableau contenant au minimum deux tableaux, mais cela revient au même. Vous devinerez donc qu'il ne sera pas plus compliqué d'initialiser ce genre de tableaux :

int tableau[][] = new int[7][3]; //Nombre de lignes, puis nombre de colonnes

int tableau2[][] = { { 0  , 1  , 2  , 3  , 4  , 5  , 6  }, //Contenu de la première ligne 
                     { 7  , 8  , 9  , 10 , 11 , 12 , 13 }, //Contenu de la deuxième ligne
                     { 14 , 15 , 16 , 17 , 18 , 19 , 20 } }; //Contenu de la troisième ligne

 

Pensez bien à ne pas oublier les deux accolades englobant la totalité des tableaux. Comme je vous le disais, on voit bien ici qu'il s'agit de plusieurs tableaux, car on retrouve les accolades, et les virgules entre chaque valeur. ;)

Vous devriez aussi apercevoir une espèce de tableau comme vous les connaissez, grâce au fait que j'ai bien aligné tous les nombres. :)

 

Sachez qu'il existe aussi les tableaux tridimensionnels, quadridimensionnels, etc...! Vous pouvez ajouter autant de dimensions que vous le voulez, mais au delà de trois cela devient très très abstrait et demande de bonnes connaissances en mathématiques (étudiées au supérieur).

 

C'est bien joli tout ça, mais vous ne savez toujours pas comment naviguer dans ces tableaux, comment récupérer les valeurs qu'il contient ni comment modifier ces valeurs. Vous naviguerez grâce à des index. Chaque case a sa position, comme pour une bataille navale, mais en ( x , y ) s'il s'agit d'un tableau bidimensionnel.

 

YEGXGoy.png

 

Notez bien que le premier indice est 0 ! En informatique, prenez le réflexe de compter en partant de 0 et non de 1, car c'est bien plus logique non? ^_^

 

Je pense qu'il n'est pas nécessaire de s'attarder plus longtemps sur les index, ce n'est pas bien compliqué à comprendre. Passons plutôt à la partie intéressante: naviguer dans son tableau.

 

Encore une fois ce n'est pas compliqué, les coordonnées seront insérées entre les crochets :

int tableau[] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 };

System.out.println(tableau[3]); //Affichera "4"
//Et oui n'oubliez pas que l'on compte à partir de zéro!
//Vous voyez désormais l'importance de bien faire attention à cela ;)

 

Dans le cas d'un tableau bidimensionnel, c'est le même principe :

int tableau[][] = { { 0  , 1  , 2  , 3  , 4  , 5  , 6  }, 
                    { 7  , 8  , 9  , 10 , 11 , 12 , 13 },
                    { 14 , 15 , 16 , 17 , 18 , 19 , 20 } };

System.out.println(tableau[2][1]); //Ligne puis colonne!
//Affichera "15"

 

Vous avez surement deviné comment modifier une valeur :

tableau[2] = 42; //La troisième valeur du tableau sera égale à 42

tableau2[1][4] = 7; //La cinquième valeur de la seconde ligne sera égale à 7

 

Pour finir, il est possible récupérer la taille d'un tableau, c'est à dire son nombre de cases :

tableau.length;

tableau2[2].length; //Dans le cas d'un tableau bidimensionnel
//Retournera le nombre de cases dans la troisième ligne

tableau2.length; //Retournera donc le nombre de lignes et non le nombre total de cases!

 

Faites bien attention, il s'agit bien du nombre de cases et non de l'index maximum ! D'ailleurs si jamais vous décidez d'aller chercher une valeur à l'aide d'un index plus grand que l'index de la dernière case, que se passera-t-il? :huh:

 

Une erreur, appelée exception sera lancée, il s'agit de ArrayIndexOutOfBoundsException, qui signifie tout simplement que vous allez chercher une valeur dans une case qui n'existe pas !

 

Voici un petit bout de code qui vous fera mijoter un moment ;) Des notions qu'il contient seront expliquées en détails dans le prochain chapitre.

int nombres[][] = { { 0 , 1 , 2 , 3 , 4 },
                    { 1 , 3 , 5 , 7 , 9 }};

 

for(int i = 0; i < 2; i++) {    

  for(int j = 0; j < 5; j++) {

    System.out.print(nombres[i][j]);       

  }

  System.out.println("");     

}

int nombres2[] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 };

for( int k : nombres2 )
     System.out.println(k);

 

Résumé :

  • Un tableau est un série de cases contenant des valeurs du même type.
  • Tous les types sont supportés, autant les types primitifs que les Objets.
  • Les tableaux multidimensionnels sont des tableaux contenant plusieurs tableaux.
  • Chaque valeur se trouve dans une case ayant ses coordonnées, sous forme d'index.
  • Le premier index est l'index 0 !
  • Vous pouvez récupérer le nombre de cases d'un tableau grâce à length.

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png

ilicos

blog-0436006001446747183.jpg

Bonjour tout le monde,

 

Jackblue semblant être bien trop occupé pour avancer les cours de spigot actuellement, je me suis décidé à m'y mettre et contribuer à l'avancement du programme! :)

Étant programmeur étudiant dans le domaine du jeux-vidéo, je risque de généraliser un peu des concepts avant d'aborder le développement craftbukkit/spigot.

 

I - Introduction

 

Listener, écouteur en français... mais à quoi servent-il donc? à écouter, certes mais quoi? Des événements.

Les listeners vont capter un événement puis exécuter une callBack (fonction).

Un joueur ouvre son inventaire, l'événement InventoryOpenEvent va être dispatché et les listeners qui écouteront cet événement vont le capter et exécuter leurs fonctions.

 

II - Pourquoi utiliser des listeners && events

 

Imaginons que je programme un plateformer... mon joueur meurt, je pourrais lui faire appeler une fonction public de mon HUD pour changer le nombre de vies restantes.

Cependant, imaginons que plus tard je veuille que tout les ennemis aux alentours se réjouissent de la mort de mon héros. Je vais être contraint de rajouter cela sur mon joueur et de rajouter des fonctions publiques sur mes ennemis. Est-ce vraiment à un élément de mon jeu d'appliquer à tout les autres éléments les comportements qu'ils devraient avoir? Non, c'est plutôt à eux d'observer // d'écouter un événement PlayerDieEvent et de changer leurs animations en conséquence.

 

En supplément, utiliser un événement permet de simplifier le travail en équipe.

Je m'occupe du Player, JeremGamer des ennemis, mon player meurt:

- Dans le cas où je décide d'appeler une fonction publics des ennemis : "Hey jerem', tu pourrais rajouter cette fonction publique?"

- Dans le cas d'un événement, JeremGamer rajoute un listener et fait ce qu'il veut avec.

 

Cela permet d'avoir plus de liberté en séparant mieux les causes et les conséquences.

 

III - En pratique, les listeners

 

Avec bukkit, il faut créer sa propre class Listener qui va écouter un ou plusieurs événements et attacher cette class au pluginManager.

On commence par la création de la classe:

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener { 
}

 

La méthode pour attacher la class au pluginManager prend en paramètre un Listener d'où la nécessité d'implémenter Listener à votre Listener

 

Pour l'exemple, nous allons envoyer un message au joueur quand il se connecte.

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener {
    @EventHandler
    public void onPlayerConnection(PlayerJoinEvent event){        
        event.getPlayer().sendMessage("Bienvenue à toi! :D");    
    }
}

 

@EventHandler est une annotation permettant de signaler la fonction qui suit comme étant une callBack de listener. Le type d'event passé en paramètre déterminera quel événement est écouté. Le nom de la fonction importe peu, toujours est-il qu'il est préférable qu'elle soit compréhensible.

La documentation vous permettra de trouver l’événement qui correspond à ce que vous souhaitez écouter.

Ce même objet passé en paramètre contient différent informations et méthodes pour les récupérer. Certains événements peuvent être annulé par exemple BlockBreakEvent.

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperListener implements Listener {    
    @EventHandler    
    public void onBlockBreak(BlockBreakEvent event){        
        event.setCancelled(true);    
    }
}

 

Le joueur va casser un block, l'évènement va être dispatché, intercepté par le listener, mon callBack va annuler l’événement et donc le bloc va ré-apparaître.

 

Faites attention, là j'écris qu'une seule fonction à chaque fois, mais je peux en mettre plusieurs, par contre il doit y avoir toujours @EventHandler devant chaque fonction. Sinon elles ne seront pas prise en compte comme callback.

 

Maintenant que l'on a créé un belle classe Listener, il va falloir l'ajouter au plugin manager, sinon, ça ne risque pas de fonctionner.

Pour ce faire, on récupère le pluginManager, on lui assigne le listener et on lui passe en second paramètre le plugin qui ajoute ce listener:

 
monInstanceDePlugin.getServer().getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

// - ou -

Bukkit.getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

// - ou -

Bukkit.getServer().getPluginManager().registerEvents(monInstanceDeListener, monInstanceDePlugin);

 

J'aurais tendance à conseiller le 2ème, le chemin de fonctions étant le plus cours.

 

Vous pouvez également supprimer un Listener

 
HandlerList.unregisterAll(monInstanceDeListener);

 

ou supprimer l'écoute d'un événement particulier sur un listener;

 
PlayerJoinEvent.getHandlerList().unregister(monInstanceDeListener);

 

Attention! L'instance doit être la même entre l'ajout et la suppression.

 

Il est bon de savoir que l'annotation @EventHandler peut prendre un paramètre: la priorité:

il y a 6 étapes:

  • EventPriority.LOWEST
  • EventPriority.LOW
  • EventPriority.NORMAL
  • EventPriority.HIGH
  • EventPriority.HIGHEST
  • EventPriority.MONITOR

 

 

Lorsqu'un évènement survient, Craftbukkit appelle les méthodes d'écoute qui ont une faible priorité en premier, et celle qui ont une forte priorité en dernier, afin que ces dernières aient le dernier mot sur le sort de l'évènement (notamment s'il est annulé ou pas). Par défaut la priorité est NORMAL.

 

Attention : La priorité MONITOR existe pour de l'observation, il ne faut pas l'utiliser pour avoir le dernier mot sur une modification//annulation d'événement.

Pour déclarer une propriété, au lieu d'écrire:

 
@EventHandler

 

on écrit:

 
@EventHandler(priority = EventPriority.HIGH)

 

Bien entendu, vous choisissez la propriété qui vous convient et vous utilisé une propriété seulement si vous en avez besoin. (Plusieurs plugins qui écoutent le même événement)

 

IV - Création d'événements

 

Vous pouvez également ajouter vos propres événements, pour cela, il faut créer sa classe qui étends Event.

 
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; 

public class MonSuperEvent extends Event {    
    private static final HandlerList handlers = new HandlerList();     
  
    @Override    
    public HandlerList getHandlers() {        
        return handlers;    
    }     
  
    public static HandlerList getHandlerList() {        
        return handlers;    
    }
}

 

Attention, il faut conserver ces méthodes et cette propriété. C'est elle qui contient tout les listeners.

Je peux rajouter d'autres méthodes et d'autres propriétés.

Je peux aussi implémenter Cancellable qui m'obligera à implémenter les méthodes

 
public boolean isCancelled()
public void setCancelled(boolean cancel)

 

J'aurais alors à les compléter pour les rendre fonctionnelles

 
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; 

public class MonSuperEvent extends Event implements Cancellable{    
    private static final HandlerList handlers = new HandlerList();     

    @Override    
    public HandlerList getHandlers() {        
        return handlers;    
    }     

    public static HandlerList getHandlerList() {        
        return handlers;    
    }    

    public boolean isCancelled() {       
        return cancelled;    
    }     

    public void setCancelled(boolean cancel) {       
        this.cancelled = cancel;    
    }
}

 

Maintenant que j'ai créé mon Event, je peux tout à fait l'écouter comme un Evenement classique. Cependant, faut-il encore le dispatcher pour que mes Listener reçoivent l'événement.

Pour ce faire:

 
MonSuperEvent event = new MonSuperEvent();
Bukkit.getPluginManager().callEvent(event); 
//Je dispatche l'événement, tout mes listeners qui écoute l'évènement le captent et agissent éventuellement dessus, décident éventuellement de l'annuler...

if (event.isCancelled()){    
// Par conséquent, si mon évènement est annulé, J'annule l'action.
}

 

Rien ne m'empêche de rajouter des paramètres au constructeur de l’événement pour y ajouter des informations.

Je pourrais créer l'événement TeamWinEvent, et avoir des méthodes .getTeam() ou .getPlayersTeam() qui me renvoient des informations importantes et qui sont intéressantes.

 

V - Une chose à savoir mais pas forcément à faire

Au lieu de créer une class pour votre listener, vous pouvez directement implémenter Listener à votre plugin et utiliser votre propre classe plugin comme listener

 
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public class MonSuperPlugin extends JavaPlugin implements Listener {    
    @Override    
    public void onEnable(){        
        getServer().getPluginManager().registerEvents(this, this);    
    }    

    @EventHandler    
    public void onPlayerJoin(PlayerJoinEvent event){        
        event.getPlayer().sendMessage("Koukou twa ! :D");    
    }
}

 

C'est bien si c'est juste pour tester quelque chose rapidement... mais ça devient vite le foutoir sur votre classe principale.

 

Résumé:

  • Événements et listeners offrent une plus grande liberté d'action en séparant cause et conséquences.
  • Une fois notre classe listener créée, on lui ajoute les méthodes d'écoutes sans oublier l'annotation @EventHandler et on enregistre notre listener auprès du PluginManager
  • Possibilité d'annuler certains événements : setCancelled(true);
  • Possibilité de créer ses propres événements, de les dispatcher quand on veut et de les écouter comme les événements classiques

 

JeremGamer a également créé des cours sur les évènements et les listeners relatifs aux guis pour javax.swing et java.awt.

http://www.bukkit.fr/blog/3/entry-61-chapitre-28-les-%C3%A9v%C3%A8nements-partie-1/

http://www.bukkit.fr/blog/3/entry-62-chapitre-29-les-%C3%A9v%C3%A8nements-partie-2/

 

ilicos

SystemGlitch

blog-0400991001439390756.png

Vous les connaissez, il s'agit de ces petites fenêtres servant à afficher une information comme un avertissement ou une erreur, à demander une validation du style "Voulez-vous vraiment quitter? -> Oui / Non" ou encore demander une information à l'utilisateur.

En Java, elles portent le nom de JDialog tout simplement! Le JDK vous en propose déjà plusieurs toutes prêtes, ce qui est très pratique, mais si jamais vous avez besoin d'une boite de dialogue plus spécifique, il faudra alors la faire vous-même! N'ayez crainte, rien de bien difficile, c'est la même chose que pour les JFrame à une ou deux différences près.

 

Première différence: le reste du programme est figé tant que la boite de dialogue n'est pas fermée, à moins d'utiliser un Thread à part, mais nous n'avons pas encore vu comment faire.

Seconde différence: il est possible de rendre les JDialog modales, c'est à dire que tant qu'elles seront ouvertes, on ne pourra rien faire d'autre sur le logiciel que d’interagir avec la boite de dialogue. Vous en avez aussi rencontré j'en suis sûr.

 

Commençons par la partie la plus simple : les boites de dialogue informatives. Attention, pour les dialogs préfabriquées on utilisera JOptionPane et non pas JDialog ! Nous allons ajouter trois boutons à notre content pane, chacun ouvrira une boite de dialogue différente. Ces dernières sont modales, ce qui vous permettra de vous faire d'ores et déjà un idée de ce que cela signifie.

 
JButton info = new JButton("Ouvrir boite d'information");
info.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent arg0) {
		JOptionPane.showMessageDialog(null, "Message d'information", "Information", JOptionPane.INFORMATION_MESSAGE); //message d'information
	}
});

JButton warn = new JButton("Ouvrir boite d'avertissement");
warn.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent arg0) {
		JOptionPane.showMessageDialog(null, "Message préventif", "Attention", JOptionPane.WARNING_MESSAGE); //Message d'avertissement
	}

});

JButton err = new JButton("Ouvrir boite d'information");
err.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent arg0) {
		JOptionPane.showMessageDialog(null, "Message d'erreur", "Erreur", JOptionPane.ERROR_MESSAGE); //Message d'erreur
	}

});

 

kiF8YQb.pngYSZhJgv.pngQHrE7Sy.png

 

Revenons plus en détails sur la méthode que j'ai utilisé :

JOptionPane.showMessageDialog(null, "Message d'information", "Information", JOptionPane.INFORMATION_MESSAGE);

 

Le premier argument est le JComponent parent. C'est à dire le composant au dessus du quel devra s'ouvrir la fenêtre. S'il y en a pas comme ici, on met null. On aurait cependant pu mettre this pour centrer la boite de dialogue au dessus du content pane, même si la fenêtre principale avait été déplacée.

Le second argument est le message que l'utilisateur verra dans la boite de dialogue.

Le troisième est le titre de la boite de dialogue, affiché dans la barre d'action.

Et le dernier est celui qui définira s'il s'agit d'un message d'information, d'erreur ou d'avertissement. D'ailleurs il est possible de simplement mettre un message, sans icône, à l'aide de JOptionPane.PLAIN_MESSAGE, ou alors une question avec JOptionPane.QUESTION_MESSAGE.

 

Cette méthode est surchargée. Voyons un peu ce que l'on peut faire de plus ! :) Nous avons deux surcharges à notre disposition, l'une rajoute un argument de type ImageIcon, qui nous permettra donc de changer l'icône, l'autre permet de créer un boite de dialogue la plus simple qui soit car seuls les deux premiers arguments sont conservés.

 

Voici comment changer l'icône qui sera affichée :

ImageIcon img = new ImageIcon("check.png");
JOptionPane.showMessageDialog(null, "Sauvegarde réussie!", "Succès", JOptionPane.INFORMATION_MESSAGE , img);

 

4BPvWff.png

 

Jetons maintenant un œil aux boites de confirmation. Cette fois la méthode utilisée sera showConfirmDialog(). La différence c'est que celle-ci retourne un int indiquant le choix de l'utilisateur. Vous verrez ce sera tout de suite plus clair en voyant le code :

int option =JOptionPane.showConfirmDialog(null, "Êtes-vous sûr de vouloir quitter?", "Vraiment?" , JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); //Vous pouvez encore changer l'icône en ajoutant une argument du type ImageIcon
if(option == JOptionPane.YES_OPTION)
	System.out.println("Quitter");
else if(option == JOptionPane.NO_OPTION)
	System.out.println("Ne pas quitter");

 

tDbYkvK.png

 
 
int option =JOptionPane.showConfirmDialog(null, "Le fichier est introuvable, continuer?", "Fichier introuvable" , JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
if(option == JOptionPane.YES_OPTION)
	System.out.println("Continuer");
else if(option == JOptionPane.NO_OPTION)
	System.out.println("Ne pas continuer");
else if(option == JOptionPane.CANCEL_OPTION)
	System.out.println("Annuler");
else if(option == JOptionPane.CLOSED_OPTION) //L'utilisateur a fermé la boite de dialogue sans passer par les boutons "Oui" "Non" ou "Annuler"
        System.out.println("Fermer");

 

eDGwsly.png

 

Le principe est acquis, on passe à la suite! En effet ici on stockait une int renvoyée par la méthode, mais si on faisait une boite de dialogue qui demande à l'utilisateur d'écrire une chaine de caractères? Et bien c'est pareil! Sauf qu'on aura une String en retour :

String answer = JOptionPane.showInputDialog(null, "Comment vous appelez-vous?", "Vos identifiants" , JOptionPane.QUESTION_MESSAGE);
System.out.println("L'utilisateur s'appelle \""+ answer + "\".");

 

W60Bb0P.png

 

 

Allons un peu plus loin et proposons différents choix via un menu déroulant. On créera un tableau contenant les valeurs possibles et le donnera en argument :

String[] sex = { "Homme" , "Femme" , "Autre" };
String answer = (String) JOptionPane.showInputDialog(null, "Veuillez indiquer votre sexe.", "Vos identifiants" , JOptionPane.QUESTION_MESSAGE , null , sex , sex[0]);
System.out.println("Sexe de l'utilisateur: " + answer);

 

AlhcOuR.png

 

Le dernier argument est celui qui sera sélectionné par défaut dans le menu déroulant. Attention si l'utilisateur ferme la boite de dialogue autrement qu'en appuyant sur "OK", la valeur retournée sera null, et cela est aussi valable pour le champ de saisie vu juste au dessus! Il faudra donc bien vérifier vos résultats! Quand à l'argument null donné dans la méthode, il s'agit de l'icône modifiée. On ne souhaite pas la changer donc on donne null. ^_^

 

Voici la dernière variante de boite de dialogue préfabriquée: c'est le même principe que celle que nous venons de voir mais cette fois il y aura plusieurs boutons et non pas un menu déroulant.

String[] sex = { "Homme" , "Femme" , "Autre" };
int answer = JOptionPane.showOptionDialog(null, "Veuillez indiquer votre sexe.", "Vos identifiants" , JOptionPane.YES_NO_CANCEL_OPTION , JOptionPane.QUESTION_MESSAGE, null , sex , sex[0]);
//answer est le numéro du bouton qui a été cliqué par l'utilisateur, -1 si la fenêtre à été fermée par un autre moyen
//Vous pouvez donc mettre plus ou moins de trois boutons
if(answer >= 0)
	System.out.println("Sexe de l'utilisateur: " + sex[answer]);

 

14EDh1L.png

 

Bien, vous avez déjà de quoi faire. Mais certains cas ne sont pas gérés, ou alors, vous souhaitez simplement faire un boite de dialogue ayant un style visuel bien particulier. Vous savez déjà faire tout ça! Le procédé est exactement le même que pour la création d'une JFrame, sauf que votre classe héritera de JDialog. ;)

Votre code cadeau sera une boite de dialogue d'erreur faite maison! Pensez à l'utiliser avec le code cadeau donné dans le chapitre sur les exceptions ! :)

package fr.bukkit.jeremgamer.cours;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;

public class CustomDialog extends JDialog {

    private JLabel message = new JLabel("<html><b>Une erreur est survenue.</b><br>Certaines fonctionnalités risquent des disfonctions.<br>Il est conseillé de redémarrer le logiciel.<br><em>Support: [email protected]<script cf-hash='f9e31' type="text/javascript">
/*  */</script></em></html>");
    private JButton copy = new JButton("Copier le rapport");
    private JButton close = new JButton("Ok");
    
    private Toolkit toolkit = Toolkit.getDefaultToolkit();
    private Clipboard cb = toolkit.getSystemClipboard();
    
    private DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    private Date date;

    private StringWriter sw = new StringWriter();
    private PrintWriter pw = new PrintWriter(sw);
    
    private Throwable e;
    
    public CustomDialog(final Throwable e) {
        
        date = new Date();
        this.e = e;
        
        this.setModal(true); //On rend notre boite de dialogue modale
        this.setTitle("Erreur");
        this.setResizable(false);
        this.setSize(new Dimension(400, 150));
        this.setLocationRelativeTo(null);
        
        JPanel messageContent = new JPanel() {

            /**
             *
             */
            private static final long serialVersionUID = 3692136522118161020L;

            protected void paintComponent(final Graphics g) {
                Icon icon = UIManager.getIcon("OptionPane.errorIcon");    
                BufferedImage image = new BufferedImage( icon.getIconWidth() , icon.getIconHeight() , BufferedImage.TRANSLUCENT );
                icon.paintIcon(null, image.getGraphics() , 0 , 0 );
                g.drawImage(image, 20 , 35, 48 , 48 , null);
                super.paintComponents(g);
            }
        };

        messageContent.add(Box.createRigidArea(new Dimension(400 , 0)));
        messageContent.add(Box.createRigidArea(new Dimension(70 , 0)));

        FlowLayout flow = new FlowLayout();
        flow.setAlignment(FlowLayout.RIGHT);
        flow.setVgap(5);
        flow.setHgap(5);
        JPanel buttons = new JPanel(flow);
        buttons.add(copy);
        buttons.add(close);
        final Container glass = (Container) this.getGlassPane();
        glass.setVisible(true);
        glass.setLayout(new BorderLayout());
        glass.add(buttons , BorderLayout.SOUTH);

        messageContent.add(message);

        close.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                dispose();
            }            
        });

        copy.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                cb.setContents( new StringSelection(getReport()) , null );             
            }            
        });

        this.setContentPane(messageContent);        
        
        this.setVisible(true);
    }
    
    private String getReport() {
        e.printStackTrace(pw);
        return new String( "Rapport d'erreur :\n"
                + "Version : " + "0.0.1" + "\n"
                + "Date : " + dateFormat.format(date) + "\n"
                + "Système d'exploitation : " + System.getProperty("os.name") + " " + System.getProperty("os.version") +"\n\n"
                + "StackTrace :\n" + sw.toString());
    }
    
}

 

TKuM2ih.png

 

 

Résumé :

 

  • Les boites de dialogue sont de petites fenêtres permettant d'afficher une information ou d'en demander une à l'utilisateur.
  • Elles figent le reste du programme tant qu'elles sont ouvertes.
  • Les boites de dialogues modales empêchent toute interaction avec le reste du logiciel tant qu'elle sont ouvertes.
  • Pour les boites de dialogue préfabriquées, on utilisera JOptionPane.
  • Pour les boites de dialogue personnalisées, on créera une classe qui hérite de JDialog.

 

 

JeremGamer

 

2cp1ED5.png

SystemGlitch

blog-0359394001438853478.png

Dans ce chapitre, vous apprendrez à créer des barres d'outils, des listes sous forme graphique ainsi qu'à utiliser un explorateur de fichiers. Vous n'en serez pas surpris vu le titre du chapitre. ^_^

Commençons par les barres d'outils. Vous les connaissez bien et elles vous servent tous les jours! Ce sont en effet ces barres regroupant un certain nombres d'icônes cliquables qui permettent donc des actions rapides comme changer la police ou le gras, souligné, etc... dans les logiciels de traitement de texte! Nous utiliserons l'objet JToolBar. C'est très simple : le principe est d'y ajouter des JComponent comme les JButtons et d'indiquer où elle apparaitra. Car il faudra le spécifier lors de sa création.

 
JToolBar toolBar = new JToolBar();

JToggleButton bold = new JToggleButton("<html><b>B</b></html>");
JToggleButton italic = new JToggleButton("<html><i>I</i></html>");
JToggleButton underlined = new JToggleButton("<html><u>U</u></html>");
JComboBox<String> font = new JComboBox<String>();

GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment(); //On récupère l'environnement graphique
Font[] fonts = e.getAllFonts(); //Puis toutes les polices installées
for (Font f : fonts) { 
	font.addItem(f.getName()); //Afin de les ajouter dans le menu déroulant
}

toolBar.add(bold);
toolBar.add(italic);
toolBar.add(underlined);
toolBar.addSeparator(); //On ajoute une barre de séparation
toolBar.add(font);

this.setLayout(new BorderLayout());
this.add(toolBar , BorderLayout.NORTH); //On positionne la barre en haut du panneau

 

YKlMDeS.png

 

Certains auront remarqué que la barre d'outil est déplaçable à l'aide de la petite zone sur la gauche de la barre.

 

5tEBweX.png

 

En effet il sera possible de la repositionner en bas du panneau, à sa gauche, à sa droite, etc... et même dans une petite boite de dialogue à part ! :D

Il est possible de désactiver la possibilité de la déplacer ainsi :

toolBar.setFloatable(false);

 

Vous aurez peut-être remarqué que les boutons ne se "surlignent" pas lors du survol de la souris. Il faut activer cette fonctionnalité qui ne l'est pas par défaut sur les barres d'outils :

toolBar.setRollover(true);

 

Passons aux listes graphiques. L'objet que nous utiliserons s'appelle JList. La généricité est importante dans l'utilisation de cet objet. Nous utiliserons un argument générique de type String la plupart du temps. Mais attention, pour une fois c'est un tout petit peu plus compliqué car nous devrons passer par un autre objet, un modèle pour la liste : DefaultListModel.

JList<String> productList = new JList<String>();
DefaultListModel<String> data = new DefaultListModel<String>();
data.addElement("Aspirateur");
data.addElement("Moteur");
data.addElement("Tondeuse");
data.addElement("Machine à laver");
data.addElement("Fer à repasser");
data.addElement("Mixeur");
data.addElement("Micro-ondes");
data.addElement("Four");
data.addElement("Plaque de cuisson");
//...
		
productList.setModel(data); //On applique le modèle à la liste

 

9jMJtEg.png

 

Voila l'utilisation la plus basique d'une JList. Maintenant voyons les autres possibilités...

Pour commencer nous allons modifier les paramètres de sélection. Par défaut, la sélection est unique, voici comment gérer la sélection multiple :

productList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); //Sélection unique
productList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); //Sélection multiple 

 

k3aDQ6y.png

 

Vous devrez utiliser CTRL ou SHIFT pour effectuer une sélection multiple comme vous avez l'habitude de le faire avec n'importe quelle autre application. ;)

Et si on changeait la disposition de notre liste?

productList.setLayoutOrientation(JList.VERTICAL); //Verticale, par défaut
productList.setLayoutOrientation(JList.VERTICAL_WRAP); //Du haut vers le bas, puis affiche une autre colonne lorsqu'on a atteint le bas de la liste
productList.setLayoutOrientation(JList.HORIZONTAL_WRAP); //Horizontale, de gauche à droite, puis retour à la ligne

 

Le screenshot suivant montre le résultat avec JList.HORIZONTAL_WRAP :

 

Taz4S4Y.png

 

Nous allons mettre notre liste dans un JScrollPane, puis définir le nombre d'items visibles à la fois :

productList.setVisibleRowCount(4); //Mettre -1 pour ne pas donner de limite, 8 par défaut
JScrollPane listScroller = new JScrollPane(productList);

this.add(listScroller);

 

BOhQG12.png

 

Vous pouvez aussi changer le layout complet des listes afin d'avoir un rendu complètement personnalisé. Attention, cette fois on utilisera des JComponent directement ajoutés à la liste, plus de modèle! Mais enfin, vous avouerez que c'est n'est pas très utile, autant utiliser un JPanel. Surtout que le layout ne fonctionne pas vraiment comme on l'espérait sur la liste :

JList<String> productList = new JList<String>();
productList.setLayout(new GridLayout(5,5));


productList.add(new JButton("Aspirateur"));
productList.add(new JButton("Moteur"));
productList.add(new JButton("Tondeuse"));
productList.add(new JButton("Machine à laver"));
productList.add(new JButton("Fer à repasser"));
productList.add(new JButton("Mixeur"));
productList.add(new JButton("Micro-ondes"));
productList.add(new JButton("Four"));
productList.add(new JButton("Plaque de cuisson"));
//...
		
JScrollPane listScroller = new JScrollPane(productList);
		
this.add(listScroller);

 

Pc0Cb7i.png

 

Pour faire cela correctement on utilisera plutôt un ListCellRenderer que vous devrez écrire vous-même! Celui par défaut n'affiche que des String.

Tout ce que vous avez à faire c'est créer une classe qui implémente ListCellRenderer puis appeler la méthode setCellRenderer() et donner une instance de cette classe en argument ! ;)

Voici un petit exemple pour pouvoir afficher des JLabel (ce sera votre code cadeau :) ) :

public class CustomCellRenderer extends JLabel implements ListCellRenderer<Object> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6145242041026326434L;


	private String[] texts = { "Allemagne" , "Belgique" , "France" , "Italie" };
	private ImageIcon[] images = new ImageIcon[texts.length];

	public CustomCellRenderer() {
		setOpaque(true);
		setVerticalAlignment(CENTER);
		for(int i = 0; i < texts.length ; i++) {
			images[i] = new ImageIcon(texts[i] + ".png");
			images[i].setDescription(texts[i]);
		}
	}

	@Override
	public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {


		if (isSelected) {
			setBackground(list.getSelectionBackground());
			setForeground(list.getSelectionForeground());
		} else {
			setBackground(list.getBackground());
			setForeground(list.getForeground());
		}

		ImageIcon icon = images[index];
		String text = texts[index];
		setIcon(icon);
		if (icon != null) {
			setText(text);
			setFont(list.getFont());
		}
		return this;
	}
}

 

Et instanciez votre JList de cette manière :

JList countryList = new JList(new Integer[4]); //4 étant le nombre d'items
CustomCellRenderer renderer = new CustomCellRenderer();
countryList.setCellRenderer(renderer);

 

wj8Z1Lu.png

 

Il reste une chose à voir avec les JList. Comment les écouter? Nous utiliserons un MouseAdapter. Mais il faudra faire attention à plusieurs choses !

productList.addMouseListener(new MouseAdapter() {

	@Override
	public void mouseClicked(MouseEvent e) { //Nous allons effectuer quelque chose lors du double clic sur un item
		int index = productList.locationToIndex(e.getPoint()); //égal à -1 si l'utilisateur clique en dehors d'un item
		if (e.getClickCount() == 2 && index != -1) { //Double clic et on s'assure que l'utilisateur clique bien sur un item
			//...
		} else if (e.getClickCount() == 3 && index != -1) { //Supporter le triple clic
			//...
		}
	}
});

 

C'est tout pour les listes! Il y a bien d'autres choses à faire avec mais ce serait trop long de tout détailler alors je vous laisse vous renseigner par vous-même. ;)

Pour finir ce chapitre, je vais vous présenter un outil très pratique, à votre disposition: j'ai nommé le JFileChooser.

Le principe est de faire choisir un fichier par l'utilisateur, vous en rencontrez souvent, par exemple lorsque vous faites "Enregistrer sous...". C'est très simple en soi, mais de nombreuses subtilités peuvent être ajoutées :

String path = null;
JFileChooser chooser = new JFileChooser();
int option = chooser.showOpenDialog(null);
if(option == JFileChooser.APPROVE_OPTION) { //Si l'utilisateur clique sur "Ouvrir" ou appuie sur Entrée
	path = chooser.getSelectedFile().getAbsolutePath();
	System.out.println(path);
}

 

eiTKlkt.png

 

Une GUI toute faite ! Pourquoi s'en priver? :)

Sans plus tarder, voici les subtilités évoquées il y a un instant :

Tout d'abord, vous pouvez modifier ce qui est sélectionnable :

chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); //Fichiers uniquement
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); //Dossiers uniquement 
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); //Fichiers ou dossiers
chooser.setMultiSelectionEnabled(true); //Pour activer les sélections multiples

 

Ensuite, vous pouvez appliquer des filtres. C'est à dire que vous pouvez choisir les extensions de fichiers qui seront affichées. Avec le code suivant, seules les images seront affichées dans le sélecteur :

FileNameExtensionFilter filter = new FileNameExtensionFilter("Images", "jpg", "png", "gif", "jpeg" , "bmp");
//Le premier argument sera l'indication affichée à l'utilisateur
chooser.setFileFilter(filter);
chooser.setAcceptAllFileFilterUsed(false); //Permet d'empêcher l'utilisateur de retirer le filtre grâce au menu déroulant

 

A l'aide de setCurrentDirectory(File dir), vous pouvez rediriger le sélecteur vers un dossier donné.

Sinon, vous pouvez définir dans quel dossier s'ouvrira le sélecteur. Pour cela il faudra directement le spécifier dans le constructeur :

JFileChooser chooser = new JFileChooser("C:\\Cours Java");

 

 

Résumé :

 

  • Les JToolBar peuvent accueillir tous les JComponent.
  • Les JList s'utilisent avec un modèle en général, du type DefaultListModel.
  • Pensez à prévoir un JScrollPane pour les JList au cas où il y aurait beaucoup d'items.
  • Les JFileChooser permettent à l'utilisateur de sélectionner un fichier.

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0266210001438172279.png

Dans ce chapitre, vous apprendrez à créer vos propres menus! Nous verrons les barres de menu que vous avez l'habitude de voir en haut des fenêtres, là où se trouve "Fichier", "Édition", etc... ainsi que les menus pop-up, aussi appelés menus contextuels, pouvant apparaître n'importe où! Vous avez l’habitude de voir ces derniers apparaitre lorsque vous cliquez-droit. ;)

 

Comme tout ce que nous voyons depuis un moment, il ne s'agit que de l'utilisation de composants Swing, ce qui veut dire que ce sera très simple une fois de plus. :P

 

Voici le principe: une barre de menu JMenuBar, des menus JMenu et des items à mettre dedans, les JMenuItem. Attention cependant : cette fois-ci nous travaillons sur l'objet de notre fenêtre et non sur le content pane. Il existe des variantes de JMenuItem qui permettent d'insérer les autres composants de formulaire que vous avez vu jusque là: le JCheckBoxMenuItem et JRadioButtonMenuItem.

 

En pratique, cela donne quelque chose qui ressemble à ça :

 
JMenuBar menuBar = new JMenuBar();
		
JMenu file = new JMenu("Fichier");
JMenuItem new_ = new JMenuItem("Nouveau");
JMenuItem open = new JMenuItem("Ouvrir");
JMenuItem save = new JMenuItem("Sauvegarder");
		
JMenu subMenu = new JMenu("Sous-menu");
JRadioButtonMenuItem rb0 = new JRadioButtonMenuItem("Choix n°1");
JRadioButtonMenuItem rb1 = new JRadioButtonMenuItem("Choix n°2");
ButtonGroup bg = new ButtonGroup();
bg.add(rb0);
bg.add(rb1);
subMenu.add(rb0);
subMenu.add(rb1);

file.add(new_);
file.add(open);
file.addSeparator(); //On ajoute une petite barre de séparation
file.add(subMenu);
file.addSeparator();
file.add(save);
		
JMenu edit = new JMenu("Édition");
JCheckBoxMenuItem cb0 = new JCheckBoxMenuItem("Option n°1");
JCheckBoxMenuItem cb1 = new JCheckBoxMenuItem("Option n°2");
edit.add(cb0);
edit.add(cb1);
		
menuBar.add(file);
menuBar.add(edit);
		
this.setJMenuBar(menuBar); //On applique la barre à la fenêtre

 

I30RHmW.png

 

Je vous laisse expérimenter par vous-même. ;) Vous aurez surement deviné la manière d’interagir avec nos items. Car pour l'instant, ils ne font rien, absolument rien. Comme d'habitude, nous utiliserons les Listener :

JMenuItem new_ = new JMenuItem("Nouveau");
new_.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("Menu \"" + new_.getText() + "\" cliqué!");
	}
	
});

 

Allons plus loin : ajoutons des raccourcis clavier. Il en existe deux types: les accélérateurs, qui permettent un simple raccourci vers un élément du menu, et les mnémoniques qui permettent de simuler un clic sur un point de menu, ce qui revient presque au même. Ces derniers seront utilisés pour les menus et non pour les items.

JMenu file = new JMenu("Fichier");
JMenuItem new_ = new JMenuItem("Nouveau");
new_.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("Item \"" + new_.getText() + "\" cliqué!");
	}
	
});
new_.setAccelerator(KeyStroke.getKeyStroke('n')); //Touche n
		
		
JMenuItem open = new JMenuItem("Ouvrir");
open.addActionListener(new ActionListener() {

       @Override
       public void actionPerformed(ActionEvent e) {
               System.out.println("Item \"" + open.getText() + "\" cliqué!");
       }
            
});
open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O , KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK)); //CTRL+SHIFT+O

JMenuItem save = new JMenuItem("Sauvegarder");
save.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("Item \"" + save.getText() + "\" cliqué!");
	}
	
});
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S , KeyEvent.CTRL_MASK)); //CTRL+S

 

GOFRLz4.png

 

Vous pouvez voir que les raccourcis s'affichent à côté de l'item en plus de ça ! :D

 

Pour les mnémoniques, c'est le même principe, sauf qu'il faudra presser Alt + la touche définie pour que le menu se déroule :

JMenu file = new JMenu("Fichier");
file.setMnemonic('F');
//...
JMenu edit = new JMenu("Édition");
edit.setMnemonic('É');

 

ojxsRCF.png

 

Cette fois le caractère défini est souligné s'il est présent dans le texte du menu.

 

Vous pouvez aussi initialiser les JMenu avec un mnémonique directement :

JMenuItem open = new JMenuItem("Ouvrir" , 'O');

 

J'ai une bonne nouvelle : ça ne s'arrête pas là ! Il est possible, en réalité, d'ajouter n'importe quel JComponent au menu !

file.add(new JButton("Bouton"));
file.add(new JLabel("Label"));
file.addSeparator();
JPanel pan = new JPanel();
pan.setBackground(Color.RED);
file.add(pan);

 

y1pSTuv.png

 

Et mieux encore : il est même possible de leur attribuer un mnémonique ! (Mais pas d'accélérateur) Ce dernier fonctionnera uniquement si le menu est déjà déroulé. Il y a quand cependant quelques exceptions : les JLabel ou les JPanel par exemple, car ils ne sont pas censé être des composants avec lesquels l'utilisateur interagit.

 

 

Passons aux menus contextuels. Vous savez l'essentiel, plus qu'à rajouter quelques fonctionnalités comme la position où apparaitra le menu ainsi que le fait qu'il apparaisse à l'aide d'un clic droit. Commençons par préparer notre menu :

JPopupMenu menu = new JPopupMenu();
        
JMenuItem new_ = new JMenuItem("Nouveau");
JMenu subMenu = new JMenu("Sous-menu");
JRadioButtonMenuItem rb0 = new JRadioButtonMenuItem("Choix n°1");
JRadioButtonMenuItem rb1 = new JRadioButtonMenuItem("Choix n°2");
ButtonGroup bg = new ButtonGroup();
bg.add(rb0);
bg.add(rb1);
subMenu.add(rb0);
subMenu.add(rb1);
	
menu.add(new_);
menu.add(open);
menu.addSeparator();
menu.add(subMenu);
menu.addSeparator();
menu.add(save);

 

Parfait. Maintenant plus qu'à faire en sorte qu'il apparaisse avec le clic droit :

JPanel content = new JPanel();
		
content.addMouseListener(new MouseAdapter(){

	public void mouseReleased(MouseEvent event){
		if(event.isPopupTrigger())   //Clic droit    
			menu.show(content, event.getX(), event.getY()); //Afficher le menu sur le contentPane 
	}

});

this.setContentPane(content);

 

EARUm3b.png

 

Pour vous montrer une autre application possible des JPopupMenu, voici un petit code cadeau que je vous invite fortement à tester. Ce n'est pas le meilleur moyen de faire ce qu'il fait, pas non plus le plus optimisé, mais ça illustre bien ce que pourrait faire cet objet.

ArrayList<String> producList = new ArrayList<String>();
productList.add("Aspirateur");
productList.add("Moteur");
productList.add("Tondeuse");
productList.add("Machine à laver");
productList.add("Fer à repasser");
productList.add("Mixeur");
productList.add("Micro-ondes");
productList.add("Four");
productList.add("Plaque de cuisson");
//...

JPopupMenu suggestions = new JPopupMenu();
suggestions.setMinimumSize(new Dimension(200 , 25));
suggestions.setFocusable(false);

JTextField searchField = new JTextField();
searchField.setPreferredSize(new Dimension(200 , 25));

searchField.addCaretListener(new CaretListener() {

	@Override
	public void caretUpdate(CaretEvent e) {
		suggestions.removeAll();
		for(String s : productList)
			if(s.startsWith(searchField.getText()))
				suggestions.add(new JMenuItem(s));
		if(suggestions.getComponents().length > 0) {
			suggestions.show(searchField, searchField.getX(), searchField.getY() + searchField.getHeight() - 7);
			suggestions.pack();
			suggestions.revalidate();
			suggestions.repaint();
		}
	}
});

 

 

Résumé :

 

  • Les JMenu sont placés dans une JMenuBar ou dans un JPopupMenu.
  • Ils contiennent des JMenuItem.
  • Tous les JComponent peuvent être ajoutés aux JMenu.

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0123823001437053856.png

Jusque là, vos GUI restent tout de même assez fades, nous allons y remédier !

Et en plus de cela, nous verrons aussi de nouveaux objets ouvrant la porte à de nouvelles possibilités, il s'agira essentiellement de conteneurs. ;)

 

Pour commencer, nous allons créer des bordures de toutes sortes autour de nos panneaux !

Voici l'objet que nous allons utiliser: BorderFactory. Ce n'est pas bien compliqué alors je ne vais pas trop m'attarder sur les explications, jetez simplement un œil à l'exemple ci-dessous :

 

 

 
	private String[] list = {
			"Bevel Border",
			"Etched Border",
			"Line Border",
			"Matted Border",
			"Raised Bevel Border",
			"Title Border",
			"Compound Border"
	};

	//C'est à cette partie qu'il faut s'intéresser
	private Border[] listBorder = { //Pour limiter le nombre de lignes de code
			BorderFactory.createRaisedBevelBorder(),
			BorderFactory.createTitledBorder("Titre"),
			BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.black, Color.red),
			BorderFactory.createEtchedBorder(Color.BLUE, Color.GRAY),
			BorderFactory.createLineBorder(Color.RED),
			BorderFactory.createMatteBorder(5, 2, 5, 2, Color.MAGENTA),
			BorderFactory.createCompoundBorder( 
					BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.black, Color.blue), 
					BorderFactory.createMatteBorder(5, 2, 5, 2, Color.MAGENTA))
	};

	public ExamplePanel() {
		for(int i = 0 ; i < list.length ; i++) {
			JPanel pan = new JPanel();
			pan.setBorder(listBorder[i]);
			JLabel label = new JLabel(list[i]);
			label.setPreferredSize(new Dimension(150, 50));
			label.setAlignmentX(JLabel.CENTER);
			label.setHorizontalAlignment(JLabel.CENTER);
			pan.add(label);
			this.add(pan);
		}
	}

 

vp5kyMt.png

 

Ici j'ai décidé d'appliquer les bordures sur les panneaux, mais il est possible de les appliquer à n'importe quel composant héritant de JComponent, à l'aide de la même méthode setBorder(). Sachez également que vous pouvez choisir de donner null en argument afin de retirer les bordures. ;)

 

Vous vous souvenez du texte qui ne s'affichait pas entièrement des les JTextArea lorsque ce dernier était trop long?

Sur les applications que vous utilisez, vous auriez vu apparaitre des barres d'ascenseurs sur le côté et en bas, appelées scroll bars. A notre tour de les mettre en place ! Nous utiliserons le conteneur JScrollPane et étudierons rapidement quelques unes de ses méthodes.

 

Il s'agit d'un conteneur, alors nous allons procéder de la même manière qu'avec les JPanel. Cependant, je vous conseille plutôt d'ajouter un JPanel au JScrollPane. ;)

Pourquoi cela? Tout simplement car notre conteneur est dynamique et peut faire apparaitre ou disparaitre les scroll bars en fonction de la taille de ce qu'il contient. Si son contenu ne dépasse pas sa propre taille, alors les barres n'apparaitront pas! (Par défaut, il sera possible de les laisser affichées en permanence si vous le souhaitez. Nous verrons comment faire juste après.)

JTextArea text = new JTextArea();
JScrollPane scroll = new JScrollPane(text);

this.setLayout(new BorderLayout());	
this.add(scroll , BorderLayout.CENTER);

 

uPXbGyF.png

 

Voici un exemple concernant les panneaux. Ce conteneur étant très adapté à l'utilisation du BoxLayout, il sera judicieux de l'utiliser même si la taille par défaut est suffisante pour tout afficher, afin de réaliser des GUI plus modulables pour l'utilisateur. ^_^

JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel , BoxLayout.LINE_AXIS));

for(int i = 0 ; i < 5 ; i++)
	panel.add(new JButton("Bouton n°" + i));

JScrollPane scroll = new JScrollPane(panel);
scroll.setPreferredSize(new Dimension(300 , 50));
		
this.setLayout(new BorderLayout());	
this.add(scroll , BorderLayout.CENTER);

 

MXN9rx1.png

 

Comme je le disais plus haut, il est possible de changer la "politique d'affichage" des scroll bars. C'est tout simple :

scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); //La barre verticale est toujours affichée
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); //Par défaut, affiche la barre si besoin 
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);  //N'affiche jamais la barre verticale
		
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); //La barre horizontale est toujours affichée
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); //Par défaut, affiche la barre si besoin
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //N'affiche jamais la barre horizontale

 

Les JTabbedPane vous permettrons, à l'image du CardLayout, d'empiler plusieurs panneaux. Cependant, l'utilisateur pourra facilement y accéder grâce aux onglets qui seront disposés en haut de l'écran! :)

C'est vraiment tout simple à utiliser :

JTabbedPane tabs = new JTabbedPane();
		
JPanel red = new JPanel();
red.setBackground(Color.RED);
		
JPanel green = new JPanel();
green.setBackground(Color.GREEN);
		
JPanel blue = new JPanel();
blue.setBackground(Color.BLUE);	
		
tabs.addTab("Rouge", red);
tabs.addTab("Vert", green);
tabs.addTab("Bleu", blue);

 

7MVrZo9.png

 

Grâce à addTab(), vous pouvez ajouter des onglets; de la même manière, vous pouvez en retirer à l'aide de removeTab(int index)

Mais ça ne s'arrête pas là! Il y a pleins d'autres possibilités comme changer l'orientation de la barre d'onglets :

//A l'initialisation
JTabbedPane tabs = new JTabbedPane(JTabbedPane.LEFT); //Affichera les onglets à gauche
//ou avec la méthode
tabs.setTabPlacement(JTabbedPane.RIGHT); //Affichera les onglets à droite
tabs.setTabPlacement(JTabbedPane.BOTTOM); //Affichera les onglets en bas

 

92pS3ta.png

 

Avez-vous essayé de réduire la fenêtre pour voir ce qu'il se passait si les onglets occupent plus d'espace qu'ils en ont à leur disposition? Les onglets se redisposerons sur plusieurs lignes ou colonnes selon l'orientation. Il est possible de changer ce comportement pour le remplacer par l'ajout d'une petite flèche faisant défiler les onglets. ;)

tabs.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); //Par défaut, redisposera les onglets sur plusieurs lignes si besoin
tabs.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); //Ajoutera un scroll si besoin

 

jwFrc5I.png

 

Le screenshot ci-dessus utilise SCROLL_TAB_LAYOUT.

 

Et pour finir en beauté avec ces onglets, voyons comment insérer des icônes !

JTabbedPane tabs = new JTabbedPane(JTabbedPane.LEFT);
		
JPanel red = new JPanel();
red.setBackground(Color.RED);
		
JPanel green = new JPanel();
green.setBackground(Color.GREEN);
		
JPanel blue = new JPanel();
blue.setBackground(Color.BLUE);	
		
tabs.addTab("Accueil", red);
tabs.setIconAt(0, new ImageIcon("home.png"));
		
tabs.addTab("Rechercher", green);
tabs.setIconAt(1, new ImageIcon("search.png"));
		
tabs.addTab("Informations", blue);
tabs.setIconAt(2, new ImageIcon("infos.png"));

 

WgcKk0I.png

 

Vous avez sans doute déjà rencontré des applications avec des fenêtres internes, comme bloquées dans la fenêtre principale. En Java, on combinera des JInternalWindow avec un JDesktopPane. Ce dernier est un conteneur du type bureau comme son nom l'indique. Le principe est simple une fois de plus : un bureau et des fenêtres ! Voici un petit exemple :

public ExamplePanel() {
		
	this.setPreferredSize(new Dimension(300 , 300));
		
	JDesktopPane desktop = new JDesktopPane();
		
	for(int i = 1 ; i < 6 ; i++)
		desktop.add(new CustomInternalFrame(i));
		
	this.setLayout(new BorderLayout());	
	this.add(desktop , BorderLayout.CENTER);
}
	
class CustomInternalFrame extends JInternalFrame {

	CustomInternalFrame(int number) {
	     this.setTitle("Fenêtre n°"+ number);
	      this.setClosable(true);
	      this.setResizable(true);
	      this.setSize(150, 80);
	      this.setVisible(true);
	}
}

 

qUMHYGF.png

 

Dans l'image, j'ai repositionné et redimensionné les cinq fenêtres, car à l'initialisation, elles apparaissent toutes au même endroit et à la même taille, vu que je n'ai pas pris le temps de m'occuper de ça dans le code. Il y a de nombreuses possibilités que je ne vais pas vous expliquer, je vous invite donc à jeter un œil à la documentation, vous êtes devriez commencer à avoir ce réflexe. ;) Pour ce qui est d'habiller tout ça, vous savez déjà le faire car JDesktopPane hérite de JLayeredPane.

 

On enchaîne ! Voici désormais les JEditorPane ! Ces conteneurs permettent d'afficher du html, mais de façon un peu limitée tout de même. C'est largement suffisant pour du texte riche et des images comme dans cet exemple :

 

SBvXMOt.png

 

Oui vous saurez faire cela plus tard ! Sympa n'est-ce pas? ^_^ Le panneau à droite contenant le texte est un JEditorPane contenant une mise en page html. Voici un exemple plus simple :

JEditorPane html = new JEditorPane();
JScrollPane scroll = new JScrollPane(html);
		
html.setEditable(false);
html.setEditorKit(new HTMLEditorKit());
html.setText("<html>Du <b>texte</b> <i>riche</i> en <u>HTML</u>.</html>");		
		
this.setLayout(new BorderLayout());	
this.add(scroll, BorderLayout.CENTER);

 

PNNhKLw.png

 

Ce conteneur peut également se comporter comme un JTextArea si l'on n'utilisait pas la méthode setEditable(false), de même que le JTextPane que je vous invite à essayer rapidement. ;)

 

Pour terminer ce chapitre, nous allons nous intéresser aux JSplitPane. Ils permettent de scinder votre conteneur en plusieurs "compartiments". Un exemple vaut mieux que de nombreux mots, je sais que vous reconnaitrez tout de suite de quoi il s'agit.

 

9m8gTOx.png

 

La barre de séparation peut être déplacée afin d'agrandir l'un des deux panneaux, et bien évidemment, de réduire l'autre.

Voici le code correspondant :

JPanel red = new JPanel();
red.setBackground(Color.RED);
	      
JPanel green = new JPanel();
green.setBackground(Color.GREEN);

JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT , red , green);

 

Rien de bien compliqué n'est-ce pas? ^_^

Comme d'habitude, nous n'allons pas nous arrêter là!

 

Tout d'abord, ici nous avons séparé horizontalement, à l'aide de JSplitPane.HORIZONTAL_SPLIT; pour séparer verticalement, on utilisera JSplitPane.VERTICAL_SPLIT.

Ici on a utilisé des JPanel, mais il peut s'agir de n'importe quel composant ! ;)

 

Nous allons améliorer notre barre de séparation et y ajouter deux petits boutons permettant de déplacer cette dernière à une extrémité de l'écran. Je conseille fortement d'essayer par vous-même car cela n'est pas illustrable par captures d'écran. C'est vraiment très simple :

split.setOneTouchExpandable(true);

 

G1qMdPp.png

 

Maintenant nous allons définir la taille de la barre. Encore une fois, rien de plus simple :

split.setDividerSize(20); //20 pixels

 

NydV9L4.png

 

Et pour en finir avec cette barre, voici comment choisir sa position. J'imagine que vous avez remarqué que cette dernière apparait quasiment entièrement à gauche lors de l’initialisation. Nous allons la faire apparaitre de façon à ce que le panneau de gauche soit deux fois plus grand que celui de droite.

split.setDividerLocation(0.75); //De manière proportionelle, ici le panneau de gauche occupera 75% de l'espace
//Ou en pixels si vous donnez un int

 

Attention, cette méthode ne fonctionnera pas si vous l'appelez avant que la fenêtre soit affichée, c'est à dire qu'il faut que JFrame.setVisible(true) soit appelé avant l'appel de la méthode.

 

Vous vous êtes peut-être demandé : et si je voulais combiner les deux séparations en mettant plusieurs panneaux? :lol:

C'est possible bien-sûr ! Il suffit de combiner plusieurs JSplitPane !

JPanel red = new JPanel();
red.setBackground(Color.RED);
	      
JPanel green = new JPanel();
green.setBackground(Color.GREEN);
	    
JPanel blue = new JPanel();
blue.setBackground(Color.BLUE);
	    
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT , red , green);
	
JSplitPane split2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT , split , blue);
		
contentPanel.setLayout(new BorderLayout()); 	
contentPanel.add(split2, BorderLayout.CENTER);

 

45NoNYp.png

 

Nous allons nous arrêter là pour ce chapitre. Dans le prochain chapitre, nous nous pencherons sur les menus ! ;)

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0507549001433339939.png

Dans ce chapitre, je vous présenterai de nombreux nouveaux composants qui vous permettront d'étoffer vos GUI. ;)

Il n'y aura que très peu d'explications car ce chapitre n'est absolument pas difficile, et le peu de notions que nous utiliserons dans ce dernier sont normalement déjà connues. Je vous invite fortement à essayer tous les bouts de code que je vous fournirai pendant ce chapitre.

 

Sans plus tarder, commençons avec quelque chose de très proche de ce que vous connaissez déjà : il s'agit d'un bouton restant enfoncé quand on clique dessus, j'ai nommé le JToggleButton.

 
JToggleButton button = new JToggleButton("Désactivé");
		
button.addItemListener(new ItemListener() {

	@Override
	public void itemStateChanged(ItemEvent e) {
		JToggleButton b = (JToggleButton) e.getSource();
		if(e.getStateChange() == ItemEvent.SELECTED)
			b.setText("Activé");
		else if(e.getStateChange() == ItemEvent.DESELECTED)
			b.setText("Désactivé");
	}
			
});

 

Rien de bien compliqué ! ^_^ Seule nouveauté, j'utilise ici un ItemListener et non pas un ActionListener comme vous savez déjà le faire. J'aurais très bien pu le faire également de la manière suivante, mais le but est ici de vous montrer les différents moyens d'arriver au même résultat. Choisissez celui que vous préférez. ;)

button.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		JToggleButton b = (JToggleButton) e.getSource();
		if(b.isSelected())
			b.setText("Activé");
		else
			b.setText("Désactivé");
	}

});

 

Le fonctionnement de ce bouton est finalement le même que celui des cases à cocher, que vous avez surement rencontré plus souvent dans l'utilisation courante. En Java, elles s'appellent les JCheckBox.

JCheckBox box = new JCheckBox("Cochez cette case");
		
box.addItemListener(new ItemListener() {

	@Override
	public void itemStateChanged(ItemEvent e) {
		if(e.getStateChange() == ItemEvent.SELECTED)
			System.out.println("Coché");
		else if(e.getStateChange() == ItemEvent.DESELECTED)
			System.out.println("Décoché");
	}
	
});

 

w6WaSOx.png

 

 

 

Dans un tout autre style, le JLabel ne permet pas d’interaction native avec l'utilisateur. Il sera possible d'en ajouter manuellement cependant. Il s'agit de texte, tout simplement, mais contenu dans un composant Swing rigide, ce qui le rend bien plus pratique que d'écrire le texte grâce à l'objet Graphics.

JLabel label = new JLabel("Un JLabel.");

 

ACygFmq.png

 

Voici tout ce qu'il y a de plus simple n'est-ce pas? ^_^ Les JLabel proposent de nombreuses options de personnalisation, ce qui va nous permettre de faire quelque chose d'un peu plus joli et adapté à nos envie. Tout d'abord, l'alignement peut être changé. Ici il est centré, mais on peut le caler à gauche ou à droite, etc... Ceci fonctionnera uniquement avec le BoxLayout.

JLabel label = new JLabel("Un JLabel." , JLabel.LEFT); //A gauche
JLabel label2 = new JLabel("Un JLabel." , JLabel.RIGHT); //A droite
		
//Ou à l'aide de cette méthode
label.setHorizontalAlignment(JLabel.LEFT); 

 

On peut ensuite choisir la couleur et la police du texte :

label.setForeground(Color.RED); //Couleur du texte
label.setFont(new Font("Impact" , Font.BOLD , 42)); //Police de caractère

 

VteuC8i.png

 

Les JLabel sont également utilisés pour afficher des images. Notre image aura donc les mêmes caractéristiques qu'un composant Swing! :) C'est une fois de plus un avantage dans certaines situations par rapport à l'utilisation de Graphics.

JLabel label = new JLabel();
try {
	label.setIcon(new ImageIcon(ImageIO.read(new File("image.png"))));
} catch (IOException e) {
	e.printStackTrace();
}

 

rAC4FK4.png

 

Il est bien-sûr possible d'afficher du texte à côté de l'image. Vous savez déjà comment vous occuper du texte avec les JLabel. ;)

Si vous voulez changer le texte après avoir instancié votre label, vous pouvez utiliser la méthode setText().

 

 

 

Passons à un autre composant : le JComboBox. Vous le connaissez peut-être plutôt sous le nom de menu déroulant.

Nous allons pouvoir ajouter autant d'item que l'on souhaite, et mieux encore : programmer un comportement différent pour chaque item !

JComboBox<String> box = new JComboBox<String>(); //Attention à la généricité !
//On ajoute les items
box.addItem("Item n°0"); 
box.addItem("Item n°1");
box.addItem("Item n°2");
box.addItem("Item n°3");

//Ou instancié à l'aide d'un tableau pour rentrer directement tous les items :
String[] items = { "Item n°0" , "Item n°1" , "Item n°2" , "Item n°3"};
JComboBox<String> box2 = new JComboBox<String>(items);

 

CCXzocb.png

 

Maintenant, ajoutons un Listener pour rendre tout ça un peu plus dynamique ! Pour l'exemple, nous allons ajouter un bouton et un label. Lors du clic sur le bouton, on actualisera le label pour lui faire afficher le texte contenu dans l'item sélectionné.

JComboBox<String> box = new JComboBox<String>(); //Attention à la généricité !
//On ajoute les items
box.addItem("Item n°0"); 
box.addItem("Item n°1");
box.addItem("Item n°2");
box.addItem("Item n°3");
		
JLabel label = new JLabel((String) box.getSelectedItem());
		
JButton button = new JButton("Actualiser");
button.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		label.setText((String)box.getSelectedItem());
	}
			
});

 

C'est bien, mais finalement on n'a pas écouté la JComboBox mais le JButton...

Retirons le bouton et actualisons le label automatiquement lorsque l'item sélectionné change :

JComboBox<String> box = new JComboBox<String>();

box.addItem("Item n°0"); 
box.addItem("Item n°1");
box.addItem("Item n°2");
box.addItem("Item n°3");
		
JLabel label = new JLabel((String) box.getSelectedItem());

box.addItemListener(new ItemListener() {

	@Override
	public void itemStateChanged(ItemEvent e) {
		label.setText((String)e.getItem());	
	}
			
});

 

Avec les JComboBox, il est préférable d'utiliser les ItemListener plutôt que les ActionListener, car je pense que vous avez compris qu'ils sont littéralement faits pour ça. ^_^ Il est possible d'utiliser un ActionListener mais il s'avèrera moins pratique. A vous de choisir une fois de plus. ;)

 

 

 

Dans la même catégorie du choix unique parmi plusieurs options, le JRadioButton est aussi très régulièrement utilisé.

Avant de vous montrer le code, je pense que vous présenter sa représentation pourra vous faciliter la compréhension du code qui suit.

 

qbbSBPr.png

ButtonGroup grp = new ButtonGroup(); //On créé un groupe dans lequel on ajoutera nos JRadioButton
//Si on ne le fait pas, on pourra sélectionner les deux boutons en même temps
//Or on souhaite qu'une seule option puisse être choisie
		
JRadioButton rb1 = new JRadioButton("Option n°1");
JRadioButton rb2 = new JRadioButton("Option n°2");
	
grp.add(rb1);
grp.add(rb2);

panel.add(rb1);
panel.add(rb2);

 

Encore une fois ce n'est pas bien compliqué. Pour ce qui est des Listener, on utilisera des ActionListener en général, et on les appliquera aux boutons directement, et non au groupe.

 

Et maintenant, j'ai l'honneur de vous présenter les JSpinner ! :D

XxAp0KZ.png

Vous connaissez désormais leur nom ! ^_^

La particularité de ceux-ci est que nous devons leur donner un modèle pour qu'ils sachent quoi afficher. Pour l'exemple, nous utiliserons un SpinnerNumberModel, qui permettra donc l'affichage de nombres. Sachez qu'il existe également les AbstractSpinnerModel, SpinnerDateModel et les SpinnerListModel. Je vous invite à jeter un œil à la documentation sur ces modèles afin de savoir tous les maitriser.

 

Pour réaliser le spinner présenté au dessus, le code est le suivant :

SpinnerModel model = new SpinnerNumberModel(0 , 0 , 100 , 1); //Valeur de base, minimum, maximum, palier
JSpinner spin = new JSpinner(model); //On instancie le spinner avec notre model
((DefaultEditor) spin.getEditor()).getTextField().setEditable(false); //Optionnel, détails ci-dessous

 

La dernière ligne permet de désactiver l'édition du champ de texte où est affichée la valeur par l'utilisateur. C'est bien-sûr optionnel.

 

Pour soulever les doutes possibles sur les paliers dans le modèle, voici une petite explication. Les paliers définiront quelle valeur sera ajoutée ou retirée lors du clic sur les flèches à droite du spinner. Si par exemple on a 0 en base et 2 en palier, quand on cliquera sur la flèche en haut (pour ajouter donc), le spinner affichera 2, puis 4, puis 6, etc...

 

 

Les JSlider sont des barres dont l'utilisateur peut déplacer le curseur. Elles sont notamment utilisées pour régler le volume sur les lecteurs multimédias.

 

BriFSd8.png

 

Voici le code correspondant :

JLabel label = new JLabel("Valeur : " + 50);
		
JSlider slider = new JSlider();
slider.setMinimum(0); //Valeur minimum
slider.setMaximum(100); //Valeur maximum
slider.setValue(50); //Valeur actuelle
slider.setPaintTicks(true); //Afficher des graduations
slider.setPaintLabels(true); //Afficher les valeurs sous les graduations supérieures
		
//En unité du slider, c'est à dire par rapport aux valeurs minimum et maximum.		
slider.setMinorTickSpacing(10); //Espace entre les graduations inférieures
slider.setMajorTickSpacing(20); //Espace entre les graduations supérieures
		
slider.addChangeListener(new ChangeListener() {

	@Override
	public void stateChanged(ChangeEvent e) {
		label.setText("Valeur : " + slider.getValue());
	}
			
});
		
panel.add(slider);
panel.add(label);

 

Il existe de nombreuses méthodes chez le JSlider, je vous suggère donc une fois de plus d'aller voir la documentation. ;)

 

 

 

Pour finir ce chapitre, je vais vous présenter une jolie famille qui vous sera surement bien utile : les champs de saisie ! Nous en verrons quatre.

 

Le plus simple pour commencer: JTextField. Comme d'habitude c'est toujours très simple de les utiliser, cependant il faudra leur donner une taille préférée sinon ils seront tout petits dans les layouts n'imposant pas de contrainte de taille comme le FlowLayout.

JTextField field = new JTextField();
field.setPreferredSize(new Dimension(110 , 25));
		
JTextField field2 = new JTextField("Texte par défaut"); //Le texte sera présent directement dans le champ
//Le champ de saisie prendra la taille adaptée par rapport au texte par défaut
		
panel.add(field);
panel.add(field2);

 

JNWll7p.png

 

Voila l'utilisation la plus simple que l'on peut en faire, mais il y a mieux ! Comme pour les JLabel, il est possible de changer la police et la couleur ! ;)

JTextField field = new JTextField();
field.setPreferredSize(new Dimension(110 , 25));
		
field.setForeground(Color.RED); //Couleur du texte
field.setFont(new Font("Impact" , Font.PLAIN , 16)); //Police

 

2G8ondN.png

 

Grâce aux méthodes getText() et setText(), vous pouvez respectivement récupérer le contenu du champ de saisie ou alors le modifier. Il est possible de personnaliser le caret également (le trait clignotant). Une fois de plus, la documentation sera votre meilleur ami ! ;)

 

Il y a une autre spécificité aux champs de saisie: on écoutera ce qui s'y passe avec un CaretListener et non un ChangeListener.

Voici un exemple :

JLabel label = new JLabel();
		
JTextField field = new JTextField();
field.setPreferredSize(new Dimension(110 , 25));
		
field.addCaretListener(new CaretListener() {

	@Override
	public void caretUpdate(CaretEvent e) {
		label.setText(field.getText());
	}
	
});

		
panel.add(field);
panel.add(label);

 

xmUgs5t.png

 

Bien, vous savez à peu près tout sur les JTextField. Mais ses frères et sœur ont d'autres options à offrir ! Ce que je viens de vous apprendre reste bien évidemment valable pour eux. ;)

 

Si vous avez essayé d'écrire un texte un petit peu plus long, vous avez remarqué qu'il n'y a pas de retour à la ligne, et que la fin n'est pas visible. Si l'on veut pouvoir faire des retours à la ligne, alors on devra utiliser des zones de texte bien plus grandes. On utilisera sa sœur, la JTextArea. Pour ce qui est du texte non visible, nous verrons cela dans le prochain chapitre. ;)

JTextArea field = new JTextArea();
field.setPreferredSize(new Dimension(200 , 100));

2Pg7zIo.png

 

Vous remarquerez qu'il n'y a plus de bordures, ce qui peut être un peu moche je vous l'accorde. Pas de souci, nous y remédierons dans un autre chapitre également.

Vous pouvez définir un retour à la ligne automatique :

field.setLineWrap(true); //Retour à la ligne activé

field.setWrapStyleWord(true); //Empêche la coupure des mots

 

Voyons désormais une autre variante: le JPasswordField. Il est identique au JTextField à la différence que seul le programme sera capable de lire se qu'il contient. Peu importe ce que vous écrirez, le même caractère s'affichera à chaque fois ('*' par défaut) :

 

deRvFyN.png

 

JPasswordField pass = new JPasswordField();
pass.setPreferredSize(new Dimension(110 , 25));
pass.setEchoChar('•'); //Pour choisir le caractère à afficher

 

Autre petite différence, il faut utiliser la méthode getPassword() et non getText() pour récupérer le contenu de la zone de saisie. Évidemment, il vous sera retourné ce que l'utilisateur aura vraiment tapé et non une multitude de points comme l'utilisateur peut le voir. Ça n'aurait aucun intérêt sinon...

 

Et pour clôturer ce long chapitre riche en contenu, le plus compliqué de champs de saisie: le JFormattedTextField. Ce dernier permet de filtrer ce que l'utilisateur entre, ou de limiter le nombre de caractères. Par exemple, on pourra choisir qu'il soit uniquement possible de rentrer des nombres. Ce qui le rendra bien plus pratique qu'un simple JTextField dans certains cas, et qui évitera de nombreux tests superflus.

 

Dans l'exemple je vais en empiler plusieurs à l'aide d'un BoxLayout, chacun aura un filtre différent :

JFormattedTextField ft1 = new JFormattedTextField(NumberFormat.getIntegerInstance()); //Uniquement des nombres entiers
ft1.setPreferredSize(new Dimension(110 , 25));
		
JFormattedTextField ft2 = new JFormattedTextField(NumberFormat.getNumberInstance()); //Uniquement des nombres
ft2.setPreferredSize(new Dimension(110 , 25));
		
JFormattedTextField ft3 = new JFormattedTextField(NumberFormat.getPercentInstance()); //Uniquement des pourcentages
ft3.setPreferredSize(new Dimension(110 , 25));
		
JFormattedTextField ft4 = new JFormattedTextField(DateFormat.getDateInstance(DateFormat.SHORT)); //Uniquement des dates sous la forme jj/mm/aa
ft4.setPreferredSize(new Dimension(110 , 25));
		
JFormattedTextField ft5 = new JFormattedTextField(DateFormat.getTimeInstance()); //Uniquement des heures sous la forme hh:mm:ss
ft5.setPreferredSize(new Dimension(110 , 25));

		
panel.setLayout(new BoxLayout(this , BoxLayout.PAGE_AXIS));
panel.add(ft1);
panel.add(ft2);
panel.add(ft3);
panel.add(ft4);
panel.add(ft5);

 

TqcQZGv.png

 

Il faut avouer que les possibilités des filtrage restent assez limitées. Alors voila ce que je vous propose: nous allons créer notre propre modèle ! :D Nous allons utiliser des MaskFormatter, adaptés aux numéros de série, de téléphone, etc...

MaskFormatter mask = new MaskFormatter();
try {
	mask.setMask("## ## ## ## ##"); //Numéro de téléphone français
} catch (ParseException e) {
	e.printStackTrace();
}
		
JFormattedTextField ft1 = new JFormattedTextField(mask);
ft1.setPreferredSize(new Dimension(110 , 25));

 

ZJR8Ppz.png

 

Je pense que cette histoire n'est pas très claire pour vous. Pourquoi avoir mis plein de dièses en argument du constructeur du MaskFormatter? Il s'agit de symboles représentant un ensemble de caractères. La dièse représente donc un nombre encore inconnu. Voici une liste détaillée:

  • # : Un chiffre
  • ' : Un symbole comme '!' ou '$', appelé caractère d'échappement. Cela comprend aussi '\n' '\t'.
  • U : Une lettre (les minuscules sont changées en majuscules)
  • L : Une lettre (les majuscules sont changées en minuscules)
  • A : Un chiffre ou une lettre
  • ? : Une lettre
  • * : N'importe quel caractère
  • H : N'importe quel caractère hexadécimal (0-9, a-f ou A-F)

 

 

Voici un exemple: Nous souhaitons que l'utilisateur entre un chiffre puis une lettre, puis n'importe quel caractère, on fera alors :

mask.setMask("# ? *"); //Les espaces sont facultatifs, mais s'ajouteront automatiquement lors de la saisie

 

Il y a une autre manière de procéder : autoriser des caractères ou en interdire :

MaskFormatter mask = new MaskFormatter();
try {
	mask.setMask("***************"); //15 caractères max
} catch (ParseException e) {
	e.printStackTrace();
}
mask.setValidCharacters("abcdefghijklmnopqrstuvwxyz"); //Caractères autorisés
mask.setInvalidCharacters("0123456789"); //Caractères interdits (dans le cas où on n'utilise pas setValidCharacters())
		
JFormattedTextField ft1 = new JFormattedTextField(mask);
ft1.setPreferredSize(new Dimension(110 , 25));

 

Problème : impossible de créer un masque dont le nombre de caractères est illimité. -_-

Le code cadeau va donc porter là dessus ! ;) Nous allons créer un KeyListener qui s'occupera de tester si le caractère est autorisé ou non :

package fr.bukkit.jeremgamer.cours;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;
import javax.swing.JTextField;

public class ContentPanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7311158212818984619L;

	public ContentPanel() {	
		
		JTextField field = new JTextField();
		field.setPreferredSize(new Dimension(110 , 25));

		TextFieldFormatter form = new TextFieldFormatter();
		form.setValidCharacter("abcdefghijklmnopqrstuvwxyz/*-+&é\"\'(-è_çà)=~#{[|`\\^@]}²");
		field.addKeyListener(form);
		
		this.add(field);

	}
	
	class TextFieldFormatter extends KeyAdapter {

		private String validCharacters = "";
		private String invalidCharacters = "";

		public void setValidCharacter(String s) {
			this.validCharacters = s;
		}
		
		public void setInvalidCharacters(String s) {
			this.invalidCharacters = s;
		}
		
		@Override
		public void keyTyped(KeyEvent e) {
			char c = e.getKeyChar();
			if((c!=KeyEvent.VK_BACK_SPACE) && (c!=KeyEvent.VK_DELETE) && (c!=KeyEvent.VK_ENTER) && (c!=KeyEvent.VK_SPACE))
				if(invalidCharacters.contains(Character.toString(c)) || !validCharacters.contains(Character.toString(c))) {
					Toolkit.getDefaultToolkit().beep(); //Notifier l'erreur par un son du système d'exploitation
					e.consume(); //On stoppe l'event, ainsi le caractère n'est pas ajouté
				}
		}
		
	}
}

 

Je pense que vous allez revenir ici régulièrement avant de tout maitriser, car il est difficile de tout retenir ! De plus je pense qu'un résumé ne sera pas nécessaire sachant que tout ce que je vous ai présenté ici était assez synthétique. Normalement vous êtes désormais en mesure de créer de belles interfaces graphiques interactives et dynamiques. ;) Vous savez donc ce qui vous attend, un TP ! ^_^ Cela faisait bien trop longtemps que je ne vous en avais pas fait faire.

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0582123001431870590.png

Le bout de code donné à la fin du chapitre précédent vous le criait haut et fort, nous allons parler des structures conditionnelles dans ce chapitre! Enfin nous allons nous attaquer au code ! Préparez vos petits doigts ! ^_^

Tout d'abord, commencez par créer une classe dans votre projet en faisant un clic droit sur "src" et en choisissant "New -> Class" :

 

E046LwC.png

 

 

Une boite de dialogue s'ouvrira, comme quand vous souhaitiez créer un projet. Nommez votre classe "Main" et cliquez sur "Finish" :

 

iYxAt0i.png

 

L'instant Convention :

 

Il est de retour ! ^_^

Cette fois, cela concerne le nommage de vos classes.

  • La première lettre doit être une majuscule.
  • Son nom ne doit pas être intégralement en majuscules.
  • Il est mélangé de majuscules et minuscules, sans caractères spéciaux ni espaces.
  • Comme pour les variables, mettez une majuscule au début de chaque mot composant le nom.
    class NomDeLaClasse

     

  • Évitez les acronymes et donnez des noms simples et descriptifs.

 

Voila ! Votre nouvelle classe toute neuve devrait ressembler à ça :

public class Main {
	
}

 

Nous allons la fournir un peu et faire en sorte que votre programme puisse se démarrer !

Nous allons donc ajouter la méthode principale. Les instructions qu'elle contient seront exécutées lors de chaque démarrage du programme.

Avant cela, je voudrais insister sur un point très important: les accolades.

Sachez que les accolades englobent et forment des sortes de paquets, ici, tout ce qui se trouvera entre les accolades déjà présentes fera partie de la classe "Main". Rien à part les imports ne peuvent se trouver à l'extérieur !

Pour se repérer, voir à quelle accolade ouvrante correspond quelle accolade fermante et inversement, on utilise quelque chose qui s'appelle l'indent. C'est simplement le fait d'aligner les portions de codes se trouvant entre plusieurs accolades. Un exemple vaut bien plus que de longues phrases :

public class Main {
	
	int i = 0;
	
	public static void main(String args[]) {
		System.out.println("Salut les bukkitiens!");
	}
}

 

Vous constatez que plus on "s'enfonce" profondément dans les accolades, plus la ligne est décalée. Eclipse s'en occupe en général, mais sinon faites-le vous même à l'aide de la touche tabulation ! ;)

L'indent n'est pas obligatoire mais c'est juste un moyen pour les développeurs de se retrouver dans leur propre code, sinon ce serait un véritable enfer !

L'argument utilisé ici entre les parenthèses est de type String. Il se syntaxe toujours avec des guillemets. C'est une chaîne de caractère extrêmement utilisée mais elle n'est pas un type primitif! Nous entrerons dans les détails de ce type plutôt spécial plus tard. ;)

Maintenant nous pouvons nous intéresser au contenu de ce code. Recopiez-le dans votre IDE. Vous pouvez retirer la ligne "int i = 0;" car elle ne nous servira pas. Elle était là juste à titre d'exemple pour l'indent.

Vous avez sûrement repéré deux nouveaux mots-clefs et d'autres choses bizarres. Ne vous en souciez pas pour l'instant. La méthode principale, c'est ceci !

Ici, le programme sait juste écrire "Salut les bukkitiens" dans la console. Désormais, vous savez aussi le faire !

Testons notre programme grâce à notre IDE. Cliquez sur la flèche verte dans votre barre d'outils. Eclipse vous demandera de sauvegarder avant d'exécuter, cliquez sur OK.

 

 

NMnx7GK.png

 

Vous pouvez constater que la phrase voulue s'est inscrite dans la console! Votre programme est fonctionnel! Sachez que la ligne "System.out.println()" permet d'imprimer n'importe quel type dans la console ! Aussi bien des variables numériques que des chaines de caractères ou bien plus encore !

Nous allons pouvoir enfin rentrer dans le vif du sujet. Nous allons corser un peu la chose.

Commençons par la structure conditionnelle la plus simple: if/else.

Celle-ci permet tout simplement d'exécuter des instructions en fonction du résultat d'un test. Il est possible d'y ajouter "else" à la fin. C'est littéralement "Si quelque chose, faire ceci, sinon, faire ceci." ! Reprenez le code fourni à la fin du chapitre précédent et vous comprendrez tout de suite.

int nombre1 = 6;
int nombre2 = 2;
boolean isMultiple;

if(nombre1 % nombre2 == 0) {
	isMultiple = true;
} else {
	isMultiple = false;
}

 

Observons pas-à-pas ce qu'il se passe.

  1. On déclare deux variables de type int en leur assignant directement une valeur.
  2. On déclare une variable boolean qui nous permettra de savoir si les deux nombres sont multiples ou non mais on ne lui assigne pas de valeur.
  3. On ajoute un if qui teste si le modulo de nombre1 par nombre2 est égal à 0.
  4. Accolade ouvrante. Tout ce qui se trouvera ici s'exécutera si nombre1 % nombre2 = 0.
  5. Accolade fermante, else puis accolade ouvrante.
  6. Tout ce qui se trouvera ici s'exécutera si nombre1 % nombre2 != 0. (N'est pas égal à 0).

 

Je vous propose de modifier un peu ce code pour qu'il puisse communiquer avec l'utilisateur.

int nombre1 = 6;
int nombre2 = 2; //Nous n'avons plus besoin de la variable boolean

if(nombre1 % nombre2 == 0) {
	System.out.println(nombre1 + " est un multiple de " + nombre2 + ".");
} else {
	System.out.println(nombre1 + " n'est pas un multiple de " + nombre2 + ".");
}

 

Vous suivez toujours? Rien de compliqué n'est-ce pas? :) Juste une chose, pensez à mettre des "+" pour les phrases comme je l'ai fait! C'est ce que l'on appelle la concaténation.

Maintenant, exécutez votre programme de la même manière que je l'ai expliqué plus haut. Vous allez voir que votre programme vous répond bien que 6 est multiple de 2! Désormais, essayer de modifier ces nombres et plus précisément, choisissez des nombres non multiples. Relancez votre programme et constatez que la deuxième option s'est déclenchée! C'est pas beau tout ça?

Il est possible de mettre plus encore de conditions. Repensez au chapitre sur les opérateurs. && et || peuvent être utilisés ici.

Exemple :

if(nombre1 != nombre2 && nombre1 != nombre3)

 

Une autre solution ajoutant de nouvelles possibilités ainsi que de l'optimisation existe: else if

Au lieu d'écrire une autre structure, on fait comme suit :

if(...) {
	//Instructions
} else if (...) {
	//Instructions
} else {
	//Instructions
}

 

Vous pouvez mettre autant de else if que vous le souhaitez.

Ce cas de figure fonctionne ainsi:

  1. Si quelque chose, alors on fait cela (if)
  2. Sinon si quelque chose d'autre, on fait cela (else if)
  3. Sinon, en dernier recourt, on fait cela. (else)

 

Essayez donc cette forme dans votre logiciel, toujours dans la méthode principale !

int nombre1 = 0;

if(nombre1 == 1) {
	System.out.println("Ce nombre est égal à 1");
} else if (nombre1 == 2) {
	System.out.println("Ce nombre est égal à 2");
} else {
	System.out.println("Ce nombre n'est ni égal à 1, ni égal à 2");
}

 

Lancez-le et expérimentez en changeant la valeur de nombre1 ! ;)

Il est aussi possible d'écrire les if "sur une seule ligne". Cependant, il faut bien faire attention car si plusieurs action sont à effectuer lorsqu'une condition est remplie, il faudra utiliser les accolades !

if(nombre1 == 0)
	System.out.println("Ce nombre est égal à 0");
else if(nombre1 == 1)
	System.out.println("Ce nombre est égal à 1");
else
	System.out.println("Ce nombre n'est ni égal à 0, ni égal à 1");

System.out.println("Le nombre a été testé!"); //Cette ligne ne fera pas partie du else! Ici l'indent vous le fait savoir sans même regarder qu'il n'y a pas d'accolades au if!

 

L'optimisation qu'apporte else if est la suivante : Quand une des conditions est remplie, le reste des tests n'est pas lu. Du coup, votre programme est accéléré car il peut directement passer à la suite !

Avouez qu'il serait barbant et très long de mettre plein de if partout quand il y a un grand nombre de deux possibilités. Pour cela, il existe une structure conditionnelle très pratique qui s'appelle switch ! Sa syntaxe est assez spéciale alors lisez bien !

switch(nombre1) {
	case 0: //Instructions
		break; //On passe le reste du switch jusqu'a l'accolade fermante.
	case 1:	//Instructions
		break;
	case 2:	//Instructions
		break;
	default: //Instructions
		break;
}

 

Je vous avait prévenu! Voyons ça en détails.

Tout d'abord, on écrit le mot-clef switch puis entre parenthèses, on met la variable à tester. ATTENTION, cette structure ne fonctionne qu'avec des types primitifs, ainsi que les String depuis Java 7.

Le switch va alors vérifier la valeur de "nombre1". Dans le cas où "nombre1" est égal à la valeur spécifiée après le mot-clef case, on exécute les instructions.

Vous pouvez mettre autant de case vous voulez !

default est différent. Premièrement, pas besoin de spécifier de valeur cette fois-ci car les actions spécifiées s'exécutent si la variable a une valeur différente de tous les case au dessus ! Deuxièmement, il n'est pas obligatoire. Dans le cas où vous ne l'avez pas ajouté, rien ne se passe si aucun case ne correspond à la valeur de la variable choisie.

Prenons un exemple concret qui parlera à tout le monde: manger. :P

Nous allons vérifier à quel moment de la journée l'utilisateur mange et nous allons définir le comportement du programme en fonction de cela !

String moment = "Nuit";

switch(moment) {
	case "Matin":
		System.out.println("Le repas le plus important de la journée! C'est bien!");
		break;
	case "Midi":
		System.out.println("La pause midi est toujours la bienvenue!");
		break;
	case "Soir":
		System.out.println("Ça fait du bien de manger après une dure journée de travail!");
		break;
	default:
		System.out.println("Ce n'est pas bien de grignoter entre les repas!");
		break;
}

 

Les trois grands repas de la journée sont précisés dans les case. Mais si on mange à un autre moment, comme ici, la nuit, le programme nous répondra que c'est mal de grignoter en dehors des repas! Essayez donc ce bout de code dans votre programme. Pensez à vider le contenu de la méthode principale avant.

Un dernier aspect du switch qu'il faut connaître, c'est que l'on peu effectuer une action pour différentes possibilités, de la même manière qu'un if avec plein de "||" :

switch(mois){
	case 1: case 3: case 5:
	case 7: case 8: case 10:
	case 12:
		jours = 31;
		break;
	case 4: case 6:
	case 9: case 11:
		jours = 30;
		break;
	case 2:
		jours=28;
		break;
}

 

Ici, on vérifie de quel mois il s'agit, le nombre étant ceux que vous connaissez soit 1 pour Janvier, 2 pour Février, etc...

Pensez à faire ceci plutôt que de recopier plein de fois la même instruction !

La dernière structure est très peu utilisée mais peu s'avérer utile dans certains cas. Elle porte le nom barbare de condition ternaire.

Le principe est simple en soi, mais la pratique l'est moins si on a pas bien saisi son fonctionnement. Ne vous découragez pas en voyant la tête qu'elle a, vous comprendrez bientôt.

int i = 5;
int j = 10;
int max = (i < j) ? j : i;

 

En réalité, nous faisons un test avant d'assigner une nouvelle valeur à max.

Je m'explique.

Entre les parenthèses, on a le test, exactement comme dans un if !

C'est là qu'intervient un nouvel opérateur! "? :" porte le nom d'opérateur ternaire de condition. Il est spécifique à cette structure, vous ne le verrez nul par ailleurs.

Bref, il s'occupe de faire le test puis de choisir entre les deux valeurs données à côté du ":".

Si le test renvoie true, donc ici que i est bien inférieur à j, alors la variable qui se trouve juste après le "?" sera assignée à max. Sinon ce sera la variable après les ":" qui le sera.

Finalement, faire ceci revient au même mais est beaucoup moins rapide :

int i = 5;
int j = 10;
int max;

if(i < j)
	max = j;
else
	max = i;

 

Résumé :

 

  • Vous savez désormais créer un programme fonctionnel !
  • Les instructions contenues dans la méthode principale seront exécutées lors du démarrage du programme.
  • La commande "System.out.println()" permet d'écrire quelque chose dans la console.
  • L'indent correspond au décalage des lignes et permet de se repérer au sein de son code.
  • Il existe trois types de structures conditionnelles:
    • if(...){...}else if(...){...}else{...}
    • switch(...) {case argument:...}
    • (...) ? ... : ... --> La condition ternaire.
    • Faites bien attention aux accolades. C'est très important de bien les placer!
    • Les tests se font à l'aide de plusieurs variables ainsi que des opérateurs logiques.
    • Faire son choix parmi ces structures conditionnelles est une question de pratique, et parfois d'optimisation.

     

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0937398001432731892.png

Comme promis, nous allons revenir en détails sur les Listener, comment fonctionnent-t-ils? Comment font ils pour savoir qu'ils peuvent écouter tel objet? Par quel procédé remarquent-ils que quelque chose c'est produit dans cet objet? Toutes ces questions vont trouver une réponse dans ce chapitre ;)

 

Reprenons l'exemple du début du chapitre précédent :

Citation

Imaginez une situation peu probable: des enfants jouent dans leur chambre (ce sont nos objets), quand soudain leurs parents les appellent à table. Les enfants écoutent leurs parents et viennent déjeuner. Ici le principe est le même, nos objets écouteront d'autres objets, et quand ils se manifesteront, on définira un comportement.

 

Nous allons entrer un peu plus dans les détails, en faisant le lien avec du code. Imaginons qu'il y a deux enfants. Sous forme de code on aura quelque chose qui ressemble à ça :

//Dans la classe Parents
private void appelerATable() {
     enfant1.venirATable();
     enfant2.venirATable();
}

 

Problème: imaginez que le couple décide d'avoir un nouvel enfant. Quand ils appelleront à table, seuls les deux premiers viendront. -_-

Vous allez me dire qu'il suffit d'une petite ArrayList et un boucle for, en ajoutant le nouvel enfant à la liste. J'ai mieux à proposer ! Nous allons élever ces enfants pour qu'ils écoutent et non qu'ils soient forcés à exécuter ce que l'on leur demande. Car dans le code ci-dessus, finalement les enfants ne viennent pas tout seul, ce sont les parents qui viennent les chercher ! :o Cependant vous remarquerez bien vite que cette proposition n'est pas sans intérêt, au contraire ! ;) il faudra juste y ajouter quelques subtilités.

 

Première étape: apprendre aux parents à se faire écouter par leurs enfants, peu importe le nombre qu'ils sont. Ce qui est bien, c'est que cela ne s'appliquera pas qu'aux enfants ! Je m'explique: nos parents seront donc écoutables, ce qui signifie que n'importe quel objet pourra agir en conséquences des actes de ces derniers. Si jamais vous avez à rajouter des éléments dans votre programme, comme par exemple les grands-parents ou les amis, et bien il faudra adapter votre classe Parents afin qu'elle supporte cette nouveauté. Nous allons optimiser tout ça, plus besoin de toucher au code des parents !

 

On appelle cela le pattern observer. Les patterns sont des logiques de programmation pour optimiser le code en vue de futurs changements possibles, afin de rendre chaque objet complètement indépendant et rendre votre code 100% modulable !

Ici on utilisera le patter observer car il se prête totalement à notre exemple: il s'agit "d'écouter".

 

Maintenant que le concept est clair dans votre tête, passons à la pratique ! :D Lisez attentivement le code qui suit.

package fr.bukkit.jeremgamer.cours;

import java.util.Observable;

public class Parent extends Observable {
	
	public static final String APPEL_A_TABLE = "AAAAAAAAAAAA TAAAAAAAABBLEEEEEEEUUUUUUX!!!!";
	
	protected void appelerATable() {
		crier(APPEL_A_TABLE);
	}
	
	private void crier(String message) {
		setChanged(); //Héritée de Observable, indique qu'un changement est effectué
		//Utile lorsqu'une variable est changée et que les Observers doivent en être informés
		notifyObservers(message); //On notifie le message aux objets écoutant
	}
	
	protected Enfant faireEnfant() {
		Enfant enfant = new Enfant(); //L'enfant est né!

		//On ajoute l'enfant aux Observer du Parent
		addObserver(enfant); //Méthode héritée de Observable
		return enfant;
	}

}
package fr.bukkit.jeremgamer.cours;

import java.util.Observable;
import java.util.Observer;

public class Enfant implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		if(o instanceof Parent)
			if(arg.equals(Parent.APPEL_A_TABLE))
				venirATable();
		
	}
	
	private void venirATable() {
		System.out.println("Un enfant est venu à table.");
	}

}

 

Et pour finir, dans la méthode principale :

public static void main(String[] args) {
		
	Parent parent = new Parent();
		
	parent.faireEnfant(); //On fait deux enfants
	parent.faireEnfant();
	
	parent.appelerATable();
}

 

Essayons :

Un enfant est venu à table.
Un enfant est venu à table.

 

C'est bien ce que nous voulions ! Cela fonctionne très bien ! ^_^ Mis a part le fait que le parent peut faire des enfants tout seul et qu'il les appelle directement à table à peine leur naissance terminée, on peut voir que ces derniers écoutent bien ! :D Pour le réalisme, nous allons faire abstraction pour cette fois. :ph34r:

 

Revenons en détails sur ce code :

Vous pouvez constater que l'on a effectué aucun référencement! Ce qui est déjà un grand pas. Regardez à nouveau le code ci-dessus et constatez que... Nos objets Enfant et Parent sont pas encore complètement indépendants car dans la méthode faireEnfant() de la classe Parent, on instancie un Enfant. Le problème est simple à régler, je suis certain que vous avez déjà deviné la solution ! ;)

 

Rien de bien compliqué, retirons cette méthode. Nous procéderons donc ainsi, ce qui revient strictement au même :

Parent parent = new Parent();
		
parent.addObserver(new Enfant());
parent.addObserver(new Enfant());
		
parent.appelerATable();

 

Nos deux classes sont désormais bien indépendantes! Tellement que l'on pourra comme je vous l'ai dis tout à l'heure ajouter un nouveau type de personnes sans aucun problème, et sans avoir à toucher au code d'une autre classe que celle du nouveau personnage ! ;)

 

C'est bien beau tout ça mais moi il y a quand même quelque chose qui me chiffonne... Vous ne savez pas de quoi il s'agit?

Si je vous rappelle que Observable est une classe, toujours aucune réaction? :huh:

 

Je pense que cette dernière information suffira donc à vous mettre en évidence le problème : rappelez-vous que Java ne gère pas l'héritage multiple !

Ah voila! Je sais que vous avez saisi désormais ! Comment faire si notre objet à écouter hérite déjà d'une autre classe? :unsure: Ce qui sera d'ailleurs très souvent le cas dans la programmation de GUI... Et oui, quasiment toutes nos classes hériteront de classes issues du package swing ou AWT, comme nous l'avons déjà fait avec les JPanel ou les JButton.

 

Mais comme toujours, il existe une solution ! B) Car il y a toujours une solution! Nous allons réarranger tout ça à l'aide de nos propres interfaces. De plus cela vous permettra de savoir exactement comment fonctionne les Observable; c'est tout simple :

package fr.bukkit.jeremgamer.cours;

public interface Observable_ { //Notez bien l'underscore, c'est une convention lorsqu'on utilise des noms déjà utilisés dans l'API Java

	  public void addObserver(Observer_ obs);
	  public void updateObservers(String message);
	  public void deleteObserver(Observer_ obs);
	
}
package fr.bukkit.jeremgamer.cours;

public interface Observer_ {	
	public void update(String message);
}
package fr.bukkit.jeremgamer.cours;

import java.util.ArrayList;


public class Parent implements Observable_ {
	
	public static final String APPEL_A_TABLE = "AAAAAAAAAAAA TAAAAAAAABBLEEEEEEEUUUUUUX!!!!";
	
	private ArrayList<Observer_> listObservers = new ArrayList<Observer_>();
	
	protected void appelerATable() {
		crier(APPEL_A_TABLE);
	}
	
	private void crier(String message) {
		updateObservers(message);
	}
	
	protected Enfant faireEnfant() {
		Enfant enfant = new Enfant();
		addObserver(enfant);
		return enfant;
	}

	@Override
	public void addObserver(Observer_ obs) {
		listObservers.add(obs);
	}

	@Override
	public void updateObservers(String message) {
		for(Observer_ obs : listObservers)
			obs.update(message);
	}

	@Override
	public void deleteObserver(Observer_ obs) {
		listObservers.remove(obs);
	}

}
package fr.bukkit.jeremgamer.cours;


public class Enfant implements Observer_ {

	@Override
	public void update(String message) {
			if(message.equals(Parent.APPEL_A_TABLE))
				venirATable();
		
	}
	
	private void venirATable() {
		System.out.println("Un enfant est venu à table.");
	}

}

 

Si vous testez ce code, vous remarquerez qu'il fonctionne aussi bien qu'en utilisant la méthode proposée par l'API Java, mais l'héritage de l'Observable est désormais libre ! :)

 

Il faudra bien-sûr adapter ce code à vos besoins. Ici on as juste un message donc on se contentera de cette version simplifiée, mais rien ne vous empêche d'essayer de reproduire quelque chose d'aussi pratique et adapté à toutes les situations que celui proposé par l'API Java.

 

 

Résumé :

 

  • Les patterns sont des logiques de programmation visant à préparer le code à de futurs ajouts et modifications, le tout avec une facilité déconcertante.
  • Observable est une classe permettant à celles qui en héritent de pouvoir être écoutées par les classes implémentant l'interface Observer.

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0623585001432129495.png

Nous entamons une toute nouvelle notion: la programmation évènementielle. Dans ce chapitre, vous ferez vos premiers pas dans ce domaine.

 

Il s'agira "d'écouter" ses composants, mais pas forcément, il peut également s'agir d'un objet comme les autres ! Cette fois-ci nous verrons simplement comment définir une action à réaliser lors de différents évènements possibles sur un bouton.

 

Le concept n'est pas bien compliqué :

Imaginez une situation peu probable : des enfants jouent dans leur chambre (ce sont nos objets), quand soudain leurs parents les appellent à table. Les enfants écoutent leurs parents et viennent déjeuner. Ici le principe est le même, nos objets écouteront d'autres objets, et quand ils se manifesteront, on définira un comportement.

 

Pour cela nous utiliserons des Listener. Il en existe plusieurs, qui sont tous des interfaces, et qui nous permettrons de prendre en compte plusieurs genres d'évènements. Par exemple on aura tout d'abord le plus fréquent : ActionListener, que l'on détaillera dans un instant, puis MouseListener, qui permet d'écouter la souris de l'utilisateur, ou KeyListener, qui permet quand à lui d'écouter le clavier.

 

Nous travaillerons sur de nombreuses classes anonymes, alors si vous ne vous sentez pas très à l'aise avec cette notion, je vous invite à relire le chapitre sur l'anonymat.

 

Reprenons une fenêtre toute simple, contenant simplement un bouton avec lequel nous allons interagir. Nous allons ensuite y ajouter un ActionListener.

 

Une seconde! Il s'agit bien d'une interface? Comment en faire une classe?

Souvenez-vous ! Il est possible de créer une classe anonyme à l'aide d'une interface. ;)

 

Voici alors la forme que cela prendra :

JButton button = new JButton("Un bouton");
		
button.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		//Notre action à effectuer lors du clic
		System.out.println("Vous avez cliqué sur le bouton");
	}
	
});

Je vous invite à tester, on voit que la phrase s'affichera bien dans la console à chaque clic sur le bouton ! :)

 

Vous voyez, rien de bien sorcier pour l'instant. C'est dans la seconde partie de ce chapitre que cela se compliquera, quand je vous expliquerai en détails comment cela fonctionne, et comment le réaliser sur vos propres objets. ^_^

 

Fermons la parenthèse, rien ne vous empêche d'ajouter plusieurs Listener à vos boutons, même s'il est préférable de tout gérer en un seul, ce qui est bien plus optimisé. Cependant s'il vous faut des Listener différents, pour écouter le clavier et la souris en même temps par exemple, alors il sera nécessaire d'en ajouter plusieurs, ce qui parait logique. Voyons un peu ce qui est réalisable à l'aide ce cet outil :

button.addActionListener(new ActionListener() {

	@Override
	public void actionPerformed(ActionEvent e) {
		JButton source = (JButton) e.getSource(); //Pour récupérer le composant source, ici on est sûr qu'il s'agit d'un bouton donc le cast est sans risque
			
		source.setText("Bouton cliqué"); //Changer le texte du bouton lors du clic
		source.setEnabled(false); //Griser le bouton après le clic
		//Toutes les autres méthodes de JButton
			
		//N'oubliez pas que nous sommes dans une autre classe, faites bien attention à l'accessibilité des variables utilisées!
	}
			
});

 

Voyons désormais comment écouter le clavier de l'utilisateur. Nous allons implémenter KeyListener à notre panneau.

package fr.bukkit.jeremgamer.cours;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;

public class ContentPanel extends JPanel implements KeyListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7311158212818984619L;

	public ContentPanel() {
		
		this.addKeyListener(this); //Il faut penser à ajouter le Listener!
		this.setFocusable(true);
		this.requestFocus(); //Pour s'assurer que le panneau a bien le focus
		//Car les évènements seront déclenchés uniquement si le panneau a le focus

	}

	@Override
	public void keyPressed(KeyEvent e) { //Quand une touche sera enfoncée
		System.out.println("Key pressed: " + e.getKeyChar());
	}

	@Override
	public void keyReleased(KeyEvent e) { //Quand une touche sera relâchée
		System.out.println("Key released: " + e.getKeyChar());
	}

	@Override 
	public void keyTyped(KeyEvent e) { //Quand une touche sera tapée (enfoncée puis relâchée)
		System.out.println("Key typed: " + e.getKeyChar());
	}
}
Key pressed: b
Key typed: b
Key released: b
Key pressed: u
Key typed: u
Key released: u
Key pressed: k
Key typed: k
Key released: k

 

On peut constater que KeyTyped() est appelé avant KeyReleased(), ce qui pourrait être pratique dans certain cas.

Avez-vous essayé les flèches directionnelles ou des touches comme Ctrl ou Alt? Le résultat est un peu décevant :

Key pressed: ?
Key released: ?
Key pressed: ?
Key released: ?

 

Sans parler du fait que KeyTyped() n'est pas appelé, on n'a le droit qu'à un point d'interrogation! Cela est du au fait que pour récupérer la touche pressée, on utilise la méthode getKeyChar(), qui retourne forcément un char, or ces touches pourraient difficilement retourner une telle valeur! On utilisera donc une autre méthode: getKeyCode(), qui retournera l'identifiant de la touche pressée.

Key pressed: 38
Key released: 38
//38: flèche haut
Key pressed: 65
Key typed: 0
Key released: 65
//65: touche 'a'

 

Hum tout de suite on est capables récupérer toutes les touches, mais tous ces numéros ne sont pas très pratiques... :unsure: Comment s'y retrouver et les reconnaitre?

 

Miracle, l'API Java nous sauve la vie encore une fois ! ^_^ La classe KeyEvent nous propose de nombreuses constantes statiques recensant toutes les touches de notre clavier !

 

Par exemple, si on veut faire un petit jeu 2D qui se joue avec les flèches du clavier, rien de plus simple maintenant que l'on a ces constantes !

int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_LEFT: 
	System.out.println("Aller à gauche");
	break;
case KeyEvent.VK_UP: 
	System.out.println("Aller en haut");
	break;
case KeyEvent.VK_RIGHT: 
	System.out.println("Aller à droite");
	break;
case KeyEvent.VK_DOWN: 
	System.out.println("Aller en bas");
	break;
}

 

Et voila un résultat plus convenable ! :)

 

Vous avez sans doute remarqué que maintenant que nous utilisons getKeyCode(), KeyTyped() nous affirme toujours que la touche tapée porte le code 0. :huh: C'est parce que cette méthode est utilisée pour supporter toutes les touches. getKeyChar() sera surtout utilisé pour du traitement de texte.

 

Nous n'avons pas besoin de cette méthode, dans l'idéal, on aimerait bien pouvoir s'en débarrasser pour ne pas charger le code inutilement. Magie magie! Un autre merveilleux outil fournit pas notre API préférée est là pour nous ! N'est-ce pas génial?

On appelle cela les Adapter, ce sont des classes héritant des interfaces Listener, mais qui nous laissent le choix des méthodes utilisées. Comme il s'agit de classes, on devra alors procéder différemment :

package fr.bukkit.jeremgamer.cours;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;

public class ContentPanel extends JPanel {

    /**
     *
     */
    private static final long serialVersionUID = -7311158212818984619L;

    public ContentPanel() {
        
        this.addKeyListener(new KeyboardListener()); //Cette fois on instancie notre classe interne
        this.setFocusable(true);
        this.requestFocus();
    }
    
    class KeyboardListener extends KeyAdapter { //Classe interne hériant de Keyadapter
        
        public void keyPressed(KeyEvent e) {
            int code = e.getKeyCode();
            switch (code) {
            case KeyEvent.VK_LEFT:
                System.out.println("Aller à gauche");
                break;
            case KeyEvent.VK_UP:
                System.out.println("Aller en haut");
                break;
            case KeyEvent.VK_RIGHT:
                System.out.println("Aller à droite");
                break;
            case KeyEvent.VK_DOWN:
                System.out.println("Aller en bas");
                break;
            }
        }
        
        //On s'est débarrassé de keyReleased() et keyTyped()
        
    }
}
package fr.bukkit.jeremgamer.cours;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;

public class ContentPanel extends JPanel {

    /**
     *
     */
    private static final long serialVersionUID = -7311158212818984619L;

    public ContentPanel() {
        
        this.addKeyListener(new KeyboardListener()); //Cette fois on instancie notre classe interne
        this.setFocusable(true);
        this.requestFocus();
    }
    
    class KeyboardListener extends KeyAdapter { //Classe interne hériant de Keyadapter
        
        public void keyPressed(KeyEvent e) {
            int code = e.getKeyCode();
            switch (code) {
            case KeyEvent.VK_LEFT:
                System.out.println("Aller à gauche");
                break;
            case KeyEvent.VK_UP:
                System.out.println("Aller en haut");
                break;
            case KeyEvent.VK_RIGHT:
                System.out.println("Aller à droite");
                break;
            case KeyEvent.VK_DOWN:
                System.out.println("Aller en bas");
                break;
            }
        }
        
        //On s'est débarrassé de keyReleased() et keyTyped()
        
    }
}

 

Et maintenant, la souris ! Pour en tirer une application intéressante, nous allons utiliser le MouseListener sur une classe de bouton personnalisé ! Nous nous contenterons de changer la couleur de fond du bouton à titre d'exemple.

package fr.bukkit.jeremgamer.cours;

import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;

public class CustomButton extends JButton implements MouseListener {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = 7877964058790016354L;

	public CustomButton(String title) {
		super(title);
		this.addMouseListener(this);
		this.setBackground(Color.BLUE);
		this.setForeground(Color.white);
	}
	
	@Override
	public void mouseClicked(MouseEvent e) { //Lors du clic
		//On ne met rien ici car on s'occupe du changement de couleur dans
		//mousePressed() et mouseReleased()
   	         //On utilisera d'ailleurs un MouseAdapter en temps normal pour retirer cette méthode inutile.
	}

 	@Override
	public void mouseEntered(MouseEvent e) { //Lorsque la souris entre dans la zone du bouton
		this.setBackground(Color.CYAN);
		this.setForeground(Color.black);
	}

 	@Override
 	public void mouseExited(MouseEvent e) { //Lorsque la souris sors de la zone du bouton
		this.setBackground(Color.BLUE);
		this.setForeground(Color.white);
	}

	 @Override
 	public void mousePressed(MouseEvent e) { //Lorsque que le bouton du clic est enfoncé
		this.setForeground(Color.BLACK);
	}

 	@Override
	public void mouseReleased(MouseEvent e) { //Lorsque le bouton du clic est relâché
		this.setBackground(Color.CYAN);
		this.setForeground(Color.black);
	}

}

 

Je vous invite à essayer ce code ;)

Je pense que vous avez compris le principe.

 

Dans la seconde partie de ce chapitre nous verrons plus en détails comment fonctionnent réellement les Listener, comment faire les votres, ainsi que comment écouter vos objets maison ! :D

 

 

Résumé :

 

  • Les interfaces Listener permettent d'écouter des objets.
  • C'est à dire être "informé" lorsqu'un évènement en relation avec cet objet ce produit.
  • ActionListener permet d'écouter lorsqu'une action comme un clic sur un bouton est effectuée.
  • KeyListener permet d'écouter le clavier.
  • MouseListener permet d'écouter la souris.
  • Les Adapter sont des classes implémentant les Listener et permettant de se passer des méthodes superflues.

 

 

JeremGamer

 

2cp1ED5.pngtNIpRtq.png

SystemGlitch

blog-0373382001431880416.png

Dans ce chapitre nous verrons deux nouveaux layouts, le premier est assez simple à utiliser et permet de superposer plusieurs panneaux et de passer de l'un à l'autre facilement et le second est quand à lui très complexe mais permet de créer une disposition en grille avec des cases de différentes tailles.

 

Commençons sans plus tarder avec le CardLayout ! Comme expliqué ci-dessus, il permet de vous faciliter la vie lorsque vous avec besoin de passer d'une scène à l'autre de votre logiciel. Par exemple, lorsque vous avez un menu permettant d'accéder aux différentes fonctionnalités du logiciel sur la gauche, et les options de ces fonctionnalités à droite en grand. Pour passer de l'une à l'autre, vous n'allez pas retirer un panneau puis en ajouter un autre à chaque fois. Premièrement cela risque fort de perturber votre disposition générale. De plus, ce n'est absolument pas optimisé et cela consommera beaucoup de ressources de recalculer les panneaux et le layout à chaque changement. On utilisera alors le CardLayout sur un conteneur qui contiendra tous ces panneaux ! Nos panneaux seront tout simplement tous calculés à l'instanciation du conteneur, la disposition ne changera pas et on pourra changer de panneau à volonté sans aucun problème !

 

Trêve de parlotte, voici le code permettant de le faire. Je l'expliquerais ensuite. Je vous invite fortement à le recopier et le tester pour voir le résultat. Vous ne comprendrez pas tout c'est normal, car il y a des notions que vous ne connaissez pas encore à l'intérieur, notamment les actions sur les boutons.

 
package fr.bukkit.jeremgamer.cours;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;

public class ContentPanel extends JPanel {

    /**
     *
     */
    private static final long serialVersionUID = -7311158212818984619L;
    
    private CardLayout cl = new CardLayout(); //On instancie le layout
    private final String CONTENT[] = {"red" , "green" , "blue"}; //On crée un tableau contenant les identifiants
    JPanel container = new JPanel(cl); //On instancie le conteneur
    
    public ContentPanel() {        
        
        //On instancie les panneaux que l'on ajoutera au conteneur
        JPanel red = new JPanel();
        red.setBackground(Color.RED); //On change leur couleur de fond pour les différencier
        red.setName(CONTENT[0]); //Facultatif, on l'utilisera juste pour retrouver quel panneau est acutellement affiché
        
        JPanel green = new JPanel();
        green.setBackground(Color.GREEN);
        green.setName(CONTENT[1]);
        
        JPanel blue = new JPanel();
        blue.setBackground(Color.BLUE);
        blue.setName(CONTENT[2]);
        
        container.add(red , CONTENT[0]); //On ajoute le panneau rouge avec l'identifiant "red"
        container.add(green , CONTENT[1]); //On ajoute le panneau vert avec l'identifiant "green"
        container.add(blue , CONTENT[2]); //On ajoute le panneau bleu avec l'identifiant "blue"
        
        
        //----------------------------------------
        //On passe à la création du panneau de contrôle qui nous permattra de passer d'un panneau à l'autre
        //Ne vous attardez pas trop sur cette partie, ce qu'elle contient n'est pas encore de votre niveau
        
        JPanel control = new JPanel();
        
        
        JComboBox<String> index = new JComboBox<String>();
        for(String s : CONTENT)
            index.addItem(s);
        
        index.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                @SuppressWarnings("unchecked")
                JComboBox<String> box = (JComboBox<String>) e.getSource();
                cl.show(container, (String)box.getSelectedItem()); //On affiche le panneau portant l'identifiant sélectionné dans le menu déroulant
            }
            
        });
        
        JButton previous = new JButton("Précédent");
        previous.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                cl.previous(container); //On affiche le panneau précédent (Ajouté avant celui acutellement affiché)
                //Si le panneau affiché et le premier, alors le dernier panneau sera affiché à l'appel de cette méthode
                index.setSelectedItem(getCurrentCard().getName()); //On actualise le menu déroulant pour qu'il affiche le bon identifiant
            }
            
        });
        
        JButton next = new JButton("Suivant");
        next.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                cl.next(container); //On affiche le panneau suivant (Ajouté après celui acutellement affiché)
                //Si le panneau affiché et le dernier, alors le premier panneau sera affiché à l'appel de cette méthode
                index.setSelectedItem(getCurrentCard().getName());
            }
            
        });
        
        //On ajoute tous les contrôles au panneau de contrôle
        control.add(previous);
        control.add(next);
        control.add(index);
        
        //On ajoute le conteneur et le panneau de contrôle au panneau principal
        this.setLayout(new BorderLayout());
        this.add(container , BorderLayout.CENTER);
        this.add(control , BorderLayout.SOUTH);
        
    }
    
    private JPanel getCurrentCard() { //Pour récupérer le panneau actuellement affiché
        JPanel card = null;

        for (Component comp : container.getComponents())
            if (comp.isVisible() == true)
                card = (JPanel)comp;
        return card;
    }

}

 

Oui c'est un peu long, mais le plus important est en haut du constructeur, avant le trait de séparation fait avec un commentaire. ;) Je vous avais prévenu que la longueur de vos programmes allait beaucoup augmenter ! ^_^

Voici le résultat en images :

 

iUrVxDo.png

 

Vous avez vu que j'utilisais un tableau pour stocker les identifiants, mais vous pouvez très bien faire sans et spécifier directement les identifiants lors de l'ajout au conteneur :

container.add(panel , "id");

 

Utiliser un tableau assure simplement de s'y retrouver dans les identifiants et de ne pas en oublier. C'est d'ailleurs aussi efficace pour tous les utiliser rapidement comme je l'ai fait ici :

for(String s : CONTENT)
	index.addItem(s);

 

Vous n'avez très certainement pas compris le reste et c'est normal car cela relève de la programmation événementielle, que nous aborderons très bientôt.

 

 

Passons maintenant aux choses sérieuses ! Nous allons nous attaquer à un gros morceau en parlant du GridBagLayout !

 

Le conteneur contiendra de nombreuses cellules faisant office de cases dans un grille, chaque composant sera ajouté à l'aide de la coordonnée de la cellule voulue, et pourra occuper une ou plusieurs d'entre elles ! C'est ainsi que comme je l'ai dit au début de ce chapitre, on pourra obtenir une grille avec des cases de tailles différentes.

 

Les coordonnées se décomposent de la même manière que dans un tableau bi-dimensionnel, c'est à dire que la première case sera aux coordonnées (0 , 0) celle en dessous se trouvera à (0 , 1), la case à droite de cette dernière sera à (1 , 1).

Gardez à l'esprit que la coordonnée x est le numéro de la colonne, et y le numéro de la ligne.

 

Nous procèderons ainsi :

  • Définir les coordonnées
  • Indiquer si le composant utilisera plusieurs cellules en vertical ou en horizontal.
  • Indiquer quand une ligne est terminée

 

Voici quelle forme cela va prendre :

package fr.bukkit.jeremgamer.cours;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JPanel;

public class ContentPanel extends JPanel {

    /**
     *
     */
    private static final long serialVersionUID = -7311158212818984619L;

    public ContentPanel() {

        //Instanciation des différentes cellules
        JPanel cell0 = new JPanel();
        cell0.setBackground(Color.BLACK);

        JPanel cell1 = new JPanel();
        cell1.setBackground(Color.BLUE);

        JPanel cell2 = new JPanel();
        cell2.setBackground(Color.CYAN);

        JPanel cell3 = new JPanel();
        cell3.setBackground(Color.GREEN);

        JPanel cell4 = new JPanel();
        cell4.setBackground(Color.MAGENTA);

        JPanel cell5 = new JPanel();
        cell5.setBackground(Color.ORANGE);

        JPanel cell6 = new JPanel();
        cell6.setBackground(Color.RED);


        //Conteneur
        JPanel container = new JPanel(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints(); //Instanciation de l'objet gérant les contraintes

        gbc.weightx = 1; //On demande de l'espace supplémentaire pour le redimensionnement
        gbc.weighty = 1; //Chaque cellule serait très petite sinon
        gbc.fill = GridBagConstraints.BOTH; //On remplit autant de cases que l'on peut en verticalité et en horizontalité

        //On positionne dans la première case.
        gbc.gridx = 0;
        gbc.gridy = 0;

        //On définit la taille que le composant empruntera (en cases)
        gbc.gridwidth = 1;
        gbc.gridheight = 1;
        container.add(cell0 , gbc); //On ajoute la cellule 0 en spécifiant la contrainte

        //-------------------------

        gbc.gridx = 1;
        gbc.gridheight = 2;
        container.add(cell1 , gbc);

        //-------------------------

        gbc.gridx = 2;
        gbc.gridheight = 1;
        container.add(cell2 , gbc);

        //-------------------------

        gbc.gridx = 3;
        container.add(cell3 , gbc);

        //-------------------------

        gbc.gridwidth = GridBagConstraints.REMAINDER; //Fin de ligne
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.gridwidth = 1;
        container.add(cell4 , gbc);

        //-------------------------

        gbc.gridx = 2;
        gbc.gridwidth = 3;
        container.add(cell5 , gbc);

        //-------------------------

        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.gridy = 2;
        gbc.gridx = 0;
        gbc.gridwidth = 5;        
        container.add(cell6 , gbc);


        this.setLayout(new BorderLayout());
        this.add(container , BorderLayout.CENTER);

    }
}

 

d53QkC2.png

 

Voila qui peut être pratique non? ^_^ C'est complexe à comprendre, complexe à utiliser, mais cela permet de faire les GUI les plus élaborés et les plus complets ! ;)

Comme ce layout propose de très nombreuses possibilités, je vous conseille fortement d'aller lire la page de documentation qui en parle. Avec ça, vous saurez tout !

 

Voila c'est tout pour aujourd'hui! Vous êtes maintenant capable de disposer vos composants exactement comme vous le souhaitez! Dans le prochain chapitre, nous nous attaquerons à la programmation événementielle, et donc notamment comment interagir avec ses boutons !

 

 

Résumé :

 

  • Le CardLayout permet d'empiler, de superposer plusieurs panneaux de manière optimisée, et de pouvoir passer facilement d'un panneau à l'autre dans l'affichage.
  • Chaque panneau ajouté avec un CardLayout doit être ajouté avec son identifiant sous forme de String.
  • Le GridBagLayout est un layout permettant la création de grille dont chaque cellule peut avoir une taille différente, de la même manière qu'un tableau Excel.
  • Chaque composant doit être ajouté selon une contrainte du type GridBagConstraints.
  • On parcourt la grille à l'aide de coordonnées.
  • On choisi la taille de chaque composant en unités de cellules avec gridwidth et gridheight.

 

 

JeremGamer

 

 

2cp1ED5.pngtNIpRtq.png