03. april 2004 - 23:02Der er
10 kommentarer og 1 løsning
Update ListBox
Når jeg skal opdatere en ListBox med data fra en db, hvad skal jeg så gøre?? Helt konkret skal den hente data fra db når programmet starter. Ligeledes skal den opdatere så snart man indsætter, sletter eller retter i data.
Jeg forestiller mig noget med en funktion (UpdateListBox), der kan kaldes ved programstart samt når man trykker på en knap for at indsætte, slette eller rette data.
Jeg har følgende kode der virker når man indsætter det ved buttonclick, men hvordan får jeg det indkapslet i en function og i hvilken fil (.pas eller .dfm??) skal det indsættes?
procedure TAnsoeg.SamtalerButtonClick(Sender: TObject); var Q1: TADODataset; begin Q1 := TADODataset.Create(self); Q1.Connection := ADOConnection1;
Q1.Close; Q1.CommandText := 'SELECT * FROM Firma'; Q1.Open;
While not Q1.Eof do begin ListBox1.Items.Add(Q1.FieldByName('Firmanavn').AsString); Q1.Next; end; Q1.Free; end;
Jeg forstår ikke hvorfor I aldrig sætter en try finally omkring sådan en operation. Det er et eksempel, det ved jeg, men det ødelægges ikke af tre linier mere. Jeg har tit oplevet at løbe ind i en låst tabel eller andre fejl, i en ellers velfungerende funktion - og så har mine utallige try-finally'er ryddet pænt op efter mig.
Min version vill fylde lidt mere (men er den også kørt lidt til de modsatte ekstremer). Jeg ville foretrække at nedarve TADOTable til at indeholde funktionen - hvilket jeg ikke har gjort her. I nedenstående er det en procedure i TAnsogs private sektion.
I øvrigt har jeg gjort den mere generel vha. at sende ListBoksens TStringList som parameter, hvorved du nu sende hvilken som helst liste til den: UpdateStringlist(listBox.Items); // eller andre
Procedure UpdateStringlist(aList : TStrings); // TStrings er baseklasse for strenglisterne var Q1: TADODataset; begin // Sæt timeglas og opret objekt - husk at fjerne dem igen Screen.Cursor := crHourglass; Q1 := TADODataset.Create(self); try // Gik det godt at oprette objekt, så start try-sektion Q1.Connection := ADOConnection1;
// Q1.Close; // Den er lukket - du har lige oprettet den! Q1.CommandText := 'SELECT * FROM Firma'; Q1.Open;
// Det går hurtigere på denne måde - husk at slå det fra igen aList.BeginUpdate; try aList.Clear; while not Q1.Eof do begin aList.Items.Add(Q1['Firmanavn']); // Tror nok at det her også virker Q1.Next; end; finally aList.Items.EndUpdate; // Slå fra end; finally // To operationer i samme try-finally. Start med de sikreste Screen.Cursor := crDefault; Q1.Free; // Frigiv opjekt end; end;
Man kunne overveje om der skulle en try-except på også:
try operation except on e: exception do raise exception.create('Error in UpdateStringlist'+#13#10+e.Message); end;
Nu har du funktionen der læser data fra tabellen. Der er ingen SQL-funktion der automatisk "fortæller", at der er sket noget i tabellen. Dette løses normalt vha. den Refresh-knap som du også overvejer.
Hvis du bruger Paradox- eller Access-tabeller ville jeg overveje at koble DataSettet sammen med en TDataSource. Den har et OnDataChange-event som du kan bruge, men der er faktisk ingen grund til ovenstående kode nu, idet du derefter bare kan bruge en TDBListBox som forbindes til TDataSourcen.
Sæt du bare den til nil - det sker der ikke noget ved, bare at dy husker at frigive den igen. Fejlen er, at self er pointeren til det pågældende objekt og når nu både UpdateListbox og UpdateStringlist ikke er del af et objekt (eks. "TfrmMain."UpdateStringList), så er self ikke eksisterende.
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.