PureBasic     Discussion     Modifier     Historique     Forums     Salon IRC

PureBasic:Console PureBasic

Un article de Games Creators Network.



PureBasic:Console PureBasic

<< Précédent | Sommaire | Suivant >>


Sommaire

[modifier] Introduction

Différents points seront abordés dans ce tutoriel :

  • Utilisation de la console
  • Utilisation d'une liste chaînée
  • Tri d'une liste chaînée
  • Enregistrement et lecture d'un fichier

Plutôt que d'énumérer un à un ces points, nous allons construire un répertoire téléphonique qui regroupera l'ensemble.

Image:Repertoire.PNG

Notre répertoire téléphonique devra contenir le nom et le prénom d'une personne ainsi que son numéro de téléphone, ce qui peut se traduire sous la forme d'une structure :

Structure s_Personne
  Nom.s
  Prenom.s
  Telephone.l
EndStructure

Remarque : Il était aussi possible d'utiliser des chaînes fixes pour limiter la taille des champs. Pour fixer la longueur d'une chaîne il suffit d'indiquer la longueur maxi de la chaîne entre des accolades.

Structure s_Personne
  Nom.s{20}
  Prenom.s{15}
  Telephone.s{10}
EndStructure

Mais cette méthode pose un problème pour utiliser les fonctions de tri, puisqu'elles ne supportent pas les chaînes fixes.




Puisque nous ne connaissons pas à l'avance le nombre d'entrées que comportera notre répertoire, nous ne pouvons pas utiliser un tableau, il nous reste heureusement la solution d'utiliser une Liste chaînée.

Pour déclarer une liste chaînée utilisez la commande Newlist.

NewList Repertoire.s_Personne()

Depuis la V4 de PureBasic, les tableaux ainsi que les listes chaînées ne sont plus globaux.
Si vous voulez que votre liste chaînée soit globale comme dans les versions précédentes ajoutez simplement le mot Global devant la déclaration, c'est le même principe pour déclarer un tableau global.

Global NewList Repertoire.s_Personne()

Nous n'utiliserons pas cette possibilité, comme il est déconseillé de travailler avec des variables globales et donc des tableaux ou listes chaînées globaux, nous allons voir comment passer en paramètre une liste chaînée à une procédure dans la suite de ce tutoriel.

Pour finir nous aurons besoin d'une variable pour tester le clavier.

Define Touche$




Autre point important, ajoutez systématiquement la commande EnableExplicit au début de vos programmes, ça vous évitera de longues recherches pour un problème lié à une simple faute de frappe. En effet toutes les variables qui ne sont pas explicitement déclarées avec Define, Global, Protected, Static ou Shared ne seront pas acceptées par le compilateur et génèreront une erreur.

Par exemple :

Define MaVariable.l, Resultat.l
MaVariable = 3
Resultat = MqVariable * 3
Debug Resultat

Le résultat sera faux parce que MqVariable est une variable déclarée à la volée, et qui vaut zéro. Si vous ajoutez EnableExplicit au début du programme

EnableExplicit
Define MaVariable.l, Resultat.l
MaVariable = 3
Resultat = MqVariable * 3
Debug Resultat

Cette fois ci vous serez averti que MqVariable n'est pas déclarée, et vous gagnerez beaucoup de temps, surtout dans un programme comportant de nombreuses lignes, voire de nombreux fichiers.

[modifier] Console

Nous allons utiliser la console pour saisir et afficher notre répertoire téléphonique.

Liste des commandes de la bibliothèque Console qui seront utilisées dans ce tutoriel :

  • OpenConsole()
  • CloseConsole()
  • EnableGraphicalConsole(1)
  • ClearConsole()
  • ConsoleTitle()
  • ConsoleLocate()
  • ConsoleColor()
  • Input()
  • Print()
  • Inkey()
  • RawKey()

[modifier] Programme de base

Une console peut fonctionner dans deux modes :

  • Le mode texte : le texte ne peut pas être positionné arbitrairement dans la console. Cependant, les redirections (pipes) fonctionnent correctement, ce qui peut être utile si le programme est destiné à être utilisé dans des scripts.
  • Le mode graphique : le texte peut être positionné n'importe où dans la console, ce qui permet de faire des jeux ou des applications console. les redirections (pipes) ne fonctionnent pas dans ce mode.

La sélection du mode se fait avec la commande EnableGraphicalConsole(), nous utiliserons le mode graphique.

Les commandes Inkey() et RawKey() permettent de tester l'appui d'une touche :

  • Inkey() : Renvoi un 'Caractere$' si la touche appuyée a une correspondance dans la table ASCII, toutes les touches alphanumériques et les touches Echap (valeur ASCII 27) ou Entree (valeur ASCII 10) par exemple.
  • RawKey() : Renvoie l'identifiant numérique de la touche capturée lors du dernier appel de la commande Inkey(). Cela permet de gérer les touches qui n'ont pas de caractères ASCII associés (par exemple F1, F2, les flèches etc.).
EnableExplicit

Structure s_Personne
  Nom.s
  Prenom.s
  Telephone.l
EndStructure

NewList Repertoire.s_Personne()
Define Touche$

;Ouvre une console
If OpenConsole() = 0 
  MessageRequester("Erreur", "Impossible d'ouvrir une console", 0)
  End 
EndIf

EnableGraphicalConsole(1) ; Mode graphique
ConsoleTitle("Repertoire telephonique") ; Titre de la console

Print("Appuyez sur la touche [Echap] pour quitter")
Repeat
  Touche$ = Inkey()
  
  Delay(20) ; Evite de monopoliser tout le temps processeur. Utile pour un OS multi-tâches.

Until Touche$ = Chr(27) ; Attends jusqu'à ce que la touche [Echap] soit appuyée

[modifier] Le menu

Pour créer notre répertoire téléphonique nous aurons besoin :

  • D'ajouter une personne dans le répertoire
  • Supprimer une personne du répertoire
  • Afficher le contenu du répertoire
  • Sauvegarder le répertoire sur le disque dur
  • Charger en mémoire le répertoire pour le consulter

On pourrait aussi ajouter la recherche d'un nom si on connait le N° de téléphone, et bien d'autres choses. Je vous laisse le soin de compléter ce programme comme bon vous semble, nous nous en tiendrons à ces fonctions pour ce tutoriel.

L'affichage du menu ne comporte pas de difficulté particulière. Les commandes utilisées sont :

  • ConsoleColor() pour sélectionner la couleur du texte et la couleur de fond
  • ClearConsole() efface l'écran de la console avec la couleur de fond en cours
  • ConsoleLocate() permet de déplacer le curseur de la console à la position x et y indiquée.

En largeur on dispose de 80 positions (0 à 79) En hauteur nous nous limiterons aux positions 0 à 24 pour éviter d'utiliser l'ascenseur de la console.

  • Print() Affiche un texte sur la console sans retour de ligne à la fin.
Procedure AfficheMenu()
  ConsoleColor(15, 2)
  ClearConsole()
  ConsoleColor(15, 1)
  ConsoleLocate( 0, 22) : Print("     F1     ")
  ConsoleLocate( 0, 23) : Print("   Ajoute   ")
  ConsoleLocate( 0, 24) : Print("  Personne  ")
  
  ConsoleLocate(15, 22) : Print("     F2     ")
  ConsoleLocate(15, 23) : Print("  Supprime  ")
  ConsoleLocate(15, 24) : Print("  Personne  ") 
  
  ConsoleLocate(30, 22) : Print("     F3     ")
  ConsoleLocate(30, 23) : Print("  Affiche   ")
  ConsoleLocate(30, 24) : Print(" repertoire ")  
  
  ConsoleLocate(45, 22) : Print("     F4     ")
  ConsoleLocate(45, 23) : Print(" Sauvegarde ")
  ConsoleLocate(45, 24) : Print(" repertoire ")
  
  ConsoleLocate(60, 22) : Print("     F5     ")
  ConsoleLocate(60, 23) : Print("   Charge   ")
  ConsoleLocate(60, 24) : Print(" repertoire ")
EndProcedure

[modifier] Cadre

Pour faire plus joli on peut aussi s'amuser à construire des cadres pour afficher des messages ou pour améliorer la présentation.

Cette partie ne présente pas de difficulté particulière, on utilise les mêmes commandes vues précédemment. Il y a tout de même une petite nouveauté, c'est la bouche For Next. Je vous renvoie à la documentation pour plus de détails, si toutefois ce n'était pas assez clair n'hésitez pas à laisser un message dans la section discussion.

Procedure AfficheCadre(Titre.s, x.l, y.l, w.l, h.l, ct.l, cf.l)
  Define.s HautGauche, Haut , HautDroit, Gauche, Centre, Droit, BasGauche, Bas, BasDroit
  Define.l i, j
    
  ;Inutile de tracer un cadre si les paramètres ne sont pas corrects
  If w < 3 Or h < 3 Or x < 0 Or y < 0 Or x > 79 Or y > 24
    ProcedureReturn #False
  EndIf
    
  HautGauche = Chr(201) 
  Haut       = Chr(205)
  HautDroit  = Chr(187)
  Gauche     = Chr(186)
  Centre     = Chr(32)
  Droit      = Chr(186)
  BasGauche  = Chr(200)
  Bas        = Chr(205)
  BasDroit   = Chr(188)

  ConsoleColor(ct, cf)
  ConsoleLocate(x, y) : Print(HautGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y): Print(Haut)
  Next i
  ConsoleLocate(x + w - 1, y) : Print(HautDroit)
  
  For j = 1 To h - 2   
    ConsoleLocate(x, y + j) : Print(Gauche)
    For i = 1 To w - 2 
      ConsoleLocate(x + i, y + j): Print(Centre)
    Next i
    ConsoleLocate(x + w - 1, y + j) : Print(Droit)
  Next j
  
  ConsoleLocate(x, y + h - 1) : Print(BasGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y + h - 1): Print(Bas)
  Next i
  ConsoleLocate(x + w - 1, y + h -1 ) : Print(BasDroit)  
  
  If titre <> ""
    ConsoleLocate(x + 2, y) : Print(Titre)  
  EndIf
    
