Le StringGrid facile avec Lazarus

Dimanche2003

À l'heure où l'on sait tout sur le graphène et ses inventeurs, André Geim et Konstantin Novoselov, grâce au Nobel de physique, qui connaît Jesus Reyes Aguilar ?

Les pages qui suivent constituent une introduction au composant TStringGrid : quelques lignes de code suffiront pour révéler une petite partie de sa puissance au sein de l'environnement Lazarus.
Mais derrière ces quelques lignes se cache un outil impressionnant, l'unité Grids.pas, avec ses 10186 lignes de code dans l'édition du 25 septembre 2009, mis à disposition de la communauté mondiale par son auteur, Jesus Reyes Aguilar.

Hommage.

Le code correspond à la version 0.9.28.2 beta de Lazarus, sous Vista 32 bits.

J'adresse mes remerciements à jacques_jean pour sa relecture.

Commentez

- Titre : Le StringGrid facile avec Lazarus

- Auteur : Dimanche2003

- Parution : 24 octobre 2010

- Mise à jour : 24 octobre 2010

- Licence : Copyright ® 2010 Dimanche2003. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Le formulaire

- I-1. Création du formulaire : nom, dimensions

- I-2. Enregistrement du projet

- I-3. Résultat

- II. La grille

- II-1. Introduction de la grille

- II-2. Première utilisation

- II-3. Bilan

- III. Remplir la grille

- III-1. Numérotation des lignes

- III-2. Alternance des couleurs

- III-3. Événement OnCreate

- III-4. Autres cases

- III-5. Bilan

- IV. Coordonnées de la souris

- IV-1. L'événement OnMouseMove

- IV-2. Coordonnées colonne et ligne

- IV-3. Bilan

- V. Edition des cases, curseur

- V-1. Options dimensions et édition

- V-2. L'événement OnDrawCell

- V-3. Surlignement de la ligne, de la colonne

- V-4. Horizontale et verticale

- V-5. Cadre

- V-6. Bilan

- VI. Mise en oeuvre des options

- VI-1. Liste des options disponibles

- VI-2. Curseurs

- VI-3. Remplissage de la grille

- VI-3-A. Couleur de la grille

- VI-3-B. Texte des cellules

- VI-4. Bilan

I - Le formulaire

Ce premier chapitre expose la façon de créer un formulaire, avec présentation de quelques paramètres.

I-1 - Création du formulaire : nom, dimensions

Pour charger la version complète du logiciel (gratuit), cliquer sur le bouton vert Download Now ! situé sur la page http://sourceforge.net/projects/lazarus/files/.

Une fois l'installation terminée, lancer Lazarus, cliquer sur Fichier/Nouveau/Projet/Application :

puis sur le bouton OK de la fenêtre. Lazarus crée un formulaire dont les propriétés sont affichées dans une fenêtre spécialisée, l'inspecteur d'objets. Dans cette fenêtre, on va éditer (modifier) quatre propriétés, par ordre alphabétique :

- Caption : remplacer Form1 par MonFormulaire ;

- Height : remplacer 300 par 400 ;

- Name : remplacer Form1 par MonFormulaire ;

- Width : remplacer 400 par 600.

Le dessin de la fenêtre est maintenant terminé.

I-2 - Enregistrement du projet

Les étapes suivantes sont nécessaires pour tester, modifier et relancer à volonté notre projet :

1. Il faut le sauvegarder ; Pour cela, il faut créer un répertoire avec l'aide de l'explorateur, il s'appellera par exemple EssaiStringGrid.

2. Cliquer ensuite sur Fichier/Enregistrer-sous dans la barre de menu de Lazarus. Chercher le nouveau répertoire et renommer Unit1.pas en EssaiGrille.pas. Une fenêtre propose de tout mettre en minuscules, choisir Préserver ;

3. Une nouvelle fenêtre propose d'enregistrer le projet sous le nom project1.lpr, remplacer ce nom par ProjetGrille.lpr, qui est plus explicite ;

4. Enfin, il faut configurer le compilateur pour que le programme à créer soit écrit dans le bon répertoire : cliquer sur Projet, Options du compilateur. Sur la ligne Répertoire de sortie, cliquer sur le bouton où apparaissent trois points. Une fenêtre Recherche de dossier apparaît, choisir le même répertoire que précédemment et cliquer sur OK.

Pour lancer l'exécution, cliquer sur le petit triangle vert, ou cliquer sur Exécuter/Exécuter, ou appuyer sur la touche F9. Pour y voir plus clair, il est préférable de réduire la présence de Lazarus sur l'écran en cliquant sur le petit segment horizontal en haut et à droite de l'éditeur.

Une fenêtre intitulée MonFormulaire apparaît, avec à gauche du titre une icône Lazarus et à droite les trois boutons de réduction, d'extension et de clôture.

Pour fermer cette fenêtre, cliquer sur le bouton de clôture, ou sur le petit carré rouge qui apparaît dans la barre de menus de Lazarus. Chacune de ces deux actions interrompt l'exécution : cliquer sur OK pour confirmer.

I-3 - Résultat

