2017-10-14 12 views
1

Il y a quelque chose que je n'ai pas compris avec TListBox et TListBoxItem dans Delphi 10.2 Tokyo.ListBoxItem Visible Error

Certaines valeurs (TListBoxItem) sont chargées dans ma ListBox, lorsque la première lettre change, j'ajoute un TListBoxGroupHeader.

procedure TForm1.Button1Click(Sender: TObject); 
var 
    lbItem: TListBoxItem; 
    Letter: string; 
    ListBoxGroupHeader: TListBoxGroupHeader; 
    i: integer; 
    ListValue: TStringList; 
begin 
    Letter := ''; 

    ListValue := TStringList.Create; 
    try 
     ListValue.Add('Germany'); 
     ListValue.Add('Georgie'); 
     ListValue.Add('France'); 
     ListValue.Add('Venezuela'); 
     ListValue.Add('Poland'); 
     ListValue.Add('Russia'); 
     ListValue.Add('Sweden'); 
     ListValue.Add('Denmark'); 

     ListBox1.BeginUpdate; 

     for i := 0 to ListValue.Count - 1 do 
     begin 
     if Letter <> Copy(ListValue[i], 0, 1).ToUpper then 
     begin 
      ListBoxGroupHeader  := TListBoxGroupHeader.Create(ListBox1); 
      ListBoxGroupHeader.Text := Copy(ListValue[i], 0, 1).ToUpper; 
      ListBox1.AddObject(ListBoxGroupHeader); 
     end; 

     lbItem := TListBoxItem.Create(ListBox1); 
     lbItem.Text := ListValue[i]; 
     lbItem.Tag := i; 

     ListBox1.AddObject(lbItem); 
     Letter := Copy(ListValue[i], 0, 1).ToUpper; 
     end; 

    finally 
     ListBox1.EndUpdate; 
     FreeAndNil(ListValue); 
    end; 
end; 

J'utilise un TEdit pour effectuer une recherche dans ce ListBox. C'est ici que j'ai un problème. Si ListBoxItem contient le contenu de l'Edit, je mets Visible à True, sinon je le mets à False.

procedure TForm1.Edit1ChangeTracking(Sender: TObject); 
var 
    i   : integer; 
    ListBoxItem: TListBoxItem; 
begin 
    ListBox1.BeginUpdate; 
    try 
     for i := 0 to ListBox1.Items.Count - 1 do 
     begin 
     if ListBox1.ListItems[i] is TListBoxItem then 
     begin 
      ListBoxItem := TListBoxItem(ListBox1.ListItems[i]); 

      if Edit1.Text.Trim = '' then 
      begin 
       ListBoxItem.Visible := True 
      end 
      else 
      begin 
       if ListBox1.ListItems[i] is TListBoxGroupHeader then 
        ListBoxItem.Visible := False 
       else 
        ListBoxItem.Visible := ListBoxItem.Text.ToLower.Contains(Edit1.Text.Trim.ToLower); 
      end; 
     end; 
     end; 
    finally 
     ListBox1.EndUpdate; 
    end; 
end; 

Le premier GroupHeader (lettre G) est toujours visible! et il semble qu'il y ait un ListBoxItem derrière le GroupHeader .. Quand j'utilise un point de contrôle Visible est défini sur false .. donc je n'ai pas compris ..

Si j'écris la lettre "V", je ne vois que le GroupHeader avec la lettre "G".

J'ai même essayé de changer la valeur du texte si c'est un GroupHeader.

if ListBox1.ListItems[i] is TListBoxGroupHeader then 
    ListBoxItem.Text := '>>' + ListBoxItem.Text + '<<' 

Cest texte de changement, mais pas pour la première GroupHeader (lettre G) ...

Je ne sais pas si je l'utilise mal, ou si elle est un bug ??

+0

Oui. Il y a un bug (lors de la définition de la visibilité de l'élément). De toute façon, je ne pense pas que ce soit ce que tu veux faire. Je pense que vous voulez rechercher des pays et afficher uniquement ceux qui correspondent à un texte avec un en-tête correspondant, ce qui nécessite une recherche dans les éléments non en-tête et masquer les en-têtes qui n'ont aucun élément. Est-ce ce que vous voulez accomplir? – Victoria

+0

@Victoria merci pour la réponse, tout ce que j'essaye échoué. J'ai décidé de créer mon propre menu avec un TVertScrollBox et TLayout où je crée mon TRecangle .. c'est faire le travail, je vais créer une tâche sur le bug tracker d'Embarcadero. – Bosshoss

Répondre

1

J'aurais pu reproduire ce que vous avez décrit et cela a quelque chose à voir avec le fait de cacher l'en-tête tout en gardant visible l'élément sous cet en-tête. Dans ce cas, l'application affiche l'en-tête plutôt que l'élément. Je n'ai pas vérifié ce qui ne va pas à l'intérieur mais il semble que ce n'est pas ce que vous voulez. À mon humble avis vous voulez garder les éléments visibles qui correspondent à un texte de recherche avec leur en-tête respectif et ne cacher que les en-têtes sans éléments sous.

Si c'est le cas, essayez ceci:

procedure FilterItems(const Text: string; ListBox: TListBox); 
var 
    I: Integer; { ← loop variable } 
    Hide: Boolean; { ← flag indicating if we want to hide the last header we passed } 
    Item: TListBoxItem; { ← currently iterated item } 
    Head: TListBoxGroupHeader; { ← last header item we passed during iteration } 
begin 
    Head := nil; 
    Hide := True; 

    ListBox.BeginUpdate; 
    try 
    { if search text is empty, show all items } 
    if Text.IsEmpty then 
     for I := 0 to ListBox.Content.ControlsCount - 1 do 
     ListBox.ListItems[I].Visible := True 
    else 
    { otherwise compare text in non header items } 
    begin 
     for I := 0 to ListBox.Content.ControlsCount - 1 do 
     begin 
     Item := ListBox.ListItems[I]; 
     { if the iterated item is header } 
     if Item is TListBoxGroupHeader then 
     begin 
      { set the previous header visibility by at least one visible item } 
      if Assigned(Head) then 
      Head.Visible := not Hide; 
      { assume hiding this header and store its reference } 
      Hide := True; 
      Head := TListBoxGroupHeader(Item); 
     end 
     else 
     { if the iterated item is a regular item } 
     if Item is TListBoxItem then 
     begin 
      { set the item visibility by matching text; if the item remains visible, it 
      means we don't want to hide the header, so set our flag variable as well } 
      if Item.Text.ToLower.Contains(Text) then 
      begin 
      Hide := False; 
      Item.Visible := True; 
      end 
      else 
      Item.Visible := False; 
     end; 
     end; 
     { the iteration finished, so now setup visibility of the last header we passed } 
     if Assigned(Head) then 
     Head.Visible := not Hide; 
    end; 
    finally 
    ListBox.EndUpdate; 
    end; 
end; 

procedure TForm1.Edit1ChangeTracking(Sender: TObject); 
begin 
    FilterItems(Edit1.Text.Trim.ToLower, ListBox1); 
end;