Avatar billede hugopedersen Nybegynder
11. december 2008 - 13:35 Der er 9 kommentarer og
1 løsning

Listbox med flere kolonner - kan man ikke det

Kan det passe at det ikke er muligt at lave en listbox med flere kolonner i Delphi?
Det lyder da for usandsynligt synes jeg.
Avatar billede borrisholt Novice
11. december 2008 - 13:49 #1
Brug en ListView i stedet
Avatar billede a_nor Nybegynder
11. december 2008 - 13:51 #2
og brug så Viewstyle = vsReport  ...
Avatar billede hrc Mester
11. december 2008 - 14:04 #3
TListView er løsningen. Kan sagtens komme til at ligne en listbox med flere kolonner.
Avatar billede hugopedersen Nybegynder
11. december 2008 - 14:21 #4
Jamen det lyder da helt fint - så må jeg 'bare' finde ud af hvordan det virker :-)
Avatar billede hrc Mester
11. december 2008 - 16:32 #5
Det er ret let. Kolonnerne opretter du ved at dobbeltklikke på listviewet. For at oprette linjer kører du ListView.Items.Add returnerer et TListItem objekt som har Caption for første kolonne, SubItems for de efterfølgende (en TStringList hvor du bare adder ny kolonner)

  with ListView.Items.Add do
  begin
    Data := MyObject; // Smart at hægte eventuelle objekter på her (hvis man har dem)
    // men det skal være før du sætter Caption for det trigger en OnChange
    Caption := 'Hej';
    SubItems.Add('mor');
  end;
Avatar billede hugopedersen Nybegynder
11. december 2008 - 17:12 #6
Hvad er det for objekter du tænker på?

hrc> du har også givet guldkorn i dette indlæg der 'kræver' et svar fra dig.
Avatar billede hrc Mester
12. december 2008 - 09:44 #7
Jeg fulgte bare op på borrisholt og a_nors kommentarer. TListItem.Data (TTreeViews items har også .Data) er en bekvem måde at hægte et objekt på den linje hvor den vises. Eksempelvis kan du have en instans af TPersonData som indeholder cpr, navn, adresse, postnr, postby.

  PersonData := TPersonData.Create('131233-1231','Hans Tauchen','Isvej 1','5000','Odense);
  with ListView.Items.Add do
  begin
    Data := PersonData;
    Caption := PersonData.CPR;
    SubItems.Add(PersonData.Navn);
    SubItems.Add(PersonData.Adresse);
    SubItems.Add(PersonData.PostNr);
    SubItems.Add(PersonData.PostBy);
  end;

Hvis du hægter dig på ListViewets OnSelected event får du direkte adgang til det objekt som linjen viser:

begin
  PersonData := Item.Data;
  PersonData.Navn := 'Henry Blikfang';
  Item.SubItems[0] := PersonData.Navn;
end;

Et andet sted hvor det tit er praktisk at have adgang til objektet bag, fremfor Item'et er, hvis du sorterer (OnColumnClicked og OnCompare).

Bemærk: fColumnClicked og fSortAscending er private attributter (det hedder det!) i formen. Lidt et kiks at det ikke er i komponenten (det er det i .NET versionen). Desuden har jeg en imagelist koblet på SmallImages, der indeholder små ikoner der viser sorteringsretningen (i den valgte kolonne)

I OnCreate initieres de:

    fColumnClicked := 0; // CPR kolonnen
    fSortAscending := true; // Stigende orden
    ListView.Columns[fColumnClicked].ImageIndex := integer(fSortAscending);

procedure ... OnColumnClick(aSender: TObject; aColumn: TListColumn);
begin
  if fColumnClicked = aColumn.Index then
    fSortAscending := not fSortAscending
  else begin
    ListView.Columns[fColumnClicked].ImageIndex := -1; // Fjern sorteringsretningsikon
    fColumnClicked := aColumn.Index;
    fSortAscending := true;
  end;
  // Sæt ikon i rette kolonne
  ListView.Columns[fColumnClicked].ImageIndex := integer(fSortAscending);

  ListView.Items.BeginUpdate;
  try
    ListView.AlphaSort;
  finally
    ListView.Items.EndUpdate;
  end;
end;

procedure .. OnCompare(Sender: TObject;
  Item1, Item2: TListItem; Data: Integer; var Compare: Integer);
var
  PD1, PD2 : TPersonData;
begin
  PD1 := Item1.Data;
  PD2 := Item2.Data;
  case fColumnClicked of
    0 : Compare := AnsiCompareStr(PD1.CPR,PD2.CPR);
    1 : Compare := AnsiCompareStr(PD1.Navn,PD2.Navn);
    2 : Compare := AnsiCompareStr(PD1.Adresse,PD2.Adresse);
    3 : Compare := AnsiCompareStr(PD1.PostNr, PD2.PostNr);
    4 : Compare := AnsiCompareStr(PD1.PostBy, PD2.PostBy);
  end;
  // Vend sorteringsordenen hvis der er klikket to gange på samme kolonne
  if not fSortAscending then
    aCompare := - aCompare;
end;
Avatar billede hrc Mester
12. december 2008 - 09:45 #8
Glemte at sige, at hvis du opretter et objekt sådan som jeg har vist heroppe, så kan du bruge OnDeletion til at frigive det igen:

  TObject(Item.Data).Free;
Avatar billede loopit Nybegynder
12. december 2008 - 23:04 #9
Kan det her bruges?

procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.TabWidth := 20;
ListBox1.Items.Add('Column1'^I'Column2'^I'Column3');  // ^I is the Tab char
ListBox1.Items.Add('Column1'^I'Column2'^I'Column3');  // ^I is the Tab char
end;
Avatar billede hrc Mester
15. december 2008 - 02:59 #10
loopit: Hvis det skal se fint ud skal du vel bruge en fast font, såsom Courier New. Mange muligheder for at det bliver grimt og spørgsmålet er også, hvorfor man ikke bare springer på TListView.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester