Auf Data von per Assign kopierten TreeView.Items zugreifen

Für Fragen von Einsteigern und Programmieranfängern...

Auf Data von per Assign kopierten TreeView.Items zugreifen

Beitragvon cle » 6. Jul 2018, 16:28 Auf Data von per Assign kopierten TreeView.Items zugreifen

Moin,

ich brauche zwei synchronisierte TreeViews. Dazu kopiere ich den Inhalt des ersten per Items.Assign in den zweiten, was soweit auch funktioniert. Laut Doku sollen dabei auch die mit den Items verknüpften Objekte 'kopiert' werden. Allerdings erhalte ich einen SIGSEGV, wenn ich auf die Daten des zweiten zugreifen will.
Zur Verdeutlichung erstelle ich eine Beispielklasse, hänge eine erstellte Instanz an einen Knoten im TreeView1 und lasse mir im onChange Ereigniss eine Info in einem Label anzeigen. Das funktioniert, wenn ich einen Eintrag im TreeView1 auswähle, im zweiten nicht.
Offensichtlich mache ich etwas falsch!?

Gruß
Alex

Code: Alles auswählen
 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  ComCtrls, StdCtrls;
 
type
 
  TTestClass = class(TObject)
    private
      FText: String;
    public
      constructor Create;
      destructor Destroy; override;
      procedure ShowInfo;
  end;
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Label1: TLabel;
    TreeView1: TTreeView;
    TreeView2: TTreeView;
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
    procedure TreeView2Change(Sender: TObject; Node: TTreeNode);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
 
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
{ TForm1 }
 
procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
  tc: TTestClass;
begin
  for i := 0 to 9 do
  begin
    tc := TTestClass.Create;
    tc.FText := 'Node Info Nr.' + IntToStr(i);
    TreeView1.Items.AddObject(TreeView1.Items.GetLastNode, 'node' + inttostr(i), tc);
  end;
  TreeView2.Items.Assign(TreeView1.Items);
end;
 
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
  i: Integer;
begin
  for i := 0 to TreeView1.Items.Count-1 do
  begin
    TTestClass(TreeView1.Items[i].Data).Free;
  end;
end;
 
procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
  if Assigned(Node.Data) then TTestClass(Node.Data).ShowInfo;
end;
 
procedure TForm1.TreeView2Change(Sender: TObject; Node: TTreeNode);
begin
  if Assigned(Node.Data) then TTestClass(Node.Data).ShowInfo;   // ********* Hier rumpelts
end;
 
 
constructor TTestClass.Create;
begin
  inherited Create;
end;
 
destructor TTestClass.Destroy;
begin
  inherited Destroy;
end;
 
procedure TTestClass.ShowInfo;
begin
  Form1.Label1.Caption := FText;
end;
 
end.
 
cle
 
Beiträge: 16
Registriert: 31. Jan 2018, 11:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3.0.0) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Michl » 6. Jul 2018, 21:41 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Ich habe dein Beispiel eben unter Lazarus Trunk probiert, da geht es. Eben noch unter Lazarus 1.8.5, da geht es nicht. Der Bug ist daher im nächsten Major Release behoben. Bis dahin könntest du Lazarus Trunk nutzen oder müsstest nachträglich händisch die Objekte verknüpfen.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2260
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon wp_xyz » 6. Jul 2018, 22:15 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Ich glaube nicht, dass es auch unter Trunk ein sauberes Programm ergibt:

Die "Objekte", die im Code per AddObject an den TreeNode hängt, sind im allgemeinen Fall nur Pointer.
Code: Alles auswählen
 // TTreeNodes:
     function AddObject(SiblingNode: TTreeNode; const S: string; Data: Pointer): TTreeNode;

Das heißt, das Assign "weiß" gar nicht, wieviele Daten zu kopieren sind. Und in TTreeNode.Assign von Laz-Trunk sieht man tatsächlich, dass nur der Pointer kopiert wird:
Code: Alles auswählen
procedure TTreeNode.Assign(Source: TPersistent);
var
  ANode: TTreeNode;
begin
  if Owner<>nil then Owner.ClearCache;
  if Source is TTreeNode then
  begin
    ANode := TTreeNode(Source);
    Text := ANode.Text;
    Data := ANode.Data;   // <---- HIER
 ...
  end
  else inherited Assign(Source);
end;

Hat der 1.Tree die Nodes sauber aufräumt und dabei die eingehängten Objekte zerstört, kracht es, wenn anschließend der 2.Tree dasselbe macht, weil die eingehängten Objekte nicht mehr existieren - die gab es ja nur 1x.

Besser wäre es, alle Daten außerhalb der TreeViews zu speichern, so dass es sie nur 1x gibt; die beiden Trees müssten sich dann die Daten von der zentralen Stelle abholen und nur anzeigen. TTreeView kann das nicht, aber mit VirtualTreeView sollte es funktionieren.

Oder du stellst sicher dass der 2.Tree die in die Nodes eingehängten Objekte nicht zerstören kann. Erscheint mir allerdings eine Zeitbombe zu sein...
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon af0815 » 7. Jul 2018, 07:41 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Irgendwie passt das mir jetzt das vom Verhalten bei Assign nicht zusammen.

Wenn ich mit Assign einem 2ten Objekt etwas zuweise, dann erwarte ich mir das ich es auch wieder zerstören kann ohne Auswirkung auf das andere Objekt. Entweder dürfen die Objecte nicht zerstört werden oder sind nur referenzgezählte Objekte oder müssen kopiert werden.

Weil wer ist nach einem Assign wirklich für die Verwaltung der Objekte zuständig ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3457
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
CPU-Target: 32Bit (64Bit)
Nach oben

