J'ai eu du mal à m'en empêcher, je ne voulais pas que le lecteur reste sur une fausse impression, à savoir que cela ne pouvait fonctionner qu'avec un TProtypeBindSource.
J'ai donc concocté un petit fichier XML à partir du fichier customers.xml des exemples de données fournis, bien choisi car les clients semblent être des écoles de plongée
Par l'intermédiaire d'un FDBatchMove je n'ai récupéré que les colonnes CustNo, Company et Country suffisant pour ma liste.
Pour traiter ce fichier j'utiliserai un TFDMemtable et y ait ajouté un index composé des colonnes Country et Company qui me permettra d'avoir une liste ordonnée.
Comme il n'y avait que peu de nouveauté par rapport aux méthodes déjà exposées chapitre III dans du billet précédent je me suis attaché à la navigation au sein des éléments sélectionnés.
Pour se positionner sur le premier élément sélectionné, facile puisque l'on peut obtenir ce dernier par l'intermédiaire de la fonction FirstChecked(True)
procedure TBonus.PremierClick(Sender: TObject);
begin
If ListViewReal.Items.FirstChecked(True)>-1
then begin
ListViewReal.BeginUpdate;
ListViewReal.Selected:=ListViewReal.Items[ListViewReal.Items.FirstChecked(True)];
ListViewReal.EndUpdate;
end;
end;
Seule astuce à relever, il faut forcer un rafraichissement de la liste après positionnement (couple d'instruction encadrante BeginUpdate/EndUpdate) sous peine que la liste défile incorrectement (sauf si votre liste est synchronisée avec votre source de données).
Pour se déplacer en avant ou en arrière une seconde astuce consiste à obtenir la liste triée (elle l'est toujours) dans le bon sens, ce que permet la surcharge de la fonction CheckedIndexes(const AOrder : TListViewItems.TOrder; const AChecked: Boolean)
procedure TBonus.PrécédentClick(Sender: TObject);
var CheckList : TArray<Integer>;
Index, C : Integer;
begin
Index:=ListViewReal.Selected.Index;
CheckList:=ListViewReal.Items.CheckedIndexes(TListViewItems.TOrder.LastToFirst,True);
ListViewReal.BeginUpdate;
for C in CheckList do
if C<Index then
begin
ListViewReal.Selected:=ListViewReal.Items[C];
Break;
end;
ListViewReal.EndUpdate;
end;
procedure TBonus.SuivantClick(Sender: TObject);
var CheckList : TArray<Integer>;
Index, C : Integer;
begin
Index:=ListViewReal.Selected.Index;
CheckList:=ListViewReal.Items.CheckedIndexes(TListViewItems.TOrder.FirstToLast,True);
ListViewReal.BeginUpdate;
for C in CheckList do
if C>Index then
begin
ListViewReal.Selected:=ListViewReal.Items[C];
Break;
end;
ListViewReal.EndUpdate;
end;
Cette première étape finie j'ai voulu abattre certaines remarques que j'avais pu faire sur l'entête de groupe et son apparence custom (mettre une image) et sur la possibilité de faire de cette liste une sorte de menu.
C'est chose faite. Oui, c'est possible, cela ne veut qu'il faut utiliser cette astuce pour tous vos menus, mais c'était trop tentant
Pour ajouter une image, c'est dans l'évènement OnUpdateObject de la liste que je le code.
procedure TBonus.ListViewMenuUpdateObjects(const Sender: TObject;
const AItem: TListViewItem);
begin
if AItem.Purpose=TListItemPurpose.Header then
AItem.Objects.ImageObject.Bitmap.LoadFromFile('..\..\fleche.png');
end;
Il y a d'autres possibilités de chargement de l'image, par exemple à partir d'un TImageList
je joue mon jocker pour l'utilisation d'image multi-résolution.
L'important est surtout la manière d'accéder à l'ImageObject
Réduire le groupe a été un peu plus décevant car il est impossible d'indiquer zéro ou un nombre négatif pour la hauteur d'un élément. Plus il y aura d'éléments, plus un gap gris, plus ou moins important selon le nombre d'éléments du groupe, apparaitra (dommage).
procedure TBonus.ListViewMenuItemClick(const Sender: TObject;
const AItem: TListViewItem);
var AnItem : TListViewItem;
i : Integer;
begin
if AItem.Purpose=TListItemPurpose.Header then
begin
if AItem.Tag=0 then AItem.Tag:=1 else AItem.Tag:=0; // mémorise si le groupe est ouvert ou fermé
for I:= AItem.Index+1 to listviewmenu.items.count-1 do
begin
AnItem:=ListViewMenu.Items[i];
if AnItem.Purpose=TListItemPurpose.Header then Break;
if AItem.Tag=0 then AnItem.Height:=44 else AnItem.Height:=1; // change la taille de l'élément
AnItem.Objects.TextObject.Visible:=AItem.Tag=0; // texte invisible si groupe fermé
end;
AItem.Objects.ImageObject.Bitmap.Rotate(180); // retourne l'image
end;
end;
Vous retrouverez tout le code dans cette nouvelle archive en pièce jointe.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité,
merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.