EndProcedure

[modifier] Messages console

La macro EFFACE_ECRAN() permet d'effacer la zone d'affichage.

Macro EFFACE_ECRAN()
  AfficheCadre("Repertoire telephonique", 0, 0, 80, 21, 15, 2)
EndMacro

Une petite procédure pour afficher des messages d'aide ou d'alarme.

Procedure MessageConsole(Titre.s, x, y, Message.s)
  Define.l Longueur, Hauteur
  Longueur = Len(Message) + 2
  Hauteur  = 5
  AfficheCadre("", x, y, Longueur, Hauteur, 14, 5)
  ConsoleLocate(x + 1, Y + 2) : Print(Message)
  ConsoleLocate(x + (Len(Message)/2) - 3, Y + 4) : Print("[ Entree ]")
  If titre <> ""
    ConsoleLocate(x + 2, y) : Print(Titre)  
  EndIf
  WaitKey(Chr(13)) ; Attends l'appui de la touche [Entree]
  EFFACE_ECRAN()
EndProcedure

[modifier] Fonctions de saisies améliorées

La procedure InputNombre() comme son nom l'indique, n'accepte que des nombres lors d'une saisie, de plus elle permet de limiter la taille du nombre (avec le paramètre maxi). Cette procédure sera utile pour saisir le numéro de téléphone, et pour limiter la taille du champ de saisie à 10 chiffres.

Procedure InputNombre(x.l, y.l, maxi.l)
  Define Touche$, Nombre$
  
  Repeat
    Touche$ = Inkey()
   
    If Touche$ >= "0" And Touche$ <= "9" And Len(Nombre$) < maxi
    
      Nombre$ + Touche$
      ConsoleLocate(x, y) : Print(Nombre$) ; Affiche le nombre
    
    ElseIf Touche$ = Chr(8) ; Touche backSpace
    
      Nombre$ = Left(Nombre$, Len(Nombre$)-1) ; Supprime un caractère
      ConsoleLocate(x + Len(Nombre$), y) : Print(" ") ;Efface le caractère
      ConsoleLocate(x, y) : Print(Nombre$) ; Affiche le nombre
    
    EndIf 
     
  Until Touche$ = Chr(13) Or Touche$ = Chr(27)
  If Touche$ = Chr(13)
    ProcedureReturn Val(Nombre$)
  Else
    ProcedureReturn 0
  EndIf  
EndProcedure

La procedure InputTexte() comme son nom l'indique, permet de saisir un texte, de plus elle permet de limiter la taille du texte (avec le paramètre maxi). Cette procédure sera utile pour saisir le nom et le prénom d'une personne, et pour limiter la taille des champs.

Procedure.s InputTexte(x.l, y.l, maxi.l)
  Define Touche$, Texte$
  
  Repeat
    Touche$ = Inkey()
   
    If Touche$ <> "" And (Len(Texte$) < maxi Or Touche$ = Chr(8)) And Touche$ <> Chr(13) And Touche$ <> Chr(27)
    
      If Touche$ = Chr(8) ; Touche backSpace
        Texte$ = Left(Texte$, Len(Texte$)-1) ; Supprime un caractère
        ConsoleLocate(x + Len(Texte$), y) : Print(" ") ;Efface le caractère
        ConsoleLocate(x, y) : Print(Texte$) ; Affiche le texte
      Else
        Texte$ + Touche$
        ConsoleLocate(x, y) : Print(Texte$) ; Affiche le nombre
      EndIf
      
    EndIf 
     
  Until Touche$ = Chr(13) Or Touche$ = Chr(27)
  If Touche$ = Chr(13)
    ProcedureReturn Texte$
  Else
    ProcedureReturn ""
  EndIf  
EndProcedure

Et pour finir la procédure WaitKey() attend l'appui d'une touche quelconque si aucun paramètre n'est précisé, sinon l'appui de la touche en paramètre. Exemple pour attendre l'appui de la touche [Entree] :

WaitKey(Chr(13))

Voici la procédure complète :

Procedure WaitKey(T$) 
; Si T$ est indiqué la procédure attend l'appui d'une touche précise
; Sinon n'importe quelle touche peut être appuyée

  Define Touche$, Quitte.l
  Repeat
    Touche$ = Inkey()
    If T$ <> "" 
      If Touche$ = T$
        Quitte = #True
      EndIf
    ElseIf Touche$ <> "" Or RawKey() 
      Quitte = #True
    EndIf  
          
  Until Quitte 
EndProcedure

[modifier] Premier programme de test

Ce programme vous permet de tester une première partie du programme.
Appuyez sur le clavier, seules les touches alphanumériques sont gérées pour l'instant :

EnableExplicit

Structure s_Personne
  Nom.s
  Prenom.s{15}
  Telephone.s{10}
EndStructure

NewList Repertoire.s_Personne()
Define Touche$, MemTouche$, Texte$

;-Declare
Declare AfficheMenu()
Declare AfficheCadre(Titre.s, x.l, y.l, w.l, h.l,  ct.l, cf.l)

