Re: TStringlist Feld Objects adressieren, wie?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mario Peters
Beiträge: 3
Registriert: Sa 26. Apr 2025, 22:41

TStringlist Feld Objects adressieren, wie?

Beitrag von Mario Peters »

Hallo,

ich programmiere noch nicht so lange mit Object Pascal. Bin gerade bei der Stringliste. Dabei stoße ich auf folgendes Problem:

Ich will ein zusätzliches Objekt in die Stringliste einfügen, was mit der Methode AddObject gehen sollte.

Das Objekt scheut so aus:

Code: Alles auswählen

Type
TSelectedStrings = class
    FSelected: boolean;
    FNumber: dword;
public
    Create;
    property Selected: boolean read FSelected write FSelected;
    property Number: dword read FNumber;
end;
Dann eine normale TStringList:

Code: Alles auswählen

var Strings: TStringList;

strings := TStringlist.Create;
Nun will ich erreichen dass für eine spätere Liste eine Abfrage möglich wird, ob der String in der Liste ausgewählt wurde.
Dazu muss ich den mit AddObject("MeinString", TSelectedStrings.Create); eingefügten String adressieren können um dann den String als ausgewählt zu markieren.

Das wollte ich so hier machen:

Code: Alles auswählen

TSelectedStrings(strings[cur].Objects[cur]).selected:=true;


Hier aber meckert der Compiler. (Typkonflikt, und illegal qualifier, es gebe kein member Objects Warum? TStringlist stammt doch von TStrings ab und TStrings enthält doch den Member Objects. Wie adressiere ich also den String richtig?
Ist die Numerirung von Objects richtig bei dieser Typdefinition im Feld Objects?

Erreichen will ich die Markierung eines oder mehrerer meiner Strings in der Liste als ausggewählt oder nicht ausgewählt.
Zuletzt geändert von Mario Peters am Mo 5. Mai 2025, 13:54, insgesamt 1-mal geändert.

Benutzeravatar
theo
Beiträge: 10867
Registriert: Mo 11. Sep 2006, 19:01

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von theo »

Code: Alles auswählen

TSelectedStrings(Strings.Objects[cur]).Selected:=true;    

Mario Peters
Beiträge: 3
Registriert: Sa 26. Apr 2025, 22:41

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Mario Peters »

Danke, aber wie mache ich das?

Ich könnte meine Klasse TSelectedStrings so ändern:

Code: Alles auswählen

TSelectedStrings = class
 private   
    FDataStr: String;
    fselected: boolean;
 public
    constructor create;   
    DataStr: String read FDataStr write FDataStr;
    selected: boolean read fselected write fselected;
end;

StringsListe: specialize TFPGObjectList<TSelectedStrings>;
Dann würde ich das hier coden, was ich danach gleich mal teste, wenn kein Erfolg dann muss ich wohl noch mal fragen:

Code: Alles auswählen

var
SelStr1:TSelectedStrings;
SelStr2:TSelectedStrings;
SelStr3:TSelectedStrings;
SelStr4:TSelectedStrings;
SelStr5:TSelectedStrings;

begin
  SelStr1 := TSelectedStrings.Create;
  SelStr1.DataStr := 'Erster String';
  SelStr1.Selected := false;
  StringsListe.Add(SelStr1);

  SelStr2 := TSelectedStrings.Create;
  SelStr2.DataStr := 'Erster String';
  SelStr2.Selected := false;
  StringsListe.Add(SelStr2);

  SelStr3 := TSelectedStrings.Create;
  SelStr3.DataStr := 'Erster String';
  SelStr3.Selected := false;
  StringsListe.Add(SelStr3);

  SelStr4 := TSelectedStrings.Create;
  SelStr4.DataStr := 'Erster String';
  SelStr4.Selected := false;
  StringsListe.Add(SelStr4);

  SelStr5 := TSelectedStrings.Create;
  SelStr5.DataStr := 'Erster String';
  SelStr5.Selected := false;
  StringsListe.Add(SelStr5);
Damit sollte sich mein Problem nach meinem bisherigen Verständnis lösen lassen. Habe ich von hier: viewtopic.php?t=16821, da war vor einiger Zeit eine Frage die mit der Empfehling von Generics beantwortet wurde.
Zuletzt geändert von Mario Peters am Mo 5. Mai 2025, 14:20, insgesamt 2-mal geändert.

Benutzeravatar
theo
Beiträge: 10867
Registriert: Mo 11. Sep 2006, 19:01

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von theo »

Mario Peters hat geschrieben: Mo 5. Mai 2025, 13:55 Danke, aber wie mache ich das?
Was meinst du damit?
Statt
TSelectedStrings(Strings[cur].Objects[cur]).selected:=true; schreibst du
TSelectedStrings(Strings.Objects[cur]).Selected:=true;

Nicht vergessen die Objekte am Ende freizugeben, bzw. "OwnsObjects" auf true zu setzen.

Benutzeravatar
Zvoni
Beiträge: 368
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Zvoni »

Wieso überhaupt eine zusätzliche Klasse?

Ein stumpfer Boolean sollte doch reichen

Code: Alles auswählen

program Project1;
{$mode objfpc}{$H+}
Uses SysUtils, Classes;

Var
  SL:TStringList;
  i:Integer;

begin
  SL:=TStringList.Create;
  SL.AddObject('Eintrag 1',TObject(True));
  SL.AddObject('Eintrag 2',TObject(False));
  For i:=0 To SL.Count-1 Do Writeln('String=',SL.Strings[i],' - Boolean=',Integer(SL.Objects[i]).ToBoolean);
  SL.Free;
  Readln;
end.
Falls du jedoch zusätzliche Informationen zu dem True/False speichern willst (ich sehe ein Number:DWord), wäre vielleicht ein Record besser.

Unabhängig davon: Wenn du ein Objekt aus der Stringlist ansprechen willst, musst du immer zurück casten wie es Theo gezeigt hat

Und was deine Fehlermeldung betrifft (Typkonflikt/Illegal Qualifier/Kein Member Object):
Du verwendest "Strings" ohne Qualifier, und FPC kennt in diesem Moment nicht den TYP bzw. Variable namens "Strings" (achte auf das letzte "s").
Du willst die Property "Strings" der Stringlist ansprechen, also musst du FPC auch sagen, dass "Strings" zu deiner Stringlist gehört.

EDIT:
Anbei wie man dann einen Boolean im Object ändert. Noch nie gemacht. Sieht ein wenig skurril aus.

Code: Alles auswählen

program Project1;
{$mode objfpc}{$H+}
Uses SysUtils, Classes;

Var
  SL:TStringList;
  i:Integer;

begin
  SL:=TStringList.Create;
  SL.AddObject('Eintrag 1',TObject(True));
  SL.AddObject('Eintrag 2',TObject(False));
  For i:=0 To SL.Count-1 Do Writeln('String=',SL.Strings[i],' - Boolean=',Integer(SL.Objects[i]).ToBoolean);
  Writeln('----------------------------');
  For i:=0 To SL.Count-1 Do SL.Objects[i]:=TObject(Integer(Not Integer(SL.Objects[i]).ToBoolean));  //Flip the Boolean
  For i:=0 To SL.Count-1 Do Writeln('String=',SL.Strings[i],' - Boolean=',Integer(SL.Objects[i]).ToBoolean);
  SL.Free;
  Readln;
end.
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von m.fuchs »

Zvoni hat geschrieben: Mo 5. Mai 2025, 14:35 Wieso überhaupt eine zusätzliche Klasse?

Ein stumpfer Boolean sollte doch reichen

Code: Alles auswählen

  SL.AddObject('Eintrag 1',TObject(True));
Könntest du bitte gerade Neulingen nicht so etwas beibringen. Ich weiß, dass diese Casterei zwischen Objekten und einfachen Datentypen beliebt ist, schön ist aber anders.
Das merkst du ja auch selber:
Zvoni hat geschrieben: Mo 5. Mai 2025, 14:35 [...]Sieht ein wenig skurril aus.
@Mario Peters: Bleib bei deinem ursprünglichen Ansatz da ein Objekt reinzuhängen, das ist der korrekte Weg.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
Zvoni
Beiträge: 368
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Zvoni »

Hier das gleiche aber mit Record

Code: Alles auswählen

program Project1;
{$mode objfpc}{$H+}
Uses SysUtils, Classes;

Type
  PRec = ^TRec;
  TRec=Record
    Selected:Boolean;
    Number:Integer;
  end;

Var
  SL:TStringList;
  i:Integer;
  r:PRec;

begin
  SL:=TStringList.Create;
  New(r);
  r^.Selected:=True;
  r^.Number:=42;
  SL.AddObject('Eintrag 1',TObject(r));
  New(r);
  r^.Selected:=False;
  r^.Number:=84;
  SL.AddObject('Eintrag 2',TObject(r));
  For i:=0 To SL.Count-1 Do Writeln('String=',SL.Strings[i],' - Selected=',prec(SL.Objects[i])^.Selected,' - Number=',PRec(SL.Objects[i])^.Number);
  Writeln('----------------------------');
  For i:=0 To SL.Count-1 Do PRec(SL.Objects[i])^.Selected:=Not PRec(SL.Objects[i])^.Selected;  //Flip the Boolean
  For i:=0 To SL.Count-1 Do Writeln('String=',SL.Strings[i],' - Selected=',prec(SL.Objects[i])^.Selected,' - Number=',PRec(SL.Objects[i])^.Number);
  For i:=0 To SL.Count-1 Do Dispose(PRec(SL.Objects[i]));
  SL.Free;
  Readln;
end.
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Mario Peters
Beiträge: 3
Registriert: Sa 26. Apr 2025, 22:41

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Mario Peters »

@theo:

Aaaah Ok, danke, so geht das also. Generics dürften zwar in Zukunft die bessere Wahl sein, aber nun weiß ich endlich wie ich in einer nicht generischen Stringliste sowas adressiere. :)

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2807
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von m.fuchs »

