Premiers liens▲
Introduction▲
Notre liste de mots peut maintenant faire l'objet d'une consultation aisée, mais son utilité reste modeste puisque l'accès à un mot donné, aussi rapide soit-il, débouche sur… le néant ! Dans ce chapitre, nous allons voir comment attacher une information à ce mot, la stocker et la retrouver.
Environnement▲
Chapitre 5… Adoptons cet indice pour cette phase du projet : il n'y aura pas de répertoire Lex4.
Créons un répertoire Lex5 et recopions dans ce nouveau répertoire tous les fichiers du répertoire Lex3 utilisé précédemment. Pour éviter toute difficulté ultérieure, suivez la check-list :
- ouvrir pLex3.lpi dans Lex5 avec Lazarus ;
- enregistrer uLex3.pas sous le nom de uLex5.pas ;
- accepter la suppression des références à uLex3.pas ;
- enregistrer pLex3.pas sous le nom de pLex5.pas ;
- renommer la fenêtre Form1 : Lex3 devient Lex5 ;
- dans le répertoire Lex5 supprimer les anciens fichiers contenant la mention Lex3 ;
- relancer le projet en ouvrant pLex5.lpi avec Lazarus ;
- renommer l'interface graphique de Lex3 Ã Lex5.
Nous retrouvons le projet dans l'état où nous l'avions laissé, et les modifications que nous allons effectuer n'affecteront pas l'étape précédente conservée dans le répertoire Lex3.
Code▲
Pour alléger l'écriture du code, nous allons remplacer dans l'unité uLex5 toutes les occurrences de « listeMots.Count » par « nMots ».
Dans la procédure FormCreate, nous initions la variable par l'instruction :
nMots:= listeMots.Count ;
Nous complétons enfin la liste des variables globales (avant le bloc implementation) par la déclaration :
iMot, nMots : integer ;
Un essai d'exécution (petit triangle vert) pour vérifier que tout va bien…
Au plan graphique, un espace supplémentaire est nécessaire. Nous avons déjà vu que ce n'était pas compliqué.
Dans la fenêtre Lex5, clic droit sur la ligne en grisé, à droite de l'onglet Balayage. Dans le menu contextuel, choisissez Ajouter une page.
Dans la fenêtre Inspecteur d'objets, onglet Propriétés, remplacez TabSheet (ou Page, selon le composant utilisé) par Info, à la ligne Caption.
Le nouvel espace de travail est disponible.
Événement TrackBar1▲
Lors de la mise en place du composant TrackBar, qui donne un aperçu de la position du mot dans la liste principale, nous avons choisi d'utiliser l'événement onChange pour actualiser la relation entre la position du curseur et la valeur de l'index.
Il apparaît que des interférences peuvent perturber le balayage de la liste, notamment lors de l'utilisation d'un filtre.
Pour éviter ce type de problème dans la suite de notre projet, nous décidons d'abandonner cette procédure et d'utiliser à la place l'événement MouseUp, qui se déclenche tout simplement dès que le bouton de la souris est relâché à la fin du déplacement du curseur.
Voici la marche à suivre :
- cliquer sur le composant TrackBar dans l'onglet Balayage ;
- dans l'inspecteur d'objets, onglet Événements, ligne OnMouseUp, cliquer sur les trois points ;
- dans l'éditeur de source, entre les mots begin et end, recopier les instructions qui figuraient dans la procédure TrackBar1Change :
procedure
TForm1.TrackBar1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer
);
begin
iMot := Round(TrackBar1.Position*nMots/1000
);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
Toujours dans l'éditeur de source, supprimez complètement l'ancienne procédure, y compris sa déclaration avant implémentation. Dans l'inspecteur d'objets, onglet Événement, supprimez toute référence dans la ligne OnChange.
Un clic sur le petit triangle vert, vérifiez que votre curseur fonctionne bien…
Le conteneur de la liste de mots (StringList) possède une structure dotée de nombreuses propriétés dont certaines permettent de lier un élément de la liste à une information externe :
- utilisation du couple Nom-Valeur ;
- utilisation de la propriété Object.
Nous allons aborder leur mise en œuvre pour les évaluer.
Couple Nom-Valeur▲
C'est la solution la plus simple : elle est précâblée dans la liste, il est donc inutile d'entrer dans le cambouis. Pratique pour faire correspondre le nom d'une personne avec un numéro d'identification, une commune avec un code postal, etc.
Pour l'utiliser, il suffit d'affecter une chaîne quelconque à un élément de la liste.
Supposons que l'on s'intéresse au mot « a » et que l'on veuille le relier au mot « voyelle », il suffit d'écrire, en remplacement du premier mot :
'a=voyelle'
pour établir la liaison.
À chaque fois que l'on consultera le premier mot, le lien sera activé.
Il ne s'agit pas d'affecter une valeur à une variable.
Le signe « = » est le caractère de séparation par défaut.
On peut en changer, par exemple avec « > ».
Dans ce cas, il faudra ajouter, dans la procédure de création de la liste, l'instruction :
listeMots.NameValueSeparator:='>' ;
Notons que la propriété Value est alphanumérique, ce qui permet d'introduire, au choix, des expressions numériques ou littérales.
Dans l'onglet Info, nous ajoutons successivement :
- un Label (Propriété Font/Size portée à 14) ;
- un Memo (Propriété ScrollBars portée à ssAutoVertical) ;
- un Edit ;
- et un bouton (Propriété Caption portée à Value).
Après divers agencements, l'onglet Info se présente sensiblement comme ceci :
Valeur littérale▲
Un double-clic sur le bouton Value crée le squelette de la procédure événement dans l'éditeur de source. Entre les mots begin et end, on place l'instruction :
MAJInfo ;
procedure
TForm1.Button3Click(Sender: TObject);
begin
MAJInfo;
end
;
Pour créer la procédure MAJInfo, nous commençons par la déclarer en tête de l'unité, dans la classe Tform, à la suite des autres procédures. Un appui sur les touches Ctrl+Maj+C crée la structure recherchée ; entre les mots begin et end, nous recopions :
procedure
TForm1.MAJInfo;
begin
listeMots[0
] := 'a=voyelle'
;
Label3.Caption:= listeMots.Names[0
];
Edit1.Caption:= listeMots.Values[listeMots.Names[0
]];
Memo2.Append('en mémoire : '
+listeMots[0
]);
end
;
La première instruction institue le lien voulu, en remplacement de la chaîne qui existait auparavant.
La seconde affiche la partie gauche de l'élément (propriété Names).
La troisième affiche la partie droite (propriété Values) ; il faut remarquer que l'index n'est plus numérique, c'est la partie gauche de l'élément qui constitue le nouvel index.
La quatrième ligne affiche l'élément au complet.
Pour vérifier ces indications, cliquez sur le petit triangle vert, puis sur le bouton Value.
Utilisez le balayage dans l'onglet précédent : après un aller et retour sur le mot courant, on peut constater que la chaîne d'origine a bien été remplacée par un binôme.
Les autres chaînes n'ont pas été modifiées et s'affichent correctement. Dans l'onglet Info, le mot titre est bien « a » qui est bien relié au mot « voyelle ».
- La procédure MAJBalayage peut être modifiée pour que soit affichée en titre non pas l'enregistrement complet correspondant à l'index iMot, mais seulement sa partie gauche (Names[iMot]).
- L'enregistrement de la liste « enrichie » est aisé : il suffit d'utiliser l'instruction SaveToFile().
En cas de problème, remplacez le fichier corrompu par celui qui est resté dans le répertoire Lex3.
Valeur numérique▲
L'intérêt du lien entre le mot « a » et l'information « voyelle » est incontestable, mais… limité. D'autant qu'il n'est pas réversible : en l'état, si on consulte le mot « voyelle », aucune indication n'est donnée quant à son lien avec le mot « a ».
Et si, par excès de zèle, on décide d'établir la réciprocité au moyen de l'instruction 'voyelle=a', nous arrivons à une absurdité, puisque « a » n'est pas la seule voyelle, et que notre système ne permet pas l'établissement de liens multiples…
Un lien numérique est autrement plus puissant : le nombre éventuellement détecté peut servir d'index dans une table auxiliaire qui regrouperait une collection d'objets quelconques, par exemple des textes, des images, des sons, etc.
Nous allons voir comment procéder avec quatre mémos qui seront affectés respectivement aux mots « couleur », « teinte », « vert » et « rouge »(le désordre est intentionnel).
Saisie des mémos▲
Une consultation rapide de Wikipedia nous donne un peu de matière (totalement dépourvue d'humour, désolé…) pour nos mémos. Chaque texte va être stocké(10) dans une chaîne (string) et les quatre chaînes dans une liste (StringList). Pour commencer, il faut déclarer la nouvelle variable globale listeInfo : TStringList avant implementation :
Nous créons la procédure regInfo qui se chargera de placer les chaînes en mémoire :
- déclarez procedure regInfo ; avant implementation ;
- appuyez sur Ctrl+Maj+C pour créer le squelette de la procédure ;
- entre les mots clés begin et end recopiez les instructions :
procedure
TForm1.regInfo;
begin
listeInfo := TstringList.Create;
//indice 0
listeInfo.Add('Resa'
);
//indice 1
listeInfo.Add('La couleur est la perception subjective qu''a un animal '
+'d''une ou plusieurs fréquences d''ondes lumineuses, '
+'avec une (ou des) amplitude(s) donnée(s), au travers de sa vision oculaire.'
);
//indice 2
listeInfo.Add('Une teinte est la forme pure d''une couleur, '
+'c''est-Ã -dire sans adjonction de blanc ou de noir qui permettent d''obtenir '
+'ses nuances. Les teintes sont visualisées sur le pourtour d''une roue chromatique.'
);
//indice 3
listeInfo.Add('La perception de la couleur verte est évoquée par la lumière d''un'
+' spectre dominé par de l''énergie avec une longueur d''onde d''environ 520-570 nm.'
);
//indice 4
listeInfo.Add('Le rouge est, sur le cercle chromatique, une des trois couleurs '
+'(avec le jaune et le bleu) primaires. Pour la théorie ondulatoire de la lumière, '
+'son rayonnement se situe entre l''orange et l''infrarouge du spectre électromagnétique.'
);
end
;
Les indices 1 à 4 correspondent aux chaînes associées aux mots « couleur », « teinte », « vert » et « rouge ».
Une lecture attentive permet de remarquer que l'indice 0 est utilisé implicitement pour adresser le mot « Resa »qui ne sert à rien… sinon à éviter les pièges de l'indice zéro.
Notez à nouveau que l'ordre des mots est indifférent.
Pour automatiser cette procédure, nous allons l'ajouter à la liste des tâches réalisées lors de la création de la fiche :
procedure
TForm1.FormCreate(Sender: TObject);
begin
listeMots := TStringList.Create;
LireFichier(listeMots);
nMots:= listeMots.Count;
Memo1.Append('Premier mot : '
+listeMots[0
]);
Memo1.Append('Dernier mot : '
+listeMots[nMots-1
]);
iMot := 0
;
regInfo;
MAJAffichage;
MAJBalayage;
end
;
Un clic sur le bouton Value doit réaliser les liens entre les mots-clés et les chaînes correspondantes :
procedure
TForm1.Button3Click(Sender: TObject);
begin
listeMots[listeMots.IndexOf('couleur'
)] := 'couleur=1'
;
listeMots[listeMots.IndexOf('teinte'
)] := 'teinte=2'
;
listeMots[listeMots.IndexOf('vert'
)] := 'vert=3'
;
listeMots[listeMots.IndexOf('rouge'
)] := 'rouge=4'
;
end
;
La procédure modifie la liste de mots (liste principale) en ajoutant aux mots choisis le numéro du texte les concernant, mots et numéros étant séparés par le signe « = ».
Cliquez sur le petit triangle vert pour exécuter le programme :
- la création de la fenêtre provoque la mise en mémoire de quatre textes ;
- un clic sur le bouton Value remplace les mots choisis par le couple mot=index.
Dans l'onglet Balayage, cherchez un des mots-clés, par exemple « teinte » et vérifiez que le mémo correspondant s'affiche.
Affichage▲
L'onglet Balayage permet d'atteindre n'importe quel mot de la liste. Nous allons le compléter pour qu'il affiche, à côté du mot, le mémo qui lui est affecté, s'il existe.
Dans le menu Lazarus, cliquez sur le composant TMemo, puis cliquez sur l'onglet Balayage et placez le composant à droite du zoom ; dans l'onglet Propriétés de l'Inspecteur d'objets, ligne ScrollBars, choisissez ssAutoVertical pour faire apparaître un ascenseur.
Les procédures MAJBalayage et MAJInfo sont modifiées comme suit :
procedure
TForm1.MAJBalayage;
var
i : integer
;
begin
Label2.Caption:=AnsiToUTF8(listeMots[iMot]);
Label3.Caption:= Label2.Caption;
TrackBar1.Position:= Round(iMot*1000
/nMots);
AffListe.Clear;
for
i := 0
to
10
do
AffListe.Items.Add(AnsiToUTF8(listeMots[(iMot-5
+ i
+ nMots) mod
nMots]));
AffListe.Selected[5
] := True
;
Memo3.Clear;
if
(Pos('='
, listeMots[iMot])>0
) then
MAJInfo;
end
;
procedure
TForm1.MAJInfo;
begin
//listeMots[0] := 'a=voyelle';
Label3.Caption:= listeMots.Names[iMot];
Edit1.Caption:= listeMots.Values[Label3.Caption];
Memo2.Clear;
Memo2.Append(listeInfo[StrToInt(Edit1.Caption)]);
Label2.Caption:= listeMots.Names[iMot];
Memo3.Append(listeInfo[StrToInt(Edit1.Caption)]);
end
;
Le programme est opérationnel.
Pour le vérifier, clic sur le petit triangle vert. Dans l'onglet Info, clic sur le bouton Value pour lier les mémos à la liste principale.
Dans l'onglet Balayage, actionnez le curseur et les flèches de navigation, en utilisant le zoom si nécessaire, et vérifiez que, pour chacun des mots « couleur », « teinte », « vert » et « rouge », le mémo correspondant s'affiche.
Navigation▲
La recherche de nos mots « renseignés » se révèle fastidieuse : la liste principale est immense et il faut beaucoup de manœuvres pour les retrouver.
Un filtre va régler ce problème.
Dans l'onglet Balayage, on ajoute un CheckBox, propriété Caption modifiée avec « Filtre ».
Dans l'onglet Événements, ligne OnChange, cliquez sur les trois points pour provoquer la création de la procédure CheckBox1Change, où l'on insérera les lignes :
if CheckBox1.Checked then CheckBox1.Caption := 'Avec filtre'
else CheckBox1.Caption := 'Sans filtre';
La procédure UpDown2 est modifiée pour traiter le cas où la case est cochée (filtre actif) :
procedure
TForm1.UpDown2Click(Sender: TObject; Button: TUDBtnType);
begin
if
CheckBox1.Checked then
repeat
inc(iMot);
until
(iMot=nMots) or
(Pos('='
, listeMots[iMot])>0
)
else
if
Button=btNext then
Inc(iMot, UpDown2.Increment)
else
Dec(iMot, UpDown2.Increment);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
Si une flèche est cliquée alors que le filtre est actif, la liste de mots est balayée automatiquement jusqu'à ce qu'un mot « renseigné » (décelé par la présence du signe « = ») apparaisse.
Relancez le programme. Dans l'onglet Info, cliquez sur le bouton Value pour établir les liens. Dans l'onglet Balayage, activez le filtre et… naviguez.
Développements complémentaires▲
Chaque mot peut maintenant être relié au texte de son choix.
Par exemple, le mot « rouge » est présenté avec une notice immédiatement accessible.
Mais il reste à faire pour que le programme soit réellement opérationnel : il manque notamment les procédures d'édition (modification, suppression, ajout, enregistrement) des mémos.
Notez que la suppression d'un lien au niveau de la liste principale devra être suivie par sa suppression du mémo correspondant dans la liste secondaire.
Ces étapes sont plus simples, et nous aurons l'occasion d'y revenir.
Propriété Object▲
Pour simplifier, nous dirons que cette propriété fonctionne comme la précédente, sous réserve de remplacer l'affectation
listeMots[listeMots.IndexOf('rouge')] := 'rouge=4' ;
par l'instruction
listeMots.Objects[listeMots.IndexOf('rouge')]:= Tobject(4)Â ;
Dans le premier cas, le lien s'établit sous forme d'une chaîne de caractères qui remplace (complète) la chaîne de caractères existante ; dans le second, le lien est réalisé par un pointeur : la chaîne de caractères reste inchangée mais se trouve liée à un « objet ». Là débute un aspect de l'informatique un peu plus complexe, celui des pointeurs(11). Notre projet a pour ambition de rendre toutes les opérations facilement accessibles, donc l'expérimentation restera succincte.
Rappelons, pour commencer, que le lien peut viser n'importe quel type d'information, que ce soit des images, du son, des fichiers PDF… Ici, nous reprendrons l'adressage de texte.
Saisie des mémos▲
Sur l'interface graphique, onglet Info, nous ajoutons un bouton, propriété Caption portée à Object.
Un double-clic sur ce composant crée la structure de la procédure :
procedure
TForm1.Button4Click(Sender: TObject);
begin
listeMots.Objects[listeMots.IndexOf('couleur'
)] := TObject(1
);
listeMots.Objects[listeMots.IndexOf('teinte'
)] := TObject(2
);
listeMots.Objects[listeMots.IndexOf('vert'
)] := TObject(3
);
listeMots.Objects[listeMots.IndexOf('rouge'
)] := TObject(4
);
end
;
En somme, c'est la même procédure que pour le bouton Value, avec les modifications propres aux liens-objets.
Notez encore que l'affectation des objets se fait sans tenir compte de l'ordre alphabétique des mots.
Affichage▲
Les procédures MAJBalayage et MAJInfo sont modifiées comme suit :
procedure
TForm1.MAJBalayage;
var
i : integer
;
begin
Label2.Caption:=AnsiToUTF8(listeMots[iMot]);
Label3.Caption:= Label2.Caption;
//Label2.Caption:=AnsiToUTF8(listeMots.Names[iMot]);
TrackBar1.Position:= Round(iMot*1000
/nMots);
AffListe.Clear;
for
i := 0
to
10
do
AffListe.Items.Add(AnsiToUTF8(listeMots[(iMot-5
+ i + nMots) mod
nMots]));
AffListe.Selected[5
] := True
;
Memo3.Clear;
if
(Pos('='
, listeMots[iMot])>0
) then
MAJInfo;
if
listeMots.Objects[iMot]<> nil
then
MAJInfo;
end
;
procedure
TForm1.MAJInfo;
begin
Label3.Caption:= listeMots.Names[iMot];
//Edit1.Caption:= listeMots.Values[Label3.Caption];
//Memo2.Clear;
//Memo2.Append(listeInfo[StrToInt(Edit1.Caption)]);
//Label2.Caption:= listeMots.Names[iMot];
//Memo3.Append(listeInfo[StrToInt(Edit1.Caption)]);
Memo3.Append(listeInfo[integer
(listeMots.Objects[iMot])]);
end
;
Notez la dernière ligne de la première procédure : elle contrôle l'existence d'un objet lié à la chaîne d'index iMot. S'il n'y a pas d'objet, le contrôle rencontre la valeur nil, c'est-à -dire rien. Dans le cas contraire, elle déclenche la procédure d'affichage.
Celle-ci est complétée par une ligne qui calcule la valeur de l'index (cette valeur est le contenu de l'objet) et affiche le texte correspondant à cet index.
Les lignes concernant les couples name-value sont désactivées car les deux méthodes sont - en l'état - incompatibles.
Pour essayer, un clic sur le petit triangle vert dans le menu Lazarus. Un clic sur le bouton Object dans l'onglet Info, et navigation dans l'onglet Balayage. Les mémos s'affichent.
Filtre▲
L'exécution montre que la recherche et l'affichage des mémos sont aussi fastidieux qu'avec la méthode précédente, d'autant que le filtre se révèle sans effet.
Pour le réactiver, il suffit de rajouter un contrôle dans la procédure UpDown2Click :
procedure
TForm1.UpDown2Click(Sender: TObject; Button: TUDBtnType);
begin
if
CheckBox1.Checked then
repeat
inc(iMot);
until
(iMot=nMots) or
(Pos('='
, listeMots[iMot])>0
)
or
(listeMots.Objects[iMot]<> nil
)
else
if
Button=btNext then
Inc(iMot, UpDown2.Increment)
else
Dec(iMot, UpDown2.Increment);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
Si la case Filtre est cochée, le balayage de la liste se poursuit automatiquement jusqu'à ce que le mot soit lié à un objet.
Essayez…
Compatibilité▲
A priori, rien n'indique qu'une méthode neutralise l'autre. Le mieux est quand même de le vérifier.
Pour cela, nous allons doubler la mise en mémoire de texte et l'affichage :
- dans l'onglet Balayage, nous ajoutons un memo avec ascenseur vertical ;
- nous ajoutons la variable globale qui recevra les textes objets :
listeObj : TstringList ;
- dans la procédure FormCreate nous ajoutons l'instruction :
regObj ;
- la procédure regObj(12) placera en mémoire les textes à lier sous forme d'objets :
procedure
TForm1.regObj;
begin
listeObj := TStringList.Create;
listeObj.Add('ResaObj'
); //index 0
listeObj.Add('Ceci est un complément d''information pour le mot couleur'
);
listeObj.Add('Voici une information qui sera liée au mot violet'
);
end
;
- Et nous scindons l'affichage en deux parties dédiées, ce qui fait intervenir trois procédures(13) :
procedure
TForm1.MAJBalayage;
var
i : integer
;
begin
Label2.Caption:=AnsiToUTF8(listeMots[iMot]);
Label3.Caption:= Label2.Caption;
//Label2.Caption:=AnsiToUTF8(listeMots.Names[iMot]);
TrackBar1.Position:= Round(iMot*1000
/nMots);
AffListe.Clear;
for
i := 0
to
10
do
AffListe.Items.Add(AnsiToUTF8(listeMots[(iMot-delta + i
+ nMots) mod
nMots]));
AffListe.Selected[delta] := True
;
Memo3.Clear;
Memo4.Clear;
if
(Pos('='
, listeMots[iMot])>0
) then
MAJInfo;
if
listeMots.Objects[iMot]<> nil
then
MAJObj;
end
;
procedure
TForm1.MAJInfo;
begin
Label3.Caption:= listeMots.Names[iMot];
Edit1.Caption:= listeMots.Values[Label3.Caption];
Memo2.Clear;
Memo2.Append(listeInfo[StrToInt(Edit1.Caption)]);
Label2.Caption:= listeMots.Names[iMot];
Memo3.Append(listeInfo[StrToInt(Edit1.Caption)]);
//Memo3.Append(listeInfo[integer(listeMots.Objects[iMot])]);
end
;
procedure
TForm1.MAJObj;
begin
Memo4.Append(listeObj[integer
(listeMots.Objects[iMot])]);
end
;
Enfin, les instructions propres au bouton Object doivent être modifiées :
procedure
TForm1.Button4Click(Sender: TObject);
begin
listeMots.Objects[listeMots.IndexOf('couleur'
)] := TObject(1
);
listeMots.Objects[listeMots.IndexOf('violet'
)] := TObject(2
);
//listeMots.Objects[listeMots.IndexOf('vert')] := TObject(3);
//listeMots.Objects[listeMots.IndexOf('rouge')] := TObject(4);
end
;
Un clic sur le petit triangle vert pour lancer l'exécution. Dans l'onglet Info, cliquez sur le bouton Object pour établir les liens entre les mots et les textes-objets. Dans l'onglet Balayage, actionnez le filtre et balayez : les textes apparaissent dans le nouveau mémo, pour les mots « couleur » et « violet ».
Donc le fonctionnement est correct pour la propriété Object.
Revenez sur l'onglet Info, cliquez sur le bouton Value. Reprenez le balayage : les textes-values s'affichent correctement, accompagnés des textes-objets : les liens sont donc validés sous les deux formes simultanément.
Mais…
Arrêtez le programme, relancez-le et chargez les textes dans l'ordre inverse : Value d'abord, Object ensuite ; cette fois, il y a une erreur :
Pourquoi ?
La réponse est très simple : nous avons vu que le lien Value s'établissait en complétant la chaîne d'origine par un signe « = » suivi d'une autre chaîne. Donc lorsque le lien Object va chercher sa cible, il ne pourra pas la trouver puisqu'elle aura été modifiée.
Ce problème va-t-il compromettre définitivement la compatibilité entre les deux méthodes ?
Nous nous souvenons que la chaîne d'origine se retrouve sous forme de Value. Donc nous allons tout simplement remplacer la fonction
listeMots.IndexOf()
par la fonction plus élaborée
chercheValue()
qui peut s'écrire ainsi(14) :
function
TForm1.chercheValue(motAchercher: string
): integer
;
var
i : integer
;
begin
i := 0
;
chercheValue := listeMots.IndexOf(motAchercher);
if
chercheValue<0
then
repeat
inc(i)
until
(i = nMots) or
(listeMots.Names[i] = motAchercher);
if
listeMots.Names[i]=motAchercher then
chercheValue := i;
end
;
Nous corrigeons la procédure qui établit les liens-objets :
procedure
TForm1.Button4Click(Sender: TObject);
begin
listeMots.Objects[chercheValue('couleur'
)] := TObject(1
);
listeMots.Objects[chercheValue('violet'
)] := TObject(2
);
end
;
Relancez l'exécution en chargeant (onglet Info) les liens Value, puis les liens Object. Dans l'onglet Balayage, actionnez le filtre et naviguez…
Impeccable !
Nos liens Value et Object cohabitent parfaitement.
Conclusion▲
Nous disposons maintenant de deux méthodes pour attacher à chaque mot toutes sortes d'informations que nous pourrions désirer.
En gros, on peut dire que les deux méthodes sont équivalentes en termes de mise en œuvre.
- La première surcharge la liste principale avec une chaîne de deux à sept octets (depuis '=1' jusqu'à '=900000') si le nombre de liens reste inférieur à un million(15). Pour déterminer la partie droite de la chaîne, il faut indiquer la partie gauche, qui est une chaîne de caractères.
- La seconde utilise pour chaque lien un pointeur, qui occupe quatre octets. Les affichages sont simplifiés puisque le signe « = » et l'index n'apparaissent pas dans la liste principale. Pour déterminer le pointeur, il faut indiquer la position de la chaîne dans la liste principale, qui est un entier.
Resterait à analyser les performances au niveau des temps d'accès et occupation de la mémoire, sans compter les compléments d'enregistrement et d'édition déjà mentionnés. Mais…
Mais il faut reconnaître que l'avancée est bien mince au regard des performances offertes par les dictionnaires en ligne : chacun de nos mots peut être relié à une information et une seule (ou deux en combinant les deux méthodes), ce qui largement insuffisant.
Il est donc nécessaire de sortir des solutions « précâblées  », et c'est ce que nous ferons dans le prochain chapitre.
Âge : ne reste pas longtemps ingrat.
Tristan Bernard
Pour l'instant, l'unité uLex5 se présente comme suit :
unit
uLex5;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, ComCtrls, uDisque;
type
{ TForm1 }
TForm1 = class
(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
CheckBox1: TCheckBox;
Edit1: TEdit;
Edit2: TEdit;
Label3: TLabel;
Memo2: TMemo;
Memo3: TMemo;
Memo4: TMemo;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
TabSheet2: TTabSheet;
Zoom: TGroupBox;
Label1: TLabel;
Label2: TLabel;
AffListe: TListBox;
Memo1: TMemo;
PageControl1: TPageControl;
Page1: TTabSheet;
TabSheet1: TTabSheet;
TrackBar1: TTrackBar;
UpDown1: TUpDown;
UpDown2: TUpDown;
procedure
AffListeClick(Sender: TObject);
procedure
Button1Click(Sender: TObject);
procedure
Button2Click(Sender: TObject);
procedure
Button3Click(Sender: TObject);
procedure
Button4Click(Sender: TObject);
procedure
CheckBox1Change(Sender: TObject);
procedure
FormCreate(Sender: TObject);
procedure
Recherche(rechMot: string
);
procedure
TrackBar1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer
);
procedure
UpDown1Click(Sender: TObject; Button: TUDBtnType);
procedure
MAJAffichage;
procedure
MAJBalayage;
procedure
UpDown2Click(Sender: TObject; Button: TUDBtnType);
procedure
ZoomMouseLeave(Sender: TObject);
procedure
MAJInfo;
procedure
regInfo;
procedure
regObj;
procedure
MAJObj;
function
chercheValue(motAchercher : string
) : integer
;
private
{ private declarations }
public
{ public declarations }
end
;
const
delta=5
;
var
Form1: TForm1;
listeMots, listeInfo, listeObj : TstringList;
iMot, nMots : integer
;
implementation
{$R *.lfm}
{ TForm1 }
procedure
TForm1.Button1Click(Sender: TObject);
begin
listeMots.Free;
Application.Terminate;
end
;
procedure
TForm1.AffListeClick(Sender: TObject);
begin
iMot := (iMot -delta + AffListe.ItemIndex + nMots) mod
nMots;
MAJBalayage;
end
;
procedure
TForm1.Button2Click(Sender: TObject);
begin
Recherche(Edit2.Caption);
end
;
procedure
TForm1.Button3Click(Sender: TObject);
begin
//MAJInfo;
listeMots[listeMots.IndexOf('couleur'
)] := 'couleur=1'
;
listeMots[listeMots.IndexOf('teinte'
)] := 'teinte=2'
;
listeMots[listeMots.IndexOf('vert'
)] := 'vert=3'
;
listeMots[listeMots.IndexOf('rouge'
)] := 'rouge=4'
;
end
;
procedure
TForm1.Button4Click(Sender: TObject);
begin
listeMots.Objects[chercheValue('couleur'
)] := TObject(1
);
listeMots.Objects[chercheValue('violet'
)] := TObject(2
);
end
;
procedure
TForm1.CheckBox1Change(Sender: TObject);
begin
if
CheckBox1.Checked then
CheckBox1.Caption := 'Avec filtre'
else
CheckBox1.Caption := 'Sans filtre'
;
end
;
procedure
TForm1.FormCreate(Sender: TObject);
begin
listeMots := TStringList.Create;
LireFichier(listeMots);
nMots:= listeMots.Count;
Memo1.Append('Premier mot : '
+listeMots[0
]);
Memo1.Append('Dernier mot : '
+listeMots[nMots-1
]);
iMot := 0
;
regInfo;
regObj;
MAJAffichage;
MAJBalayage;
end
;
procedure
TForm1.MAJBalayage;
var
i : integer
;
begin
Label2.Caption:=AnsiToUTF8(listeMots[iMot]);
Label3.Caption:= Label2.Caption;
//Label2.Caption:=AnsiToUTF8(listeMots.Names[iMot]);
TrackBar1.Position:= Round(iMot*1000
/nMots);
AffListe.Clear;
for
i := 0
to
10
do
AffListe.Items.Add(AnsiToUTF8(listeMots[(iMot-delta + i
+ nMots) mod
nMots]));
AffListe.Selected[delta] := True
;
Memo3.Clear;
Memo4.Clear;
if
(Pos('='
, listeMots[iMot])>0
) then
MAJInfo;
if
listeMots.Objects[iMot]<> nil
then
MAJObj;
end
;
procedure
TForm1.UpDown2Click(Sender: TObject; Button: TUDBtnType);
begin
if
CheckBox1.Checked then
repeat
inc(iMot);
until
(iMot=nMots) or
(Pos('='
, listeMots[iMot])>0
)
or
(listeMots.Objects[iMot]<> nil
)
else
if
Button=btNext then
Inc(iMot, UpDown2.Increment)
else
Dec(iMot, UpDown2.Increment);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
procedure
TForm1.ZoomMouseLeave(Sender: TObject);
begin
if
RadioButton1.Checked then
UpDown2.Increment := 1
else
if
RadioButton2.Checked then
UpDown2.Increment := 10
else
if
RadioButton3.Checked then
UpDown2.Increment := 100
else
if
RadioButton4.Checked then
UpDown2.Increment := 1000
;
end
;
procedure
TForm1.MAJInfo;
begin
Label3.Caption:= listeMots.Names[iMot];
Edit1.Caption:= listeMots.Values[Label3.Caption];
Memo2.Clear;
Memo2.Append(listeInfo[StrToInt(Edit1.Caption)]);
Label2.Caption:= listeMots.Names[iMot];
Memo3.Append(listeInfo[StrToInt(Edit1.Caption)]);
//Memo3.Append(listeInfo[integer(listeMots.Objects[iMot])]);
end
;
procedure
TForm1.regInfo;
begin
listeInfo := TStringList.Create;
listeInfo.Add('Resa'
);
listeInfo.Add('La couleur est la perception subjective qu''a un animal '
+'d''une ou plusieurs fréquences d''ondes lumineuses, '
+'avec une (ou des) amplitude(s) donnée(s), au travers de sa vision oculaire.'
);
listeInfo.Add('Une teinte est la forme pure d''une couleur, '
+'c''est-Ã -dire sans adjonction de blanc ou de noir qui permettent d''obtenir '
+'ses nuances. Les teintes sont visualisées sur le pourtour d''une roue chromatique.'
);
listeInfo.Add('La perception de la couleur verte est évoquée par la lumière d''un'
+' spectre dominé par de l''énergie avec une longueur d''onde d''environ 520-570 nm.'
);
listeInfo.Add('Le rouge est, sur le cercle chromatique, une des trois couleurs '
+'(avec le jaune et le bleu) primaires. Pour la théorie ondulatoire de la lumière, '
+'son rayonnement se situe entre l''orange et l''infrarouge du spectre électromagnétique.'
);
end
;
procedure
TForm1.regObj;
begin
listeObj := TStringList.Create;
listeObj.Add('ResaObj'
);
listeObj.Add('Ceci est un complément d''information pour le mot couleur'
);
listeObj.Add('Voici une information qui sera liée au mot violet'
);
end
;
procedure
TForm1.MAJObj;
begin
Memo4.Append(listeObj[integer
(listeMots.Objects[iMot])]);
end
;
function
TForm1.chercheValue(motAchercher: string
): integer
;
var
i : integer
;
begin
i := 0
;
chercheValue := listeMots.IndexOf(motAchercher);
if
chercheValue<0
then
repeat
inc(i)
until
(i = nMots) or
(listeMots.Names[i] = motAChercher);
if
listeMots.Names[i]=motAChercher then
chercheValue := i;
end
;
procedure
TForm1.TrackBar1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer
);
begin
iMot := Round(TrackBar1.Position*nMots/1000
);
iMot := (iMot + nMots) mod
nMots;
MAJBalayage;
end
;
procedure
TForm1.Recherche(rechMot: string
);
var
iMot : integer
;
begin
iMot := listeMots.IndexOf(rechMot);
if
iMot >= 0
then
Label1.Caption:= listeMots[iMot]
else
Label1.Caption:= 'échec'
;
Memo1.Append('Index '
+IntToStr(iMot));
end
;
procedure
TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
if
Button=btNext then
Inc(iMot)
else
Dec(iMot);
iMot := iMot + nMots mod
nMots;
MAJAffichage;
end
;
procedure
TForm1.MAJAffichage;
begin
Label1.Caption:=listeMots[iMot];
Edit2.Caption:= ''
;
Memo1.Append('Index '
+IntToStr(iMot));
end
;
end
.