[Erledigt] Object in StringGrid mit TFPGObjectList

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

[Erledigt] Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Ich möchte in einem Stringgrid ein Object ablegen und auch wieder auslesen. Dabei bin ich nach Anleitung vor gegangen, wobei ich allerdings das Objekt aus einer TFPGObjectList beziehe. Vermutlich habe ich hier etwas nicht verstanden:

Code: Alles auswählen

procedure TfrmArtikel.btnEditPreisClick(Sender: TObject);
var
  ID: integer;
  P: TArtikelPreis;
begin
  P:= TArtikelPreis(sgPreise.Objects[4, sgPreise.Row]);
  //  Hier will ich mit P arbeiten, also einem Object vom Typ TArtikelPreis 
  Debugln(P.BezPreisgruppe);
  P.Free;
end;       


übergeben habe ich so:

Code: Alles auswählen

 
ArtikelpreisListe: TArtikelPreisListe;
ArtikelpreisListe:= TArtikelPreisListe.Create();
FillArtikelpreisListe;
 
 
...
with sgPreise do
begin     
    RowCount := ArtikelpreisListe.Count;
    for i := 0 to ArtikelpreisListe.Count - 1 do
    begin
    { Zeit  Lohn  Service  Material  Geraet  Fremdleistung   VKNetto   VKBrutto  }
      Cells[0, i] := IntToStr(ArtikelpreisListe.Items[i].ID);
      Cells[1, i] := ArtikelpreisListe.Items[i].BezPreisgruppe;
      Cells[2, i] := ArtikelpreisListe.Items[i].BezMengeneinheit;
      Cells[3, i] := ArtikelpreisListe.Items[i].BezSteuersatz;
// bis hier alles OK
// und jetzt noch das Objekt:
      Objects[0, i] := ArtikelgruppenListe.Items[i];
    end;
end;
FreeAndNil(ArtikelpreisListe);               


Code: Alles auswählen

  TArtikelPreisListe = class(specialize TFPGObjectList<TArtikelPreis>)
  private
 
  public
    function Add(Obj: TArtikelPreis): integer;// override;
    procedure ReadAllData;
    procedure ReadAllByArtikelID(IDArtikel: integer);
    procedure ReadListData(Query: string);
  published
 
  end;   

Ist ArtikelgruppenListe.Items[i] kein Objct des Typs TArtikelPreis?

Wenn ich Warf im Thread zur Combobox richtig verstanden habe, geht das wieder über TypeCast ? - Ich bekomme es nicht hin :oops:
Zuletzt geändert von MacWomble am Do 17. Jan 2019, 20:48, insgesamt 3-mal geändert.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Object in StringGrid mit TFPGObjectList

Beitrag von Michl »

MacWomble hat geschrieben:

Code: Alles auswählen

      Cells[3, i] := ArtikelpreisListe.Items[i].BezSteuersatz;
// bis hier alles OK
// und jetzt noch das Objekt:
      Objects[0, i] := ArtikelgruppenListe.Items[i];
Bist du sicher, daß du ArtikelgruppenListe und nicht ArtikelpreisListe haben wolltest? Wie sieht denn die Deklaration der ArtikelgruppenListe aus?

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

braunbär
Beiträge: 369
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: 64Bit
Wohnort: Wien

Re: Object in StringGrid mit TFPGObjectList

Beitrag von braunbär »

Das erste, was mir auffällt:

Code: Alles auswählen

P:= TArtikelPreis(sgPreise.Objects[4, sgPreise.Row]);

Jetzt ist P ein Zeiger (Klassenvariable sind immer Zeiger auf die eigentlichen Klasseninstanzen) auf eine Klasseninstanz, die in deiner TFPGObjectList gespeichert ist.

Code: Alles auswählen

P.free

Jetzt hast du das Objekt, auf das P gezeigt hat, freigegeben, es ist also das Objekt in der TFPGObjectList freigegeben worden und nicht mehr in der Liste drin, der entsprechende Objects-Pointer ist aber nicht nil (nur der Zeiger p ist hier durch freeandnil =nil gesetzt worden), sondern zeigt immer auf das freigegebene Objekt.. Ich denke, das wolltest du nicht, oder?

P ist nicht eine Kopie des Objekts, sondern nur eine Kopie des Zeigers auf das Objekt.

Das gleiche passiert bei

Code: Alles auswählen

FreeAndNil(ArtikelpreisListe); 

Alle Objekte der Artikelpreisliste werden hier vermutlich freigegeben (abhängig von der Property freeobjects), dadurch zeigen aber die Zeiger, die du in deiner TFPGObjectList gespeichert hast, auch ins Nirwana.

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Michl hat geschrieben:Bist du sicher, daß du ArtikelgruppenListe und nicht ArtikelpreisListe haben wolltest? Wie sieht denn die Deklaration der ArtikelgruppenListe aus?