If OpenConsole() = 0
  MessageRequester("Erreur", "Impossible d'ouvrir une console", 0)
  End
EndIf

EnableGraphicalConsole(1)
ConsoleTitle("Repertoire telephonique")

AfficheMenu()

Repeat

  Touche$ = Inkey()
  If MemTouche$ <> Touche$ And Touche$ <> ""
    MemTouche$ = Touche$
    Texte$ = "Vous avez appuye la touche " + Touche$
    AfficheCadre("", 19, 10, Len(Texte$) + 2, 3, 14, 4)
    ConsoleLocate(20, 11) 
    Print(Texte$)
  EndIf
    
  Delay(20) ; Evite de monopoliser tout le temps processeur. Utile pour un OS multi-tâches.

Until Touche$ = Chr(27) ; Attends jusqu'à ce que la touche [Echap] soit appuyée 

;-Les procédures

Procedure AfficheMenu()
  ConsoleColor(15, 2)
  ClearConsole()
  ConsoleColor(15, 1)
  ConsoleLocate( 0, 22) : Print("     F1     ")
  ConsoleLocate( 0, 23) : Print("   Ajoute   ")
  ConsoleLocate( 0, 24) : Print("  Personne  ")
  
  ConsoleLocate(15, 22) : Print("     F2     ")
  ConsoleLocate(15, 23) : Print("  Supprime  ")
  ConsoleLocate(15, 24) : Print("  Personne  ") 
  
  ConsoleLocate(30, 22) : Print("     F3     ")
  ConsoleLocate(30, 23) : Print("  Affiche   ")
  ConsoleLocate(30, 24) : Print(" repertoire ")  
  
  ConsoleLocate(45, 22) : Print("     F4     ")
  ConsoleLocate(45, 23) : Print(" Sauvegarde ")
  ConsoleLocate(45, 24) : Print(" repertoire ")
  
  ConsoleLocate(60, 22) : Print("     F5     ")
  ConsoleLocate(60, 23) : Print("   Charge   ")
  ConsoleLocate(60, 24) : Print(" repertoire ")
EndProcedure

Procedure AfficheCadre(Titre.s, x.l, y.l, w.l, h.l, ct.l, cf.l)
  Define.s HautGauche, Haut , HautDroit, Gauche, Centre, Droit, BasGauche, Bas, BasDroit
  Define.l i, j
  
  
  ;Inutile de tracer un cadre si les paramètres ne sont pas corrects
  If w < 3 Or h < 3 Or x < 0 Or y < 0 Or x > 79 Or y > 24
    ProcedureReturn #False
  EndIf
    
  HautGauche = Chr(201) 
  Haut       = Chr(205)
  HautDroit  = Chr(187)
  Gauche     = Chr(186)
  Centre     = Chr(32)
  Droit      = Chr(186)
  BasGauche  = Chr(200)
  Bas        = Chr(205)
  BasDroit   = Chr(188)

  ConsoleColor(ct, cf)
  ConsoleLocate(x, y) : Print(HautGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y): Print(Haut)
  Next i
  ConsoleLocate(x + w - 1, y) : Print(HautDroit)
  
  For j = 1 To h - 2   
    ConsoleLocate(x, y + j) : Print(Gauche)
    For i = 1 To w - 2 
      ConsoleLocate(x + i, y + j): Print(Centre)
    Next i
    ConsoleLocate(x + w - 1, y + j) : Print(Droit)
  Next j
  
  ConsoleLocate(x, y + h - 1) : Print(BasGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y + h - 1): Print(Bas)
  Next i
  ConsoleLocate(x + w - 1, y + h -1 ) : Print(BasDroit)  
  
  If titre <> ""
    ConsoleLocate(x + 2, y) : Print(Titre)  
  EndIf
    
EndProcedure


[modifier] Gestion du répertoire téléphonique

[modifier] Liste chaînée en paramètre d'une procédure

Comme nous l'avons dit précédemment notre liste chaînée n'est pas globale, il est nécessaire de la passer en paramètre aux procédures qui en auront l'usage.

Voici un premier exemple :

NewList MaListe() ; Déclare une nouvelle liste chaînée

; Cette procédure attend une liste chainée en paramètre
Procedure MaProc(ListeEnParametre()) 
  ;La liste passée en paramètre peut être modifiée dans la procédure
  AddElement(ListeEnParametre())
  ListeEnParametre() = 12
Endprocedure

MaProc(MaListe()) ; Appelle la procédure MaProc avec la liste MaListe() en paramètre

Si la liste chaînée comporte une structure, il faut renseigner la procédure :

NewList MaListe.Point() ; Déclare une nouvelle liste chaînée de point

; Cette procédure attend une liste chainée en paramètre
Procedure MaProc(ListeEnParametre.Point()) 
  ;La liste passée en paramètre peut être modifiée dans la procédure
  AddElement(ListeEnParametre())
  ListeEnParametre()\x = 12
  ListeEnParametre()\y = 21
Endprocedure

