Salut,

Envoyé par
Njoy's
Bonsoir si je reviens une fois de plus auprès de vous c'est vous demander comment est ce que je peux faire pour gérer l'affichage de mes instructions sur le compilateur...
Au niveau du compilateur, la seule solution est de founrir un code adéquat.
Car, ce que tu veux, c'est présenter un menu à l'utilisateur au moment de l'exécution de ton programme, qui n'a plus rien à voir avec le compilateur 
Mon problème c'est :
- quel syntaxe pourra me permettre d'afficher sur la console uniquement le contenu du sous menu que j'aurais choisi sans toute fois passer Ala ligne à chaque moment?
- quel syntaxe me permettra que des que je tape "3" sur mon clavier ma console se ferme automatiquement?
La règle d'or en programmation est toujours de "diviser pour mieux régner".
Elle te permettra de respecter plus facilement la règle de platine connue sous l'acronyme DRY (Don't Repeat Yourself ou, si tu préfères en français "Ne vous répétez pas").
la règle d'or t'impose de comprendre les étapes qui devront être suivies pour remplir ton besoin, qui peut être divisé en cinq étapes "plus simples", à savoir:
- afficher le menu
- attendre une introduction de la part de l'utilisateur
- vérifier que l'introduction de l'utilisateur respecte les consignes (engueuler l'utilisateur si ce n'est pas le cas et recommencer en (1)
- utiliser la valeur obtenue pour décider de ce qui est fait (engueuler l'utilisateur si l'option choisie n'est pas valide)
- recommencer en (1) "Jusqu'à ce que l'utilisateur en décide autrement" (*)
(*) Cette manière d'exprimer les choses nous permet de fournir une "règle générale" qui peut s'appliquer à n'importe quel menu, qu'il s'agisse du menu principal, ou de n'importe quel sous menu que tu pourras créer.
1- Afficher le menu
Menu principal
1-gestion des étudiants par tableau
2-A propos
3-sortir du programme
Veuillez entrer une valeur comprise entre 1 et 3.....
Au vu de ce menu, on se rend compte qu'il y aura sans doute un sous menu à afficher si l'utilisateur choisi l'option 1. On peut, en outre, estimer que le programme risque d'évoluer par la suite, t'obligeant des entrées supplémentaires dans les menus existants, voire, carrément, à ajouter de nouveaux sous menus.
Il est donc, plus que jamais nécessaire de respecter le DRY, car, plus tu répéteras du code, plus ton code contiendra de versions différentes d'un code sensiblement identique "à quelques détails près", plus tu risques de faire des erreurs, de créer des bugs, et plus la maintenance ou l'ajout de nouvelles fonctionnalités deviendront difficiles.
L'énorme avantage, c'est que la logique que je viens d'exprimer peut s'appliquer à n'importe quelle sorte de menu. La seule chose qui nous reste à faire maintenant, c'est de définir à quoi pourrait ressembler les différentes entrées de menu.
Pour cela, on va se baser sur le menu dont on dispose déjà, à savoir le menu principal, et on va réfléchir à la forme que l'on souhaite lui donner lors de l'affichage, vu que c'est la première étape qui doit être exécutée.
A priori, on voudras sans doute que l'affichage ressemble à quelque chose comme
1 2 3 4 5 6 7
| menu principal
==============
1- Gestion des étudiants
2- A propos
3- Quitter
Votre choix (1 - 3)? |
Ca ne nous avance pas vraiment, parce qu'il existe plusieurs moyens d'obtenir un tel affichage. Réfléchissons donc à ce que l'on voudrait afficher pour le (sous) menu de gestion des étudiants. On voudra sans doute que cela ressemble à
1 2 3 4 5 6 7 8 9 10 11
| Gestion des etudiants
=====================
1- Afficher la liste
2- chercher
3- Ajouter
4- Supprimer
5- Charger
6- Sauvegarder
7- (Retour au) Menu principal
Votre choix (1 - 7)? |
Ahh, cela commence à devenir sympa, car on peut tout doucement définir la structure des différents menu en se disant qu'elle est composée de trois éléments distincts, à savoir:
- le titre du menu, qui devra être sous-ligné
- "un certain nombre" d'options, qui devront être numérotées, et qui dépend du menu dans lequel on se trouve (*) (**)
- un message indiquant clairement à l'utilisateur que l'on attend qu'il choisisse le numéro associé à une des options données, ainsi que l'intervalle des valeurs admises
(*) Tu remarquera que la dernière option correspond toujours à ce fameux choix "de sortir du menu actuel", ce qui revient, dans le cas du menu principal à ... quitter l'application, et, dans le cas d'un sous-menu, à retourner au menu supérieur et ce, quel que soit le niiveau de menu auquel nous sommes.
Le meilleur moyen de représenter "un certain nombre" d'option consiste sans doute à utiliser std::vector, qui permet de représenter un nombre d'élément inconnu à l'avance. Nous pouvons donc envisager de transmettre un std::vector de std::string à la fonction qui devra s'occuper de l'affichage du menu, simplement parce que les options à afficher prendront -- effectivement -- la forme de ... chaines de caractères.
Cela nous permettrait de généraliser l'affichage de n'importe quel menu grâce à une fonction ressemblant à quelque chose comme
void afficherMenu(std::string const & title, std::vector<std::string> const & options);
de manière à ce que la fonction puisse afficher le titre (et le sous-ligner) suivi de toutes les options offertes à l'utilisateur.
Cependant, cette forme va nous poser un léger problème. Ce n'est rien de bien grave, mais cela pourrait compliquer un peu les choses, car la numérotation des indices commence à 0 dans un tableau (et le dernier indice a la valeur N-1, où N correspond au nombre d'éléments du tableau), or, la numérotation des options devrait commencer à ... 1.
Ce qui est chouette, c'est que le titre du menu est lui aussi une chaine de caractères. Nous pourrions donc parfaitement envisager de dire que, par convention, le premier élément du tableau (c'est à dire: celui qui se trouvera à l'indice 0) sera toujours et obligatoirement le titre du menu que l'on affiche. De cette manière, l'indice des différentes options pourra, effectivement, correspondre au nombre permettant à l'utilisateur de les choisir.
Nous pourirons donc créer notre fonction sous une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void afficherMenu(std::vector<std::string> const & options){
for(size_t i = 0; i<options.size();++i){
if(i == 0){ // cas particulier, on affiche le titre du menu
std::cout<<options[0]<<"\n";
for(size_t size = 0; size <options[0].size();++size){ // pour chaque caractère du titre
std::cout<<'='; // on affiche un caractère de sous-lignage
}
std::cout<<"\n"; //puis on va a la ligne
} else{ // pour tous les autres cas (en gros, pour toutes les options)
std::cout<<i<<"- "<<options[i]<<"\n"; // on affiche l'indice de l'option suivie de l'option en question
}
}
/* Arrivé ici, il n'y a plus qu'à afficher le message indiquant à l'utilisateur que l'on attend son choix */
std::cout<<"\nVotre Choix (1 -"<<options.size()-1<<")?"; //le dernier indice admis correspond à la taille du tableau -1
} |
Cette fonction pourra tout aussi bien être utilisée, dans la fonction main, pour l'affichage du menu principal sous la forme de
1 2 3 4 5 6 7
| int main(){
std::vector<std::string> const menuPrincipal={{"Menu principal"},
{"Gestion des etudiants"},
{"A propos"},
{"Quitter"}};
afficherMenu(menuPrincipal);
} |
De la même manière, si nous avions à afficher un menu quelconque dans n'importe quelle fonction, cela pourrait prendre la forme de (pour la gestion des étudiants ici):
1 2 3 4 5 6 7 8 9 10 11 12
| void foo(){
std::vector<std::string> const gestionEtudiants={{"Gestion des etudiants"},
{"Afficher la liste"},
{"Chercher"},
{"Ajouter"},
{"Supprimer"},
{"Charger"},
{"Sauvegarder"},
{"Menu Principal"}};
afficherMenu(gestionEtudiants);
} |
2 et 3 Attendre l'introduction de l'utilisateur et la valider
Après avoir affiché un menu, nous voulons attendre que l'utilisateur introduise le numéro de l'option qui l'intéresse.
Seulement, il existe une règle empirique qui dit que

Envoyé par
loi de murphy
Si vous laissez l'occasion à quelqu'un de faire une connerie, il finira tôt ou tard par la commettre.
Dans le cas présent, la connerie que l'utilisateur pourrait commettre est d'introduire n'importe quoi sauf une valeur numérique entière. Il peut tout aussi bien introduire "hello world" (qui est une chaine de caractères) que 3.1415926 (qui est une valeur numérique réelle et non une valeur numérique entière).
Il ne faut même pas perdre son temps à se demander s'il commettra ce genre de connerie ou non, car tu peux être sur qu'il la commettra à un moment ou à un autre. La vrai bonne question à se poser est donc "quand fera-t-il cette connerie
".
Malheureusement la réponse à cette question est bien connue et n'est vraiment pas à ton avantage, car c'est "au pire moment qui soit" :S .
On ne peut donc pas se contenter d'un simple
1 2 3
| size_tchoix;
std::cin>>choix;
return choix |
dans le cas présent, car il faut pourvoir s'assurer que ce que l'utilisateur introduit sera bel et bien une valeur numérique entière.
Afin de prendre toutes les possibilités en compte, nous allons devoir travailler en deux temps:- nous récupérerons d'abord l'introduction de l'utilisateur sous la forme la plus générique possible, à savoir, sous la forme d'une chaine de caractères puis
- nous essayons de convertir cette chaine de caractères en entier non signé, en nous assurant que l'ensemble de la chaine de caractères a été converti.
NOTA: à ce niveau, on peut, finalement, se foutre pas mal de l'intervalle des valeurs admises pour les options, parce que tout ce que nous voulons, c'est être sur que l'utilisateur aura bel et bien introduit une valeur numérique entière.
Nous allons donc devoir créer deux fonctions afin de respecter -- une fois encore -- notre règle d'or. La première sera une fonction de conversion qui prendra une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| /* converti une chaine de caractères en size_t
*
* @return la valeur convertie si la chaine de caractères
* représente une valeur numérique entière non signée.
* 0 en cas d'erreur lors de la conversion ou si
* la valeur n'est pas un entier
* @note : ratttrape les exceptions qui pourraient être lancées
* en cas de problème lors de la conversion
*/
size_t convertToValue(std::string const & str){
if(str.size() == 0){
std::cout<<"Une entree vide n'est pas admise\n";
return 0;
};
size_t pos{0};
try{ // car une exception risque d'être lancée, et que nous voulons
// la rattraper si c'est le cas
size_t result = std::stoull(str, &pos);
if(pos < str.size()){ // si l'intégralité de la chaine n'a pas été convertie
// on engueule l'utilisateur
std::cout<<"Veuillez introduire une valeur numérique entiere uniquement!\n";
return 0; // et on renvoie une valeur invalide
}
// si on arrive ici, c'est que la conversion s'est bien passée
return result;
}catch(std::exception const & e){
// si on passe ici, c'est que la conversion a échoué
// on engueule l'utilisateur
std::cout<<"Seules les valeurs numeriques sont admises\n";
}
/* si on arrive ici, c'est qu'il y a eu un problème, on renvoie une valeur invalide */
return 0;
} |
et la fonction qui attend l'introduction de l'utilisateur qui prendrait la forme de
1 2 3 4 5 6 7 8 9 10 11
|
/* @brief Attend l'introduction de l'utilisateur
*
* @return le choix de l'utilisateur converti en size_t
* 0 si cette conversion a échoué
*/
size_t waitUserInput(){
std::string str;
std::getline(std::cin, str);
return convertToValue(str);
} |
Alors, je te vois déjà venir: tu pourrais très facilement me demander
mais pourquoi t'em...des-tu à créer une fonction de conversion

Ne pourrait-on pas tout faire en une seule fonction

Ce serait finalement beaucoup plus simple, non
Il y a au moins deux raisons à cela:
La première, c'est que la chaine de caractères à convertir pourrait parfaitement venir d'ailleurs que du clavier de l'utilisateur. Rien ne nous empêcherait de créer un fichier qui prendrait la forme de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| # repond au menu principal: on veut gerer les etudiant
1
# dans la gestion des etudiants, on veut charger la sauvegarde
5
# il faut le nom du fichier a charger
etudiants_1840.txt
# on veut ajouter un etudiant
3
# les informations dans l'ordre requis: le nom, le prenom, la date de naissance
Vernes
Jules
8/2/1828
# on enregistre les modifications
6
# on garde le même nom de fichier
etudiants_1840.txt
# on quitte la gestion des etudiants
7
# on quitte l'application
3 |
Les lignes qui commencent par un # représentent un commentaire (pour que tu puisse suivre ce qui est fait), toutes les autres représentent une "introduction de la part de l'utilisateur". Ici aussi, il faut savoir j'ai bien introduit des chiffres à chaque fois que je voulais choisir une option de menu.
En déléguant la vérification à une fonction qui ne fait que cela, je me mets en mesure de la réutiliser "n'importe où", y compris si la chaine de caractères vient "d'ailleurs", ou même si je me trouve dans une situation où l'utilisateur doit introduire une valeur qui est forcément de type size_t, mais qui n'a rien à voir avec le choix d'une option de menu.
Le rôle d'un développeur est de se casser la tête de manière à ce que l'utilisateur n'ait pas à le faire. Or, on n'est développeur d'une fonctionnalité que ... le temps nécessaire à en écrire le code. Dés que la fonctionnalité en question a été développée et testée, dés que l'on arrête de s'intéresser au code de cette fonctionnalité, on en devient forcément un utilisateur "comme les autres", avec toutes les faiblesses que cela implique 
Je me casse donc la tête pendant quelque secondes pour créer deux fonctions au lieu d'une seule uniquement pour ne pas avoir à le faire plus tard, lorsque de nouveaux besoins apparaitront. Et au final, j'y gagne énormément de temps, parce que cela va m'éviter de commettre de nombreuses erreurs, que je n'aurai pas à corriger par la suite.
4 et 5 choisir ce qui doit être fait et recommencer
Maintenant que nous pouvons déterminer avec précision le choix de l'utilisateur, nous sommes en mesure de modifier notre fonction main (pour l'affichage du menu principal) et notre fonction foo données en exemple.
Pour représenter cette notion de "jusqu'à ce que l'utilisateur en décide autrement", nous allons tout simplement créer une boucle, ce qui fait que la fonction main pourrait prendre une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| int main(){
std::vector<std::string> const menuPrincipal={{"Menu principal"},
{"Gestion des etudiants"},
{"A propos"},
{"Quitter"}};
size_t choix{0};
while(choix !=menuPrincipal.size()-1){ // on arrête quand l'option 3 est choisie
afficherMenu(menuPrincipal);
if(choix >0){ // si la conversion s'est bien passée
std::cout<<"Vous avez choisi l'option "<<choix<<".";
/* il faut choisir ce qui est fait: */
case 1:
std::cout<<"\n\n";
foo(); // vu que la fonction existe, autant l'utiliser
break;
case 2:
std::cout<<"\n\n";
about(); // fonction à développer toi-même
break;
case 3 :
std::cout<<"\n\n";
/* il faudra sans doute s'assurer qu'il n'est pas utile de
* sauvegarder les modifications ici
*/
break;
default:
/* toutes les valeurs différentes de 1, 2 et 3 passent par ici */
std::cout<<" Cette option est invalide !!!\n"
<<"Veuillez vous concentrer sur ce que vous faites\n\n";
}
} |
et la fonction foo (vu que c'est le nom, très mal choisi, que j'ai utilisé à la base) prendrait une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| void foo(){
std::vector<std::string> const gestionEtudiants={{"Gestion des etudiants"},
{"Afficher la liste"},
{"Chercher"},
{"Ajouter"},
{"Supprimer"},
{"Charger"},
{"Sauvegarder"},
{"Menu Principal"}};
int choix{0};
while(choix !=gestionEtudiants.size()-1){ // retourne au menu principal quand l'option 7 est choisie
afficherMenu(gestionEtudiants);
if(choix >0){ // si la conversion s'est bien passée
std::cout<<"Vous avez choisi l'option "<<choix<<".";
/* il faut choisir ce qui est fait: */
case 1:
std::cout<<"\n\n";
afficherListe(); // (*)
break;
case 2:
std::cout<<"\n\n";
chercherEtudiant();
break;
case 3 :
std::cout<<"\n\n";
ajouterEtudiant(); // (*)
break;
case 4 :
std::cout<<"\n\n";
supprimerEtudiant(); // (*)
break;
case 5:
std::cout<<"\n\n";
chargerListe(); // (*)
break;
case 6 :
std::cout<<"\n\n";
sauvegarderListe(); // (*)
break;
case 7 :
std::cout<<"\n\n";
/* rien à faire, a priori */
break;
default:
/* toutes les valeurs différentes de 1, 2 et 3 passent par ici */
std::cout<<" Cette option est invalide !!!\n"
<<"Veuillez vous concentrer sur ce que vous faites\n\n";
}else{
std;;cout<<"Veuillez vous concentrer sur ce que vous faites\n\n"
}
}
} |
(*) Toutes ces fonctions devront être développées par toi-même, car ce ne sont que des exemples ici 
Une fois que tout cela sera fait, l'exécution de ton programme devrait pouvoir ressembler à quelque chose comme ceci
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| a.exe
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?
Une entree vide n'est pas admise
Veuillez vous concentrer sur ce que vous faites
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?3.141592
Veuillez introduire une valeur numerique entiere uniquement!
Veuillez vous concentrer sur ce que vous faites
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?hello
Seules les valeurs numeriques sont admises
Veuillez vous concentrer sur ce que vous faites
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?1
Vous avez choisi l'option 1.
Gestion des etudiants
=====================
1- Afficher la liste
2- Chercher
3- Ajouter
4- Supprimer
5- Charger
6- Sauvegarder
7- Menu Principal
Votre Choix (1 -7)?9
Vous avez choisi l'option 9. Cette option est invalide !!!
Veuillez vous concentrer sur ce que vous faites
Gestion des etudiants
=====================
1- Afficher la liste
2- Chercher
3- Ajouter
4- Supprimer
5- Charger
6- Sauvegarder
7- Menu Principal
Votre Choix (1 -7)?3
Vous avez choisi l'option 3.
Gestion des etudiants
=====================
1- Afficher la liste
2- Chercher
3- Ajouter
4- Supprimer
5- Charger
6- Sauvegarder
7- Menu Principal
Votre Choix (1 -7)?7
Vous avez choisi l'option 7.
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?5
Vous avez choisi l'option 5. Cette option est invalide !!!
Veuillez vous concentrer sur ce que vous faites
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?4
Vous avez choisi l'option 4. Cette option est invalide !!!
Veuillez vous concentrer sur ce que vous faites
Menu principal
==============
1- Gestion des etudiants
2- A propos
3- Quitter
Votre Choix (1 -3)?3
Vous avez choisi l'option 3. |
(tu remarqueras que ton programme engueule systématiquement l'utilisateur lorsqu'il fait une erreur, et lui indique quelle erreur il a commise
Partager