Avec l'explorateur, ouvrir le répertoire EssaiStringGrid : on peut ainsi constater que la compilation a produit un fichier exécutable nommé ProjetGrille.exe, d'une taille respectable puisqu'elle atteint 12 Mo, alors qu'aucune ligne de code n'a encore été écrite : Lazarus a déjà incorporé au programme un grand nombre de fonctions (bibliothèques) susceptibles d'être activées très simplement selon les besoins qui pourraient apparaître ultérieurement.

Cette fenêtre en apparence simpliste possède de nombreuses propriétés : on peut la déplacer, modifier ses dimensions, la fermer... mais on ne peut rien y inscrire pour l'instant.

L'étape suivante introduit un composant puissant : le StringGrid.

II - La grille

Le formulaire est créé : il va être utilisé comme conteneur pour recevoir un composant, le TstringGrid. La gestion d'un événement va permettre de remplir et effacer une case.

II-1 - Introduction de la grille

Le projet intitulé ProjetGrille aboutit pour l'instant à une simple fenêtre appelée MonFormulaire qui sera utilisée pour recevoir une grille.

Ouvrir le projet. Pour cela, avec l'explorateur, ouvrir le répertoire EssaiStringGrid et double-cliquer sur le fichier ProjetGrille.lpi : Lazarus se lance et affiche le projet.

Pour faire apparaître la fenêtre du projet, cliquer sur Voir/Fiches et choisir MonFormulaire.

Autre méthode : appuyer simultanément sur les touches Shift et F12 ; ou encore, cliquer sur la deuxième icône de la 2e ligne, sous Fichier.

Il s'agit de placer sur la fenêtre du projet un composant StringGrid.

Les principaux composants s'affichent sous forme d'icône : sur la 2e ligne du menu apparaît l'onglet Standard, puis l'onglet Additional, puis CommonControls...

Dans l'onglet Additional, dans le 3e tiers de la ligne d'icônes apparaît le composant TStringGrid qui se distingue par les trois lettres abc.
Cliquer une fois dessus : il est entouré d'un grisé qui indique la sélection. Pour le glisser dans la fenêtre, il suffit maintenant de cliquer une fois dans la fenêtre.
Le composant s'insère précisément au point où la fenêtre a reçu le clic. L'inspecteur d'objets reconnaît maintenant deux objets : MonFormulaire et StringGrid1. Un clic sur le second fait apparaître ses propriétés modifiables, les événements que l'on pourra utiliser, les favoris et les restrictions.

Dans l'onglet Propriétés, quelques valeurs vont être modifiées :

1. ColCount : passer de 5 à 21 (nombre de colonnes) ;

2. Height : passer de 100 à 300, (hauteur visible de la grille) ;

3. Left : passer de 10 à 0, (espace entre la gauche de la fenêtre et la gauche du composant) ;

4. Name : passer de StringGrid1 à MaGrille, (nom utilisable dans le code) ;

5. RowCount : passer de 5 à 21 (nombre de lignes) ;

6. Top : passer de 10 à 0 (espace entre le haut de la fenêtre et le haut du composant) ;

7. Width : passer de 200 à 600 (largeur visible de la grille).

Certaines modifications peuvent être menées graphiquement, directement depuis la fenêtre : à l'aide de la souris, il est facile de placer le composant en haut et à gauche de la fenêtre (mise à zéro de Top et Left), et d'étirer le composant pour ajuster ses dimensions aux valeurs souhaitées (Height et Width).

Les autres propriétés sont toujours accessibles via l'inspecteur d'objets, ou encore en écrivant quelques lignes de code.

II-2 - Première utilisation

En première étape, il faut vérifier que la grille peut afficher une information et l'effacer.

Pour cela, insérer un bouton dans MonFormulaire (Voir/Composant/TButton), le positionner dans la partie inférieure droite de MonFormulaire et modifier son titre (Caption) en remplaçant Button1 par Affichage.

L'idée est de cliquer sur le bouton pour écrire le mot Bonjour dans la case qui a 1,1 pour coordonnées. Si la case est vide, ce mot est inscrit. Sinon, elle sera vidée. Le code s'écrit ainsi :

With MaGrille do
If Cells[1,1]='' Then Cells[1,1]:='Bonjour'
Else Cells[1,1]:='';

Explications :

au lieu d'écrire trois fois MaGrille.Cells[1,1], syntaxe normale, il est plus rapide de déclarer l'identification de Cells par l'instruction With MaGrille do...

Mais où écrire ces lignes ? Lazarus fait tout, ou presque : revenir au formulaire et double-cliquer sur le bouton Affichage : le formulaire passe au second plan au bénéfice de l'éditeur de source, le curseur clignote précisément sur la nouvelle procédure créée automatiquement :

procedure TMonFormulaire.Button1Click(Sender: TObject);
begin

end;

Entre les mots clés begin et end, insérer le code précédent, ce qui donne :

procedure TMonFormulaire.Button1Click(Sender: TObject);
begin
With MaGrille do
If Cells[1,1]='' Then Cells[1,1]:='Bonjour'
Else Cells[1,1]:='';
end;