MaProc(MaListe()) ; Appelle la procédure MaProc avec la liste MaListe() en paramètre

Remarque : La structure Point est déjà présente dans les résidents , c'est pourquoi elle peut être utilisée sans être créée au préalable. Vous pouvez afficher son contenu avec le visualisateur de structures accessible depuis l'IDE , dans le menu Outils.

Image:Structureviewer.JPG

Voici à quoi elle ressemble

Structure POINT
   x.l
   y.l
EndStructure




Nous allons décomposer en différentes procédures les actions à accomplir :

  • AjoutePersonne()
  • SupprimePersonne()
  • AfficheRepertoire()

[modifier] Ajoute une personne

Procedure AjoutePersonne(Rep.s_Personne())
  Define Personne.s_Personne
  
  AfficheCadre("Ajout d'une personne", 8, 8, 40, 7, 0, 7)
  
  ConsoleLocate( 10, 10) : Print("Nom       = ")
  ConsoleLocate( 10, 11) : Print("Prenom    = ")
  ConsoleLocate( 10, 12) : Print("Telephone = ")
  
  ConsoleLocate( 22, 10) : Personne\Nom       = InputTexte(22, 10, 20)
  ConsoleLocate( 22, 11) : Personne\Prenom    = InputTexte(22, 11, 15)
  ConsoleLocate( 22, 12) : Personne\Telephone = InputNombre(22, 12, 10) 
  
  ConsoleLocate( 10, 14) : Print("Appuyez sur une touche")

  WaitKey("") ; Attends l'appui sur une touche
  
  EFFACE_ECRAN()
  
  ;Ajoute la personne dans le répertoire
  If Len(Personne\Nom) 
    AddElement(Rep())
    Rep()\Nom       = Personne\Nom
    Rep()\Prenom    = Personne\Prenom
    Rep()\Telephone = Personne\Telephone
  EndIf
    
EndProcedure

[modifier] Supprime une personne

Cette procédure utilise deux nouvelles commandes :

  • Trim(Chaine$) : Supprime tous les espaces situés au début et à la fin de la chaîne de caractères.
  • UCase(Chaine$) : Renvoie une chaine convertie en lettres majuscules.
Procedure SupprimePersonne(Rep.s_Personne())
  Define Trouve.l, Personne.s_Personne
  
  If CountList(Rep())
    
    ConsoleColor(15, 2)
    ConsoleLocate( 10, 10) : Print("Nom de la personne a supprimer du repertoire = ")
    
    ConsoleLocate( 57, 10) : Personne\Nom = Input()
   
    ConsoleLocate( 10, 14) : Print("Suppression en cours...")
    
    ForEach Rep()
      If Trim(UCase(Rep()\Nom)) = Trim(UCase(Personne\Nom))
        DeleteElement(Rep())
        Trouve = #True
        Break
      EndIf  
    Next
    
    EFFACE_ECRAN()
    
    If Trouve 
      MessageConsole("Supprime Personne", 20, 7, "Suppression de " + Personne\Nom + " terminee")
    Else
      MessageConsole("Supprime Personne", 20, 7, Personne\Nom + " est introuvable dans le repertoire")
    EndIf
    
    EFFACE_ECRAN()
  
  Else
    MessageConsole("Supprime personne", 30, 7, "Le repertoire est vide") 
  EndIf  
EndProcedure

[modifier] Affiche le répertoire

Avant d'afficher le répertoire, nous effectuons un tri de la liste chaînée en utilisant la commande SortStructuredList().

