Stringlist speichern?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Stringlist speichern?

Beitrag von Curry »

Hallo,
für die Schule muss ich gerade ein Projekt über eine Datenbank erstellen.
Dazu habe ich ein Record erstellt, wo auch eine Stringlist gespeichert werden soll, da ich mehrere Darsteller speichern möchte.

Code: Alles auswählen

TFilm = record
 
    Darsteller: TStringList;
 
  end;               


Wenn ich jetzt einen neuen Eintrag in die DB eingeben will, gibt er mir auch keine Fehlermeldung.

Code: Alles auswählen

Reset(Unit1.dat);
    while not (eof(dat)) do read(dat,Film);
 [...]
    Unit1.Film.Darsteller := str;
    str.Clear;
[...]
    Write(Unit1.dat,Unit1.Film)


Str ist dabei meine temporäre Stringlist, in die ich nacheinander die verschiedenen Darsteller eingebe.

Wenn ich jetzt aber die Werte mir ausgeben lassen möchte, gibt er mir einen Zugriffsfehler.

Bild

Hier der Code für die Ausgabe:

Code: Alles auswählen

procedure TForm4.Details(pos: integer);
var
  strl:TStringlist;
begin
  Reset(unit1.dat);
  Seek(unit1.dat, pos - 1);
  Read(dat, unit1.Film);
 [...]
  Strl:=TStringlist.create;
  Strl:=Unit1.Film.Darsteller;
 
  ListBox1.Items.Assign(Strl);           
[...]
 
end;


Ich habe jetzt auch schon mehrere Seiten gesucht, die sich mit mein Problem beschäftigen, bin aber zu keiner Lösung gekommen. Geht das gar nicht oder warum funktioniert das nicht? :c

Liebe Grüße,
Curry.

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringlist speichern?

Beitrag von Mathias »

Eine StringList speichert man am einfachsten mit

Code: Alles auswählen

var str:TStringList;
....
str.SaveToFile('test.txt');

ab.

Code: Alles auswählen

  Strl:=TStringlist.create;
  Strl:=Unit1.Film.Darsteller;

Hier kopierst du nur den Zeiger der StringList, ich nehme an du willst den Inhalt kopieren,

Code: Alles auswählen

  Strl:=TStringlist.create;
  Strl.text:=Unit1.Film.Darsteller.text;


Aber irgendwie sehe ich nicht durch was du schlussendlich machen willst.
Eine kleine DVD-Datenbank ?

Oder vielleicht reicht dir ein einfacher String dafür.

Code: Alles auswählen

TFilm = record 
    Darsteller: String;
  end
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Linkat
Lazarusforum e. V.
Beiträge: 530
Registriert: So 10. Sep 2006, 23:24
OS, Lazarus, FPC: Linux Mint 21.3; Lazarus 3.0 FPC 3.2.2; RaspiOS
CPU-Target: AMD 64, ARM 32
Wohnort: nr Stuttgart

Re: Stringlist speichern?

Beitrag von Linkat »

Hallo Curry,
zunächst mal herzlich willkommen im Lazarusforum. Viel Spaß und Erfolg beim Programmieren.

Aus deinen paar Codezeilen kann man nicht verstehen was du genau vorhast. Du schreibst etwas von einer Datenbank, steckst eine Sringlist in einen record und willst eine Unit1.Film.Darsteller in einer Stringliste zuweisen.
Alles ein bischen "strange".
Bitte vertiefe deine Grundlagen bezüglich Records, Stringlisten, Arrays noch ein bisschen.

Deine Fehlermeldung könnte von einer nicht initialisierte Stringlist (StringList.Create) herrühren.

Gruß, Linkat
Linux Mint 21; Lazarus 2.2.4 FPC 3.2.2; RaspiOS

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Hallo Mathias und Linkat,
danke für eure schnellen Antworten.

Mathias hat geschrieben:Eine StringList speichert man am einfachsten mit

Code: Alles auswählen

var str:TStringList;
....
str.SaveToFile('test.txt');

ab.

Ja, die Funktion ist mir auch bereits bekannt, jedoch sollen wir alles in ein Record speichern.

Mathias hat geschrieben:Aber irgendwie sehe ich nicht durch was du schlussendlich machen willst.
Eine kleine DVD-Datenbank ?

Oder vielleicht reicht dir ein einfacher String dafür.

Code: Alles auswählen

TFilm = record 
    Darsteller: String;
  end


Ja, es soll eine Videothek als Datenbank werden, und da sollen halt mehrere Darsteller gespeichert werden. Dazu reicht mMn ein einfacher String als Datentyp nicht aus.


Ich dachte, es reicht, wenn ich euch obigen Quelltext schicke,
also so hab ich es mir gedacht:
Ich lege ein Record fest und die dazugehörigen Variablen:

Code: Alles auswählen

 TDatum = record
    d, m, y: integer;
  end;
 
  TFilm = record
    Name: string[40];
    Genre: string[20];
    Regisseur: string[40];
    Darsteller: TStringList;
    Zuletzt: TDatum;
    Info: string[250];
  end;
 
var
  Form1: TForm1;
  dat: file of TFilm;
  Film: TFilm;   


Nun füge ich neue Daten auf dem dritten Formblatt hinzu:

Code: Alles auswählen

uses
  Unit1;
 
{$R *.lfm}
 
{ TForm3 }
 
procedure TForm3.Button1Click(Sender: TObject);
begin
  if (edit1.Text <> '') and (edit3.Text <> '') and (radiogroup1.ItemIndex <> -1) and
    (Memo1.Text <> '') and (Str.Count > 0) then
  begin
    Reset(Unit1.dat);
    while not (eof(dat)) do read(dat,Film);
    Unit1.Film.Name := edit1.Text;
    edit1.text:='';
    case Radiogroup1.ItemIndex of
      0: Unit1.Film.Genre := 'Action';
      1: Unit1.Film.Genre := 'Thriller';
    end;
    Radiogroup1.itemindex:=-1;
    Unit1.Film.Regisseur := edit3.Text;
    Edit3.text:='';
    Unit1.Film.Darsteller := str;
    Edit2.text:='';
    str.Clear;
    Unit1.Film.Info := Memo1.Text;
    Memo1.text:='';
 
    Write(Unit1.dat,Unit1.Film);
  end else ShowMessage('NÖ');
end;
 
procedure TForm3.Button2Click(Sender: TObject);
begin
  if edit2.Text <> '' then
    Str.Add(edit2.Text);
  edit2.Text := '';
end;
 
procedure TForm3.FormShow(Sender: TObject);
begin
  str := TStringList.Create;
 
end;


Und möchte sie nun auf dem vierten Formblatt ausgeben.

Code: Alles auswählen

uses
  Unit1;
 
{$R *.lfm}
 
{ TForm4 }
procedure TForm4.Details(pos: integer);
var
  strl:TStringlist;
begin
  Reset(unit1.dat);
  Seek(unit1.dat, pos - 1);
  Read(dat, unit1.Film);
  label2.Caption := Unit1.Film.Name;
  label4.Caption := Unit1.Film.Genre;
  label6.Caption := Unit1.Film.Regisseur;
{  Strl:=TStringlist.create;
  Strl:=Unit1.Film.Darsteller;
 
  ListBox1.Items.Assign(Strl);           }

 
  if (Unit1.film.Zuletzt.d = 0) and (Unit1.film.Zuletzt.m = 0) and
    (Unit1.film.Zuletzt.y = 0) then
  label8.Caption := 'Noch nicht angeschaut!'
  else
    label8.Caption := 'Zuletzt am ' + IntToStr(Unit1.Film.Zuletzt.d) + '.' +
      IntToStr(Unit1.Film.Zuletzt.m) + '.' + IntToStr(Unit1.Film.Zuletzt.y) + ' angeschaut!';
  Memo1.text:=Unit1.film.Info;
 
end;

Die Position (Pos) ist dabei bereits bekannt.
Nun gibt er mir, da wo der Kommentar ist, eine Fehlermeldung, s.o.

Linkat hat geschrieben:Deine Fehlermeldung könnte von einer nicht initialisierte Stringlist (StringList.Create) herrühren.

Aber, wenn ich die Stringlist neu erstellte, wird doch deren Inhalt überschrieben?
Also wenn ich das so schreibe, ist der Inhalt leer ( ist ja eigentlich klar ...).

Code: Alles auswählen

 
  Unit1.Film.Darsteller:=TStringlist.create;
   ListBox1.Items.Assign(Unit1.Film.Darsteller);   


Naja, und jetzt weiß ich nicht mehr weiter... :c

Liebe Grüße,
Curry.

Linkat hat geschrieben:Bitte vertiefe deine Grundlagen bezüglich Records, Stringlisten, Arrays noch ein bisschen.

In welchen Bereichen denn? Wenn du irgendwas sinnloses u.a. oben im Quelltext findest, lass es mich gerne wissen - Dann werde ich hoffentlich noch was Besseres finden. :)

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringlist speichern?

Beitrag von Mathias »

Code: Alles auswählen

TDatum = record
    d, m, y: integer;
  end

Für das Datum gibt es schon ein fertigen Daten-Typ.
http://www.freepascal.org/docs-html/rtl ... tines.html

das unit1. kannst du auch sparen

Code: Alles auswählen

  if (Unit1.film.Zuletzt.d = 0) and (Unit1.film.Zuletzt.m = 0) and    (Unit1.film.Zuletzt.y = 0) then // alt
  if (film.Zuletzt.d = 0) and (film.Zuletzt.m = 0) and    (film.Zuletzt.y = 0) then  // neu


Der Record sieht nicht schlecht aus, bis auf Darsteller.
Wieso nimmst du dafür TStringList und nicht einfach einen String ?

Code: Alles auswählen

  TFilm = record
    Name: string[40];
    Genre: string[20];
    Regisseur: string[40];
    Darsteller: TStringList;
    Zuletzt: TDatum;
    Info: string[250];
  end;



Code: Alles auswählen

 Reset(unit1.dat);
Nach Konform nimmt man für file-Bezeichner ein vorangestelltes "f", in deinem Fall "fdat"
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Mathias hat geschrieben:Für das Datum gibt es schon ein fertigen Daten-Typ.
http://www.freepascal.org/docs-html/rtl ... tines.html


Ja, ich weiß auch nicht. Hab sogar schonmal damit gearbeitet ... Naja, werde ich nochmal umschreiben.

Mathias hat geschrieben:das unit1. kannst du auch sparen

Okay, habe ich irgendwo so im Internet gefunden, aber nicht weiter rum experimentiert. Naja, mach ich dann auch noch besser. :D

Mathias hat geschrieben:Der Record sieht nicht schlecht aus, bis auf Darsteller.
Wieso nimmst du dafür TStringList und nicht einfach einen String ?


Naja, wenn man mehrere Darsteller hat, dachte ich, ist es besser, wenn man sie in separaten Strings hat. Da ich sie denn auch besser (in einer Tabelle) ausgeben kann.


Also geht es theoretisch gar nicht mit einer TStringlist? :o

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringlist speichern?

Beitrag von Mathias »

Naja, wenn man mehrere Darsteller hat, dachte ich, ist es besser, wenn man sie in separaten Strings hat. Da ich sie denn auch besser (in einer Tabelle) ausgeben kann.

Also geht es theoretisch gar nicht mit einer TStringlist? :o

Gehen tut es schon, aber mit deinem Speicherkonzept mit Assign, reset, etc. ist dies nicht möglich.
Wen du sowas machen willst, müsste man mit TFileStream arbeiten und dies ist für den Anfang sehr komplex.

Ich würde dies für den Anfang mit einem einfachen Array lösen.

ZB. für 3 Darsteller:

Code: Alles auswählen

Darsteller : array[0..2] of String[40]
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Alles klar,
dann mach ich jetzt einfach, dass man max. 5 Darsteller hinzufügen kann - Sollte reichen. ;)

Dann hat sich das Thema erledigt - Danke für eure Hilfe.

Liebe Grüße,
Curry.

Linkat
Lazarusforum e. V.
Beiträge: 530
Registriert: So 10. Sep 2006, 23:24
OS, Lazarus, FPC: Linux Mint 21.3; Lazarus 3.0 FPC 3.2.2; RaspiOS
CPU-Target: AMD 64, ARM 32
Wohnort: nr Stuttgart

Re: Stringlist speichern?

Beitrag von Linkat »

Du kannst auch die Darsteller in einen String mit Kommas getrennt erfassen.
z.B.:

Code: Alles auswählen

 
var darsteller,:String;
......
darsteller:='Bruce Willis, Denzel Washington, Robert de Niro';


Du kannst dann mit der Funktion 'ExtractDelimited' aus der Unit 'strutils' auf die einzelnen Darsteller zugreifen.

Code: Alles auswählen

s:=ExtractDelimited(1,darsteller,[',']);

weist s den Wert 'Bruce Willis' und

Code: Alles auswählen

s:=ExtractDelimited(3,darsteller,[',']);

weist s den Wert 'Robert de Niro' zu.

Gruß, Linkat
Linux Mint 21; Lazarus 2.2.4 FPC 3.2.2; RaspiOS

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Okay, danke dir - Werde ich mir die Tage mal genauer anschauen. :)

Curry

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Stringlist speichern?

Beitrag von Mathias »

Code: Alles auswählen

s:=ExtractDelimited(1,darsteller,[',']);

Und was passiert, wen im Darsteller-Name ein ',' vorkommt.
Ich würde es bei der Array belassen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Mathias hat geschrieben:

Code: Alles auswählen

s:=ExtractDelimited(1,darsteller,[',']);

Und was passiert, wen im Darsteller-Name ein ',' vorkommt.
Ich würde es bei der Array belassen.



Warum sollte im Namen ein Kommata vorkommen? :D

Ich werde mir die versch. Vorschläge nochmal anschauen und mir davon die für mich passendste aussuchen - Auf jeden Fall danke ich euch beide für euren Input. :)

Linkat
Lazarusforum e. V.
Beiträge: 530
Registriert: So 10. Sep 2006, 23:24
OS, Lazarus, FPC: Linux Mint 21.3; Lazarus 3.0 FPC 3.2.2; RaspiOS
CPU-Target: AMD 64, ARM 32
Wohnort: nr Stuttgart

Re: Stringlist speichern?

Beitrag von Linkat »

Das Trennzeichen, hier im Beispiel ein ',' kann natürlich auch durch jedes andere Zeichen ersetzt werden.

Gruß, Linkat
Linux Mint 21; Lazarus 2.2.4 FPC 3.2.2; RaspiOS

Curry
Beiträge: 8
Registriert: Di 27. Dez 2016, 18:00

Re: Stringlist speichern?

Beitrag von Curry »

Ich bin es nochmal .... :c
Also ich habe es jetzt probiert mit dem Array umzusetzen. Da bekomme ich aber einen mir unbekannten Fehler, welchen ich nicht verstehe.

Das ist jetzt meine neue Recorddeklaration:

Code: Alles auswählen

  TFilm = record
    Name: string[40];
    Genre: string[20];
    Regisseur: string[40];
    Darsteller: Array[1..5] of string[40];
    Zuletzt: TDatum;
    Info: string[250];
  end;
 
var
  Form1: TForm1;
  dat: file of TFilm;
  Film: TFilm;


Und hier soll dann ein neuer Datensatz angelegt werden:

Code: Alles auswählen

procedure TForm3.Button1Click(Sender: TObject);
var
  i: integer;
begin
    Reset(Unit1.dat);
    while not (EOF(dat)) do
      Read(dat, Film);
    Film.Name := edit1.Text;
    edit1.Text := '';
    case Radiogroup1.ItemIndex of
      0: Unit1.Film.Genre := 'Action';
      1: Unit1.Film.Genre := 'Thriller';
    end;
    Radiogroup1.ItemIndex := -1;
    Film.Regisseur := edit3.Text;
    Edit3.Text := '';
    for i := 1 to Listbox1.Items.Count do
      Film.Darsteller[i] := Listbox1.Items[i];
    Listbox1.Items.Clear;
    Film.Info := Memo1.Text;
    Memo1.Text := '';
    Listbox1.Visible := False;
    Button3.Visible := False;
    Write(Unit1.dat, Unit1.Film);


Der Fehler muss irgendwo hier liegen, wenn ich den Teil nämlich als Kommentar schreibe, gibt es den Fehler nicht:

Code: Alles auswählen

    for i := 1 to Listbox1.Items.Count do
      Film.Darsteller[i] := Listbox1.Items[i];


Also er kompiliert auch alles, aber wenn ich dann eben auf den Button klicke stürzt das Programm mit der Fehlermeldung ab:
Bild
und öffnet mir das Fenster "win32listsl.inc" auf die Stelle

Code: Alles auswählen

function TWin32ListStringList.Get(Index: Integer): String;
Var
  s: string;
  w: widestring;
begin
  if (Index < 0) Or (Index >= Count) then
    raise Exception.Create('Out of bounds.')
  else
  begin
    if UnicodeEnabledOS then
    begin
      SetLength(w, Windows.SendMessageW(FWin32List, FFlagGetTextLen, Index, 0));
      Windows.SendMessageW(FWin32List, FFlagGetText, Index, LPARAM(PWideChar(w)));
      Result := UTF16ToUTF8(w);
    end
    else
    begin
      SetLength(s, Windows.SendMessage(FWin32List, FFlagGetTextLen, Index, 0));
      Windows.SendMessage(FWin32List, FFlagGetText, Index, LPARAM(PChar(s)));
      Result := AnsiToUtf8(s);
    end;
  end;
end;


Das ist ja irgendeine Funktion für eine Stringlist, aber ich habe doch alle meine Stringlisten entfernt?
Und wenn ich eine Grenze von meinem Array überschreite, gibt er mir doch normalerweise eine andere Fehlermeldung?

Also irgendwie bin ich ganz verwirrt. :c

Habt ihr eine Idee, woran es liegen könnte?
Curry.

shokwave
Beiträge: 470
Registriert: Do 15. Nov 2007, 16:58
OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
CPU-Target: i386, x64
Wohnort: Gera

Re: Stringlist speichern?

Beitrag von shokwave »

for i := 1 to Listbox1.Items.Count do
Film.Darsteller[i] := Listbox1.Items[i];


Eine Stringlist, also auch Listbox.Items beginnt bei 0 und endet dementsprechend bei Count - 1.
mfg Ingo

Antworten