La touche F9 lance l'exécution du projet ; elle procède en outre à l'enregistrement du code et à la fabrication du fichier exécutable EssaiGrille.exe.

Un clic sur le bouton Affichage fait apparaître le mot Bonjour, un second l'efface.

Soit, ce n'est pas grand-chose, mais un peu de fantaisie pourrait faire apparaître également les mots Au revoir... L'affichage pourrait se faire dans une case choisie au hasard... Il suffit pour cela d'un peu d'imagination et de quelques modifications du code... tous les outils sont disponibles !

À noter :

Les indices des cases commencent par zéro, les colonnes d'abord, les lignes ensuite.
MaGrille.Cells[i, j] désigne donc la case de la (i+1)ème colonne et de la (j+1)ème ligne de la grille appelée MaGrille.
Le contenu du composant StringGrid est toujours de type chaîne (String). L'affectation d'une valeur numérique provoquera donc une erreur. On écrira plutôt :
MaGrille.Cells[i, j]:='123'; ou encore MaGrille.Cells[i, j]:=IntToStr(123);
L'affectation d'une valeur chaîne peut également provoquer une erreur. Par exemple MaGrille.Cells[i, j]:=Bonjour;
Dans ce cas, le compilateur cherche la variable de type String du nom de Bonjour, qui n'existe pas. Il faut donc bien écrire comme précédemment MaGrille.Cells[i, j]:='Bonjour';

II-3 - Bilan

Le formulaire contient maintenant un composant Grille, dont on peut régler à volonté le nombre de lignes et de colonnes et afficher ce que l'on souhaite dans chacune de ses cases.

Un composant Bouton est utilisé pour modifier la grille. Pour cela, une procédure détecte le clic sur le bouton et l'interprète pour lancer une action.

La phase suivante va permettre d'identifier les lignes et les colonnes et de présenter un remplissage des cases.

Un clic sur le petit carré rouge du menu interrompt l'exécution et rend la main à Lazarus.

III - Remplir la grille

Le projet permet de construire un formulaire affichant une grille et un bouton qui alternativement remplit et vide une case. La 3e étape aborde les titres de la colonne et de la ligne fixes, l'alternance des couleurs et le remplissage de toutes les autres cellules.
La gestion de l'événement Création du formulaire va donner l'occasion « d'habiller » l'ensemble de la grille, avant tout autre traitement.

III-1 - Numérotation des lignes

C'est l'opération la plus simple : cliquer sur la grille pour faire apparaître l'inspecteur d'objets.

La ligne Options de l'onglet Propriétés présente à sa gauche un petit signe + : cliquer dessus pour faire apparaître les options disponibles.

À la ligne goFixedRowNumbering, écrire (basculer sur) True à la place de False.

C'est fait : appuyer sur la touche F9, le formulaire apparaît avec la numérotation des lignes sur la colonne fixe de gauche.

L'identification des colonnes est différente : la propriété Columns donne accès à un éditeur qui permet de définir les titres de chaque colonne une par une. Ce processus peut devenir rapidement laborieux, il est donc préférable d'envisager l'édition des titres au sein du code : voir plus loin.

III-2 - Alternance des couleurs

Une propriété intéressante de la grille est nommée AlternateColor. Par défaut, sa valeur est clWindow. D'autres couleurs sont disponibles. Par exemple choisir clMoneyGreen. Appuyer sur F9 : les lignes sont colorées blanc/vert alternativement, ce qui peut rendre bien des services pour se repérer dans un tableau de grandes dimensions. Pour la suite, revenir sur clWindow.

III-3 - Événement OnCreate

Le clic de la souris a déjà permis de remplir une case de la grille. Mais il existe des événements qui se déclenchent automatiquement, par exemple lors de la création du formulaire.

Retour sur le formulaire : un clic ramène l'inspecteur d'objets sur ses propriétés. Cliquer sur le volet Evénements. Un clic sur la méthode OnCreate, et dans la zone qui se libère, entrer CreationFormulaire (sans accent) et appuyer sur Entrer. L'éditeur de source réapparaît, une nouvelle procédure est créée, elle sera exécutée à chaque lancement du programme.

Dans cette procédure, les titres des colonnes seront définis. Par exemple Col 1, Col 2, etc.

procedure TMonFormulaire.CreationFormulaire(Sender: TObject);
var i : Integer;
begin
With MaGrille do

For i:=1 To ColCount-1 do
Cells[i,0]:='Col '+IntToStr(i);
end;

Noter la variable ColCount qui conserve le nombre de colonnes choisi. De même, RowCount désigne le nombre de lignes. La variable compteur i est locale : elle doit donc être déclarée avant le mot clé begin.

Un appui sur F9 et la grille apparaît : lignes et colonnes sont identifiées clairement.

Pour remplacer la notation Col 1, Col 2, etc. par Col A, Col B, etc., il suffit de remplacer la chaîne 'Col '+IntToStr(i) par 'Col '+Chr(64+i).
Dans ce cas, il faudra traiter le cas des grilles dont le nombre de colonnes dépasse 26, pour doubler par exemple le nombre des lettres.

