dimanche 25 février 2018

Triangle d'étoiles

Ennoncé
Ecrire un programme qui lit un entier "n" et affiche par la suite un triangle d'étoiles de hauteur "n". Par exemple, si n = 5, l'affichage sera :
*
**
***
****
*****

Solution
Cet exercice est un autre exercice classique pour aider les apprenants avec les boucles. Le principe pratiqué dans ce cas est le principe des boucles imbriquées (ici). Deux petites différences :
  1. La borne supérieure de la boucle est lue à partir du clavier.
  2. On affiche des "*" au lieu des indices utilisés dans les boucles.
Code en Pascal :


Program TriangleEtoiles;
 
Var 
 n, i, j : Integer;

Begin
 
 WriteLn('Donnez la hauteur de triangle : ');
 ReadLn(n);
 
 For i := 1 to n do
 Begin
  For j := 1 to i do
   Write('*');
  WriteLn;
 End; 
 
End.




Boucles imbriquées : boucle à l'intérieur d'une autre boucle

Pour ce petit code, je n'ai pas d'énnoncé. Je vais présenter, brièvement, la notion des boucles imbriquées.

Une boucle nous permet de faire un passage sur un ensemble de valeurs (intervalle, valeurs dans un tableau, etc.). Ce passage peut être vu comme le parcours d'une ligne; d'une seule dimension.

Les boucles imbriquées nous permettent de faire un peu plus de cela. Elles nous permettent d'effectuer un parcours dans deux dimensions : pour chaque valeur de la première boucle (boucle extérieure), nous faisons un parcours (passage) entier dans la deuxième boucle (boucle intérieure).

Un code exemple (en Pascal) :

Program ExempleBI;

Const 
 n = 10;
 
Var 
 i, j : Integer;

Begin
 
 For i := 1 to n do
 Begin
  For j := 1 to n do
   Write(j, ' ');
  WriteLn;
 End; 
 
End.

Le résultat d'exécution est :


Le parcours peut ne pas être complet : il se peut que les limites des deux boucles ne soient pas basées sur les mêmes variables :


Program ExempleBI2;

Const 
 n = 9;
 m = 15;
Var 
 i, j : Integer;

Begin
 
 For i := 1 to n do
 Begin
  Write(i, ' : ');
  For j := 1 to m do
   Write(j, ' ');
  WriteLn;
 End; 
 
End.


Il se peut même que la deuxième boucle fait appel à l'indice de la première boucle. Cela veut dire que les passages effectués par la deuxième boucle ne sont pas de même taille, néanmoins, cela ne change pas la structure du programme et cela reste un parcours en deux dimensions. Exemple :


Program ExempleBI3;

Const 
 n = 10;
 
Var 
 i, j : Integer;

Begin
 
 For i := 1 to n do
 Begin
  For j := 1 to i do
   Write(j, ' ');
  WriteLn;
 End; 
 
End.







vendredi 23 février 2018

La somme des chiffres d'un nombre entier

Exercice 
Ecrire un programme qui calcule la somme des chiffres d'un entier lu à partir du clavier

Solution 
En revenant au code pérsenté ici, la modification à apporter est minimale. En effe, dans code, nous avons affiché les chiffres du nombres, c'est à dire, nous nous sommes limités à les utiliser avec la méthode "Afficher" seulement.

Pour calculer la somme, il suffit d'utiliser ces chiffres dans une somme et non pas dans l'affichage. Ainsi, les modifications à apporter sont :
  1. Ajouter une variable qui va contenir la somme,
  2. Initialiser cette variabe à 0 ('élément neutre de l'opération d'addition),
  3. Ajouter chaque chiffre extraît à la somme au lieu de l'afficher,
  4. Améliorer l'affichage (enlever quelques "Afficher" et ajouter une autre).
Le code résultat sera, en Pascal :

Program SommeChiffres;

Var 
 n, c, s : Integer;

Begin
 s := 0;
 
 WriteLn('Donnez un nombre entier');
 ReadLn(n);
 
 While (n > 0) Do
 Begin
     c := n mod 10;
  s := s + c;
  n := n div 10;
 End;
 WriteLn('La somme des chiffres est : ', s);
End.

En Java :


import java.util.Scanner;

public class SommeChiffres {
 
 public static void main (String args[]) {
  
  Scanner s = new Scanner(System.in);
  int somme = 0;
  
  System.out.println("Donnez un nombre entier :");
  int n = s.nextInt();
  
  while(n > 0){
   somme += n % 10;
   n = n / 10;
  }
  System.out.println("La somme des chiffres est : " + somme);
  
  
 }
}

L'exécution est identique pour les deux codes :


Extraire les chiffres d'un nombre entier

Exercice
Ecrire un programme qui affiche les chiffres d'un nombre lu à partir du clavier.

Soution
Cet exercice est l'un des exercices classiques. Il vise à donner un exemple de manipulation sur deux éléments :
  1. Boucles "Tant que" (while)
  2. Extraîre les chiffres d'un nombre.
L'extraction d'un chiffre (une position) dans un nombre n'est pas aussi simple que l'extraction d'une lettre à partir d'une chaîne de caractères; il ne faut pas confondre les deux situations.

Dans le cas d'une chaîne de caractères, nous avons un tableau de caractères. En mémoire, chaque caractère occupe une case (d'un ou de deux octets, selon le langage et la plate-forme). Ainsi, il suffit de connaître la position d'un caractère pour l'extraire. Le parcours peut être réalisé avec une boucle "Pour" (connaissant la taille de la chaîne de caractères).

Dans le cas d'un nombre, nous avons une seule valeur sauvegarder dans un seul emplacement mémoire (de un, deux, quatre ou huit octets). La valeur est sauvegardée en binaire et les chiffres ne sont pas distingués. Ainsi, connaître la position d'un chiffre de facilite pas son extraction. En effet, il faut faire appel à des calculs pour extraire ce chiffre. Dans ce cas les deux opérations nécessaires sont la division et le modulo.Pour récupérer un chiffre, il faut faire deux choses :
  1. Couper le nombre pour rendre le chiffre recherché dans la position des unités. Cela est fait par la division sur une puissance de 10.
  2. Extraire le chiffre qui devient (après avoir coupé le nombre) le modulo 10.
Par exemple, si le nombre n = 123456. Pour extraire le troisième chiffre à partir de droite, il faut :
  1. Diviser le nombre sur 100 (10^(position - 1)), n devient 1234.
  2. Extraire le nombre la module 10, le chiffre extrait sera 4.
Le parcours est beaucoup plus simple parce que on fait des divisions successives sur 10; aucun besoin pour utiliser la fonction puissance de 10.

Il nous reste à signaler deux remarques très importantes :
  1. Contrairement à un tableau (ou chaîne de caractères), le parcours se fait de droite à gauche.
  2. L'opération détruit la valeur d'origine. Si vous aurez besoin d'utiliser cette valeur plus loin dans le programme alors il faut la sauvegarder dans une variable.
En Pascal :


Program ExtraireChiffres;

Var 
 n, c : Integer;

Begin
 WriteLn('Donnez un nombre entier');
 ReadLn(n);
 
 WriteLn('Ses chiffre (de droite à gauche) sont :');
 While (n > 0) Do
 Begin
     c := n mod 10;
     WriteLn(c);
     n := n div 10;
 End;
End.

En Java :


import java.util.Scanner;

public class ExtraireChiffres {
 
 public static void main (String args[]) {
  
  Scanner s = new Scanner(System.in);
  
  System.out.println("Donnez un nombre entier :");
  int n = s.nextInt();
  
  System.out.println("Ses chiffres sont :");
  while(n > 0){
   System.out.println(n % 10);
   n = n / 10;
  }
  
 }
}