Procedure AfficheRepertoire(Rep.s_Personne())
  Define i.l, T$
   
  i = 3
  
  If CountList(Rep())
    ;Tri du répertoire avant de l'afficher
    SortStructuredList(Rep(), 2, OffsetOf(s_Personne\Nom), #PB_Sort_String)
    
    ForEach Rep()
      T$ = RTrim(Rep()\Nom) + " " + RTrim(Rep()\Prenom)
      ConsoleLocate(5, i) : Print(LSet(T$,35, ".") + "... " + Str(Rep()\Telephone)) 
      i + 1
      If i > 18
        ConsoleLocate(20, 20) :  Print("Appuyez sur une touche pour continuer")
        
        WaitKey("") ; Attends l'appui sur une touche
        
        EFFACE_ECRAN()
        i = 3
      EndIf  
    Next
    
    ConsoleLocate(20, 20) : Print("Appuyez sur une touche pour continuer")
    
    WaitKey("") ; Attends l'appui sur une touche
  
    EFFACE_ECRAN()
    
  Else
    MessageConsole("Affiche repertoire", 30, 7, "Le repertoire est vide") 
  EndIf
      
EndProcedure

[modifier] Fichiers

[modifier] Ecriture répertoire

Vous pouvez compléter la procédure en utilisant la commande SaveFileRequester(). Cette commande ouvre une boîte de dialogue standard pour enregistrer un fichier.

Procedure SauvegardeRepertoire(Fichier.s, Rep.s_Personne())
  If CreateFile(0, Fichier)
    ForEach Rep()
      WriteStringN(0, Rep()\Nom)
      WriteStringN(0, Rep()\Prenom)
      WriteLong(0, Rep()\Telephone)
    Next   
    CloseFile(0)
    MessageConsole("Sauvegarde repertoire", 1, 10, "La sauvegarde du repertoire dans le fichier " + Fichier + " est terminee")
  EndIf  
EndProcedure

[modifier] Lecture répertoire

Vous pouvez compléter la procédure en utilisant la commande OpenFileRequester(). Cette commande ouvre une boîte de dialogue standard pour choisir un fichier.

Procedure ChargeRepertoire(Fichier.s, Rep.s_Personne())
  If ReadFile(0, Fichier)
    ClearList(Rep())
    While Eof(0) = 0
      AddElement(Rep())
      Rep()\Nom       = ReadString(0)
      Rep()\Prenom    = ReadString(0)
      Rep()\Telephone = ReadLong(0)
    Wend   
    CloseFile(0)
    MessageConsole("Charge repertoire", 10, 10, "Le chargement du repertoire " + Fichier + " est termine")
  EndIf   
EndProcedure

[modifier] Code complet

Et enfin voici le programme complet, n'hésitez pas à faire des remarques, des suggestions d'amélioration, ou demander des compléments d'informations si nécessaire :

;*********************************
;Gestion répertoire téléphonique
;*********************************

; PB 4.0 23 juillet 2006

EnableExplicit

Structure s_Personne
  Nom.s
  Prenom.s
  Telephone.l
EndStructure

NewList Repertoire.s_Personne()
Define Touche$

Macro EFFACE_ECRAN()
  AfficheCadre("Repertoire telephonique", 0, 0, 80, 21, 15, 2)
EndMacro


;**************************
;- Déclare les procédures
;**************************  
Declare EffaceEcran()
Declare AfficheMenu()
Declare WaitKey(T$)
Declare InputNombre(x.l, y.l, maxi.l)
Declare.s InputTexte(x.l, y.l, maxi.l)
Declare AjoutePersonne(Rep.s_Personne())
Declare SupprimePersonne(Rep.s_Personne())
Declare AfficheRepertoire(Rep.s_Personne())
Declare AfficheCadre(Titre.s, x.l, y.l, w.l, h.l,  ct.l, cf.l)
Declare MessageConsole(Titre.s, x, y, Message.s)
Declare SauvegardeRepertoire(Fichier.s, Rep.s_Personne())
Declare ChargeRepertoire(Fichier.s, Rep.s_Personne())

;*******************
;- Et c'est parti 
;*******************
If OpenConsole() = 0
  MessageRequester("Erreur", "Impossible d'ouvrir une console", 0)
  End
EndIf

EnableGraphicalConsole(1)
ConsoleTitle("Repertoire telephonique - [Echap] pour quitter")
AfficheMenu()
EFFACE_ECRAN()

Repeat

  Touche$ = Inkey()
  
  If RawKey()

    Select RawKey()
   
      Case 112 ; Touche F1
        AjoutePersonne(Repertoire())
    
      Case 113 ; Touche F2
        SupprimePersonne(Repertoire())
      
      Case 114 ; Touche F3
        AfficheRepertoire(Repertoire())
              
      Case 115 ; Touche F4
        SauvegardeRepertoire("MonRepertoire.Rep", Repertoire())
        
      Case 116 ; Touche F5
        ChargeRepertoire("MonRepertoire.Rep", Repertoire())  
          
    EndSelect   

  Else
    Delay(20) ; Evite de monopoliser tout le temps processeur. Utile pour un OS multi-tâches.
  EndIf

Until Touche$ = Chr(27) ; Attends jusqu'à ce que la touche [Echap] soit appuyée 


;*******************
;- Les procédures
;*******************
Procedure AfficheMenu()
  ConsoleColor(15, 2)
  ClearConsole()
  ConsoleColor(15, 1)
  ConsoleLocate( 0, 22) : Print("     F1     ")
  ConsoleLocate( 0, 23) : Print("   Ajoute   ")
  ConsoleLocate( 0, 24) : Print("  Personne  ")
  
  ConsoleLocate(15, 22) : Print("     F2     ")
  ConsoleLocate(15, 23) : Print("  Supprime  ")
  ConsoleLocate(15, 24) : Print("  Personne  ") 
  
  ConsoleLocate(30, 22) : Print("     F3     ")
  ConsoleLocate(30, 23) : Print("  Affiche   ")
  ConsoleLocate(30, 24) : Print(" repertoire ")  
  
  ConsoleLocate(45, 22) : Print("     F4     ")
  ConsoleLocate(45, 23) : Print(" Sauvegarde ")
  ConsoleLocate(45, 24) : Print(" repertoire ")
  
  ConsoleLocate(60, 22) : Print("     F5     ")
  ConsoleLocate(60, 23) : Print("   Charge   ")
  ConsoleLocate(60, 24) : Print(" repertoire ")
EndProcedure

Procedure WaitKey(T$) 
; Si T$ est indiqué la procédure attend l'appui d'une touche précise
; Sinon n'importe quelle touche peut être appuyée

  Define Touche$, Quitte.l
  Repeat
    Touche$ = Inkey()
    If T$ <> "" 
      If Touche$ = T$
        Quitte = #True
      EndIf
    ElseIf Touche$ <> "" Or RawKey() 
      Quitte = #True
    EndIf  
          
  Until Quitte 
EndProcedure

Procedure InputNombre(x.l, y.l, maxi.l)
  Define Touche$, Nombre$
  
  Repeat
    Touche$ = Inkey()
   
    If Touche$ >= "0" And Touche$ <= "9" And Len(Nombre$) < maxi
    
      Nombre$ + Touche$
      ConsoleLocate(x, y) : Print(Nombre$) ; Affiche le nombre
    
    ElseIf Touche$ = Chr(8) ; Touche backSpace
    
      Nombre$ = Left(Nombre$, Len(Nombre$)-1) ; Supprime un caractère
      ConsoleLocate(x + Len(Nombre$), y) : Print(" ") ;Efface le caractère
      ConsoleLocate(x, y) : Print(Nombre$) ; Affiche le nombre
    
    EndIf 
     
  Until Touche$ = Chr(13) Or Touche$ = Chr(27)
  If Touche$ = Chr(13)
    ProcedureReturn Val(Nombre$)
  Else
    ProcedureReturn 0
  EndIf  
EndProcedure

Procedure.s InputTexte(x.l, y.l, maxi.l)
  Define Touche$, Texte$
  
  Repeat
    Touche$ = Inkey()
   
    If Touche$ <> "" And (Len(Texte$) < maxi Or Touche$ = Chr(8)) And Touche$ <> Chr(13) And Touche$ <> Chr(27)
    
      If Touche$ = Chr(8) ; Touche backSpace
        Texte$ = Left(Texte$, Len(Texte$)-1) ; Supprime un caractère
        ConsoleLocate(x + Len(Texte$), y) : Print(" ") ;Efface le caractère
        ConsoleLocate(x, y) : Print(Texte$) ; Affiche le texte
      Else
        Texte$ + Touche$
        ConsoleLocate(x, y) : Print(Texte$) ; Affiche le nombre
      EndIf
      
    EndIf 
     
  Until Touche$ = Chr(13) Or Touche$ = Chr(27)
  If Touche$ = Chr(13)
    ProcedureReturn Texte$
  Else
    ProcedureReturn ""
  EndIf  
EndProcedure

Procedure AjoutePersonne(Rep.s_Personne())
  Define Personne.s_Personne
  
  AfficheCadre("Ajout d'une personne", 8, 8, 40, 7, 0, 7)
  
  ConsoleLocate( 10, 10) : Print("Nom       = ")
  ConsoleLocate( 10, 11) : Print("Prenom    = ")
  ConsoleLocate( 10, 12) : Print("Telephone = ")
  
  ConsoleLocate( 22, 10) : Personne\Nom       = InputTexte(22, 10, 20)
  ConsoleLocate( 22, 11) : Personne\Prenom    = InputTexte(22, 11, 15)
  ConsoleLocate( 22, 12) : Personne\Telephone = InputNombre(22, 12, 10) 
  
  ConsoleLocate( 10, 14) : Print("Appuyez sur une touche")

  WaitKey("") ; Attends l'appui sur une touche
  
  EFFACE_ECRAN()
  
  ;Ajoute la personne dans le répertoire
  If Len(Personne\Nom) 
    AddElement(Rep())
    Rep()\Nom       = Personne\Nom
    Rep()\Prenom    = Personne\Prenom
    Rep()\Telephone = Personne\Telephone
  EndIf
    
EndProcedure

Procedure SupprimePersonne(Rep.s_Personne())
  Define Trouve.l, Personne.s_Personne
  
  If CountList(Rep())
    
    ConsoleColor(15, 2)
    ConsoleLocate( 10, 10) : Print("Nom de la personne a supprimer du repertoire = ")
    
    ConsoleLocate( 57, 10) : Personne\Nom = Input()
   
    ConsoleLocate( 10, 14) : Print("Suppression en cours...")
    
    ForEach Rep()
      If Trim(UCase(Rep()\Nom)) = Trim(UCase(Personne\Nom))
        DeleteElement(Rep())
        Trouve = #True
        Break
      EndIf  
    Next
    
    EFFACE_ECRAN()
    
    If Trouve 
      MessageConsole("Supprime Personne", 20, 7, "Suppression de " + Personne\Nom + " terminee")
    Else
      MessageConsole("Supprime Personne", 20, 7, Personne\Nom + " est introuvable dans le repertoire")
    EndIf
    
    EFFACE_ECRAN()
  
  Else
    MessageConsole("Supprime personne", 30, 7, "Le repertoire est vide") 
  EndIf  
EndProcedure
  
Procedure AfficheRepertoire(Rep.s_Personne())
  Define i.l, T$
   
  i = 3
  
  If CountList(Rep())
    ;Tri du répertoire avant de l'afficher
    SortStructuredList(Rep(), 2, OffsetOf(s_Personne\Nom), #PB_Sort_String)
    
    ForEach Rep()
      T$ = RTrim(Rep()\Nom) + " " + RTrim(Rep()\Prenom)
      ConsoleLocate(5, i) : Print(LSet(T$,35, ".") + "... " + Str(Rep()\Telephone)) 
      i + 1
      If i > 18
        ConsoleLocate(20, 20) :  Print("Appuyez sur une touche pour continuer")
        
        WaitKey("") ; Attends l'appui sur une touche
        
        EFFACE_ECRAN()
        i = 3
      EndIf  
    Next
    
    ConsoleLocate(20, 20) : Print("Appuyez sur une touche pour continuer")
    
    WaitKey("") ; Attends l'appui sur une touche
  
    EFFACE_ECRAN()
    
  Else
    MessageConsole("Affiche repertoire", 30, 7, "Le repertoire est vide") 
  EndIf
      
EndProcedure

Procedure AfficheCadre(Titre.s, x.l, y.l, w.l, h.l, ct.l, cf.l)
  Define.s HautGauche, Haut , HautDroit, Gauche, Centre, Droit, BasGauche, Bas, BasDroit
  Define.l i, j
  
  
  ;Inutile de tracer un cadre si les paramètres ne sont pas corrects
  If w < 3 Or h < 3 Or x < 0 Or y < 0 Or x > 79 Or y > 24
    ProcedureReturn #False
  EndIf
    
  HautGauche = Chr(201) 
  Haut       = Chr(205)
  HautDroit  = Chr(187)
  Gauche     = Chr(186)
  Centre     = Chr(32)
  Droit      = Chr(186)
  BasGauche  = Chr(200)
  Bas        = Chr(205)
  BasDroit   = Chr(188)

  ConsoleColor(ct, cf)
  ConsoleLocate(x, y) : Print(HautGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y): Print(Haut)
  Next i
  ConsoleLocate(x + w - 1, y) : Print(HautDroit)
  
  For j = 1 To h - 2   
    ConsoleLocate(x, y + j) : Print(Gauche)
    For i = 1 To w - 2 
      ConsoleLocate(x + i, y + j): Print(Centre)
    Next i
    ConsoleLocate(x + w - 1, y + j) : Print(Droit)
  Next j
  
  ConsoleLocate(x, y + h - 1) : Print(BasGauche)
  For i = 1 To w - 2 
    ConsoleLocate(x + i, y + h - 1): Print(Bas)
  Next i
  ConsoleLocate(x + w - 1, y + h -1 ) : Print(BasDroit)  
  
  If titre <> ""
    ConsoleLocate(x + 2, y) : Print(Titre)  
  EndIf
    
EndProcedure

Procedure MessageConsole(Titre.s, x, y, Message.s)
  Define.l Longueur, Hauteur
  Longueur = Len(Message) + 2
  Hauteur  = 5
  AfficheCadre("", x, y, Longueur, Hauteur, 14, 5)
  ConsoleLocate(x + 1, Y + 2) : Print(Message)
  ConsoleLocate(x + (Len(Message)/2) - 3, Y + 4) : Print("[ Entree ]")
  If titre <> ""
    ConsoleLocate(x + 2, y) : Print(Titre)  
  EndIf
  WaitKey(Chr(13)) ; Attends l'appui de la touche [Entree]
  EFFACE_ECRAN()
EndProcedure
 
Procedure SauvegardeRepertoire(Fichier.s, Rep.s_Personne())
  If CreateFile(0, Fichier)
    ForEach Rep()
      WriteStringN(0, Rep()\Nom)
      WriteStringN(0, Rep()\Prenom)
      WriteLong(0, Rep()\Telephone)
    Next   
    CloseFile(0)
    MessageConsole("Sauvegarde repertoire", 1, 10, "La sauvegarde du repertoire dans le fichier " + Fichier + " est terminee")
  EndIf  
EndProcedure

Procedure ChargeRepertoire(Fichier.s, Rep.s_Personne())
  If ReadFile(0, Fichier)
    ClearList(Rep())
    While Eof(0) = 0
      AddElement(Rep())
      Rep()\Nom       = ReadString(0)
      Rep()\Prenom    = ReadString(0)
      Rep()\Telephone = ReadLong(0)
    Wend   
    CloseFile(0)
    MessageConsole("Charge repertoire", 10, 10, "Le chargement du repertoire " + Fichier + " est termine")
  EndIf   
EndProcedure

[modifier] Version window avec Gadgets

Il serait intéressant de proposer ici une version Window avec des gadgets, je n'ai pas le temps de me lancer dans cette aventure, ça laisse le champ libre aux courageux qui voudront proposer une solution :)

 

Rechercher
Installer l'extension de recherche Plus d'informations

 

Comprendre
Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. - Benjamin Franklin

 

Partager
La connaissance est la seule chose qui s'accroit lorsqu'on la partage. - Sacha Boudjema

 

Créer
L'imagination est plus importante que la connaissance. - Albert Einstein

 

 

Le wiki en images Le wiki en images Image du mois: «Snowball: un prototype de jeu développé avec NeL.