Néanmoins, la simple numérotation des lignes peut se révéler insuffisante dans certaines applications. La désignation des lignes pourra être imposée par le code. Si on souhaite par exemple la notation Lig 1, Lig 2, etc. le code s'écrira :

For i:=1 to RowCount-1 do
Cells[0,i]:='Lig '+IntToStr(i);

Si la numérotation automatique des lignes est activée, la nouvelle désignation remplacera les numéros.

III-4 - Autres cases

Le remplissage des autres cases de la grille est réalisé en fonction de l'application souhaitée : à partir d'un fichier texte, d'une base de données, du presse-papier... ou manuellement. Ici, les cases seront remplies par des numéros très simples à constituer. Une variable i va balayer les colonnes, une autre j va balayer les lignes. La cellule de la colonne 1, ligne 1 portera le n° 1. Le numéro des autres cases sera donc i+(RowCount-1)*(j-1). Ce qui donne :

For i:=1 to ColCount-1 do
For j:=1 to RowCount-1 do
Cells[i,j]:=IntToStr(i+(RowCount-1)*(j-1));

Un appui sur F9 permet d'étudier le résultat : la grille est complète, l'utilisation des ascenseurs montre que la dernière case porte bien le bon numéro.

1. La variable j doit être déclarée en début de procédure.

2. Pour afficher non pas des numéros bien ordonnés mais des nombres au hasard, la dernière ligne deviendra
Cells[i,j]:=IntToStr(1+Random(10000));
Au début de la procédure de création du formulaire, l'instruction Randomize provoquera l'initialisation des nombres pseudo-aléatoires.

Un clic sur le bouton Affichage montre que son fonctionnement n'a pas été altéré.

Le code de la procédure CreationFormulaire se présente maintenant comme suit :

procedure TMonFormulaire.CreationFormulaire(Sender: TObject);
var i, j : Integer;
begin
Randomize;
With MaGrille do
Begin
For i:=1 To ColCount-1 do
Cells[i,0]:='Col '+IntToStr(i);
For i:=1 to RowCount-1 do
Cells[0,i]:='Lig '+IntToStr(i);
For i:=1 to ColCount-1 do
For j:=1 to RowCount-1 do
//Cells[i,j]:=IntToStr(i+(RowCount-1)*(j-1));
Cells[i,j]:=IntToStr(1+Random(10000));
End;

end;

III-5 - Bilan

Cette troisième étape a conduit au remplissage de la totalité de la grille et à l'identification claire de chacune de ses lignes et colonnes.

La suite fera intervenir les déplacements de la souris et permettra de déterminer -et d'afficher- ses coordonnées ainsi que les numéros de ligne et de colonne correspondants.

IV - Coordonnées de la souris

Dans son avancement actuel, le projet construit une grille entièrement remplie, colonnes et lignes clairement identifiées. Un bouton permet d'éditer une case.
Cette nouvelle étape va utiliser l'événement OnMouseMove qui détecte la position de la souris au-dessus de la grille et informe le programme de ses coordonnées au pixel près.

IV-1 - L'événement OnMouseMove

Pour relancer Lazarus et afficher le code du projet, ouvrir le répertoire EssaiStringGrid et double-cliquer sur le fichier ProjetGrille.lpi. La deuxième icône de la deuxième ligne donne accès aux fiches : cliquer sur MonFormulaire puis sur OK ; cliquer sur la grille : l'inspecteur d'objets affiche les propriétés et les événements associés. Dans l'onglet Evénements, chercher OnMouseMove, cliquer dessus : une zone de saisie apparaît, écrire le nom de la procédure à créer, ici CoordSouris, appuyer sur Entrer.

Cette commande remet l'éditeur de source au premier plan, le curseur clignotant à l'intérieur de la nouvelle procédure qui se présente ainsi :

procedure TMonFormulaire.CoordSouris(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
begin

end;

Que représentent les variables X et Y qui apparaissent dans les paramètres de cette procédure ? Pour le savoir, il suffit de les afficher dans la grille. Entre les mots begin et end ci-dessus, il suffit d'écrire :

With MaGrille do
begin
Cells[1,2]:='X ='+IntToStr(X);
Cells[1,3]:='Y ='+IntToStr(Y);
end;

Un appui sur F9 lance l'exécution. Rien ne se passe, en apparence. Par contre, si le curseur de la souris entre dans la surface occupée par la grille, les deux cases choisies affichent les coordonnées du curseur, avec une mise à jour automatique en fonction des mouvements de la souris.

Si le curseur est placé dans l'angle supérieur gauche, les coordonnées sont 0, 0.

Dans l'angle inférieur droit, les coordonnées deviennent 578, 278. Les dimensions de la grille avaient été fixées à 600 par 300 ? L'écart représente précisément la largeur des ascenseurs qui permettent de naviguer dans les parties cachées de la grille.

En conclusion, la procédure CoordSouris communique en permanence les coordonnées de la souris au pixel près.

IV-2 - Coordonnées colonne et ligne

Pour obtenir les numéros de colonne et de ligne à partir des coordonnées X et Y de la souris, il faut utiliser la procédure MouseToCell(X, Y, sCol, sLig) qui fait directement la conversion.

L'introduction de deux nouvelles variables sCol et sLig impose une déclaration en tête de la procédure (variables locales) ou avant l'implémentation (variables globales).

Pour afficher le résultat, le plus simple est d'utiliser la case restée vide en haut et à gauche de la grille (coordonnées 0,0). La procédure CoordSouris se présente alors comme suit :

procedure TMonFormulaire.CoordSouris(Sender: TObject;
Shift: TShiftState; X, Y: Integer);
var sCol, sLig : Integer;
begin
With MaGrille do
begin
Cells[1,2]:='X ='+IntToStr(X);
Cells[1,3]:='Y ='+IntToStr(Y);
MouseToCell(X, Y, sCol, sLig);
Cells[0,0]:='C '+IntToStr(sCol)+' - L '+IntToStr(sLig);
end;
end;

Un appui sur la touche F9 lance l'exécution et permet de vérifier le bon fonctionnement du projet.

IV-3 - Bilan

Dans son état actuel, le projet construit une grille complètement remplie et renseignée.

La position de la souris est détectée et affichée sous les formes de coordonnées graphiques (X et Y) et logiques (colonne, ligne).

Lors de la prochaine étape, la position de la souris sera mise en valeur par l'introduction de couleurs et de lignes. Chaque cellule pourra en outre être modifiée indépendamment.

V - Edition des cases, curseur

La grille produite par le projet est complète, mais ses cases ne sont pas modifiables. Les coordonnées de la souris sont affichées, mais le curseur reste très discret ce qui peut constituer un handicap dans le cas de grilles de grandes dimensions. L'apparition de couleurs sur le passage de la souris localiserait plus facilement sa position.
L'événement OnDrawCell va autoriser l'affichage de ce curseur particulier.

V-1 - Options dimensions et édition

Les dimensions de la grille (hauteur, largeur, nombre de colonnes, nombre de lignes, largeur de colonne, hauteur de ligne) sont renseignées dans l'inspecteur d'objets.

Retourner sur les options : un clic sur le signe + développe les possibilités.

1. Cliquer sur goColSizing, passer la valeur à True (largeur des colonnes).
2. Cliquer sur goEditing, passer la valeur à True (les cases peuvent être modifiées).
3. Cliquer sur goRowSizing, passer la valeur à True (hauteur des lignes).

Appuyer sur F9 pour lancer l'exécution et vérifier que chaque case peut être éditée, que chaque colonne, chaque ligne peut être ajustée en dimensions : les interventions sont possibles à partir des ligne et colonne fixes uniquement.

Cliquer sur le petit carré rouge qui stoppe l'exécution et cliquer sur OK pour rendre la main à Lazarus.

V-2 - L'événement OnDrawCell

Cliquer sur la grille, puis sur l'inspecteur d'objets, volet Événements et sur OnDrawCell. Dans la zone de saisie, écrire DessinGrille et appuyer sur Entrer.

Dans l'éditeur de source, une nouvelle procédure apparaît, DessinGrille, avec ses divers paramètres.

aCol et aRow désignent respectivement la colonne courante et la ligne courante, aRect est la cellule située à leur intersection. Cette procédure est exécutée lors de la création de la grille, puis à chaque instruction Repaint.

Par ailleurs, le programme connaît sCol et sLig, qui sont respectivement la colonne et la ligne survolées par la souris.

En conclusion, la condition (aCol=sCol) And (aRow=sLig) identifie la case survolée par la souris.

Pour colorer en jaune la case survolée par la souris, le code s'écrira donc ainsi :

procedure TMonFormulaire.DessinGrille(Sender: TObject;
aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);

begin
With MaGrille.Canvas do
begin
If ((aCol=sCol) And (aRow=sLig)) Then Brush.Color:=clYellow;
FillRect(aRect);

end;
end;

Un appui sur F9 permet de vérifier que... le code ne fonctionne pas comme prévu. En effet, deux compléments sont nécessaires :

1. Les variables sCol et sLig sont déclarées au sein d'une procédure, donc ignorées de la nouvelle. Il est donc nécessaire de supprimer la première déclaration et de la reporter en tête du programme, avant le mot clé implementation :

var
MonFormulaire: TMonFormulaire;
sCol, sLig : Integer;

implementation

{ TMonFormulaire }

2. La procédure est lancée au démarrage et il faut la relancer à chaque fois que la souris se déplace. Donc dans la procédure CoordSouris, il faut ajouter l'instruction Repaint.

Dès que la souris se déplace, l'événement est détecté et traité dans le cadre de la procédure CoordSouris. Il suffit d'ajouter l'instruction Repaint dans cette procédure pour que la mise à jour graphique soit déclenchée.

Un appui sur F9 montre que cette fois le but recherché est atteint.

V-3 - Surlignement de la ligne, de la colonne

Pour mettre en valeur la totalité de la ligne survolée par la souris, il suffit de remplacer la condition If ((aCol=sCol) And (aRow=sLig)) par :
If (aRow=sLig)... --> toute la ligne est surlignée.

Si au contraire, c'est l'ensemble de la colonne que l'on désire surligner, la condition deviendra :
If (aCol=sCol)... --> toute la colonne est surlignée.

Pour mettre une couleur dans toutes les cellules, il suffit de la déclarer avec Brush.Color avant l'introduction des conditions. La logique se présenterait ainsi :
Brush.Color:=Couleur0;
Si condition1, Brush.Color:=Couleur1;
Si condition2, Brush.Color:=Couleur2;
...
FillRect(aRect);

V-4 - Horizontale et verticale

Les familiers d'AutoCad et autres logiciels de dessin souhaiteront peut-être retrouver leur environnement favori à l'intérieur d'une grille.

À la déclaration de sCol et sLig, ajouter cooX et cooY (avant implementation).

Les coordonnées X et Y de la souris sont déterminées au sein de la procédure CoordSouris : compléter son code par cooX:=X et cooY:=Y.

Pour les lignes rouges, le code s'écrira, en utilisant les méthodes MoveTo et LineTo :

procedure TMonFormulaire.DessinGrille(Sender: TObject;
aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);

begin
With MaGrille.Canvas do
begin
Pen.Color:=clRed;
MoveTo(0, cooY);
LineTo(MaGrille.Width, cooY);
MoveTo(cooX, 0);
LineTo(cooX, MaGrille.Height);
end;
end;

V-5 - Cadre

Il reste une autre possibilité pour mettre en valeur la case survolée par la souris, celle de l'entourer par un cadre. Le tracé des lignes doit commencer par un angle qui aura pour coordonnées aRect.Left et aRect.Top (sommet supérieur gauche).

Le premier segment sera une horizontale de longueur égale à la largeur de la colonne moins deux pixels pour ne pas écraser la ligne frontière, soit
ColWidths[sCol]-2.
La première verticale aura pour hauteur la hauteur de la ligne moins deux pixels, soit
RowHeights[sLig]-2
et le tracé continuera jusqu'au point de départ.

Le code s'écrira donc ainsi, en reprenant les méthodes MoveTo et LineTo :

procedure TMonFormulaire.DessinGrille(Sender: TObject;
aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);
var Largeur, Hauteur : Integer;
begin
If (aCol=sCol) And (aRow=sLig) Then
With MaGrille.Canvas do
begin
Pen.Color:=clRed;
Largeur:=MaGrille.ColWidths[aCol]-2;
Hauteur:=MaGrille.RowHeights[aRow]-2;
MoveTo(aRect.Left, aRect.Top);//angle supérieur gauche
LineTo(aRect.Left+Largeur, aRect.Top);//1ère horizontale
LineTo(aRect.Left+Largeur, aRect.Top+Hauteur);//1ère verticale
LineTo(aRect.Left, aRect.Top+Hauteur);//2ème horizontale
LineTo(aRect.Left, aRect.Top);  //retour
end;
end;

Un appui sur F9 montre que l'objectif recherché est atteint.

V-6 - Bilan

Le projet permet maintenant de créer une grille de données et de suivre avec précision la position de la souris en mettant en valeur la case survolée, ou la ligne, ou la colonne. Il est également possible de constituer un curseur style AutoCad, ou simplement d'encadrer la case.

Dans le prochain chapitre, les différentes options de mise en valeur seront restructurées afin de rendre leur choix accessible à partir du formulaire.

VI - Mise en oeuvre des options

Le chapitre précédent a exposé les différentes formes que le code peut donner au curseur pour mettre en évidence la position de la souris dans une grille.
Ces options peuvent être sélectionnées facilement à l'aide de boîtes à cocher.

VI-1 - Liste des options disponibles

Le projet a présenté les méthodes permettant de surligner la case survolée par la souris :

1. En changeant la couleur du fond de la case ;

2. En encadrant la case ;

3. En changeant la couleur de toute la ligne ;

4. En changeant la couleur de toute la colonne ;

5. En dessinant une horizontale à la hauteur de la souris ;

6. En dessinant une verticale à la hauteur de la souris.

Soit six options de base, auxquelles seront ajoutées, à titre d'illustration, la mise en couleur du fond de la grille et le remplissage des cases par des nombres aléatoires. Pour autoriser un choix multiple, la solution la plus simple est d'utiliser le composant CheckBox, soit huit cases à cocher qui porteront les noms suivants (Caption) :

1. Case ;

2. Cadre ;

3. Ligne ;

4. Colonne ;

5. Horizontale ;

6. Verticale ;

7. Fond couleur ;

8. Aléatoire.

Avec Lazarus, glisser successivement les huit checkbox dans le formulaire, au-dessous de la grille. Modifier la propriété Caption pour donner à chacun la valeur ci-dessus.

VI-2 - Curseurs

Les six premières options sont conditionnées par l'identité d'un paramètre détecté par la souris (sCol par exemple) avec le paramètre traité par la procédure OnDrawCell, aCol en l'occurence.

Pour simplifier l'écriture du code, on remplacera :

If (aCol=sCol) Then...

par une expression raccourcie :

If Colonne Then...

Ceci suppose que la variable Colonne soit un booléen, qui sera déclarée en local, et définie par :

Colonne:=(aCol=sCol);

Au cours de l'exécution de la procédure DessinGrille, le programme compare les deux variables aCol et sCol. Si elles sont identiques, la variable Colonne bascule sur Vrai. Sinon, elle bascule sur Faux. Avec la même affectation pour la variable Ligne, l'ensemble des conditions qui feront apparaître un fond de couleur dans la case survolée par la souris devient :

If CheckBox1.Checked And Ligne And Colonne Then...

Pour que la ligne entière soit surlignée, la condition sera :

If CheckBox3.Checked And Ligne Then...

Et pour la colonne :

If CheckBox4.Checked And Colonne Then...

L'instruction qui suit le mot Then attribue la couleur de son choix à la variable Brush.Color. Sauf à imposer des couleurs différentes, cette instruction va se répéter trois fois. Pour l'éviter, simplifier l'écriture du code et gagner en délai d'exécution, il suffit d'introduire Or.

Le code devient, pour les trois options :

If (CheckBox1.Checked And Ligne And Colonne) Or
(CheckBox3.Checked And Ligne) Or
(CheckBox4.Checked And Colonne) Then...

Pour les lignes, il est nécessaire de définir la couleur de Pen.Color, puis de décider du point de départ et de l'arrivée. Avec l'option Cadre, le code s'écrira :

If CheckBox2.Checked And Ligne And Colonne Then
begin
Largeur:=MaGrille.ColWidths[aCol]-2;
Hauteur:=MaGrille.RowHeights[aRow]-2;
MoveTo(aRect.Left, aRect.Top);
LineTo(aRect.Left+Largeur, aRect.Top);
LineTo(aRect.Left+Largeur, aRect.Top+Hauteur);
LineTo(aRect.Left, aRect.Top+Hauteur);
LineTo(aRect.Left, aRect.Top);
end;

Avec les options Horizontale et Verticale, le code devient à son tour :

If CheckBox5.Checked And Ligne Then
begin
MoveTo(0, cooY);
LineTo(MaGrille.Width, cooY);
end;
If CheckBox6.Checked And Colonne Then
begin
MoveTo(cooX, 0);
LineTo(cooX, MaGrille.Height);
end;

VI-3 - Remplissage de la grille

Dans l'état actuel du projet, les cases sont remplies avec leur numéro, et le fond de chaque case a conservé sa couleur d'origine, à l'exception des ligne et colonne fixes et des cases retenues par les options curseurs précédentes.

Les CheckBox 7 et 8 seront utilisées en exploitant leur propriété OnChange : chaque changement d'état déclenche une procédure qui réalisera l'effet recherché.

VI-3-A - Couleur de la grille

Dans le formulaire MonFormulaire, cliquer sur le composant CheckBox7. L'inspecteur d'objets fait apparaître ses propriétés ; dans l'onglet Evénements, cliquer sur OnChange et saisir ChangeCouleur, puis appuyer sur Entrer.

Dans l'éditeur de source apparaît la nouvelle procédure et compléter le code pour alterner entre l'affichage par défaut et la couleur de votre choix :

procedure TMonFormulaire.ChangeCouleur(Sender: TObject);
begin
With MaGrille do
begin
If Color=clWindow Then Color:=$00FEFFE6
Else Color:=clWindow;
end;
end;

Le test porte sur la couleur par défaut, clWindow. La couleur proposée en échange est un bleu très pâle, mais toute autre couleur claire fera l'affaire.

Pour modifier la couleur des cellules fixes, il faut utiliser la propriété FixedColor dont la valeur par défaut est clBtnFace.

VI-3-B - Texte des cellules

Dans le formulaire MonFormulaire, cliquer sur le composant CheckBox8. L'inspecteur d'objets fait apparaître ses propriétés ; dans l'onglet Evénements, cliquer sur OnChange et saisir ChangeRemplissage, puis appuyer sur Entrer.

Dans l'éditeur de source apparaît la nouvelle procédure ; compléter le code pour alterner entre l'affichage des numéros et l'affichage de nombres aléatoires :

Les affichages Caption sont modifiés systématiquement pour que l'utilisateur ait toujours un choix clair à sa disposition.

Le remplissage de la grille est maintenant affecté à une procédure spécialisée. Le code initialement inscrit dans la procédure CreationGrille peut être supprimé.
Mais en conséquence la grille apparaîtra vide au démarrage et il faudra cliquer sur Aléatoire pour provoquer son remplissage.

VI-4 - Bilan

Le projet avait pour objectif de créer un curseur réellement pratique dans une grille ; l'objectif est maintenant atteint.

Les mouvements de la souris sont suivis selon le souhait de l'utilisateur par la mise en surbrillance d'une ligne, d'une colonne, ou d'une case de six façons différentes.

Le code exploite cinq types d'événements différents et aboutit à un affichage clair et stable.

L'article suivant abordera les usages pratiques du composant StringGrid, avec la mise en valeur de cellules particulières, indépendamment de la position de la souris.

Voici le code de l'unité EssaiGrille.pas :

unit EssaiGrille;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, Fileutil, Lresources, Forms, Controls, Graphics, Dialogs,
Grids, StdCtrls;

type

{ TMonFormulaire }

TMonFormulaire = class(TForm)
Button1:   TButton;
Checkbox1: Tcheckbox;
Checkbox2: Tcheckbox;
Checkbox3: Tcheckbox;
Checkbox4: Tcheckbox;
Checkbox5: Tcheckbox;
Checkbox6: Tcheckbox;
Checkbox7: Tcheckbox;
Checkbox8: Tcheckbox;
MaGrille:  TStringGrid;
procedure Button1click(Sender: TObject);
procedure Changecouleur(Sender: TObject);
procedure Changeremplissage(Sender: TObject);
procedure Coordsouris(Sender: TObject; Shift: Tshiftstate; X, Y: integer);
procedure Creationformulaire(Sender: TObject);
procedure Dessingrille(Sender: TObject; Acol, Arow: integer;
Arect: Trect; Astate: Tgriddrawstate);
private
{ Private Declarations }
public
{ Public Declarations }
end;

var
MonFormulaire: TMonFormulaire;

var
sCol, sLig, cooX, cooY: integer;

implementation

{ TMonFormulaire }

procedure Tmonformulaire.Button1click(Sender: TObject);
begin
with MaGrille do
if Cells[1, 1] = '' then
Cells[1, 1] := 'Bonjour'
else
Cells[1, 1] := '';
end;

procedure Tmonformulaire.Changecouleur(Sender: TObject);
begin
with MaGrille do
begin
if Color = clWindow then
Color := $00FEFFE6
else
Color := clWindow;
end;
end;

procedure Tmonformulaire.ChangeRemplissage(Sender: TObject);
var
i, j: integer;
begin
with MaGrille do
for i := 1 to ColCount - 1 do
for j := 1 to RowCount - 1 do
if CheckBox8.Checked then
Cells[i, j] := IntToStr(i + (RowCount - 1) * (j - 1))
else
Cells[i, j] := IntToStr(1 + Random(10000));
if (CheckBox8.Caption = 'Numéros') then
CheckBox8.Caption := 'Aléatoire'
else
CheckBox8.Caption := 'Numéros';
end;

procedure Tmonformulaire.Coordsouris(Sender: TObject; Shift: Tshiftstate;
X, Y: integer);

begin
with MaGrille do
begin
cooX := X;
cooY := Y;
Cells[1, 2] := 'X =' + IntToStr(X);
Cells[1, 3] := 'Y =' + IntToStr(Y);
MouseToCell(X, Y, sCol, sLig);
Cells[0, 0] := 'C ' + IntToStr(sCol) + ' - L ' + IntToStr(sLig);
Repaint;
end;
end;

procedure Tmonformulaire.Creationformulaire(Sender: TObject);
var
i, j: integer;
begin
Randomize;
with MaGrille do
begin
for i := 1 to ColCount - 1 do
Cells[i, 0] := 'Col ' + IntToStr(i);
for i := 1 to RowCount - 1 do
Cells[0, i] := 'Lig ' + IntToStr(i);

for i := 1 to ColCount - 1 do
for j := 1 to RowCount - 1 do
Cells[i, j] := IntToStr(i + (RowCount - 1) * (j - 1));
//Cells[i,j]:=IntToStr(1+Random(10000));
end;
end;

procedure Tmonformulaire.Dessingrille(Sender: TObject; Acol, Arow: integer;
Arect: Trect; Astate: Tgriddrawstate);
var
Largeur, Hauteur: integer;
Ligne, Colonne:   boolean;
begin
Ligne   := aRow = sLig;
Colonne := aCol = sCol;
with MaGrille.Canvas do
begin
if (CheckBox1.Checked and Ligne and Colonne) or (CheckBox3.Checked and Ligne) or
(CheckBox4.Checked and Colonne) then
begin
Brush.Color := clYellow;
FillRect(aRect);
end;
if CheckBox2.Checked and Ligne and Colonne then
begin
Pen.Color := clRed;
Largeur   := MaGrille.ColWidths[aCol] - 2;
Hauteur   := MaGrille.RowHeights[aRow] - 2;
MoveTo(aRect.Left, aRect.Top);  //angle supérieur gauche
LineTo(aRect.Left + Largeur, aRect.Top);//1ère horizontale
LineTo(aRect.Left + Largeur, aRect.Top + Hauteur);//1ère verticale
LineTo(aRect.Left, aRect.Top + Hauteur);//2ème horizontale
LineTo(aRect.Left, aRect.Top);  //retour
end;

if CheckBox5.Checked and Ligne then
begin
Pen.Color := clRed;
MoveTo(0, cooY);
LineTo(MaGrille.Width, cooY);
end;
if CheckBox6.Checked and Colonne then
begin
Pen.Color := clRed;
MoveTo(cooX, 0);
LineTo(cooX, MaGrille.Height);
end;

end;
end;

initialization
{$I EssaiGrille.lrs}

end.