|
Antwort |
Registriert seit: 11. Jan 2009 Ort: Wilnsdorf 1.439 Beiträge Delphi XE2 Professional |
#31
Also ich glaube ich bin zu doof dazu. Ich krieg das irgendwie nicht umgesetzt.
Ich will daher nochmal freundlichst die Frage stellen. Um mir das ganze nochmal in Ruhe ansehen zu können, würde ich gerne das Stammtisch Video 2 nochmal sehen. Aber wie ja bereits festgestellt, gibt es das nicht mehr. Hat den nicht einer der Administratoren das Video noch? Zusätzlich wäre es schon, wenn mir mal jemand den Vorschlag mit der Objektliste erklären könnte. Danke schon mal. Gruß Jens
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt. |
Zitat |
Perlsau
(Gast)
n/a Beiträge |
#32
Hab mir dein Test-Projekt heruntergeladen, ausprobiert und untersucht. Dabei ist mir aufgefallen, daß ich den VirtualStringTree (VST) ganz anders verwende als du:
Als erstes lege ich einen Record für NodeData fest, damit ich dort die Daten des Nodes eintragen kann, die am Ende in den diversen Spalten des VST angezeigt werden sollen. Das fehlt bei dir. Wenn ich Objekte erzeuge, die angezeigt werden sollen, ob nun mit oder ohne VST, verwende ich die TObjectList, und zwar nicht die aus der Unit Contnrs, sondern die aus den Generics, die es, soweit ich weiß, erst seit Delphi 2009 gibt: BList : Generics.Collections.TObjectList<TStartBild>; Ich versuch dir das mal an einem meiner etwas älteren Projekte zu erklären: In einer Unit habe ich eine Klasse für die Bilder, die angezeigt werden sollen. Eine Klasse deshalb, weil zum Bild auch ein TLabel gehört:
Delphi-Quellcode:
Die einzelnen Module dieser Anwendung befinden sich in Frames. Beim Programmstart wird der Startframe geladen und bereitgestellt. Das ist der Frame, der in den beiden Beispiel-Grafiken unten angezeigt wird. In diesem Frame kann ich nun zwischen Icon- und Baumdarstellung wählen; Grundlage für beide Darstellungsformen ist die Objektliste. In der Function ObjektNeu erzeuge ich die Objektliste und weise ihr die in der Datenbank gespeicherten Icons, Texte und Beschreibungen zu. Die Variable Objekt vom Typ TStartBild darf nicht freigegeben werden, da der darin enthaltene Pointer direkt dem jeweiligen Item der Objektliste übergeben wird:
UNIT Startbilder;
INTERFACE USES ExtCtrls, StdCtrls, Classes, Graphics; TYPE TStartBild = Class PRIVATE { Private-Deklarationen } Var fModulId : Integer; fBild : TImage; fTitel : TLabel; Function GetfModulId : Integer; Procedure SetfModulId(Const Value : Integer); Function GetfBild : TImage; Procedure SetfBild(Const Value : TImage); Function GetfTitel : TLabel; Procedure SetfTitel(Const Value : TLabel); PUBLIC { Public-Deklarationen } Constructor Create(); Destructor Destroy; override; Property ModulId : Integer read GetfModulId write SetfModulId; Property Bild : TImage read GetfBild write SetfBild; Property Titel : TLabel read GetfTitel write SetfTitel; END; IMPLEMENTATION { TStartBild } // ----- Modul-Id zurückliefern -------------------------------------------------------------------------------------------------- Privat Function TStartBild.GetfModulId: Integer; begin Result := fModulId; end; // ----- Modul-Id setzen --------------------------------------------------------------------------------------------------------- Privat Procedure TStartBild.SetfModulId(Const Value: Integer); begin fModulId := Value; end; // ----- Bild zurückliefern ------------------------------------------------------------------------------------------------------ Privat Function TStartBild.GetfBild: TImage; begin Result := fBild; end; // ----- Bild setzen ------------------------------------------------------------------------------------------------------------- Privat Procedure TStartBild.SetfBild(Const Value: TImage); begin fBild.Assign(Value); end; // ----- Label zurückliefern ----------------------------------------------------------------------------------------------------- Privat Function TStartBild.GetfTitel: TLabel; begin Result := fTitel; end; // ----- Label setzen ------------------------------------------------------------------------------------------------------------ Privat Procedure TStartBild.SetfTitel(Const Value: TLabel); begin fTitel.Assign(Value); end; // ########## PUBLIC METHODEN ######################################################################################################## // ----- Constructor Create ------------------------------------------------------------------------------------------------------ Privat Constructor TStartBild.Create; begin inherited; fBild := TImage.Create(nil); fBild.Visible := False; fBild.Constraints.MaxWidth := 500; fBild.Constraints.MaxHeight := 500; fBild.Constraints.MinWidth := 100; fBild.Constraints.MinHeight := 100; fBild.AutoSize := False; fBild.Stretch := True; fBild.Proportional := True; fBild.Center := True; fBild.Picture.Bitmap.Canvas.Brush.Style := bsClear; fBild.Picture.Bitmap.Canvas.Pen.Color := clRed; fBild.Picture.Bitmap.Canvas.Pen.Style := psSolid; fBild.Picture.Bitmap.Canvas.Pen.Width := 5; fTitel := TLabel.Create(nil); fTitel.Visible := False; fTitel.AutoSize := False; fTitel.Layout := tlCenter; fTitel.Alignment := taCenter; fTitel.WordWrap := True; fTitel.ParentFont := True; end; // ----- Destructor Destroy ------------------------------------------------------------------------------------------------------ Privat Destructor TStartBild.Destroy; begin If Assigned(fBild) Then fBild.Free; If Assigned(fTitel) Then fTitel.Free; inherited; end; end.
Delphi-Quellcode:
Je nachdem, welche Darstellungsform der Anwender nun wählt (Baum oder Icons), wird der Baum gezeichnet oder die Icons:
Function TFrame_Main.ObjektNeu(Const PId : Integer) : Integer;
Const BildPreString = 'Img_'; LabelPreString = 'Lbl_'; Var Objekt : TStartBild; LblName : String; Bild : TBitMap; R : TRect; begin Result := -1; Objekt := TStartBild.Create; Bild := TBitMap.Create; Try Bild.PixelFormat := pf24bit; Bild.Width := ImgList.Width; Bild.Height := ImgList.Height; R.Left := 0; R.Top := 0; R.Right := Bild.Width -1; R.Bottom := Bild.Height -1; Try LblName := RemoveUnwantetChars(Titel); Objekt.ModulId := fProgModus; Objekt.Bild.Parent := Panel_Start; Objekt.Bild.Name := BildPreString + LblName; Objekt.Bild.Width := Laenge; Objekt.Bild.Height := Laenge; Objekt.Bild.Canvas.Font := Panel_Start.Font; Objekt.Bild.OnClick := BildGeklickt; Objekt.Titel.Parent := Panel_Start; Objekt.Titel.Name := LabelPreString + LblName; Objekt.Titel.Caption := Titel; Objekt.Titel.OnClick := TitelGeklickt; Objekt.Titel.OnMouseMove := TitelMausBewegt; Objekt.Titel.Hint := HintText; Objekt.Titel.ShowHint := HintsZeigen; If Not DatMod.BlobToImage(Feld,Objekt.Bild.Picture.Bitmap) Then Raise Exception.Create('Fehler beim Einlesen eines Blobfelds in ein Bitmap ') at @TFrame_Main.ObjektNeu; If PId = 0 Then RahmenZeichnen(Objekt.Bild.Picture.Bitmap.Canvas); Result := BList.Add(Objekt); Objekt.Bild.Tag := fProgModus; Objekt.Titel.Tag := Result; Bild.Canvas.StretchDraw(R,Objekt.Bild.Picture.Graphic); ImgList.Add(Bild,Nil); Except On e:Exception Do Begin If Assigned(Objekt) Then Objekt.Free; fInitOkay := e.Message; End; End; Finally Bild.Free; End; end;
Delphi-Quellcode:
Die komplette UnitFrameMain incl. DFM-Datei hab ich angehängt.
// ----- Zeichnet die Bilder auf das Panel in der Scrollbox --------------------------------------------------------------------- Privat
Procedure TFrame_Main.Zeichnen; Var i,z, Titel_Breite, Titel_Hoehe, GesamtHoehe, GesamtBreite, HoehenMulti, AnzahlX, AnzahlY, X,Y : Integer; Obj : TStartBild; // Panel an Scrollbox-Breite anpassen Procedure PanelBreiteAnScrollBox; Begin If ScrollBox_Start.VertScrollBar.Visible Then Panel_Start.Width := ScrollBox_Start.ClientWidth - 4 Else Panel_Start.Width := ScrollBox_Start.ClientWidth + 15; End; // Code innerhalb der For-Schleife Procedure ObjekteZeigen; Begin Obj := BList[i]; Obj.Bild.Width := Laenge; Obj.Bild.Height := Laenge; Obj.Titel.Width := Laenge; Obj.Titel.Height := TitelHoehe; Obj.Bild.Left := X; Obj.Bild.Top := Y; Obj.Titel.Left := X; Obj.Titel.Top := Obj.Bild.Top + Laenge; Obj.Titel.Color := TitelFarbe; Obj.Titel.Font := Panel_Start.Font; Obj.Bild.Visible := True; Obj.Titel.Visible := True; // Application.ProcessMessages; X := X + GesamtBreite; If X + GesamtBreite > Panel_Start.ClientWidth Then Begin X := Abstand; Y := Y + GesamtHoehe; End; End; // ********** HAUPTPROCEDURE ********** begin If Not Self.Visible Then Exit; z := BList.Count; If z > 0 Then Begin Label_Schriftart.Color := TitelFarbe; PanelBreiteAnScrollBox; TitelHoehe := 0; For i := 0 To z-1 Do Begin Obj := BList[i]; Obj.Bild.Visible := False; Obj.Titel.Visible := False; Obj.Bild.Canvas.Font := Panel_Start.Font; Titel_Breite := Obj.Bild.Canvas.TextWidth(Obj.Titel.Caption) + 10; If Titel_Breite > Laenge Then HoehenMulti := 2 Else HoehenMulti := 1; Titel_Hoehe := (Obj.Bild.Canvas.TextHeight(Obj.Titel.Caption) + (HoehenMulti * 6)) * HoehenMulti; If Titel_Hoehe > TitelHoehe Then TitelHoehe := Titel_Hoehe; End; GesamtBreite := Laenge + Abstand; GesamtHoehe := Laenge + Abstand + TitelHoehe; X := Abstand; Y := Abstand; AnzahlX := (Panel_Start.Width - Abstand) Div GesamtBreite; If AnzahlX >= z Then Begin Panel_Start.Height := GesamtHoehe + Abstand; PanelBreiteAnScrollBox; End Else Begin AnzahlY := z Div AnzahlX; If z Mod AnzahlX > 0 Then Inc(AnzahlY); Panel_Start.Height := (AnzahlY * GesamtHoehe) + Abstand; PanelBreiteAnScrollBox; End; AnzahlX := (Panel_Start.Width - Abstand) Div GesamtBreite; If AnzahlX >= z Then Begin Panel_Start.Height := GesamtHoehe + Abstand; PanelBreiteAnScrollBox; End Else Begin AnzahlY := z Div AnzahlX; If z Mod AnzahlX > 0 Then Inc(AnzahlY); Panel_Start.Height := (AnzahlY * GesamtHoehe) + Abstand; PanelBreiteAnScrollBox; End; For i := 0 To z-1 Do ObjekteZeigen; End; end; // ----- Baumdarstelung initialisieren ------------------------------------------------------------------------------------------ Privat Function TFrame_Main.BaumInit(Sender: TBaseVirtualTree) : Boolean; Var Data : PNodeData; Node : PVirtualNode; PId : Integer; begin Try If Not DatMod.Qset_Modulix.Active Then DatMod.Qset_Modulix.Open; DatMod.Qset_Modulix.Filter := 'ID_PARENT=0 and BILD<>null'; DatMod.Qset_Modulix.Filtered := True; If DatMod.Qset_Modulix.RecordCount > 0 Then Begin DatMod.Qset_Modulix.First; VST.Clear; VST.BeginUpdate; // Haupteinträge (Parent = 0) While Not DatMod.Qset_Modulix.Eof Do Begin Node := Sender.AddChild(Sender.RootNode); Data := Sender.GetNodeData(Node); Data.ImgId := DatMod.Qset_Modulix.FieldByName('REIHENFOLGE').AsInteger; Data.Id := DatMod.Qset_Modulix.FieldByName('ID_MODULIX').AsInteger; Data.PId := DatMod.Qset_Modulix.FieldByName('ID_PARENT').AsInteger; Data.Titel := DatMod.Qset_Modulix.FieldByName('TITEL').AsString; Data.Caption := DatMod.Qset_Modulix.FieldByName('CAPTION').AsString; DatMod.Qset_Modulix.Next; End; // Untereinträge (Parent > 0) DatMod.Qset_Modulix.Filter := 'ID_PARENT>0 and BILD<>null'; If DatMod.Qset_Modulix.RecordCount > 0 Then Begin DatMod.Qset_Modulix.First; While Not DatMod.Qset_Modulix.Eof Do Begin PId := DatMod.Qset_Modulix.FieldByName('ID_PARENT').AsInteger; Node := GetNodeBy_Id(PId); If Node <> Nil Then Begin Node := VST.AddChild(Node); Data := Sender.GetNodeData(Node); Data.ImgId := DatMod.Qset_Modulix.FieldByName('REIHENFOLGE').AsInteger; Data.Id := DatMod.Qset_Modulix.FieldByName('ID_MODULIX').AsInteger; Data.PId := PId; Data.Titel := DatMod.Qset_Modulix.FieldByName('TITEL').AsString; Data.Caption := DatMod.Qset_Modulix.FieldByName('CAPTION').AsString; End; DatMod.Qset_Modulix.Next; End; End; VST.EndUpdate; DatMod.Qset_Modulix.Filtered := False; Result := True; End Else Raise Exception.Create('keine Parent=0 Einträge in der Datenbank') at @TFrame_Main.BaumInit; Except on e:exception Do Begin Result := False; fInitOkay := e.Message; End; End; end; |
Zitat |
Registriert seit: 16. Jun 2011 703 Beiträge Delphi 12 Athens |
#33
Zusätzlich wäre es schon, wenn mir mal jemand den Vorschlag mit der Objektliste erklären könnte.
Danke schon mal. Gruß Jens Du definiert die eine ObjectList. Da ich Delphi 2007 habe, nehme ich zwangsläufig die einfache TOjectList aus der Unit Contnrs;
Delphi-Quellcode:
Beim Einlesen des Trees passiert folgendes:
type
TForm1 = class(TForm) vstKunden: TVirtualStringTree; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } KundenList:TObjectList; // <----- public { Public-Deklarationen } end;
Delphi-Quellcode:
Zum Schluss musst du nur die ObjectList wieder freigeben. Damit werden automatisch auch die darin enthaltenen Objekte freigegeben. Der VST muss sich um nichts mehr kümmern.
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; // <--- Instanz der ObjectList erzeugen; // Besser wäre es, alles ab hier in eine eigene Methode auszulagern, // damit man das Einlesen des Trees vom Erzeugen des Liste trennen kann. // Vielleicht soll der Tree ja wärend der Lebenszeit des Form nochmal neu eingelesen werden. vstKunden.BeginUpdate; try vstKunden.Clear; //CustomerNode := vstKunden.AddChild(nil); wozu soll das gut sein? //vstKunden.InvalidateNode(CustomerNode); for I := 0 to 10 do begin BuildingNode := vstKunden.AddChild(nil); Daten := vstKunden.GetNodeData(BuildingNode); fk := TOCustomers.Create; // <---- Datenobjekte erzeugen fo := TOBuilding.Create; // Wahrscheinlich brauchst du nur ein Objekt pro Node, fs := TOSystems.Create; // das dann die verschiedenen Node-Typen verwalten kann. // Das ist aber ein anderes Thema Daten^.FKundedaten := fk; // <---- Datenobjekte dem VST übergeben Daten^.FObjektdaten := fo; Daten^.FSystemdaten := fs; KundenList.Add(fk); // <---- Datenobjekte der Liste hinzufügen KundenList.Add(fo); // Die Objekte gehören jetzt der ObjectList KundenList.Add(fs); end; vstKunden.SortTree(0, sdAscending, True); finally vstKunden.EndUpdate; end; end;
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin KundenList.free; end; |
Zitat |
Registriert seit: 6. Apr 2011 Ort: Berlin 3.070 Beiträge Delphi 10.4 Sydney |
#34
Also ich glaube ich bin zu doof dazu. Ich krieg das irgendwie nicht umgesetzt.
Ich will daher nochmal freundlichst die Frage stellen. Um mir das ganze nochmal in Ruhe ansehen zu können, würde ich gerne das Stammtisch Video 2 nochmal sehen. Aber wie ja bereits festgestellt, gibt es das nicht mehr. Hat den nicht einer der Administratoren das Video noch?
Auch das wird schwerlich genau auf deinen Fall eingehen, sondern nur allgemeine Vorgehensweisen beschreiben. Die Transferleistung musst du selber erbringen. Zusätzlich wäre es schon, wenn mir mal jemand den Vorschlag mit der Objektliste erklären könnte.
Was verstehst du genau nicht? Inzwischen wurde dir diese Variante vier bis fünf Mal angeraten und erklärt. |
Zitat |
Registriert seit: 11. Jan 2009 Ort: Wilnsdorf 1.439 Beiträge Delphi XE2 Professional |
#35
So, nicht das noch einer glaubt, der Beitrag interresiert mich nicht mehr. Ich bin schon die ganze Woche dabei, das VST mit verschiedenen Tutorials mir in den Kopf zu arbeiten.
Das ganze ist auch mittlerweile Verständlicher für mich. Ich mache das ganze aktuell mit einem Record und auch ohne Fehlermeldung. Mein Verständnisproblem liegt allerdings aktuell trotzallem noch in der Datenhaltung. Folgenden Aufbau möchte ich kurz darstellen:
Delphi-Quellcode:
So, und jetzt stell ich mir die Frage. Das ganze funktioniert auch, allerdings, wenn ich ja die Daten des Objekts zuweisen, dann mache ich das ja wie folgt..
//So sieht jetzt mein neuer Datenrecord aus
type pVSTNodeData = ^rVSTNodeData; rVSTNodeData = record KundenName, ObjektName, AnlagenTyp, AnlagenBezeichnung : WideString; KundenNr, ObjektNr, AnlagenNr : Integer; end; //Über folgende Funktion lade ich jetzt mein VST (Allerdings nur den ersten Root mit Daten und diesen setze ich im OnInit auf vsHASChildren) procedure TfReportClient.LoadVST; var pNode : PVirtualNode; i : Integer; begin try try vstKunden.BeginUpdate; vstKunden.Clear; //Datenpfad Knoten erstellen pNode := vstKunden.AddChild(nil); //Kundendaten laden und zugehörige Knoten erstellen LoadCustomersData(pNode); //vst Fertigstellen vstKunden.EndUpdate; ExpandedRootNodes(vstKunden); vstKunden.SortTree(0,sdAscending,True); except //... end; finally //... end; end; procedure TfReportClient.LoadCustomersData(ANode : PVirtualNode); var pNode : PVirtualNode; Daten : pVSTNodeData; i : Integer; begin try try //Kundentabelle öffnen if DMMasterData.OpenCustomerQuery then begin //Ersten Datensatz wählen DMMasterData.qryCustomerData.First; //Schleife um alle Kunden zu durchlaufen und die Knoten für die Kunden zu erstellen. for i := 0 to DMMasterData.qryCustomerData.RecordCount -1 do begin //Kunden Knoten erstellen pNode := vstKunden.AddChild(ANode); //Daten zuweisen Daten := vstKunden.GetNodeData(pNode); Daten^.KundenName := DMMasterData.qryCustomerData.FieldByName('Kunden_Kundenname').AsString; Daten^.KundenNr := DMMasterData.qryCustomerData.FieldByName('Kunden_Kundennummer').AsInteger; //Nächsten Datensatz anwählen DMMasterData.qryCustomerData.Next; end; end; except end; finally //Datenbank wieder schliessen end; end; //Die einzelnen Nodes darauf vorbereiten, das Sie Childs haben procedure TfReportClient.vstKundenInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); begin case vstKunden.GetNodeLevel(Node) of 1: begin vstKunden.CheckType[Node] := ctCheckBox; vstKunden.CheckState[Node] := csCheckedNormal; vstKunden.HasChildren[Node] := True; end; 2: begin vstKunden.HasChildren[Node] := True; end; 3: begin vstKunden.HasChildren[Node] := True; end; end; end; //Den Node für das Objekt und die zugehörigen Daten erstelle ich erst mit dem aufklappen (OnExpanding) des jeweiligen Node procedure TfReportClient.vstKundenExpanding(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean); var Daten : pVSTNodeData; begin case vstKunden.GetNodeLevel(Node) of 1: begin if Node.ChildCount = 0 then begin //Objektdaten laden und zugehörige Knoten erstellen Daten := vstKunden.GetNodeData(Node); LoadObjektData(Node, Daten^.KundenNr); end; //... end; end; end; //Objektnode erstellen und Daten laden procedure TfReportClient.LoadObjektData(ANode : PVirtualNode; AInt : integer); var i : Integer; pNode : PVirtualNode; Daten : pVSTNodeData; begin try try //Objektedaten laden aus Objektdatenbank DMMasterData.qryObjectData.Parameters.ParamByName('Kundennummer').Value := AInt; if DMMasterData.OpenObjectQuery then begin //Ersten Datensatz wählen DMMasterData.qryObjectData.First; //Schleife um alle Objekte zu durchlaufen und die Knoten für die Objekte zu erstellen. for i := 0 to DMMasterData.qryObjectData.RecordCount -1 do begin //Objekt Knoten erstellen pNode := vstKunden.AddChild(ANode); //Daten zuweisen Daten := vstKunden.GetNodeData(pNode); Daten^.ObjektName := DMMasterData.qryObjectData.FieldByName('Objekt_Objektname').AsString; Daten^.ObjektNr := DMMasterData.qryObjectData.FieldByName('Objekt_Objektnummer').AsInteger; //Nächsten Datensatz anwählen DMMasterData.qryObjectData.Next; end; end; except end; finally DMMasterData.CloseObjectQuery; end; end;
Delphi-Quellcode:
Würde ich jetzt diesen Record zu diesem Node abfragen...
Daten := vstKunden.GetNodeData(pNode);
Daten^.ObjektName := DMMasterData.qryObjectData.FieldByName('Objekt_Objektname').AsString;
Delphi-Quellcode:
wird das Ergebniss immer
Daten := vstKunden.GetNodeData(pNode);
ShowMessage(Daten^.Kundenname); ShowMeddage(Daten^.Objektname); Kundenname = ''; Objektname = 'Ich bin der Objektname von pNode' sein. Ist ja auch klar, weil der zeiger zum Kundennamen bzw. zum Datenrecord nicht vorhanden ist. Wie löst man sowas. Ist das so vorgesehen. Müsste ich hier wirklich mit...
Delphi-Quellcode:
arbeiten?
Daten := vstKunden.GetNodeData(pNode.Parent);
ShowMessage(Daten^.Kundenname);
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt. |
Zitat |
Registriert seit: 11. Jan 2009 Ort: Wilnsdorf 1.439 Beiträge Delphi XE2 Professional |
#36
*push*
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt. |
Zitat |
Registriert seit: 6. Apr 2011 Ort: Berlin 3.070 Beiträge Delphi 10.4 Sydney |
#37
Deine Frage ist unklar.
Baue ein kurzes (!!!) Beispielprojekt, zippe es und hänge es an. Im Quelltext per Kommentar deutlich machen wie der Soll- und Ist-Zustand sich darstellt. |
Zitat |
Registriert seit: 11. Jan 2009 Ort: Wilnsdorf 1.439 Beiträge Delphi XE2 Professional |
#38
Hallo TiGü,
Zitat von TiGü:
Deine Frage ist unklar.
Sie Anhang. Ich hoffe, das erklärt meine Frage etwas... Ich versuche es aber auch nochmal wie folgt darzustellen... Meine VST Struktur sieht ja in etwa so aus...
Code:
Wenn ich jetzt im VST auf Kunde1 "klicke", möchte ich natürlich die Daten des zugehörigen Kunden abfragen... Da ich ja nach aktueller Erklärung versuche das Ziel zu verfolgen, das ganze mit einem Record zu erschlagen, habe ich diesen aktuell als ersten Entwurf wie folgt aufgebaut...
-Kunde1
-Objekt1 -Objekt2 -Objekt3 -Kunde2 -Objekt1 -Objekt2 ...
Delphi-Quellcode:
Das heißt, in diesem Record sind alle notwendigen Daten. Dies ist aber falsch, da ja der Zusammenhang zwischen den verschiedenen Kunden und Objekten (Anlagen) nicht hergestellt werden kann. Dies wäre ja nur dann möglich, wenn z.B.
type
pVSTNodeData = ^rVSTNodeData; rVSTNodeData = record KundenName, ObjektName, AnlagenTyp, AnlagenBezeichnung : WideString; KundenNr, ObjektNr, AnlagenNr : Integer; end; Objektname : array of WideString wäre. In der Datenzuweisung mache ich ja immer
Delphi-Quellcode:
Dies würde aber ja bedeuten, das in der Datenebene "Kunde" die Felder "Objekt" etc. überflüssig sind (da nie genutz) und in der Datenebene "Objekt" das Felde "Kunde" überflüssig ist. Dies würde mich wieder in die Richtung meiner ehemaligen Lösung bewegen "3 Objekt/Records" zu erstellen. Je einen für die entsprechende "Node-Ebene"
//for-Schleife Kunden
pNode1 := vstKunden.AddChild(pNode); Daten := vstKunden.GetNodeDate(pNode1); Daten^.KundenName := 'Kunde'; //for-Schleife Objekte innerhalb der for-Schleife Kunden pNode2 := vstKunden.AddChild(pNode1); Daten := vstKunden.GetNodeDate(pNode2); //Hier ist ja der Zeiger auf einen ganz anderen record (logisch, anderer Node) Daten^.KundenName := 'Kunde'; Wenn ich Euch aber richtig verstanden habe, kann man das irgendwie mit dem NodeType oder ähnlich lösen. Und da Blick ich nicht richtig durch... Ich hoffe, dass man das jetzt verstehen konnte... Danke schon mal und Gruß Jens
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt. |
Zitat |
Registriert seit: 16. Jun 2011 703 Beiträge Delphi 12 Athens |
#39
Vergiss diesen Record!!
Das vermischt Datenhaltung mit visueller Darstellung, da deine Daten im Control gespeichert werden. Nicht gut. Ich würde mir eine Datenstruktur überlegen, die zuerst einmal komplett außerhab dem VST stattfindet. z.B.
Delphi-Quellcode:
Dann braucht du noch eine ObjectList für die Kunden:
TKunde = class
Name : String; Nr : String; Objects: TObjectList; constructor Create; // hier Objects erzeugen destructor Destroy; Override; // hier Objects freigeben end; TKundenObjekt = class Name : String; WasAuchImmer: String; end; KundenListe : TObjectList; Vor dem Einlesen der Daten in den VST wird jetzt erstmal diese Datenstruktur gefüllt. Dein Record für den VST sieht dann so aus:
Delphi-Quellcode:
Dann gehst du die zuvor befüllte KundenListe durch und baust den Inhalt des VST auf:
type
pVSTNodeData = ^rVSTNodeData; rVSTNodeData = record Data : TObject; end;
Delphi-Quellcode:
Jetzt kennt jeder Node des VST seine relevanten Daten und nur diese. Im OnGetText kannst du dann herausfinden, ob es sich um einen Kudnen oder ein Objekt handelt:
//for-Schleife Kunden (i)
pNode1 := vstKunden.AddChild(pNode); Daten := vstKunden.GetNodeDate(pNode1); Daten^.Data := KundenListe[i]; //for-Schleife Objekte (j) innerhalb der for-Schleife Kunden (i) pNode2 := vstKunden.AddChild(pNode1); Daten := vstKunden.GetNodeDate(pNode2); Daten^.Data:=TKunde(KundenListe[i]).Objects[j]);
Delphi-Quellcode:
Daten := vstKunden.GetNodeDate(Node);
if Daten^.Data is TKunde then // Kunde else // Objekt |
Zitat |
Registriert seit: 11. Jan 2009 Ort: Wilnsdorf 1.439 Beiträge Delphi XE2 Professional |
#40
Hallo zusammen,
ich habe das Problem gelöst. Und ich glaube sogar, das ganze zu verstehen. Abschließen nochmal vielen Dank für Eure Hilfe und folgend mal die Lösung des Problems...
Delphi-Quellcode:
//Der Record mit dem integrierten Objekt
type PTreeData = ^TTreeData; TTreeData = record FObject : TObject; end; //Im OnCreate der Form ... vstKunden.NodeDataSize := SizeOf(TTreeData); LoadVST(true); ... //Das Laden des ersten Knoten procedure TfReportClient.LoadVST(IsStarted: Boolean); var pNode : PVirtualNode; begin try vstKunden.BeginUpdate; vstKunden.Clear; .... pNode := vstKunden.AddChild(nil); //Kundendaten laden LoadCustomersData(pNode,IsStarted); vstKunden.EndUpdate; ExpandedRootNodes(vstKunden); vstKunden.SortTree(0, sdAscending, True); ... end; //Das Laden der Kunden procedure TfReportClient.LoadCustomersData(ANode : PVirtualNode; IsStarted : Boolean); var i : Integer; Daten_Kunde : TOCustomers; begin try try //Kundendaten laden aus Kundendatenbank if DMMasterData.OpenCustomerQuery then begin DMMasterData.qryCustomerData.First; for i := 0 to DMMasterData.qryCustomerData.RecordCount -1 do begin Daten_Kunde := TOCustomers.Create; with Daten_Kunde do begin Kunden_Kundennummer := DMMasterData.qryCustomerData.FieldByName('Kunden_Kundennummer').AsInteger; Kunden_ESKundennummer := DMMasterData.qryCustomerData.FieldByName('Kunden_ESKundennummer').AsInteger; Kunden_Kundenname := DMMasterData.qryCustomerData.FieldByName('Kunden_Kundenname').AsString; Kunden_Ort := DMMasterData.qryCustomerData.FieldByName('Kunden_Ort').AsString; Kunden_Straße := DMMasterData.qryCustomerData.FieldByName('Kunden_Straße').AsString; Kunden_Bemerkung := DMMasterData.qryCustomerData.FieldByName('Kunden_Bemerkung').AsString; Ansprechpartner_Id := DMMasterData.qryCustomerData.FieldByName('Ansprechpartner_Id').AsInteger; Ansprechpartner_Name := DMMasterData.qryCustomerData.FieldByName('Ansprechpartner_Name').AsString; end; vstKunden.AddChild(ANode,Daten_Kunde); DMMasterData.qryCustomerData.Next; end; end; DMMasterData.CloseCustomerQuery; except Daten_Kunde.Free; end; finally DMMasterData.CloseCustomerQuery; end; end; //Festlegung, das die Knoten Kunden Kinder haben im OnInit des VST procedure TfReportClient.vstKundenInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); begin case vstKunden.GetNodeLevel(Node) of 1: begin vstKunden.CheckType[Node] := ctCheckBox; vstKunden.CheckState[Node] := csCheckedNormal; vstKunden.HasChildren[Node] := True; end; 2: begin vstKunden.HasChildren[Node] := True; end; 3: begin vstKunden.HasChildren[Node] := True; end; end; end; //Die Objekte und Anlagen werden erst nach dem sie aufgeklappt werden erstellt procedure TfReportClient.vstKundenExpanding(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean); var NodeLevel : Integer; Daten : PTreeData; begin NodeLevel := vstKunden.GetNodeLevel(Node); if vstKunden.ChildCount[Node] = 0 then begin case NodeLevel of 1: //Objektdaten beim aufklappen des Objekt Knoten erstellen/laden begin Daten := vstKunden.GetNodeData(Node); LoadObjektData(Node, TOCustomers(Daten.FObject).Kunden_Kundennummer); end; 2: //Anlagendaten beim aufklappen des Anlagen Knoten erstellen/laden begin Daten := vstKunden.GetNodeData(Node); LoadSystemData(Node, TOBuilding(Daten.FObject).Objekt_Objektnummer); end; end; end; end; //Das Freigeben der Daten procedure TfReportClient.vstKundenFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Daten : PTreeData; begin Daten := vstKunden.GetNodeData(Node); if not Assigned(Daten) then exit; Daten.FObject.Free; end;
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt. |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |