Les bases du Ncurses/Ruby
Sommaire :
- Introduction.
- Oû trouver le nécessaire ?
- I) Initialiser et configurer Ncurses.
- II) Créer une fenêtre avec Ncurses
- III) Colorer les fenêtres.
- IV) Ecrire dans notre interface.
- V) Enjoliver son interface.
- VI) Afficher/refroidir les fenêtres créées.
- VII) Faire perdurer l'affichage de l'interface et gérer son fonctionnement.
- VIII) Supprimer une fenêtre.
- IX) Quitter Ncurses dans le programme.
- X) Quelques trucs et astuces pour bien construire son interface.
- Les liens
- Quelques exemples ...
- À propos de la documentation.
Introduction
Alors d'abord qu'est-ce que Ncurses ?
Ncurses est une librairie qui permet de créer des interfaces utilisable en mode console.
Cette librairie est supportée par tout systéme de type UNIX conforme à la norme ANSI/POSIX.
Pourquoi apprendre Ncurses ?
Le principal atout d'une interface programmée en curses c'est
qu'elle pourra être lancé n'importe oû, elle pourra aussi bien être
lancée en mode console qu'en mode X par le biais d'un terminal. Cet
atout distingue les librairies curses des librairies dites graphiques
telles que gtk ou encore qt qui ne permettent pas de créer des
interfaces utilisable en mode console pure. Cette qualité permet
aux utilitaires programmés avec une interface curses d'être
utilisable dans un environement restreint post ou pre-installation et démunit de X
par exemple. Apprendre à utiliser Ncurses permet donc de créer des
utilitaires au plus proche du systéme tout en utilisant la souplesse d'une
interface. Ncurses est la solution de réference pour programmer en
curses c'est pourquoi le tutorial traite sur son utilisation.
Pourquoi utiliser Ruby avec Ncurses ?
Grâce au binding Ncurses-Ruby le langage Ruby supporte trés bien Ncurses.
De plus les caractéristiques de ce langage telle que la programmation objet, la
simplicité ou encore la clarté de son écriture font de ce langage le parfait
allié pour écrire une interface curses réussi. Si vous ne connaissez
pas le langage Ruby vous pouvez trouvez des documentations dans la
section lien et "Ruby". Si vous désirez utiliser Ncurses avec un autre
langage que Ruby reportez-vous à la section lien et "autres langages".
En quoi différe l'utilisation de Ncurses avec Ruby ?
L'utilisation de Ncurses avec Ruby différe en trés peu de points de l'utilisation
de Ncurses avec le language C. Mis à part les quelques différences d'utilisation de certaines
fonctions (telle que stdscr = initscr et initscr(), getx/gety et getyx(), getbegx/getbegy et getbegyx(), win = window.new et
win = subwin() et quelques autres...) Ncurses s'utilise globalement de la même façon qu'en C.
À la difference du C en Ruby lorsque l'on appel des fonctions Ncurses on appel les fonctions Ncurses du module
Ncurses alors qu'en C on appel les fonctions Ncurses comme des fonctions indépendantes, exemple :
En C:
initpair(1,COLOR_GREEN,COLOR_BLACK);
En Ruby :
Ncurses.initpair(1,COLOR_GREEN,COLOR_BLACK);
Quel est le but de cette documentation ?
Cette documentation a pour but d'introduction à Ncurses avec le langage Ruby, elle
ne réference pas toutes les fonctions Ncurses ni n'explique tous les
rouages de cette librairie. Si après la lecture de cette introduction vous souhaitez
accéder à toutes les informations concernant Ncurses afin de pofiner vos connaissances sur le sujet vous
pouvez accéder à une trés bonne documentation de Ncurses avec le langage C (en anglais) dans la section lien
puis "autres langages". Comme l'utilisation de Ncurses avec le langage Ruby est proche de l'utilisation de Ncurses
avec le C vous n'aurez pas de mal à utiliser les informations contenus dans la documentation en anglais
disponible section lien et "autres langages".
Oû trouver le nécessaire ?
Nous avons besoin de Ruby, si celui-ci n'est pas déja présent
sur votre machine vous pouvez le télécharger ici :
http://www.ruby-lang.org/
Nous avons besoin des librairies Ncurses si vous ne disposez pas
des librairies Ncurses sur votre machine téléchargez les ici :
http://ftp.gnu.org/pub/gnu/ncurses/
Et enfin nous avons besoin du binding Ncurses-Ruby qui est
disponible à l'adresse suivante :
http://ncurses-ruby.berlios.de
I) Initialiser et configurer Ncurses.
Avant de pouvoir utiliser les libraires Ncurses il faut d'abord initialiser son utilisation
dans le programme ainsi que configurer les principales caractéristiques de l'interface.
Une fois Ncurses initialisé et ses principales caractéristiques configurées nous devrons
initialiser les "paires de couleurs".
1) Initialisation de la librairie Ncurses.
L'initialisation de Ncurses dans le programme se fait en utilisant la
fonction initscr du module Ncurses qui renvoie comme valeur les caractéristiques de
la fenêtre mére (stdscr). Dans toute la documentation la fenêtre mére sera nommée stdscr.
Son utilisation s'écrit comme cela :
stdscr = Ncurses.initscr;
2) Configurer les principales caractéristiques de l'interface.
Une fois Ncurses initialisé dans le programme nous pouvons configurer les principales caractéristiques
de la fenêtre mére et des fenêtres filles. Il nous sera possible d'activer/désactiver certaines caractéristiques
telle que l'affichage du curseur, l'echo du clavier ou encore l'utilisation du keypad. Ces étapes ne sont pas
obligatoires.
a) Désactiver/re-activer l'affichage du curseur.
Pour afficher ou ne pas afficher le curseur dans l'interface il nous suffit d'utiliser la fonction curs_set du
module Ncurses. Pour ne pas afficher le curseur il suffit de passer comme argument une valeur null.
Et par la suite si nous souhaitons que l'affichage du curseur soit à nouveau activé il suffit de passer comme
argument à la fonction Ncurses.curs_set une valeur non-null.
Par exemple si nous souhaitons désactiver l'affichage du curseur nous utiliserons :
Ncurses.curs_set(0);
Et si par la suite nous souhaitons re-activer l'affichage du curseur nous taperons :
Ncurses.curs_set(1);
NOTE: Activer le curseur en utilisant Ncurses.curs_set(1) est utile uniquement lorsque
l'affichage du curseur a été désactivé précédemenent et que l'on souhaite le réactiver,
étant donné que l'affichage du curseur est activé par défaut.
b) Désactiver/re-activer l'echo du clavier.
Par défaut lorsque l'on utilise le clavier il y a un echo des lettres tapées sur l'interface.
Cet echo peut devenir génant lorsque l'interface ou les widgets qui la compose ne nécessitent pas
d'affichage d'entrées de caractéres. Pour palier à ce probléme il suffit simplement d'utiliser la
fonction noecho du module Ncurses :
Ncurses.noecho;
Si par la suite vous souhaitez re-activer l'echo du clavier dans l'interface il vous suffit de taper :
Ncurses.echo;
NOTE: Désactiver l'echo du clavier n'a aucune incidence sur les fonctions permettant à l'utilisateur d'entrer
des chaînes de caratéres.
c) Activer/re-désactiver le keypad.
Lorsque l'on active le keypad on active la prise en charge par l'interface de touches
telles que ESC (ou echap), F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, les flêches
directionelles, les touches crtl et les touches alt. En quoi cela peut-il nous être utile ?
Si par exemple vous souhaitez que l'utilisateur puisse quitter votre interface en tapant sur echap,
par exemple, vous aurez besoin d'activer le keypad afin que l'appuie de la touche echap soit
"entendu" par votre interface.
Pour activer/désactiver le keypad il faut appeler la fonction keypad du module Ncurses.
La fonction Ncurses.keypad demande deux arguments : elle demande comme argument
la fenêtre mére utilisée et elle demande comme second argument TRUE ou FALSE.
Si vous souhaitez activer le keypad il vous suffit de taper :
Ncurses.keypad(stdscr,TRUE);
Autrement si par la suite vous souhaitez re-désactiver le keypad il vous faut taper :
Ncurses.keypad(stdscr,FALSE);
d) Désactiver/re-activer le "line buffering".
Alors d'abord qu'est-que le "line buffering" ? Lorsque le "line buffering" est activé le buffer s'attend à recevoir
une ligne de plusieurs code ASCII représentant les touches tapées. Or lorsque l'on souhaite que l'utilisteur puisse
piloter l'interface en appuiant sur des touches particuliéres du clavier nous avons besoin de récuperer un unique
code ASCII. C'est la fonction getch qui va nous permettre de récuperer ce code ASCII, nous l'étudierons plus tard
dans la documentation.
Pour désactiver le "line buffering" nous pouvons utiliser les fonctions cbreak ou raw :
Ncurses.cbreak;
Ncurses.raw;
Alors qu'elles sont les différences entre ces deux types de fonctions ? La fonction cbreak laisse passer
les insctructions (CTRL+Z) et (CRTL+C) alors que la fonction raw traite ces appuies de touches comme les autres.
Si par la suite vous souhaitez re-activer le "line buffering" il vous suffit d'utiliser une de ces deux fonctions :
Si vous avez appelé auparavant la fonction cbreak :
Ncurses.nocbreak;
Si vous avez appelé auparavant la fonction raw :
Ncurses.noraw;
3) Créer les paires de couleurs.
Avant de créer les paires de couleurs nous devons lancer la prise en charge des couleurs par Ncurses en lançant
la fonction start_color du module Ncurses :
Ncurses.start_color;
Afin de colorer notre interface nous devons d'abord initialiser les paires de couleurs. Une paire de couleur
est constituée d'une couleur pour le fond (background) et d'une couleur pour le texte (foreground).
Ainsi lorsque nous voudrons qu'une fenêtre soit bleu et que le texte soit noir nous appelerons la
paire de couleur correspondante.
Ncurses peut gérer 8 couleurs differentes :
COLOR_BLUE
COLOR_RED
COLOR_CYAN
COLOR_YELLOW
COLOR_MAGENTA
COLOR_GREEN
COLOR_BLACK
COLOR_WHITE
C'est avec ces 8 couleurs que nous allons créer nos paires de couleurs pour colorer nos fenêtres et nos textes.
Pour créer une paire de couleur il faut appeler la fonction init_pair du module Ncurses.
Celle-ci s'utilise comme cela :
Ncurses.init_pair(id_de_la_paire, couleur_du_texte, couleur_du_fond);
Voici un exemple d'utilisation :
Ncurses.init_pair(1,COLOR_BLACK,COLOR_CYAN);
Ci-dessus id_de_la_paire correspond à un nombre identifiant la paire de couleur. C'est avec ce nombre la
que l'on va identifier la paire de couleur par la suite. Les deux valeurs couleur_du_texte et couleur_du_fond
correspondent quant à elles aux 8 couleurs proposées ci-dessus.
II) Créer une fenêtre avec Ncurses
Lorsqu'on utilise les librairies Ncurses avec Ruby cette étape ce
retrouve simplifié par rapport au C/Ncurses.
En effet en C/Ncurses pour créer une fenêtre il faut écrire ceci:
WINDOW la_fenetre;
la_fenetre = subwin(stdscr,y,x,begin_y,begin_x);
Alors qu'avec le Ruby/Ncurses il suffit simplement d'écrire ceci :
la_fenetre = WINDOW.new(y,x,begin_y,begin_x);
Avant de vous en expliquer un peu plus je tiens à vous informer
sur la maniére dont Ncurses gére ses coordonées. En effet, contrairement
en mathématique, les valeurs y ne croissent pas de bas en haut mais
bien de haut en bas. De plus on n'écrit pas les valeurs x avant les
y mais bien les valeurs y avant les valeurs x lorsqu'on appel une fonction
nécessitant des coordonnées.
Pour créer une fenêtre en Ruby/Ncurses il suffit de procéder ainsi:
la_fenetre = WINDOW.new(y,x,begin_y,begin_x);
Maintenant je vais vous expliquer à quoi correspond les quatres valeurs begin_y, begin_x, y et x pour les fenêtres.
La valeur begin_y correspond à la valeur verticale de commencement de la fenêtre (en commençant par le haut).
Si begin_y est égal à 4 la fenêtre se placera ainsi :
1 |
2 |
3 v
4 ------------------------------
La valeur begin_x correspond quant à elle à la valeur horizontale de commencement de la fenêtre
(en commençant par la gauche).
Si begin_x est égal à 6 la fenêtre se placera ainsi :
|
|
- - - - - - >|
|
|
1 2 3 4 5 6
La valeur y correspond à la hauteur de la fenêtre.
Si y est égal à 10 et begin_y à 4 sur une hauteur totale de 20, par exemple, alors la fenêtre se situera ainsi :
1 |
2 | 4
3 v
4-------------------------------
5 ^
6 |
7 |
8 |
9 | 10
10 |
11 |
12 |
13 v
14------------------------------
15
16
17
18
19
20
La valeur x correspond à la largeur de la fenêtre.
Si x est égal à 20 et si begin_x est égal à 5 sur une largeur totale de 30 alors la fenêtre se situera ainsi :
| |
5 | 20 |
- - - - > |<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >|
| |
| |
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
Et enfin si begin_y est égal à 4, y est égal à 10, begin_x est égal à 5 et x est égal à 20 sur
une hauteur totale de 20 et une largeur totale de 30 alors la fenêtre se dessinera ainsi :
1 |
2 | 4
3 v
4 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
5 | ^ |
6 | | |
7 | | 10 |
8 5 | | 20 |
9 - - - - - > |< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > |
10 | | |
11 | | |
12 | | |
13 | v |
14 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
15
16
17
18
19
20 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
III) Colorer les fenêtres.
1) Initialiser une paire de couleur à une fenêtre.
Afin de colorer les fenêtres nous devons utiliser la fonction bkgd.
La fonction bkgd s'utilise de la maniére suivante :
fenetre_a_colorer.bkgd(Ncurses.COLOR_PAIR(id_de_la_paire));
Ici id_de_la_paire est le nombre correspondant à la paire de couleur souhaitée pour la coloration.
La fonction COLOR_PAIR du module Ncurses permet à la fonction bkgd de colorer la fenêtre fenetre_a_colorer avec
la paire de couleur correspondante à l'id donné.
NOTE: Si vous souhaitez colorer la fenêtre principale vous devez utiliser la fonction bkgd
de la façon suivante :
stdscr.bkgd(Ncurses.COLOR_PAIR(id_de_la_paire));
2) Changer la paire de couleur d'une fenêtre temporairement.
Dans la suite des sections nous apprenderons à écrire des textes dans nos fenêtres.
Mais comment dois-t-on procéder si l'on souhaite changer la couleur du texte momentanément
afin de mettre en valeur un passage de celui-ci ?
Tout d'abord nous devons créer une autre paire de couleur (voir section I 3).
Cette autre paire de couleur sera utilisée pour le changement momentané de couleur.
Ensuite nous devons utilisés les deux fonctions attron et attroff sui s'utilisent ainsi :
fenetre_a_modifier_temporairement.attron(Ncurses.COLOR_PAIR(id_de_la_paire_utilise_momentanement));
fenetre_a_modifier_temporairement.attroff(Ncurses.COLOR_PAIR(id_de_la_paire_originel));
La fonction attron nous permet de changer la couleur de la fenêtre concernée en utilisant la nouvelle paire
de couleur et la fonction attroff nous permet de désactiver la paire de couleur temporaire et de ré-activer la paire
de couleur originel.
NOTE: Le texte qui doit subir la modification de couleur doit être écrit après l'usage de attron et avant l'usage
de attoff.
IV) Ecrire dans notre interface.
Pour prevenir l'utilisateur ou le questionner il peut être utile de pouvoir écrire dans notre interface
c'est ce que nous allons étudier dans cette section.
Afin d'écrire dans l'une de nos fenêtres nous avons plusieurs types de fonctions à notre disposition :
les fonctions de type addstr et les fonctions de type printw.
1) Les fonctions de type addstr.
Il existe plusieurs fonctions de type addstr.
Parmi ces fonctions nous allons étudier les plus courantes telle que :
- la fonction Ncurses.addstr,
- la fonction Ncurses.waddstr,
- la fonction Ncurses.addnstr,
- la fonction Ncurses.waddnstr,
- la fonction Ncurses.mvaddstr,
- et la fonction Ncurses.mvwaddstr.
a) La fonction Ncurses.addstr.
La fonction addstr nous permet d'écrire un texte quelconque sur la fenêtre mére.
Ce texte commencera en haut à l'extremité gauche de la fenêtre.
La fonction addstr appartient au module Ncurses et s'utilise ainsi :
Ncurses.addstr("mon_text");
b) La fonction Ncurses.waddstr.
La fonction waddstr permet, contrairement à la fonction addstr, d'écrire un
texte quelconque sur une fenêtre fille. Le texte écrit commençera aussi en haut
et à l'extreminté gauche de la fenêtre.
La fonction waddstr appartient au module Ncurses et s'utilise ainsi :
Ncurses.waddstr(fenetre_fille,"mon_text");
c) La fonction Ncurses.addnstr.
La fonction addnstr a exactement le même comportement que la fonction
addstr (voir a) mis à part le fait que le nombre de caratéres affichés est limité
par une valeur de son choix.
La fonction addnstr du module Ncurses s'utilise ainsi :
Ncurses.addnstr("mon_text",n);
Ici n est le nombre de caractére de la chaine "mon_text" que la fonction addnstr
affichera.
Voici un exemple concret :
Ncurses.addnstr("salut comment ça va ?",5);
Ci-dessus la fonction affichera "salut".
d) La fonction Ncurses.waddnstr.
La fonction waddnstr a ici exactement le même comportement que celui de la fonction
addnstr. La seule difference est que la fonction waddnstr permet d'écrire dans des fenêtres filles.
La fonction waddnstr appartient au module Ncurses et s'utilise ainsi :
Ncurses.waddnstr(fenetre_fille,"mon_text",n);
e) La fonction Ncurses.mvaddstr.
La fonction addstr a pour principale faiblesse son incapacité à écrire un texte
à un endroit précis et voulut. C'est pourquoi la fonction mvaddstr a été créée !
Avec cette fonction nous pouvons écrire une texte là oû nous le souhaitons dans
la fenêtre mére.
La fonction mvaddstr appartient au module Ncurses et s'utilise ainsi :
Ncurses.mvaddstr(y,x,"mon_text");
NOTE: Attention contrairement en mathématique on donne les valeurs de y avant
les valeurs de x avec Ncurses.
f) La fonction Ncurses.mvwaddstr.
La fonction mvwaddstr se comportement exactement comme la fonction mvaddstr
à la seule difference qu'avec cette fonction nous pouvons écrire oû nous souhaitons
sur une fenêtre fille.
La fonction mvwaddstr appartient au module Ncurses et s'utilise ainsi :
Ncurses.mvwaddstr(fenetre_fille,y,x,"mon_text");
2) Les fonctions de type printw.
Les fonctions de type printw se distinguent des fonctions de type
addstr par leur capacité à gérer plusieurs types de données.
En effet avec les fonctions de type addstr on ne peut afficher que des chaines de caratéres.
Avec les fonctions de types printw on peut afficher des chaines de caratéres, des entiers, des
nombres à virgules etc ....
Là aussi il existe plusieurs fonctions de type printw.
Nous allons étudier les plus connues telle que :
- la fonction Ncurses.printw,
- la fonction Ncurses.wprintw,
- la fonction Ncurses.mvprintw,
- et la fonction Ncurses.mvwprintw.
a) La fonction Ncurses.printw.
La fonction printw permet d'afficher n'importe quel type de donnée dans la fenêtre mére.
Cette fonction appartient au module Ncurses est s'utilise ainsi :
Ncurses.printw("chaîne_de_contrôle",donnees);
Exactement comme en C c'est par le biais de la chaîne de contrôle que l'on gére l'affichage
des données par type. Il existe plusieurs élements de contrôle pouvant constituer la
chaîne de contrôle parmi :
- l'élement de contrôle %d pour les décimales et les entiers,
- l'élement de contrôle %s pour les chaînes de caratéres,
- l'élement de contrôle %c pour les caratéres simples,
- l'élement de contrôle %f pour les virgules flotantes etc ....
Voici plusieurs exemples concrets d'utilisation de Ncurses.printw :
Ncurses.printw("%d",1);
Ncurses.printw("%s","salut à toi");
Ncurses.printw("%c",'y');
Ncurses.printw("%f",0.12132133);
Dans la même chaîne de contrôle il est tout à fait possible d'utiliser plusieurs élements de
contrôle par exemple :
Ncurses.printw("%s : %d","Aujourd'hui nous sommes le",16);
Ce qui nous donnera : "Aujourd'hui nous comme le : 16".
b) La fonction Ncurses.wprintw.
Le comportement de wprintw est strictement identique à celui de la fonction printw (voir a)
mis à part le fait que wprintw permet d'écrire dans les fenêtres filles.
La fonction wprintw appartient au module Ncurses est s'utilise ainsi :
Ncurses.wprintw(fenetre_fille,"chaîne_de_contrôle",donnees);
c) La fonction Ncurses.mvprintw.
Là aussi concernant le traitement des types de données (voir a) le comportement de la fonction mvprintw est
identique à celui de la fonction printw. Cette fonction se distingue par le fait qu'elle permet d'afficher des
données n'importe oû dans la fenêtre mére.
La fonction mvprintw appartient au module Ncurses et s'utilise ainsi :
Ncurses.mvprintw(y,x,"chaîne_de_contrôle",donnees);
d) La fonction Ncurses.mvwprintw.
L'usage de cette fonction est analogue à celui de la fonction mvprintw exepté le fait
que cette fonction permet d'afficher des données n'importe oû dans les fenêtres filles et
non uniquement dans la fenêtre mére.
La fonction mvwprintw appartient au module Ncurses et s'utilise ainsi :
Ncurses.mvwprintw(fenetre_fille,y,x,"chaîne_de_contrôle",donnees);
V) Enjoliver son interface.
1) Rajouter un effet d'ombre aux fenêtres.
Si vous desirez donner plus de perspective à vos interfaces
vous pouvez affecter un effet d'ombre à vos fenêtres.
Pour cela il suffit de créer une fenêtre supplémentaire
à chaque fenêtre auquel vous voulez rajouter cet effet.
Cette fenêtre supplémentaire doit :
- conserver la même taille que la fenêtre auquel vous voulez rajouter
l'effet,
- avoir une couleur de fond noir (voir section I et III),
- être legerement décallé par rapport à la fenêtre auquel vous
voulez rajouter l'effet.
- être rafraichit avant la fenêtre auquel vous voulez rajouter
l'effet (voir section VI).
Comme il est écrit ci-dessus lors de la création des "fenêtres ombres"
vous devez bien faire attention à ce que les valeurs begin_y et begin_x
soient légerements différentes de celles des fenêtres auquel
vous souhaitez rajouter cet effet (voir section II).
Comme valeur begin_y pour les "fenêtres ombres" je vous conseil
de donner les valeurs begin_y des fenêtres auquelles vous voulez
rajouter l'effet +1. Pour les valeurs begin_x des "fenêtres ombres" je vous
conseil là de donner les valeurs begin_x des fenêtres auquelles vous
souhaitez rajouter l'effet +2.
2) Rajouter un contoure "box" aux fenêtres.
Afin de faire resortir un peu plus nos fenêtres nous pouvons
aussi affecter un effet "box" aux fenêtres que nous avons créées.
Cet effet "box" consiste à créer une pseudo-bordure autoure
des fenêtres. Cette effet "box" s'applique en utilisant la fonction
box du module Ncurses.
Cette fonction s'utilise ainsi :
Ncurses.box(fenetre_fille,bordure_verticale,bordure_horizontale);
Ici bordure_verticale et bordure_horizontale peuvent être
remplacés par :
ACS_VLINE,
ACS_HLINE,
ACS_ULCORNER,
ACS_URCORNER,
ACS_LLCORNER,
ACS_LRCORNER.
Pour un effet de bordure classique je vous conseil d'utiliser la
fonction comme il suit :
Ncurses.box(fenetre_fille,ACS_VLINE,ACS_HLINE);
NOTE: Comme la bordure est créée avec des caratéres nous pouvons trés
facilement changer sa couleur si nous le souhaitons afin que la couleur de la
bordure se distingue bien de la couleur des textes de la fenêtre
(voir section III).
VI) Afficher/refroidir les fenêtres créées.
Pour visualiser les modifications soumisent à l'interface de même que pour voir l'interface il est nécessaire de refroidir celle-ci.
Afin d'afficher ou de refroidir une fenêtre Ncurses nous devons utiliser la fonction refresh qui s'utilise ainsi :
fenetre_a_refroidir.refresh;
Lorsqu'une fenêtre fille a été créée il nous faut refroidir la fenêtre mére avant la
fenêtre fille afin que la fenêtre fille puisse s'afficher.
Pour refroidir la fenêtre mére nous devons taper :
stdscr.refresh;
Pour les actions suivantes il est nécessaire de refroidir la fenêtre mére :
- ajout de fenêtres filles,
- suppressions de fenêtres filles,
- ajouts de textes dans la fenêtre mére,
- modifications de taille de fenêtres filles,
- changement de couleur de la fenêtre mére.
Concernant les fenêtres filles tant que les modifications sont internes à celles-ci et qu'elles n'ont aucune
insidence sur l'exterieur il suffit de les refroidir simplement sans refroidir la fenêtre mére auparavant pour
afficher les modifications.
VII) Faire perdurer l'affichage et gérer le fonctionnement.
Si vous avez construit une interface avec tout ce qui a été dit auparavant et que vous
l'avez essayée vous vous êtes surmement aperçu d'une chose :
à pêne l'interface est lancée qu'elle se ferme.
À cela il existe une solution. Afin de faire perdurer l'affichage et surtout afin
de gérer les actions de l'interface nous devons utiliser une boucle while.
Cette boucle while continuera à boucler tant qu'une touche définit ne sera pas appuiée,
dans l'exemple ci-dessous cette touche sera ECHAP (ou dit ESC).
Si vous ne l'avez pas déja fait vous devez activer le keypad (voir section I).
Afin de verifier à chaque bouclage que la touche ECHAP n'a pas été appuiée nous devons
uiliser la fonction getch. La fonction getch permet de savoir quelle touche est appuiée
par l'utilisateur. Cette fonction s'utilise ainsi :
stdscr.getch;
La fonction getch renvoie la touche appuiée en code ASCII (pour avoir la liste de correspondance
des touches du clavier et des codes ASCII voir section lien et "autre").
Afin que l'interface soit quittée lorsque l'utilisateur tape sur ECHAP nous
allons d'abord déclarer une constante ESC avec comme valeur 27 (ECHAP en code ASCII) puis
nous allons construire la boucle while avec comme condition de s'arreter si la fonction
getch renvoie 27 (donc ESC).
Voici ce que cela donne :
ESC=27;
while stdscr.getch!=ESC
# La gestion de l'interface
end
Comme le commentaire ci-dessus le stipule toute la gestion de l'interface va se passer
dans cette boucle. C'est ici que nous allons décider des réactions de l'interface en
fonction de ce que l'utilisateur souhaite. Si par exemple nous souhaitons qu'une
certaine fenêtre s'affiche lorsque l'utilisateur tape sur F1 nous allons modeliser
la boucle while de la façon suivante :
ESC=27;
key=0;
while key!=ESC
key=stdscr.getch;
if(key==KEY_F1)
message.refresh;
end
end
NOTES: - Il n'y a pas de code ASCII pour les touches F1, F2 etc ... Afin de savoir
si une de ces touches à été appuiée il faut comparer la sortie de stdscr.getch avec
les valeurs KEY_FX prédéfinies.
- Il n'existe pas de code ASCII pour les flêches directionnelles mais il existe ces valeurs prédéfinies :
KEY_LEFT, KEY_RIGHT, KEY_UP et KEY_DOWN.
- Il est préferable de rafréchir la globalité de l'interface avant la boucle while et par la
suite dans la boucle while de rafréchir au fure et à mesure les fenêtres ayant subit des modifications
(voir section VI).
- Dans le programme après la boucle while on touve généralement les fonctions de
suppression de fenêtres et de sortie de Ncurses (voir section VIII et IX).
VIII) Supprimer une fenêtre.
Pour supprimer une fenêtre nous devons utiliser la fonction delwin du
module Ncurses. La fonction delwin prend comme argument la fenêtre à
supprimer. Voici comment s'utilise cette fonction :
Ncurses.delwin(fenetre_a_supprimer);
Si la fenêtre est volontairement supprimée en cours d'exécution du programme nous
pouvons refroidir la fenêtre mére afin de visualiser la modification en tapant :
stdscr.refresh;
Une fois l'ensemble refroidit la fenêtre supprimée n'apparaitrera plus.
NOTE: Il est recommandé de supprimer les fenêtres créées en fin de programme afin
de librérées la mémoire allouée pour celles-ci.
IX) Quitter Ncurses dans le programme.
Tout d'abord avant de quitter Ncurses dans le programme nous allons supprimer toutes
les fenêtres créées auparavant avec la fonction delwin du module Ncurses (voir section V).
Une fois les fenêtres supprimées et afin de quitter Ncurses nous allons lancer la fonction
endwin du module Ncurses :
Ncurses.endwin;
NOTE: La fonction endwin ne prend aucun argument.
X) Quelques trucs et astuces pour bien construire son interface.
1) Créer des fenêtres proportionnelles à la taille du terminal.
Afin que les fenêtres de l'interface soient toujours proportionnées
à la taille du terminal nous devons construire nos fenêtres en fonction
de la taille de la fenêtre mére (la taille maximale de l'interface).
Pour cela nous devons d'abord récuperer les valeurs y et x maximales
de la fenêtre mére en utilisant les fonctions getmaxy et getmaxx.
Ces deux fonctions renvoie des entiers et s'utilise de la maniére
suivante :
$maxy=Ncurses.getmaxy(stdscr);
$maxx=Ncurses.getmaxx(stdscr);
Une fois les valeurs y et x maximales de la fenêtre mére récuperées nous
pouvons créer, sans difficultés, des fenêtres entiérement proportionnelles
à la taille du terminal. Vous devons procéder à un calcule simple
pour obtenir la taille de la fenêtre fille que nous voulons créer en
proportion de la taille du terminal.
a) Si la fenêtre n'a pas pour but d'être centrée.
Si la fenêtre n'a pas pour but d'être centrée alors les calcules
seront les suivants :
taille_y_de_la_fenetre_fille = $maxy-(begin_y+remaining_y);
taile_x_de_la_fenetre_fille = $maxx-(begin_x+remaining_x);
Ci-dessus les valeurs begin_y et begin_x correspondent aux valeurs
de commencement de la fenêtre qui ont étées choisit auparavant (voir section II).
Les valeurs y_remaining et x_remaining correspondent quant à elles aux valeurs y
et aux valeurs x restantes.
Voici concrétement à quoi correspond les valeurs y_remaining et x_remaining :
1
2 | - - - - - - - - - - - - - - - |
3 | | x_remaining
4 | | <- - - - - - - - - - - - - >
5 | |
6 | |
7 | - - - - - - - - - - - - - - - |
8 ^
9 | y_remaining
10 v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Une fois les calcules terminés nous pouvons utiliser les valeurs obtenues pour construire
la fenêtre comme nous l'avons appris auparavant (voir section II).
b) Si la fenêtre a pour but d'être centrée.
Si la fenêtre a pour but d'être centrée les calcules seront encore plus
simple :
taille_y_de_la_fenetre_fille = $maxy-(2*y_space);
taile_x_de_la_fenetre_fille = $maxx-(2*x_space);
Ci-dessus y_space represente l'espacement en bas et en haut qu'aura la
fenêtre fille avec les bords horizontaux de la fenêtres mére. Et x_space
represente l'espacement à gauche et droite qu'aura la fenêtre fille avec les
bords verticaux de la fenêtres mére.
Voici concrétement à quoi ces espacements correspondent :
1 ^
2 | y_space
3 v
4 | - - - - - - - - - - - - - - - - - - - - |
5 x_space | | x_space
6 <-------> | | <------->
7 | |
8 | - - - - - - - - - - - - - - - - - - - - |
9 ^
10 | y_space
11 v
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Une fois les calcules finies nous pouvons utiliser les valeurs pour construire
la fenêtre comme nous l'avons appris auparavant (voir section II).
2) Centrer un message d'une ligne.
Lorsque l'on souhaite afficher un message d'une ligne dans l'interface il est
pratique de pouvoir centrer celui-ci dans la fenêtre afin que cela fasse plus
propre. Pour cela nous allons nous servir de la valeur x maximale de la
fenêtre qui va contenir le message. Si la fenêtre en question est la fenêtre
mére nous allons récuperer la valeur x maximale de stdscr autrement nous
récupérerons celle de la fenêtre fille en question.
Pour récuperer la valeur x maximale nous devons utiliser la fonction getmaxx :
$maxx=Ncurses.getmaxx(fenetre_en_question);
Une fois la valeur x maximale obtenue nous allons
nous servir de la fonction mvwaddstr ou alors de la fonction mvaddstr (si
la fenêtre qui doit afficher le message est la fenêtre mére) (voir section IV).
Afin d'illustrer l'exemple nous allons nous servir de la fonction mvwaddstr :
$text="Voici le message";
Ncurses.mvwaddstr(fenetre_fille,emplacement_y_du_message,($maxx-$text.length)/2,$text)
Le calcule ($maxx-$text.length)/2 nous permet de connaitre la marge de
commencement du message afin que celui-ci soit bien centré dans le fenêtre
NOTE: Vous pouvez aussi utiliser les fonctions mvwprintw et mvprintw
qui permettent de gérer plusieurs types de données (voir section IV).
3) Créer une barre de progression.
Afin de prevenir l'utilisateur de l'avancement d'une action par le biais de l'interface il peut
être bien utile d'utiliser une voir plusieurs barres de progressions.
Par défaut Ncurses ne propose pas de barre de progression dans ces fonctions, nous allons
donc mettre au point une fonction qui va nous permettre de créer à la volée des barres de progressions.
Nous allons apprendre à créer une barre de progression qui s'adapte entiérment à sa fenêtre support.
La barre de chargement pourra donc avoir n'importe qu'elle taille.
Nous allons nommer cette fonction "loading" (changement en français) elle prendera comme arguments
la fenêtre qui va devenir le support de la barre de progression, un texte explicatif du
chargemenent et un entier allant de 1 à 100 (pour le pourçentage d'avancement).
a) Comment allons-nous créer "l'effet de chargement" ?
Pour modéliser la barre de chargement nous allons jouer sur la création d'une fenêtre interne
à la fenêtre support. La fenetre_interne sera de hauteur taille_y_fenetre_support-2 et de largeur n.
Sa valeur begin_y sera égale à begin_y_fenetre_support+1 et sa valeur begin_x sera égale à
begin_x_fenetre_support+1 (voir section II). La largeur n sera depandante d'un l'entier allant de 1 à 100 et
qui symbolisme numeriquement le chargement. Afin de calculer la largeur de la fenêtre interne en fonction de la
largeur de la fenêtre support et en fonction de l'entier symbolisant le chargement nous allons procéder
au calcule suivant :
n=(i*(taille_x_fenetre_support-2))/100;
ATTENTION: Il peut arrivé que ce calcule donne un nombre < 1.
Dans ce cas là il est préferable d'utiliser ce bout de code suivant :
if((i*(taille_x_fenetre_support-2))/100 < 1)
n=1;
else
n=(i*(taille_x_fenetre_support-2))/100;
end
A chaque appel de la fonction "loading" la valeur n sera re-calculée.
C'est ce calcule qui va modéliser l'accroisement de la fenêtre interne et donc
l'effet de chargement. Une fois ce calcule terminé nous pouvons créer la fenêtre interne :
fenetre_interne=WINDOW.new(begin_y_fenetre_support+1,begin_x_fenetre_support+1,taille_y_fenetre_support-2,n);
Il ne faudra pas oublier de créer une paire de couleur spécifique pour la fenetre_interne et par la suite de
l'utiliser comme ci-dessous.
Jusqu'à maintenant notre fonction en construction ressemble à ceci :
def loading(fenetre_support,i)
begin_y_fenetre_support=Ncurses.getbegy(fenetre_support);
begin_x_fenetre_support=Ncurses.getbegx(fenetre_support);
taille_y_fenetre_support=Ncurses.getmaxy(fenetre_support);
taille_x_fenetre_support=Ncurses.getmaxx(fenetre_support);
# On calcule l'accroissement.
if((i*(taille_x_fenetre_support-2))/100 < 1)
n=1;
else
n=(i*(taille_x_fenetre_support-2))/100;
end
fenetre_interne=WINDOW.new(taille_y_fenetre_support-2,n,begin_y_fenetre_support+1,begin_x_fenetre_support+1);
fenetre_interne.bkgd(Ncurses.COLOR_PAIR(X));
stdscr.refresh;
fenetre_interne.refresh;
Ncurses.delwin(fenetre_interne);
end
b) Oû allons nous placer le texte explicatif du chargement ?
Nous allons nous servir de l'espace que nous avons laissé sur la fenêtre support afin d'écrire le texte
explicatif. Attention : le texte explicatif ne doit pas être plus grand que la largeur de la fenêtre
support ! Il est fortement recommandé de choisir un texte concis et explicant de maniére clair l'action se déroulant, exemple :
"Unpacking emacs pkg ..."
Nous avons le choix de mettre ce texte au milieux et en haut ou en bas.
Si vous désirez le mettre en haut vous devez utiliser la fonction mvwaddstr (ou mvwprintw)
de la maniére qui suit (voir section IV) :
Ncurses.mvwaddstr(fenetre_support, 0, (taille_x_fenetre_support-text.length)/2,"mon_texte");
Autement si vous souhaitez le mettre en bas vous devez utiliser la fonction mvwaddstr de la maniére
suivante :
Ncurses.mvwaddstr(fenetre_support, taille_y_fenetre_support-1, (taille_x_fenetre_support-text.length)/2,"mon_texte");
NOTE: Voir astuce 2).
Jusqu'à maintenant notre fonction en construction ressemble à ceci :
def loading(fenetre_support,texte_explicatif,i)
begin_y_fenetre_support=Ncurses.getbegy(fenetre_support);
begin_x_fenetre_support=Ncurses.getbegx(fenetre_support);
taille_y_fenetre_support=Ncurses.getmaxy(fenetre_support);
taille_x_fenetre_support=Ncurses.getmaxx(fenetre_support);
# On calcule l'accroissement.
if((i*(taille_x_fenetre_support-2))/100 < 1)
n=1;
else
n=(i*(taille_x_fenetre_support-2))/100;
end
fenetre_interne=WINDOW.new(taille_y_fenetre_support-2,n,begin_y_fenetre_support+1,begin_x_fenetre_support+1);
fenetre_interne.bkgd(Ncurses.COLOR_PAIR(X));
fenetre_support.erase;
Ncurses.mvwaddstr(fenetre_support, 0, (taille_x_fenetre_support-(texte_explicatif.length+2))/2," " + texte_explicatif + " ");
stdscr.refresh;
fenetre_support.refresh;
fenetre_interne.refresh;
Ncurses.delwin(fenetre_interne);
end
NOTE: Avant chaque écriture sur la fenetre_support on la "nettoie" des éventuels anciens caractéres écrits avec la
fonction erase.
c) Oû allons-nous mettre le pourcentage de chargement ?
Là aussi nous allons nous servir de l'espace que vous avons laissé exprès auparavant.
Si vous avez placé le texte explicatif en haut nous allons placer le pourcentage de chargement en bas.
Par contre si vous avez placer le texte explicatif en bas nous allons placer le pourcentage en haut.
Nous allons afficher le pourcentage de chargement avec la fonction mvwprintw car cette fonction permet
d'afficher des entiers (contrairement à la fonction mvwaddstr).
Nous allons utiliser la fonction mvwprintw de la façon suivante si vous voulez mettre le pourcentage en bas:
Ncurses.mvwprintw(fenetre_support,taille_y_fenetre_support-1,(taille_x_fenetre_support-(i.to_s.length+3))/2," %d%s ",i,"%");
Si vous voulez mettre le pourcentage en haut nous allons procéder ainsi :
Ncurses.mvwprintw(fenetre_support,0,(taille_x_fenetre_support-(i.to_s.length+3))/2," %d%s ",i,"%");
Voici au final à quoi ressemble notre fonction :
def loading(fenetre_support,texte_explicatif,i)
begin_y_fenetre_support=Ncurses.getbegy(fenetre_support);
begin_x_fenetre_support=Ncurses.getbegx(fenetre_support);
taille_y_fenetre_support=Ncurses.getmaxy(fenetre_support);
taille_x_fenetre_support=Ncurses.getmaxx(fenetre_support);
# On calcule l'accroissement.
if((i*(taille_x_fenetre_support-2))/100 < 1)
n=1;
else
n=(i*(taille_x_fenetre_support-2))/100;
end
fenetre_interne=WINDOW.new(taille_y_fenetre_support-2,n,begin_y_fenetre_support+1,begin_x_fenetre_support+1);
fenetre_interne.bkgd(Ncurses.COLOR_PAIR(X));
fenetre_support.erase;
Ncurses.mvwaddstr(fenetre_support,0,(taille_x_fenetre_support-(texte_explicatif.length+2))/2," " + texte_explicatif + " ");
Ncurses.mvwprintw(fenetre_support,taille_y_fenetre_support,(taille_x_fenetre_support-(i.to_s.length+3))/2," %d%s ",i,"%");
stdscr.refresh;
fenetre_support.refresh;
fenetre_interne.refresh;
Ncurses.delwin(fenetre_interne);
end
NOTE: Par la suite vous pouvez enjoliver la barre de chargement en rajoutant une ombre (faire cela à la création de la
fenetre_support) et un effet box (faire cela dans la fonction) (voir section V).
d) Comment utiliser notre fonction ?
Cette fonction s'utilise après chaque action fait par votre logiciel. Par exemple si notre logiciel à pour but de
décompresser tous les fichiers d'un répertoire alors après chaque décompression la fonction loading sera appelée
avec comme valeur i une valeur proportionelle au travail déja fournit. Exemple: si il y a 50 fichiers compressés
dans le répertoire à chaque fichier décompressé la barre de chargement augementera de + 2% jusqu'à 100%.
Cette gestion peut ce faire automatiquement: il suffit de récupérer le nombre de fichiers présents dans le répertoire
de diviser 100 par le nombre ainsi obtenu de tranformer le résultat obtenu en entier (si celui-ci est un nombre virgule)
et ensuite de passer la valeur multipliée du résultat par le nombre de fichiers traités à la fonction loading.
Voici un petit exemple d'utilisation basé sur ce qui est dit au-dessus :
fichiers=`ls .`;
nbr_fichiers=fichiers.count("\n");
j=1;
for i in fichiers
system("bunzip2 "+i);
# Ceci nous assure un fonctionnement propre :-)
if((100/nbr_fichiers).round*j<100 && j==nbr_fichiers) || ((100/nbr_fichiers).round*j>100))
x=100;
else
x=(100/nbr_fichiers).round*j;
end
loading(fenetre_support,i,x);
j=j+1;
end
ATTENTION: Il est nécessaire de verifier avant chaque appel de la fonction loading que la valeur x (en prenant
l'exemple
ci-dessus) est toujours supérieur ou égale à 1 et toujours inférieur ou égale à 100.
Les liens.
le Ruby :
Apprendre le Ruby (en français) :
http://www.projectomega.org/contents/fr/php/tuts/ruby/MacOSX_Ruby_Reference.pdf
Apprendre le Ruby (en anglais) :
http://www.ruby-doc.org/docs/ProgrammingRuby/
autres langages :
Apprendre à utiliser Ncurses avec le langage C (en anglais) :
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
Une bonne introduction à Ncurses avec le langage C (en français) :
http://www.linuxfocus.org/FRancais/March2002/article233.shtml
Une documentation Ncurses avec le langage python :
http://www.amk.ca/python/howto/curses/curses.html
autre :
La liste de correspondance touche/code ASCII :
http://www.asciitable.com
Quelques exemples ...
Exemple d'utilisation de la fonction loading : example_loading.rb
À propos de la documentation.
La documentation est placé sous licence FDL :
Copyright (c) 2005 BLONDEL Paul.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled "GNU
Free Documentation License".