AW: Fehler beim Programm beenden
Du benutzt den VST (meiner Meinung nach) recht .. ungewöhnlich :D Ich schaue später daheim nochmal genauer drüber und poste ein paar Verbesserungsvorschläge.
Edit: Also, ich bin immer sehr gut damit gefahren, wenn ich einen einzigen Record-Typ für alle Nodes verwendet habe. Das ist auch die einzig valide Anwendungsweise. In deinem Falle hast du nur "Glück", dass deine Records alle gleich groß sind. Wenn ich verschiedene Node Typen habe, mache ich das immer so:
Delphi-Quellcode:
Deine Methode über das NodeLevel zu differenzieren geht natürlich auch.
type
TNodeType = (ntCustomer, ntBulding, ..); PNodeData = ^TNodeData; TNodeData = record NodeType: TNodeType; NodeObject: TObject; end; Die
Delphi-Quellcode:
ist aber in jedem Falle immer
NodeDataSize
Delphi-Quellcode:
für alle Nodes.
SizeOf(TNodeData)
Bezüglich der Objektverwaltung sehe ich zwei Möglichkeiten:
|
AW: Fehler beim Programm beenden
EDIT: Videos doch gefunden...
Erstmal vielen Dank für die Tips. Ich werde das ganz jetzt mal durcharbeiten und versuchen zu verbessern. Ich werden das dann hier nochmal einstellen. PS: Kann man irgendwo noch auf das "Stammtisch" Video zum VST zugreifen? Gruß Jens |
AW: Fehler beim Programm beenden
Groß gesagt gefunden und dann war es doch nur das vom Stammtisch 1...
Weiß jemand wo das Video vom Stammtisch 2 zu finden ist? |
AW: Fehler beim Programm beenden
Hallo nochmal,
ich glaube das ich bei der Definition der Datenhaltung (Objekt, Record) schon was verbessern muss. Eventuell kann mit hier jemand einen Tip geben... Aktuell habe ich 3 Klassen "Kunde", "Objekt" und "System" Der Aufbau sieht wie folgt aus:
Delphi-Quellcode:
Den Bezug zum VST stelle ich über das NodeLevel her.
{ TObject für die Kundendaten }
type TOCustomers = class(TObject) private FID : integer; //ID FESID : integer; //ESID FName : string; //Name des Kunden FOrt : string; //Ort des Kunden FStraße : string; //Straße des Kunden FAnsprechpartnerId : integer; //Ansprechpartnernummer FAnsprechpartner : string; //Ansprechpartner FAnsPosition : string; //Position/Stellung FEMail : string; //EMail des Ansprechpartners FTel1 : string; //Telefonnummer 1 des Ansprechpartners FTel2 : string; //Telefonnummer 2 des Ansprechpartners FFax : string; //Faxnummer des Ansprechpartners FBemerkung : string; //Kunden Zusatzinformation public property Kunden_Kundennummer : integer read FID write FID; property Kunden_ESKundennummer : integer read FESID write FESID; property Kunden_Kundenname : string read FName write FName; property Kunden_Ort : string read FOrt write FOrt; property Kunden_Straße : string read FStraße write FStraße; property Kunden_Bemerkung : string read FBemerkung write FBemerkung; property Ansprechpartner_Id : integer read FAnsprechpartnerId write FAnsprechpartnerId; property Ansprechpartner_Name : string read FAnsprechpartner write FAnsprechpartner; property Ansprechpartner_Position : string read FAnsPosition write FAnsPosition; property Ansprechpartner_EMail : string read FEMail write FEMail; property Ansprechpartner_Telefon1 : string read FTel1 write FTel1; property Ansprechpartner_Telefon2 : string read FTel2 write FTel2; property Ansprechpartner_Fax : string read FFax write FFax; end; //Das Object für die Objektdaten und Systemdaten ist ähnlich. Teilweise andere Felder
Delphi-Quellcode:
Beim Click auf den jeweiligen Knoten (VST in Baumstruktur auf der Linken Programmseite), werden auf der rechten Seite in verschiedenen Frames die zugehörigen Datenangezeigt und zum editieren etc. zur Verfügung gestellt.
NodeLevel 0 = Datenbankpfad
NodeLevel 1 = Kundendaten NodeLevel 2 = Objektdaten NodeLevel 3 = Systemdaten NodeLevel 4 = Menüpunkte zum System Da ich drei Objekte habe, stellt sich mir die Frage erneut nach dem
Delphi-Quellcode:
. Wie geh man sowas an.
NodeDataSize
Vorstellen könnte ich mir folgende alternativen. 1. Das Object "TOCustomers" bekommt ein Feld
Delphi-Quellcode:
und das Object TOBulidings bekommt ein Feld
Objektdaten array of TOBuildings
Delphi-Quellcode:
2.
Systemdaten array of TOSystems
Die Objecte liegen ja je in einer eigenen Unit. Diese könnte man ja eventuell in einen Record einbinden:
Delphi-Quellcode:
Vieleicht gibt es ja noch bessere/sinnvollere Wege. Die Variante 2 scheint mir aktuell am sinnvollsten. Dabei würde ich einen Record verwenden, welchen ich dann auch dem NodeDataSize zuweisen könnte.
type
TRKundenDaten = record FKundedaten : TOCustomers; FObjektdaten : TOBuildings; FSystemdaten : TOSystems; end; PRKundenDaten = ^TRKundenDaten;
Delphi-Quellcode:
Weiterhin, wäre dann das OnFreeNode klar...
vst.NodeDataSize:=sizeof(TRKundenDaten);
Delphi-Quellcode:
Ich hoffe, das ich nicht ganz auf dem Holzweg bin...
procedure TForm1.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var daten: PRMeineDaten; begin daten := vst.GetNodeData(node); daten^.FKundendaten.free; daten^.FObjektdaten.free; daten^.FSystemdaten.free; end; |
AW: Fehler beim Programm beenden
Zitat:
http://www.delphipraxis.net/1319525-post21.html Wahrscheinlich hast du übersehen, das er ihn erweitert hat. Da steht alles drin, was du wissen musst. Punkt Nummer eins habe ich dir bspw. schon auf der vorigen Threadseite gezeigt. Du musst die Vorschläge nur verstehen und umsetzen. |
AW: Fehler beim Programm beenden
Zitat:
ja zu erstens, ich habe das übersehen. Ich glaube auch das da alles drin steht, aber der letze Punkt trifft leider auch zu. Ich habe das ganze jetzt versucht mal umzubauen. Als erstes hier mal mein neuer "record"
Delphi-Quellcode:
Aber der erste Crash kommt direkt beim einlesen...
type
TRKundenDaten = record FKundedaten : TOCustomers; FObjektdaten : TOBuilding; FSystemdaten : TOSystems; end; PRKundenDaten = ^TRKundenDaten;
Delphi-Quellcode:
var
Node, CustomerNode, BuildingNode, SystemNode, ReportNode : PVirtualNode; Daten : PRKundenDaten; begin try ... CustomerNode := vstKunden.AddChild(nil); //in diese Knoten wir nach nur der BD-Pfad geschrieben... //Kundendaten laden aus Kundendatenbank ... //Dann durch alle Datensätze mit einer Schleife... for i := 0 to DMMasterData.qryCustomerData.RecordCount -1 do begin try BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(CustomerNode); //Mit Create und ohne versucht... Aber hier kracht es {Daten^.FKundedaten := TOCustomers.create; Daten^.FObjektdaten := TOBuilding.create; Daten^.FSystemdaten := TOSystems.create;} with Daten^ do begin FKundedaten.Kunden_Kundennummer := DMMasterData.qryCustomerData.FieldByName('Kunden_Kundennummer').AsInteger; ... end; |
AW: Fehler beim Programm beenden
Ich würde den Weg von Zacherl gehen, also ein Record mit einen Enum-Typen zur Erkennung und einen allgemeinen TObject-Platzhalter, anstatt alle drei Objekte da rein zuverwursten.
Irgendwann kommt nämlich noch ein weiteres Objekt dazu und dann noch eins und noch eins... Es wäre auch super mega klasse hilfreich, wenn du ein kleines Beispielprojekt zusammenstellen könntest. Oft zeigt sich dann, dass das Problem an ganz anderen Stellen liegt. Wenn man nämlich als hilfsbereiter Threadleser sich selber sowas ähnliches zusammenzimmert - siehe im folgenden - dann kracht es nicht! So weiß man natürlich nicht, woran es genau in deinen Quelltext scheitert.
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees; type TOCustomers = class(TObject) private FID: Integer; // ID FESID: Integer; // ESID FName: string; // Name des Kunden FOrt: string; // Ort des Kunden FStraße: string; // Straße des Kunden FAnsprechpartnerId: Integer; // Ansprechpartnernummer FAnsprechpartner: string; // Ansprechpartner FAnsPosition: string; // Position/Stellung FEMail: string; // EMail des Ansprechpartners FTel1: string; // Telefonnummer 1 des Ansprechpartners FTel2: string; // Telefonnummer 2 des Ansprechpartners FFax: string; // Faxnummer des Ansprechpartners FBemerkung: string; // Kunden Zusatzinformation public property Kunden_Kundennummer: Integer read FID write FID; property Kunden_ESKundennummer: Integer read FESID write FESID; property Kunden_Kundenname: string read FName write FName; property Kunden_Ort: string read FOrt write FOrt; property Kunden_Straße: string read FStraße write FStraße; property Kunden_Bemerkung: string read FBemerkung write FBemerkung; property Ansprechpartner_Id: Integer read FAnsprechpartnerId write FAnsprechpartnerId; property Ansprechpartner_Name: string read FAnsprechpartner write FAnsprechpartner; property Ansprechpartner_Position: string read FAnsPosition write FAnsPosition; property Ansprechpartner_EMail: string read FEMail write FEMail; property Ansprechpartner_Telefon1: string read FTel1 write FTel1; property Ansprechpartner_Telefon2: string read FTel2 write FTel2; property Ansprechpartner_Fax: string read FFax write FFax; end; TOBuilding = class end; TOSystems = class end; TRKundenDaten = record FKundedaten: TOCustomers; FObjektdaten: TOBuilding; FSystemdaten: TOSystems; end; PRKundenDaten = ^TRKundenDaten; type TForm1 = class(TForm) vstKunden: TVirtualStringTree; procedure FormCreate(Sender: TObject); procedure VstKundenFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); private public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); var I : Integer; CustomerNode, BuildingNode, SystemNode: PVirtualNode; Daten: PRKundenDaten; begin vstKunden.BeginUpdate; try vstKunden.Clear; CustomerNode := vstKunden.AddChild(nil); vstKunden.InvalidateNode(CustomerNode); vstKunden.NodeDataSize := SizeOf(TRKundenDaten); for I := 0 to 10 do begin BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(CustomerNode); // das folgende geht anstandslos Daten^.FKundedaten := TOCustomers.Create; Daten^.FObjektdaten := TOBuilding.Create; Daten^.FSystemdaten := TOSystems.Create; end; vstKunden.SortTree(0, sdAscending, True); finally vstKunden.EndUpdate; end; end; procedure TForm1.VstKundenFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Kunden_Daten: PRKundenDaten; begin case vstKunden.GetNodeLevel(Node) of 0: begin Kunden_Daten := Sender.GetNodeData(Node); Finalize(Kunden_Daten^); end; end; end; end. |
AW: Fehler beim Programm beenden
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo TiGü,
als Anlage mal das Musterprojekt genau nach Deinen vorgaben. Trotzallem immer noch der gleiche Fehler. Ich habe auch mal mit FastMM eingebunden. Das EventLog liegt dem Musterprojekt bei. Selbst in diesem kleinen Projekt entsteht der gleiche Fehler. Ich habe auch nochmal mein aktuelles Projekt geprüft und bearbeitet. Ich habe diese genau nach Deinem Vorschlag zusammengebaut und wie im Musterprojekt kommt die Fehlermeldung. Grundlegend habe ich noch Fragen zu Zacherls vorschlagen und der Umsetzung. Das aber vieleicht später. Erstmal stellt sich mir die Frage, ob die Komponenten eventuell verbogen oder falsch konfiguriert ist. 2 Alternative, kann es mit Windows 10 zusammenhängen? Gruß Jens |
AW: Fehler beim Programm beenden
Zwei Sachen sind mir aufgefallen:
1.
Delphi-Quellcode:
muss vor dem ersten AddChild stehen, sonst weiß der VST ja nicht, wie groß der Node sein soll und nachfolgende Speicheroperationen laufen ins (n)irgendwo.
vstKunden.NodeDataSize := SizeOf(TRKundenDaten);
2. Wie schon gesagt, solltest du die Objekte in einer separaten Liste speichern und diese selbst wieder freigeben. Dann ist die Zuständigkeit sauber geregelt und du kannst auf das OnFreeNode komplett verzichten. Der VST arbeitet nur mit den Daten, der braucht sich nicht darum zu kümmern wo die herkommen und ob die freigegeben werden müssen.
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var I : Integer; CustomerNode, BuildingNode, SystemNode: PVirtualNode; Daten: PRKundenDaten; fk:TOCustomers; fo:TOBuilding; fs:TOSystems; begin vstKunden.NodeDataSize := SizeOf(TRKundenDaten); KundenList:=TObjectList.create; // separate Liste vstKunden.BeginUpdate; try vstKunden.Clear; CustomerNode := vstKunden.AddChild(nil); vstKunden.InvalidateNode(CustomerNode); for I := 0 to 10 do begin BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(CustomerNode); // das folgende geht anstandslos fk := TOCustomers.Create; fo := TOBuilding.Create; fs := TOSystems.Create; Daten^.FKundedaten := fk; Daten^.FObjektdaten := fo; Daten^.FSystemdaten := fs; KundenList.Add(fk); // wahrscheinlich reicht hier aber auch ein Object pro Node KundenList.Add(fo); KundenList.Add(fs); end; vstKunden.SortTree(0, sdAscending, True); finally vstKunden.EndUpdate; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin KundenList.free; end; |
AW: Fehler beim Programm beenden
Zitat:
Delphi-Quellcode:
in folgende Zeilen:for I := 0 to 10 do begin BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(CustomerNode); ...
Delphi-Quellcode:
Außerdem bitte noch das OnFreeNode ergänzen:for I := 0 to 10 do begin BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(BuildingNode); ...
Delphi-Quellcode:
Und jetzt darfst du gerne mit den Kopf auf den Tisch schlagen. :wall: :mrgreen:
procedure TForm1.vstKundenFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var Kunden_Daten: PRKundenDaten; begin case vstKunden.GetNodeLevel(Node) of 0: begin Kunden_Daten := Sender.GetNodeData(Node); Kunden_Daten^.FKundedaten.Free; Kunden_Daten^.FObjektdaten.Free; Kunden_Daten^.FSystemdaten.Free; Finalize(Kunden_Daten^); end; end; end; PS: Trotzdem wäre der Weg mit externer Datenhaltung über eine Objektliste langfristig besser! Bitte beschäftige dich damit. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz