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.
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.
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 :)