:oops: :oops: :oops:

Aber es geht trotzdem nicht weiter ...

Mit den Freigaben hast du Recht, aber um diese geht es nicht. Ich will ja dazwischen verarbeiten. Das Objekt lässt sich nicht aus dem Grid lesen, bzw. ist nach dem Auslesen = NIL

Wenn ich dich richtig verstehe ist im Grid nur ein Zeiger. d.h. das Objekt geht verloren, wenn ich die zugrunde liegende Artikelpreisliste freigebe.
Ich werde das nachher mal testen, das wäre eine für mich verständliche und logische Erklärung.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Object in StringGrid mit TFPGObjectList

Beitrag von Michl »

-

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Danke so weit. Das funktioniert jetzt auch.

... und dann war da noch die Frage aufgetaucht, wie ich in der TFPGObjectList (z.B. in der ArtikelpreisListe) einen Eintrag nach Feldinhalt finden kann.
Muss ich hierfür eine Schleife bemühen, oder gibt es eine Funktion?
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Object in StringGrid mit TFPGObjectList

Beitrag von Michl »

Wenn das Objekt bekannt ist, kannst du mit IndexOf dessen Stelle in der Liste zurückgeben lassen.

Wenn du nach Properties deines Objektes suchen willst, musst du dies selber implementieren. Dazu kannst du IndexOf überladen oder eine eigene Suchfunktion implementieren, z.B.:

Code: Alles auswählen

  TArtikelPreisListe = class(specialize TFPGObjectList<TArtikelPreis>)
...
    function IndexOf(AId: Integer): Integer; overload;
    function IndexOf(const ABezPreisgruppe: String): Integer; overload;
  end;
...
function TArtikelPreisListe.IndexOf(AId: Integer): Integer;
var
  i: Integer;
begin
  Result := -1;
  for i := 0 to Count - 1 do
    if AId = TArtikelPreis(Items[i]).ID then  // der Typecast kann weggelassen werden, ist aber zur Codevervollständigung praktisch, siehe unten
      Exit(i);
end;
 
function TArtikelPreisListe.IndexOf(const ABezPreisgruppe: String): Integer;
var
  i: Integer;
begin
  Result := -1;
  for i := 0 to Count - 1 do
    if ABezPreisgruppe = Items[i].BezPreisgruppe then
      Exit(i);
end
Der Compiler kann den generischen Bezeichner Items[i] schon übersetzen. Die Codetools können bisher nur etwas mit TArtikelPreis(Items[i]) anfangen (FPC 3.0.4, Lazarus Trunk). Die Codekomplettierung, Umbenennung Bezeichner usw. funktionieren derzeit nur mit dem Typecast.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Wow ! Danke ! :D
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Mit

Code: Alles auswählen

P := TArtikelPreis(ArtikelpreisListe.items[aIndex]); 


habe ich einen Pointer auf ein Item in der ArtikelpreisListe gesetzt.
Wenn ich nun P andere Werte zuweise, sind diese aber noch nicht in der ArtikelpreisListe sichtbar. (Ich dachte ich verändere so auch das Item, da P nur ein Pointer ist)
Was verstehe ich hier nicht?
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Object in StringGrid mit TFPGObjectList

Beitrag von Michl »

Kannst du mal die Deklaration von TArtikelPreis zeigen?

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Object in StringGrid mit TFPGObjectList

Beitrag von wp_xyz »

Ich denke, die Grundidee, im StringGrid die Pointer auf die einzelnen Einträge in der Preisliste als Object zu verwenden, ist prinzipiell fehlerträchtig, weil nicht sichergestellt ist, dass Grid und Preisliste up-to-date sind. Z.B. kann das Grid einen Eintrag löschen kann, ohne dass die Preisliste das mitkriegt, und umgekehrt. Ich würde stattdessen die ArtikelPreis-Objekte nur in der Preisliste aufführen und für die Ausgabe ein DrawGrid verwenden, anstatt eines StringGrids. Das DrawGrid holt sich die anzuzeigenden Texte aus der Preiseliste. Etwa so wie ich das in dem angehängten Beispiel realisiert habe. Zusätzlich könntest du die Liste noch mit einem OnChange-Event ausstatten, in das sich das Grid einhängt um sich bei einer Änderung der Listeneinträge neu zu zeichnen.
Dateianhänge
Preisliste.zip
(4.87 KiB) 82-mal heruntergeladen
Zuletzt geändert von wp_xyz am Do 17. Jan 2019, 11:38, insgesamt 1-mal geändert.

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