L'exécution est identique pour les deux codes :


mercredi 14 février 2018

[Java][Swing][Débutant] Lier deux fenêtres (JFrame)

En concevant une application graphique (swing), nous effectuons, souvent, le choix de créer une fenêtre principale (la mère de toutes les autres fenêtres) et plusieurs fenêtres secondaires (des fenêtres filles) selon les cas d'utilisation de notre système.
Une application de Chat, à titre d'exemple, peut utiliser ce schéma. La classe principale contiendra la liste des amis et les actions globales (Se connecter, Se déconnecter, Ajouter contact, etc..). Chaque fenêtre secondaire (fille) sera dédiée pour une conversation avec un ami. Ainsi, il faut créer autant de fenêtre filles que de conversation en cours.
Dans ce Code Simple, je vais essayer de présenter l'une parmi plusieurs autres idées pour garder le lien entre la fenêtre file et sa mère (la fenêtre principale).
L'idée que je présente est utilisée même au sein de la JDK. Voyons l'exemple :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExempleDialogue {
 
 static JFrame f;
 
 public static void main (String args[]) {
  
  f = new JFrame();
  f.setSize(500, 250);
  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  
  JButton b = new JButton("Exemple");
  b.addActionListener(ExempleDialogue::actionPerformed);
  
  f.add(b, BorderLayout.CENTER);
  f.setVisible(true);
  
 }
 
 public static void actionPerformed(ActionEvent e){
  JOptionPane.showMessageDialog(f, "Exemple");
 }
 
}



Dans ce code, nous pouvons voir que la fenêtre fille (dans ce cas la boîte de dialogue) doit recevoir sa mère comme un paramètre. Dans ce cas, la classe mère est utilisée comme référence pour positionner la boîte de dialogue et pour gérer la modalité des fenêtres.
Nous pouvons recréer cette solution dans un exemple plus global. Ainsi, nous avons besoin de deux fenêtres. La première fenêtre est la fenêtre mère qui doit recevoir une information à partir de ses filles. La deuxième fenêtre est la classe fille qui doit pouvoir envoyer des informations vers sa mère.
Ainsi,la première fenêtre sera :

class Fenetre1 extends JFrame implements ActionListener {

 JLabel message;
 JButton afficher;
 
 public Fenetre1(){
  
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setTitle("Mère");
  
  message = new JLabel("No current message ...");
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Afficher");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }

}


Cette fenêtre a comme rôle l'affichage d'un message en utilisant le JLabel. Le message doit être reçu à partir d'une fenêtre fille :


class Fenetre2 extends JFrame implements ActionListener {

 JTextField message;
 JButton afficher;
 
 public Fenetre2(){
  
  setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  setTitle("Fille");
  
  message = new JTextField();
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Envoie Message");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
}


Cette fenêtre permet de lire un message. Il nous reste de créer le lien. Cela se fait en deux étapes :

1. Ajouter un mécanisme de récepetion des donées dans la classe mère :


 public void setMessage(String m){
  message.setText(m);
 }


2. Ajouter une référence dans la classe fille pour pouvoir se rappeller de sa mère. Cette référence est utilisée pour le


class Fenetre2 extends JFrame implements ActionListener {

 // ...
 
 Fenetre1 parent;
 
 public Fenetre2(Fenetre1 p){

  //...
  parent = p;
                //...

        }

 public void actionPerformed(ActionEvent ae){
  parent.setMessage(message.getText());
 }

        //...

Le code finale sera ainsi :


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class LierDeuxFenetres {
 
 public static void main (String args[]) {
  (new Fenetre1()).setVisible(true);
 }
}

class Fenetre1 extends JFrame implements ActionListener {

 JLabel message;
 JButton afficher;
 
 public Fenetre1(){
  
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setTitle("Mère");
  
  message = new JLabel("No current message ...");
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Afficher");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
 public void setMessage(String m){
  message.setText(m);
 }
 
 public void actionPerformed(ActionEvent ae){
  (new Fenetre2(this)).setVisible(true);
 }
}

class Fenetre2 extends JFrame implements ActionListener {

 JTextField message;
 JButton afficher;
 
 Fenetre1 parent;
 
 public Fenetre2(Fenetre1 p){
  
  parent = p;
  
  setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  setTitle("Fille");
  
  message = new JTextField();
  getContentPane().add(message, BorderLayout.NORTH);
  
  afficher = new JButton("Envoie Message");
  afficher.addActionListener(this);
  getContentPane().add(afficher, BorderLayout.CENTER); 
  
  pack();
  
 }
 
 public void actionPerformed(ActionEvent ae){
  parent.setMessage(message.getText());
 }
}

Démo rapide :



mardi 5 décembre 2017

Création d'un menu

Une astuce érgonomique très répondue est la création des menus. Elle souvent utilisée lorsque le programme fait plusieurs choses (plusieurs traitements).

Pour réaliser un menu, il nous faut the structures de contrôle :
  1. Une structure Case ... of (switch en Java) : cette structure permet d'exécuter le traitement adéquat au choix effectué par l'utilisateur.
  2. Une boucle Répéter ... Jusqu'à pour garantir que l'utilisateur fera un choix valide (principe par ici).
Ainsi, le code d'un menu simple sera en Pascal :


Program Menu;

Const
 MIN = 1;
 MAX = 6;
Var 
 option : Integer;

Begin

 WriteLn('Bienvenue dans ce menu inutil :');
 WriteLn('1 - Créer un nouveau fichier');
 WriteLn('2 - Ouvrir un fichier existant');
 WriteLn('3 - Supprimer un fichier existant');
 WriteLn('4 - Créer un nouveau dossier');
 WriteLn('5 - Ouvrir un dossier existant');
 WriteLn('6 - Supprimer un dossier existant');
 WriteLn();
 
 Repeat
  WriteLn('Votre choix ?');
  ReadLn(option);
  
  Case (option) of
   1 : WriteLn('Créer un nouveau fichier');
   2 : WriteLn('Ouvrir un fichier existant');
   3 : WriteLn('Supprimer un fichier existant');
   4 : WriteLn('Créer un nouveau dossier');
   5 : WriteLn('Ouvrir un dossier existant');
   6 : WriteLn('Supprimer un dossier existant');
  else 
   WriteLn('Option invalide');
  End;
 Until ((option >= MIN) And (option <= MAX));
  
End.

 L'exécution sera :






Note : l'édition et l'exécution sont faites sous Geany (site officiel), il garde la fenêtre ouverte et vous donnera des informations sur le déroulement de l'exécution.

Garantir l'appartenance de la valeur entrée à un intervalle donné

Un problème souvent rencontré est la validation d'une valeur entrée par l'utilisateur. La forme la plus simple est de garantir l'appartenance de la valeur saisie à un intervalle donné. Par exemple, si la valeur saisie désigne un mois alors elle doit être comprise entre 1 et 12.

La solution la plus simple (sans faire recours à des bibliothèques) est l'utilisation d'une boucle de type Répéter ... Jusqu'à (Repeat ... Until) et ce pour deux raisons :

  1. Cette boucle est exécutée au moins une fois; la première lecture sera effectuée à l'intérieur de la boucle.
  2. Cette boucle garde l'utilisateur à l'intérieur jusqu'à ce qu'il fournit une valeur correcte.
Ainsi, le code suivant sera suffisant :


Program ForcerEntree;

Const
 MIN = 10;
 MAX = 100;
 
var 
 valeur : Integer;

BEGIN
 
 Repeat
  WriteLn('Faites entrer une valeur entre ', MIN, ' et ', MAX);
  ReadLn(valeur);
 Until ((valeur >= MIN) And (valeur <= MAX));
 WriteLn('Succès, vous avez saisi ', valeur);
 
END.

L'exécution sera ainsi :