10. juli 2001 - 21:05Der er
35 kommentarer og 1 løsning
Gemme objekter
Jeg har endnu ikke fundet den ideelle måde at gemme en række data på (ud over databaser). Hvis jeg nu har en række objekter i en stringlist bliver de jo ikke gemt når jeg prøver at gemme listen. Og hvis jeg har dem i en ObjectList kan jeg ikke se nogen måde at jeg kan streame eller gemme den. Så spg\'et er hvordan gemmer i jeres data, for jeg gider ikke bare have det hele i en tekststreng, men jeg vil have det som objekter?
Du kan gemme et Object\'s Published property\'es ( dette er hvad delphi gør med dinne form\'s ) dvs fra TPersistent til TComponent osv. kan du gemme propertyes med de indbyggede funtioner WriteComponent, WriteComponentRes dem kan du finde i hjælpen, det virker fint, jeg lavede en gang en \"ren\" obj. base ( et lille tlf kartotek ), som tilpassede sig DataObj. så hvis jeg skulle bruge et nyt felt lavede jeg bare en ny property på min dataobj så virkede det.
function TCardCollection.AddCard(ACardData: TCardData): Integer; begin Result := FCards.Add(ACardData); end;
constructor TCardCollection.Create(AOwner: TComponent); begin FCards := TList.Create; end;
procedure TCardCollection.DelCard( ACardID : Integer ); begin ACardID := IndexOf(ACardID); if ACardID <> -1 then FCards.Delete(ACardID); end;
destructor TCardCollection.Destroy; begin FCards.Free; end;
function TCardCollection.GetCards(Index: Integer): TCardData; begin Result := TCardData(FCards[Index]); end;
function TCardCollection.GetCardsCount: Integer; begin Result := FCards.Count; end;
function TCardCollection.IndexOf( ID : Integer ) : Integer; begin if FCards.Count > 0 then begin Result := 0; while ( Result < FCards.Count-1 ) and ( TCardData(FCards[Result]).Tag <> ID ) do Inc(Result); if TCardData(FCards[Result]).Tag <> ID then Result := -1; end else Result := -1; end;
procedure TCardCollection.LoadFromFile(AFileName: String); VAR F : TFileStream; Cnt : Integer; B : TCardData; begin if not FileExists(AFileName) then EXIT; F := TFileStream.Create(AFileName,fmOpenReadWrite + fmShareExclusive); F.Read(Cnt,SizeOf(Cnt)); FCards.Capacity := Cnt; while Cnt > 0 do begin B := TCardData.Create(Self); FCards.Add(B); F.ReadComponentRes(B); Dec(Cnt); end; F.Free; end;
procedure TCardCollection.SaveToFile(AFileName: String); VAR F : TFileStream; Cnt : Integer; begin F := TFileStream.Create(AFileName,fmCreate); Cnt := FCards.Count; F.Write(Cnt,SizeOf(Cnt)); for Cnt := 0 to FCards.Count-1 do F.WriteComponentRes(IntToStr(Cnt),TCardData(FCards[Cnt])); F.Free; end;
procedure TCardCollection.SetCrypt(const Value: TCryptMode); begin if FCrypt <> Value then begin FCrypt := Value; if FCrypt <> FFileMode then begin case FCrypt of cmNormal : ;//Decrypt the DataList and Datafile cmCrypt : ;//Crypt the DataList and Datafile end;(* case *) end; end; end;
poull >> det var nok min komentar til TCollection han mente, men jeg har faktisk gjort som han skriver i mit eks. hvis du kigger efter har jeg også brugt en TList.
Men jeg har også benyttet mig at TStream.WriteComponentRes, TStream.ReadComponentRes og det virker fint, så jeg vil anbefale dig at prøve at lege lidt med det.
borrisholt >> Det ville utrolig gerne have :) Det er måske bedere at bruge persistens som udgangspunkt til sine klasser end TComponent?
alle >> Jeg har endnu et spg: Hvis min TListe Indholder objekter der kan være to forskellige klasser, men de har begge TComponent som \"fader\", hvordan kan jeg så finde ud af om det er den ene eller anden klasse. (Er i med?)
if MyObj IS TMyComp1 then begin end else if MyObj IS TMyComp2 then begin end;
Men jeg vil nu stadig anbefale MIN løsning, da den selv finder ud af at gemme dine props, også hvis du tilføjer en ny, så skal du ikke ændre EN eneste line i Save og Load funktionerne, det er lidt smart efter min mening, og det kører faktisk også temmelig hurtigt, 100.000 rec tog ikke mange sek. at Loade eller Save, og du har jo faktisk fået skallen med det jeg har vist dig.
Martin >> kan og kan ..... kkan ikke er det ikke et stort ord at bruge ... Både du og jeg kunne lave et enromt grimt hack der kombinere records og klasser i samme TList ... ikke ? Det er brud på god skik og orden men man kan !!!
Button1.Caption := Klasse1.TekstIndhold + \' er \' + IntToStr(Klasse2.TalIndhold); end;
procedure TForm1.Button2Click(Sender: TObject); Var Klasse1: TKlasse1; Klasse2: TKlasse2; I: Integer; begin I := Pred(Liste.Count); While I >= 0 do begin if Liste[I] is TKlasse1 then Klasse1 := TKlasse1(Liste[I]) else Klasse2 := TKlasse2(Liste[I]) end; Button2.Caption := Klasse1.TekstIndhold + \' er \' + IntToStr(Klasse2.TalIndhold); end;
end.
Dette skulle bare gemme det i listen og så hente det igen
procedure TForm1.Button2Click(Sender: TObject); Var Klasse1: TKlasse1; Klasse2: TKlasse2; I: Integer; begin // I := Pred(Liste.Count); // While I >= 0 do for I := 0 to Liste.Count-1 do begin if Liste[I] is TKlasse1 then Klasse1 := TKlasse1(Liste[I]) else Klasse2 := TKlasse2(Liste[I]) end; Button2.Caption := Klasse1.TekstIndhold + \' er \' + IntToStr(Klasse2.TalIndhold); end;
Nå, men jeg kunne compilere det for den kom med denne fejl: Operator not applicable to this operand type (og det gør den også med din kode)
Så det kunen tyde på at man ikke kunne bruge is her, for hvis jeg erstatter Liste[I] med klasse1 som er den lokale variable virker det, så skal man tage hensyn til at det er en TListe?
Jep, hvis du tager hjælp ( F1 ) på en TList kan du se hvordan den er skruet sammen, kig på TObjectList og de andre også TStringList er meget brugt og god at kende som sin egen bukselomme :)
Jo men selv om jeg forstår det der i hjælp er jeg aldrig helt sikker når det angår pointere. Det kan være jeg skal bruge TObjectList istedet for TList da jeg ikke er så glad for noget med pointere ;]
Selv om jeg har ændret lidt i koden (til brug af AS) virker det ikke: procedure TForm1.Button2Click(Sender: TObject); Var Klasse1: TKlasse1; Klasse2: TKlasse2; I: Integer; begin for I := 0 to Liste.Count-1 do begin if Liste[I]^ is TKlasse1 then Klasse1 := (Liste[I]^ as TKlasse1) else Klasse2 := (Liste[I]^ as TKlasse2); end; Button2.Caption := Klasse1.TekstIndhold + \' er \' + IntToStr(Klasse2.TalIndhold); end;
begin for I := 0 to Liste.Count-1 do begin if TObject(Liste[I]^) is TKlasse1 then Klasse1 := (TObject(Liste[I]^) as TKlasse1) else Klasse2 := (TObject(Liste[I]^) as TKlasse2); end; Button2.Caption := Klasse1.TekstIndhold + \' er \' + IntToStr(Klasse2.TalIndhold);
Jeg har ikke lige delphi kørende, med det må være noget i den stil der skal til, men brug TObjectList i stedet eller TStringList, den har en Items[I] som er string og Objects[I] som er TObject, så hver Items har sin egen Object, kan bruges til mange ting, hvor man har brug for noget tekst og noget andet ( en Object ref. eller en record pointer ). Jeg prøver at få tid til et lille eks. på Delphi-kursus siden en af dagende, hvis det kan lade sig gøre.
Det er bedere end den tidligere kode, da jeg nu kan compilere mit program, men der kommer en af disse der access violations og man ved ikke hvad der er galt. Selv om der ikke ville være dette problem med TObjectList (hvilket jeg så vil bruge frem over) kunne det være rart hvis du lige som den sidste ting hjalp med at få det med tList til at virke.
Nåmen pyt hvis du ikke lige ved det sidste spg, for jeg har jo fået svar på det jeg ville.
Mange tak
Synes godt om
Ny brugerNybegynder
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.