Michl hat geschrieben:Kannst du mal die Deklaration von TArtikelPreis zeigen?


anbei die unit
Dateianhänge
uartikelpreis.pas
(14.81 KiB) 73-mal heruntergeladen
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

MacWomble
Lazarusforum e. V.
Beiträge: 999
Registriert: Do 17. Apr 2008, 01:59
OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
CPU-Target: Intel i7-10750 64Bit
Wohnort: Freiburg

Re: Object in StringGrid mit TFPGObjectList

Beitrag von MacWomble »

wp_xyz hat geschrieben:Ich denke, die Grundidee, im StringGrid die Pointer auf die einzelnen Einträge in der Preisliste als Object zu verwenden, ist prinzipiell fehlerträchtig, weil nicht sichergestellt ist, dass Grid und Preisliste up-to-date sind. Z.B. kann das Grid einen Eintrag löschen kann, ohne dass die Preisliste das mitkriegt, und umgekehrt. Ich würde stattdessen die ArtikelPreis-Objekte nur in der Preisliste aufführen und für die Ausgabe ein DrawGrid verwenden, anstatt eines StringGrids. Das DrawGrid holt sich die anzuzeigenden Texte aus der Preiseliste. Etwa so wie ich das in dem angehängten Beispiel realisiert habe.


Danke für die Hinweise und die Demo, ich schau mir das an und versuche auch hieraus zu lernen.

Genau in der von dir geäußerten Kritik liegt auch eines meiner Probleme. Ich bekomme die Preise in der Datenbank aktualisiert, aber wenn ich dann das StringGrid wieder neu bestücke (aus ArtikelPreisliste), habe ich immer noch die alten Daten. Da zeigt sich schon die Unzuverlässigkeit meiner Lösung. Die Artikelpreisliste möchte ich aber nach Möglichkeit nicht andauernd neu aus der Datenbank lesen.

Was ich machen möchte:
Im (Wieauchimmer-)Grid wird eine Zeile selektiert. Das damit in Zusammenhang stehende Objekt soll über eine Procedure an die Bearbeitungsmaske gereicht, bearbeitet und zurück gegeben werden. Wenn ich das richtig interpretiert habe, macht Deine Demo genau diese (Habe es mir nur kurz angesehen, komme erst nachmittags dazu)

Ich bin ja noch ganz am Anfang und mache meine ersten bewussten Schritte mit Objekten und Objektlisten. Da ich mein Mammutprojekt umstellen möchte, habe ich mit den einfacheren Sachen (Artikel und Preis und ein paar Listen für Comboboxen) begonnen. So nach und nach kommen dann weitere Sachen dazu. Ich denke, wenn ich die Grundlagen mal verstanden habe, ergibt sich der Rest. Ich habe jedenfalls - dank euch - bereits extrem viel in den letzten 7 Tagen dazu gelernt. :shock:, zumindest bilde ich mir das ein. :oops: :D
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Object in StringGrid mit TFPGObjectList

Beitrag von Michl »

MacWomble hat geschrieben:Mit

Code: Alles auswählen

P := TArtikelPreis(ArtikelpreisListe.items[aIndex]); 


habe ich einen Pointer auf ein Item in der ArtikelpreisListe gesetzt.
Wenn ich nun P andere Werte zuweise, sind diese aber noch nicht in der ArtikelpreisListe sichtbar. (Ich dachte ich verändere so auch das Item, da P nur ein Pointer ist)
Was verstehe ich hier nicht?
P ist gemäß obrigen Code und der Deklaration eine Instanz der Klasse TArtikelPreis. Ich hab keine Ahnung warum das nicht gehen sollte.

+1 zu wp seinem Hinweis!!

PS: Ich würde statt P einen Bezeichner wie ArtikelPreis, AArtikelPreis oder LArtikelPreis wählen.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Object in StringGrid mit TFPGObjectList

Beitrag von wp_xyz »

Das mit der Datenbank lese ich hier zum ersten Mal. Dann wäre DBGrid genau das richtige. Es verhält sich etwa genauso, wie mein DrawGrid mache. Es enthält selbst keine Daten, sondern holt sie sich aus der Datenbank. Anders beim StringGrid, das die Daten direkt enthält, und die Daten im StringGrid sind Strings, der zusätzliche Objects-Pointer ist eine Krücke, um dieses Grid etwas flexibler zu machen.

Was stört dich daran, die Preisliste "dauernd" aus der Datenbank eingelesen zu haben? Ob die Daten der Preisliste in einem TDataset liegen oder einer TObjectList oder einem Array, ist doch egal.

MacWomble hat geschrieben:in der von dir geäußerten Kritik[...]
Ich will niemanden "kritisieren"...

Antworten