Zvoni hat geschrieben: Mo 5. Mai 2025, 15:01 Hier das gleiche aber mit Record
Was soll da jetzt der Vorteil gegenüber einem Object sein?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
Zvoni
Beiträge: 368
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Zvoni »

m.fuchs hat geschrieben: Mo 5. Mai 2025, 15:15
Zvoni hat geschrieben: Mo 5. Mai 2025, 15:01 Hier das gleiche aber mit Record
Was soll da jetzt der Vorteil gegenüber einem Object sein?
Ich habe ja nicht behauptet, dass es ein Vorteil ist.
Ich sagte, es wäre eine Alternative zu einer vollen Klasse, wobei es dann auch wieder korrekt ist, dass mit einer Klasse mit dem OwnsObjects das StringList.Free dann auch alle Objekte befreit.
Wobei auch korrekt ist, dass bei einer Klasse man keinen TypeCast über TObject machen muss, da alle Klassen eh von TObject abstammen.
Der Typecast ist dann nur rückwärts, wenn man das Object auslesen will, und da nimmts es sich nichts weg zu einerm Record (ausser der manuellen Speicher-Verwaltung).
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
Zvoni
Beiträge: 368
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Zvoni »

m.fuchs hat geschrieben: Mo 5. Mai 2025, 14:58 Könntest du bitte gerade Neulingen nicht so etwas beibringen. Ich weiß, dass diese Casterei zwischen Objekten und einfachen Datentypen beliebt ist, schön ist aber anders.
Das merkst du ja auch selber:
Zvoni hat geschrieben: Mo 5. Mai 2025, 14:35 [...]Sieht ein wenig skurril aus.
@Mario Peters: Bleib bei deinem ursprünglichen Ansatz da ein Objekt reinzuhängen, das ist der korrekte Weg.
Auch richtig, wobei aber gerade bei Neulingen man aufpassen muss, dass sie nicht mit Atomraketen auf Spatzen schiessen, und sich dann in einer Sackgasse verzetteln.
Dazu haben wir aber zu wenig Informationen, weil aus der Problembeschreibung bin ich nicht ganz schlau geworden.
Ausser dass er in der Stringlist irgendwelche Strings einsammelt, und diese Kennzeichnen will ob sie ausgewählt sind oder nicht,
wobei ich noch immer nicht weiss, wie dieses Number:Dword aus seiner OP zu interpretieren ist.

Allein von seinem Original-Post hätte ich eher zu einer StringList ohne Objekte tendiert, und die StringList als Key/Value-Pair genommen.
Was wiederum aber voraussetzt, dass es keine Duplikate bei den Strings gibt
Key = der eindeutige String
Value = 0/1 (Für "Selected") gefolgt von "Number" (getrennt mit einem "|") und dann beim Auslesen einfach aufsplitten/ausparsen.
Keine kopfschmerzen wegen Objects, TObject, Hin/Her-Casten, Speichermanagment und was mir gerade nicht einfällt.

KISS = Keep It Simple Stupid
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Soner
Beiträge: 726
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: TStringlist Feld Objects adressieren, wie?

Beitrag von Soner »

m.fuchs hat geschrieben: Mo 5. Mai 2025, 15:15
Zvoni hat geschrieben: Mo 5. Mai 2025, 15:01 Hier das gleiche aber mit Record
Was soll da jetzt der Vorteil gegenüber einem Object sein?
Weil das Erstellen und Benutzen von Record schneller als von Objekt ist und Objekte mehr Speicher verbraucht.

Ich hatte über das Thema vor Jahren gepostet.

Antworten