Beitragvon wp_xyz » 7. Jul 2018, 09:05 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Genau das versuchte ich auszudrücken. Ich finde, das ist eine üble Falle.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Michl » 7. Jul 2018, 09:17 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

af0815 hat geschrieben:Weil wer ist nach einem Assign wirklich für die Verwaltung der Objekte zuständig ?
Siehe Beispiel von oben. Dort wo etwas erstellt wird, muss es auch wieder freigegeben werden. Ein TreeView macht beim Zerstören nichts mit den Objekten. Ist doch dann alles gut so.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2260
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon wp_xyz » 7. Jul 2018, 09:26 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Richtig. Da war mein Beitrag irreführend...

Trotzdem: das Unbehagen bleibt bestehen: Da greifen zwei TreeViews auf dieselben Data-Objekte zu. Letztere werden zerstört, und keiner kriegt's mit. Daher würde ich zumindest nach dem TObject(Node.Data).Free noch ein Node.Data := nil einfügen, und nochmals ein TreeView2.Items.Assign(TreeView1.Items), damit die NIL-Data auch im 2.Tree eingetragen sind. Denn nach Form.OnClose kann noch eine Menge passieren, schließlich wird dort das Formular nur versteckt. Oder meinst du OnDestroy? Dort könntest du wahrscheinlich auf diese Vorsichtsmaßnahmen verzichten.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon Michl » 7. Jul 2018, 15:24 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

wp_xyz hat geschrieben:Denn nach Form.OnClose kann noch eine Menge passieren, schließlich wird dort das Formular nur versteckt. Oder meinst du OnDestroy? Dort könntest du wahrscheinlich auf diese Vorsichtsmaßnahmen verzichten.
Richtig zu OnCreate gehört OnDestroy und müsste oben geändert werden.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2260
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon cle » 7. Jul 2018, 15:49 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Oh, da habe ich eine kleine Diskussion ausgelöst ;)
Danke jedenfalls für eure Antworten.

Trunk habe ich benutzt (vergessen zu erwähnen), war aber vielleicht ein paar Tage zu alt. Werde ich nochmal testen.
Dass die Verwaltung der Daten heikel ist, ist mir bewusst. Da muss ich schon selbst für sorgen.
Dass bei onClose das Formular nur versteckt wird, habe ich nicht gewusst. Also sollte man Aufräumprozesse in onDestroy durchführen? Woher weiß ich denn, dass die entspr. Komponenten dann überhaupt noch existieren?

Gruß
Alex
cle
 
Beiträge: 16
Registriert: 31. Jan 2018, 11:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3.0.0) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 7. Jul 2018, 16:39 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Wie Michl schon sagte, ist OnDestroy das Gegenstück zu OnCreate, es wird in umgekehrter Reihenfolge das alles aufgeräumt, was in OnCreate erzeugt wurde. Wenn es richtig gemacht ist, muss alles noch da sein: zuerst kommt das OnDestroy-Ereignis, dann gibt das Formular seine Untercontrols frei und dann sich selbst. Wenn's nicht so gut gemacht ist, muss man in der Routine, in der es evtl kracht, den Zustand abfragen:

Code: Alles auswählen
  if not (csDestroying in ComponentState) then... 

Wenn dir OnDestroy zu knapp vor dem Ende ist, kannst du auch bei OnClose bleiben, solltest aber den Parameter Action auf caFree setzen, damit sich das Formular freigibt und nicht nur verbirgt.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon cle » 7. Jul 2018, 17:24 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Okay, das ist interessant. Ich dachte immer, onClose wäre der Hinweis, alles in Sicherheit zu bringen und aufzuräumen.
Vielen Dank für die Erklärung.
cle
 
Beiträge: 16
Registriert: 31. Jan 2018, 11:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3.0.0) | 
CPU-Target: 64Bit
Nach oben

Beitragvon cle » 11. Jul 2018, 18:55 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Ich habe vor zwei Tagen mit fpcupdeluxe Lazarus Trunk aktualisiert (Linux, 64, gtk2) und damit stürzt das Programm von oben wie gehabt ab. Mit Windows hat fpcupdeluxe nicht funktioniert, bei einem Laz 1.8.2 hat immerhin das if Assigned(Node.Data) gegriffen, im Gegensatz zu Linux.
Nur zur nachträglichen Info @Michl
cle
 
Beiträge: 16
Registriert: 31. Jan 2018, 11:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3.0.0) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 11. Jul 2018, 19:36 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Ich fürchte, der Fehler liegt wo anders. Du solltest ein kleines Demo-Programm schreiben, in dem der Fehler sichtbar wird und mit dem wir hier uns das näher ansehen können. Ich weiß nicht, ob man hier schon wieder Anhänge posten kann. Wenn ja, dann schnüre pas, lfm, lpi and lpr-Dateien (sowie evtl Daten-Dateien) zu einem zip zusammmen und lade dieses hier hoch. Wenn nicht, dann speichere das Demo-Programm irgendwo in einer Cloud.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

Beitragvon cle » 12. Jul 2018, 14:58 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Ähm, aber das Beispiel steht doch schon im ersten Post, incl. Erklärung wann es crashed ...
cle
 
Beiträge: 16
Registriert: 31. Jan 2018, 11:54
OS, Lazarus, FPC: Winux (L 1.6 FPC 3.0.0) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 12. Jul 2018, 15:16 Re: Auf Data von per Assign kopierten TreeView.Items zugreif

Schon, aber das kann ich nicht kompilieren, weil das meiste fehlt: Wo ist die lfm-Datei, in der falsche Properties stecken können, wo die lpi-Datei mit evtl. falschen Compilereinstellungen usw.
wp_xyz
 
Beiträge: 2616
Registriert: 8. Apr 2011, 08:01

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Einsteigerfragen



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste

porpoises-institution
accuracy-worried