Jeg sidder og leger lidt med et tidsregistrerings program.
Den skal gemme en listbox's indhold i en "file of" et record.
type TProjektData = Record ProjektNavn : String[255]; Dato : TString; StartTid : TStrings; SlutTid : TStrings; MillisekunderArbejdet : TStrings; Beskrivelse : TStrings; end;
Jeg har 2 procedurer, gemme og åbne projektfil.
Den giver hverken fejlmeddelser når den åbner eller gemmer filen.
Men når jeg har gemt filen og åbnet den igen, er der ingen indhold i listbox'ene. Men navnet på projektet henter den fint "ProjektNavn : String[255];".
Nogen der kan fortælle mig hvad jeg gør galt, kan bare ikke forstå det.
Mvh. Jonatan
På Forhånd Tak :)
**** KODE START ****
**** GEM **** procedure TForm1.GemDatafil1Click(Sender: TObject); var Fil : File of TProjektData; begin If not ProjektEandretSidenGem then exit;
If SaveDialog1.Execute then begin If ExtractFileExt(SaveDialog1.FileName) <> '.jhc' then begin SaveDialog1.FileName := SaveDialog1.FileName + '.jhc'; end;
If FileExists(SaveDialog1.FileName) then begin If MessageDlg('Vil du erstatte projektfilen: '+ExtractFileName(SaveDialog1.FileName),mtWarning,mbOKCancel,0) = MrCancel then Exit; end;
**** ÅBEN **** procedure TForm1.bendatafil1Click(Sender: TObject); var Fil : File of TProjektData; begin If OpenDialog1.Execute then begin If FileExists(OpenDialog1.FileName) then begin AssignFile(Fil, OpenDialog1.FileName); Reset(Fil);
ProjektAabnet := True; BtnStart.Enabled := True; end else begin ShowMessage('Data filen kunne ikke findes.'); end; end; end; **** ÅBEN SLUT **** **** KODE SLUT ****
Erik har ret i hvad han skriver. De objekter du angiver i recorden har jo blot en "pointer størrelse" og det er denne du får gemt og ikke dataene.
Du er altså nødt til at gemme element for element. Lav recordstrukturen om
type TProjektData = Record ProjektNavn : String[255]; Dato : string[12]; StartTid : String[12]; SlutTid : TStrings[12]; MillisekunderArbejdet :string[12] // hva ska du med den ?? Beskrivelse : string; end;
Er det noget der skal indlæses i eksempelvis Excel? Hvis det bare er lager så synes jeg det bliver rigtig pænt om du bruger TFileStream sammen med TReader og TWriter. Meget let at gemme og hente - og så bliver det også rimeligt kompakt.
Man skal bare huske FlushBuffer hvis man har "nestede" skrivninger for ellers går det grumme galt.
Man bruger det til at gemme komponenterne med i Delphi bl.a.
Fordelen er bl.a. at du ikke er bundet af nogen strenglængde. En anden er, at hvis du har en liste med nogle objekter så skal de hver kun sørge for at gemme sig selv - og så er det at FlushBuffer bliver vigtig.
Viser her et lille eksempel på en liste der indeholder en liste af persondata-objekter. Listen skriver sine oplysninger og sender derefter stafetten videre til person-objekterne der kun bekymrer sig om at skrive sit. På den måde kan du bryde opgaven ned i mindre bidder og kompleksiteten bliver meget mindre
Data bliver i øvrigt også skrevet med felterne separeret - men dog optimeret - i en binær-fil.
procedure TPersonList.SaveToStream(aStream : TStream); var Writer : TWriter; begin Writer := TWriter.Create(aStream, 1024); try Writer.WriteString(fTitle); Writer.WriteDate(now); Writer.WriteInteger(Count); // Skriv antallet af records Writer.FlushBuffer; // Flush! for i := 0 to Count - 1 do Items[i].SaveToStream(aStream); finally Writer.Free; end; end;
hrc: Endnu engang tak. Det er godt med noget kode at studere. Hvis man indledningsvis gemmer objektnavnet kan man vel også (ustruktureret) smide objekter ned i filen, og stadig få dem læst ind igen, og du behøvede ikke at gemme 'count' ?
Du spottede den count'en - den var jeg noget i tvivl om jeg skulle tage med. Svaret er både og. Man kan nemlig også lave loopet således: "while aStream.Position < aStream.Size" og derved spare Count.
Tror du bliver nødt til at hælde en ClassType/ClassName ned før du fodrer den med et objekt. Når du indlæser skal du have en eller anden måde at finde den rette indlæsningsrutine.
procedure TPersonData.SaveToStream(aStream : TStream); var Writer : TWriter; begin Writer := TWriter.Create(aStream, 1024); try Writer.WriteXxXX(ClassType); // Sådan her Writer.WriteString(fName); Writer.WriteString(fAdresse); Writer.WriteFloat(fLoen); Writer.FlushBuffer; finally Writer.Free; end; end;
I din indlæsningsloop bliver du nødt til at lave noget i retning af
case Reader.ReadXxXX of ctPersonData : Add(TPersonData.Create(aStream)); .. end;
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.