II. Premier pas▲
II-A. Ce qu'il faut savoir▲
Lors de la compilation avec gcc, il faut spécifier que vous utilisez la bibliothèque Ncurses et pour cela il vous faut rajouter l'option lncurses.
gcc -lncurses -o HelloWorld HelloWorld.c
Il se peut que dans certains cas (et surtout au début) que vous ne quittiez pas proprement votre interface Ncurses et lors de votre retour en mode console vous ne verrez plus ce que vous tapez. De même lorsque vous essayerez de retourner à la ligne, cela décalera les lignes et ce ne sera plus du tout gérable. Pour cela je vous propose une petite astuce. Créer un fichier nommé sos, lequel vous restaurera les paramètres d'origine de la console. Il suffit d'y mettre :
#!/bin/sh
stty -raw # Réutilise le mode RAW pour l'interception des signaux et autres
stty echo # Remise en place de l'echo
stty onlcr # Remise en place du retour chariot
Suffit de rendre ce script exécutable via :
chmod +x sos
Ainsi vous n'aurez plus qu'a taper sos dans votre console pour effacer les effets dûs à de mauvaises manipulations. Il est nettement plus simple de taper sos à l'aveuglette que toute la commande en une seule fois. Cela évite aussi d'avoir à ouvrir une nouvelle console pour restaurer les paramètres par défaut.
II-B. Première fenêtre : "Hello world"▲
#include <ncurses.h>
int
main
(
void
)
{
initscr
(
); // Initialise la structure WINDOW et autres paramètres
printw
(
"
Hello World
"
); // Écrit Hello World à l'endroit où le curseur logique est positionné
refresh
(
); // Rafraîchit la fenêtre courante afin de voir le message apparaître
getch
(
); // On attend que l'utilisateur appui sur une touche pour quitter
endwin
(
); // Restaure les paramètres par défaut du terminal
return
0
;
}
En incluant la bibliothèque ncurses.h, nous n'avons plus besoin d'inclure la bibliothèque stdio.h car celle ci est inclue implicitement dans ncurses.h
II-C. Se positionner dans la fenêtre▲
Pour se positionner dans la fenêtre courante, rien de plus simple, il suffit d'utiliser la fonction move pour déplacer le curseur à l'endroit voulu et ainsi lire un texte saisi au clavier ou bien écrire tout simplement. Ainsi pour déplacer le curseur au centre de la fenêtre, on aura un code du style :
#include <ncurses.h>
int
main
(
void
) {
initscr
(
);
move
(
LINES -
1
, COLS -
1
); // Déplace le curseur tout en bas à droite de l'écran
addch
(
'
.
'
); // Écrit le caractère . au nouvel emplacement
/**
est équivalent à : *
*/
//mvaddch(LINES - 1, COLS - 1, '.');
/**
ou encore à : *
*/
//mvprintw(LINES - 1, COLS - 1, ".");
getch
(
);
endwin
(
);
return
0
;
}
Les variables LINES et COLS sont des variables représentant le nombre de lignes et colonnes du terminal actuel. Après redimensionnement du terminal, ces deux variables sont mises à jour. Faites en donc bon usage.
Il existe la fonction mvFonction pour plusieurs fonctions, comme par exemple, mvaddstr, etc. Reportez vous aux pages man correspondantes.
II-D. Écrire en utilisant les mises en forme▲
Un des avantages de Ncurses et que vous pouvez utiliser les mises en formes pour mettre en valeur certaines parties de votre code. Et il est très simple de mettre tout cela en oeuvre.
Voici donc la liste des mises en forme utilisable :
- Normal (A_NORMAL)
- Meilleur surlignement (A_STANDOUT)
- Inversion vidéo (A_REVERSE)
- À moitié brillant (A_DIM)
- Très brillant ou en gras (A_BOLD)
- Souligné (A_UNDERLINE)
- Mode invisible ou blanc (A_INVIS)
Et d'autres encore dont je ne parlerais pas ici. La fonction attron permet d'appliquer les mises en forme passées en paramètre et attroff permet d'annuler la mise en forme passée en paramètre. Le texte que l'on veut mettre en forme doit donc se situer après la balise attron. Petite précision, l'attribut A_NORMAL permet d'annuler toutes les mises en forme appliquées. Voici un bout de code suffisamment explicite pour vous montrer le résultat des différentes mises en forme possible (liste non exhaustive bien sûr) :
#include <ncurses.h>
int
main
(
void
)
{
initscr
(
);
attron
(
A_NORMAL);
printw
(
"
Texte sans mise en forme
\n
"
);
attron
(
A_STANDOUT);
printw
(
"
Texte en meilleur surlignement
\n
"
);
attroff
(
A_STANDOUT);
attron
(
A_REVERSE);
printw
(
"
Texte en inversion video
\n
"
);
attroff
(
A_REVERSE);
attron
(
A_DIM);
printw
(
"
Texte a moitie brillant
\n
"
);
attroff
(
A_DIM);
attron
(
A_BOLD);
printw
(
"
Texte en gras
\n
"
);
attroff
(
A_BOLD);
attron
(
A_UNDERLINE);
printw
(
"
Texte en souligne
\n
"
);
attroff
(
A_UNDERLINE);
attron
(
A_INVIS);
printw
(
"
Texte invisible
\n
"
);
attroff
(
A_INVIS);
attron
(
A_UNDERLINE |
A_BOLD); // Pour appliquer plusieurs type de mises en forme, on utilise l'opérateur unaire |
printw
(
"
Texte en gras souligne
\n
"
);
attron
(
A_NORMAL);
refresh
(
);
getch
(
);
endwin
(
);
return
0
;
}
Si vous désirez utiliser une mise en forme commune pour chaque fenêtre et sous-fenêtre que vous créer (par exemple écrire en gras), plutôt que d'utiliser attron à chaque fois que vous voulez écrire, vous pouvez utiliser la fonction attrset avec votre liste d'attribut. Ainsi, n'importe qu'elle fenêtre que vous créerez héritera de cet attribut et donc chaque fois que vous écrirez dedans, ça sera automatiquement mis en gras.
II-E. Lire une chaîne de caractères à partir du clavier▲
Pour rendre vos applications plus interactives et donc non statique, il peut être intéressant de demander à l'utilisateur d'entrer une chaîne de caractères (lui demander son âge ou que sais-je encore). Bien évidemment, il existe des fonctions vous permettant de lire des chaînes de caractères d'une seule traite sans avoir à passer par la méthode getch utilisée jusqu'à présent.
Cette méthode se nomme getstr et permet donc de lire une chaîne entière de caractères. Voyons maintenant comment s'en servir.
II-F. Créer plusieurs fenêtres▲
Dans les programmes un peu plus évolués, il sera sans doute utile voir indispensable de diviser la fenêtre courante en plusieurs sous fenêtre afin de mieux pouvoir les gérer et mieux organiser son prgramme. Cela allègera votre code et le rendra plus lisible, donc plus maintenable.
Vous pouvez faire une sous-fenêtre pour un menu par exemple, une autre que vous utiliserez pour affichez du texte et une dernière que vous utiliserez pour permettre à l'utilisateur de saisir une chaîne au clavier. Bien sûr vous pourrez rediviser ces dernières en autant de sous-fenêtres que vous voudrez.
La fonction subwin vous permet de faire cela de manière aisée. En effet, il suffit juste de dire quelle est la fenêtre à divisée ainsi que les dimensions voulues. Une fois fait, une nouvelle sous-fenêtre vous sera donc retournée (de type WINDOW *).
Un petit exemple simpliste divisant la fenêtre de base en deux sous-fenêtres :
#include <ncurses.h>
int
main
(
void
) {
WINDOW *
haut, *
bas;
initscr
(
);
haut=
subwin
(
stdscr, LINES /
2
, COLS, 0
, 0
); // Créé une fenêtre de 'LINES / 2' lignes et de COLS colonnes en 0, 0
bas=
subwin
(
stdscr, LINES /
2
, COLS, LINES /
2
, 0
); // Créé la même fenêtre que ci-dessus sauf que les coordonnées changent
box
(
haut, ACS_VLINE, ACS_HLINE);
box
(
bas, ACS_VLINE, ACS_HLINE);
mvwprintw
(
haut, 1
, 1
, "
Ceci est la fenetre du haut
"
);
mvwprintw
(
bas, 1
, 1
, "
Ceci est la fenetre du bas
"
);
wrefresh
(
haut);
wrefresh
(
bas);
getch
(
);
endwin
(
);
free
(
haut);
free
(
bas);
return
0
;
}
Ne vous attardez pas sur la fonction box, elle sera détaillée juste après. Je l'ai juste utilisée pour vous montrer la taille des fenêtres que j'ai créées.
II-G. Créer une bordure autour de la fenêtre▲
Pour créer une jolie bordure autour d'une zone définie, vous pouvez utiliser la fonction box sur une fenêtre (de type WINDOW *), afin d'encadrer et embellir votre interface. Pour cela deux méthodes sont possibles :
La première consiste à créer une "boîte" avec les bordures par défaut (que l'on peut choisir parmi plusieurs types de bordures prédéfinies).
La seconde consiste à définir soit même quel caractère sera sur la ligne du haut, du bas, dans les coins, etc.
Un exemple de code pour les deux méthodes :
#include <ncurses.h>
int
main
(
void
) {
WINDOW *
boite;
initscr
(
);
boite=
subwin
(
stdscr, 10
, 10
, LINES /
2
, COLS /
2
);
box
(
boite, ACS_VLINE, ACS_HLINE); // ACS_VLINE et ACS_HLINE sont des constantes qui génèrent des bordures par défaut
refresh
(
);
getch
(
);
endwin
(
);
free
(
boite);
return
0
;
}
Reportez vous aux pages man pour voir les différentes bordures disponibles (comme ACS_VLINE et ACS_HLINE par exemple).
#include <ncurses.h>
int
main
(
void
) {
WINDOW *
boite;
initscr
(
);
boite=
subwin
(
stdscr, 10
, 10
, LINES /
2
, COLS /
2
);
wborder
(
boite, '
|
'
, '
|
'
, '
-
'
, '
-
'
, '
+
'
, '
+
'
, '
+
'
, '
+
'
);
wrefresh
(
boite);
getch
(
);
endwin
(
);
free
(
boite);
return
0
;
}
Dans la méthode wborder, les deux premiers arguments après le pointeur de WINDOW que l'on passe en paramètre représentent respectivement les côtés gauche et droite, les deux suivants les côtés haut et bas et enfin les quatre derniers représentent les quatre coins de la bordure (haut gauche, haut droit, bas gauche, bas droit).
II-H. Centrer le texte sur le terminal▲
Pour centrer un texte sur le terminal ou une fenêtre donnée, nous allons nous servir des variables LINES et COLS générées par Ncurses. Ainsi, même si nous redimensionnons une fenêtre, le texte sera toujours centré. Attention cependant, lorsque vous redimensionner le terminal, c'est comme si une touche du clavier était appuyé.
Exemple :
#include <ncurses.h>
int
main
(
void
) {
WINDOW *
boite;
initscr
(
);
printw
(
"
Le terminal actuel comporte %d lignes et %d colonnes
\n
"
, LINES, COLS);
refresh
(
);
getch
(
);
endwin
(
);
free
(
boite);
return
0
;
}
Lorsque vous exécutez ce code et que vous tentez de redimensionner votre terminal, l'application s'arrête instantanément. Pour pallier à ce problème, nous utiliserons une boucle. Le code devient donc :
#include <ncurses.h>
int
main
(
void
) {
WINDOW *
boite;
initscr
(
);
while
(
1
) {
printw
(
"
Le terminal actuel comporte %d lignes et %d colonnes
\n
"
, LINES, COLS);
refresh
(
); // Rafraîchit la fenêtre par défaut (stdscr) afin d'afficher le message
if
(
getch
(
) !=
410
) // 410 est le code de la touche générée lorsqu'on redimensionne le terminal
break
;
}
endwin
(
);
free
(
boite);
return
0
;
}
Vous pouvez donc constater que lors du redimensionnement de la fenêtre, les variables LINES et COLS sont bien mises à jour lors de chaque évènement.
Néanmoins, je vous vois déjà vous demander pourquoi je vous dis ça. En réalité, selon l'utilisateur, la taille de la console ne sera pas là même, donc plutôt que de donner des nombres fixes pour le positionnement, vous pouvez donner des positions relatives à vos composants par rapport au terminal et donc, quelque soit la taille du terminal, le rendu final sera le même.
Maintenant venons au fait, pour centrer un texte, il suffit de partir du centre de la fenêtre, auquel on enlève la moitié de la longueur de notre texte.
Ce qui donne :
#include <ncurses.h>
#include <string.h>
int
main
(
void
) {
WINDOW *
boite;
char
*
msg=
"
Texte au centre
"
;
int
taille=
strlen
(
msg);
initscr
(
);
while
(
1
) {
clear
(
); // Efface la fenêtre (donc l'ancien message)
mvprintw
(
LINES/
2
, (
COLS /
2
) -
(
taille /
2
), msg);
refresh
(
);
if
(
getch
(
) !=
410
)
break
;
}
endwin
(
);
free
(
boite);
return
0
;
}
Voici donc comment centrer un texte et qui le restera toujours même après un redimensionnement du terminal. Bien évidemment, il en va de même pour centrer une fenêtre ou tout autre composant.