[Dephi][VCL]Carnet de plongées : TControlList, Jour 2 - Entrainement piscine
par
, 11/03/2021 à 15h26 (568 Affichages)
Ce billet fait suite à :
La découverte (snorkling)
Apnée
Première plongée
Aujourd'hui, pas de sortie en mer pour voir des poissons, un petit entrainement en piscine avec du matériel pro. On ne se refait pas, quand je vois ça d'accroché je ne peux pas ne pas revenir à mon ancienne profession.
En guise de piscine : votre disque dur. L'objectif, faire une sorte de browser d'images.
Comment va être composé notre interface utilisateur ?
Il va nous falloir de quoi sélectionner un répertoire, la possibilité d'avoir une liste des fichiers images et bien sûr le TControlList qui contiendra le nom du fichier et l'image réduite.
Je vous laisse vous équiper (reproduire le design) pour cette partie.
On commencera doucement par la fonctionnalité qui est de cacher ou montrer la liste : utilisation de l'évènement OnClick du CheckBox
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 procedure TForm1.CheckBox1Click(Sender: TObject); begin Memo1.Visible:=CheckBox1.Checked; end;
Premier gros oeuvre, sélectionner un répertoire. La VCL ne nous fourni pas de composant visuel pour le faire, par contre dans la VCL existe une fonction SelectDirectory qui va être parfaitement adaptée au besoin. J'en utiliserai sa seconde forme function SelectDirectory(const Caption: string; const Root: WideString; var Directory: string; Options: TSelectDirExtOpts; Parent: TWinControl): Boolean;
Première mise en place du chantier, une récupération des fichiers png existant dans le répertoire sélectionner.
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 procedure TForm1.SpeedButton1Click(Sender: TObject); var dir: String; begin if SelectDirectory('Choisissez le répertoire', '', dir, [sdshowEdit, sdShowShares, sdShowFiles], self) then begin edtDir.Text := dir; // c'est ici que nous récupérerons la liste de nos images, place du "CODE PRINCIPAL" end;
⚠ Comme cette liste sera utilisée dans au moins deux fonctions, il faut déclarer une variable FileList de type TArray<String> dans la partie privée de la forme.
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 // CODE PRINCIPAL ControlList1.Enabled := False; // désactiver le TControlList // récupérer la liste des fichiers images FileList := TDirectory.GetFiles(dir, '*.png'); // uniquement les png TDirectory est contenu dans l'unité System.IOUtils à déclarer dans la liste des uses if Memo1.Visible then begin Memo1.Lines.Clear; for var s: String in FileList do Memo1.Lines.Add(ExtractFileName(s)); end; // indiquer le nombre d'éléments que contiendra la liste ControlList1.ItemCount := Length(FileList); // activer la liste (ce qui lancera le onBeforeDrawItem) ControlList1.Enabled := True;
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 private { Déclarations privées } FileList: TArray<String>;
on n'oublie pas, bien sûr, ce que l'on a appris dans les billets précédents et l'on précode l'évènement OnDrawItem du TControlList.
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 procedure TForm1.ControlList1BeforeDrawItem(AIndex: Integer; ACanvas: TCanvas; ARect: TRect; AState: TOwnerDrawState); begin LblBrowser.Caption := TPath.GetFileNameWithoutExtension(FileList[AIndex]); imgBrowser.Picture.LoadFromFile(FileList[AIndex]); end;
Pas mal pour un premier résultat mais, lors de la sélection de tailles plus faibles, l'eau serait-elle trouble ? Non, il s'agit d'un crénelage dû au Stretch de la propriété du TImage.
Comment éviter ça ? Comme solution je me propose de récupérer la taille de l'image et, fonction de celle-ci changer la propriété Stretch.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 procedure TForm1.ControlList1BeforeDrawItem(AIndex: Integer; ACanvas: TCanvas; ARect: TRect; AState: TOwnerDrawState); begin if Length(FileList) = 0 then exit; // par précaution LblBrowser.Caption := TPath.GetFileNameWithoutExtension(FileList[AIndex]); // un peu plus q'un simple Stretch pour l'image ? // obtenir les informations fichier var vImage: Timage := TImage.Create(self); try vImage.AutoSize := True; vImage.Picture.LoadFromFile(FileList[AIndex]); imgBrowser.Stretch := (vImage.Height > imgBrowser.Height) OR (vImage.Width > imgBrowser.Width); imgBrowser.AutoSize:=not imgBrowser.Stretch; imgBrowser.Center:=not imgBrowser.Stretch; imgBrowser.Picture.LoadFromFile(FileList[AIndex]); finally vImage.Free; end; end;
Du coup, 16x16 c'est un peu petit. Il faudrait certainement améliorer ça mais je préfére passer à un autre stade : Ne pas en rester uniquement aux png mais montrer tout types d'images (du moins les plus courantes, bmp,png,jpg,jpeg,ico). Premier écueil (dans une piscine !) la fonctionTDirectory.GetFiles ne permet pas, dans son argument SearchPattern, de mettre plus d'un masque, il va falloir utiliser une de ses autres formes permettant l'ajout d'une fonction de type TFilterPredicate.
Utilisation FileList := TDirectory.GetFiles(dir, '*.*',aFilter); ou, en mode plus expert, en utilisant une méthode anonyme.
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 function aFilter(const Path: string; const SearchRec: TSearchRec): Boolean; // TFilterPredicate const extensions = '.png,.jpg,.jpeg,.bmp,.ico'; // extensions voulues begin result := extensions.Contains(ExtractFileExt(SearchRec.Name)); end;
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 FileList := TDirectory.GetFiles(dir, '*.*', function(const Path: string; const SearchRec: TSearchRec): Boolean const extensions = '.png,.jpg,.jpeg,.bmp,.ico'; // extensions voulues begin result := extensions.Contains(ExtractFileExt(SearchRec.Name)); end);
Petit incident de plongée. Pas de panique, il suffit d'ajouter dans la listes des uses l'unité VCL.Imaging.jpeg, cela aurait déjà pu se produire avec les fichiers .png mais, par chance l'utilisation de l'unité VCL.Imaging.pngimage était, elle, déclarée certainement lors du design, une chanceEnvoyé par Erreur
.
Un peu de débriefing pour clore l'exercice :
- L'utilisation des jpg ralenti considérablement le programme. Un passage par des vignettes pourrait être la solution.
- Certaines icones (.ico), s'affichent mal, une question de tailles mal récupérées.
- L'API SelectDirectory coince un peu aux entournures, le dernier répertoire utilisé, ce qui serait pratique, n'est pas mémorisé.