AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Fehler beim Programm beenden
Thema durchsuchen
Ansicht
Themen-Optionen

Fehler beim Programm beenden

Ein Thema von Jens Hartmann · begonnen am 19. Okt 2015 · letzter Beitrag vom 15. Nov 2015
Antwort Antwort
Seite 4 von 4   « Erste     234   
Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#31

AW: Fehler beim Programm beenden

  Alt 29. Okt 2015, 21:21
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.
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#32

AW: Fehler beim Programm beenden

  Alt 29. Okt 2015, 23:24
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:
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.
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:
Delphi-Quellcode:
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;
Je nachdem, welche Darstellungsform der Anwender nun wählt (Baum oder Icons), wird der Baum gezeichnet oder die Icons:
Delphi-Quellcode:
// ----- 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;
Die komplette UnitFrameMain incl. DFM-Datei hab ich angehängt.
Miniaturansicht angehängter Grafiken
rechpro_icon.jpg   rechpro_baum.jpg  
Angehängte Dateien
Dateityp: zip UnitFrameMain.zip (22,7 KB, 4x aufgerufen)
  Mit Zitat antworten Zitat
bcvs

Registriert seit: 16. Jun 2011
668 Beiträge
 
Delphi 12 Athens
 
#33

AW: Fehler beim Programm beenden

  Alt 30. Okt 2015, 07:04
Zusätzlich wäre es schon, wenn mir mal jemand den Vorschlag mit der Objektliste erklären könnte.

Danke schon mal. Gruß Jens
Ich mache es mal anhand von deinem Beispiel. Ist doch ganz einfach:

Du definiert die eine ObjectList. Da ich Delphi 2007 habe, nehme ich zwangsläufig die einfache TOjectList aus der Unit Contnrs;

Delphi-Quellcode:
type
  TForm1 = class(TForm)
    vstKunden: TVirtualStringTree;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
    KundenList:TObjectList; // <-----
  public
    { Public-Deklarationen }
  end;
Beim Einlesen des Trees passiert folgendes:

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; // <--- 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;
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.

Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  KundenList.free;
end;
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#34

AW: Fehler beim Programm beenden

  Alt 30. Okt 2015, 08:41
Also ich glaube ich bin zu doof dazu. Ich krieg das irgendwie nicht umgesetzt.
Was ist daran so schwierig, zwei/dreizeilige Codeschnipsel zu kopieren und auszutauschen?

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?
Wenn dir die ganzen Ratschläge und Codeschnipsel nicht ausreichen, mal ganz abgesehen von den vorhandenen und mit Google auffindbaren Tutorials (http://www.delphi-treff.de/tutorials...ualtreeview/6/), wie sollte dir da ein Video helfen?
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.
Stelle mal bitte konkrete Fragen dazu!
Was verstehst du genau nicht?
Inzwischen wurde dir diese Variante vier bis fünf Mal angeraten und erklärt.
  Mit Zitat antworten Zitat
Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#35

AW: Fehler beim Programm beenden

  Alt 6. Nov 2015, 20: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 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;
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..

Delphi-Quellcode:
   Daten := vstKunden.GetNodeData(pNode);
   Daten^.ObjektName := DMMasterData.qryObjectData.FieldByName('Objekt_Objektname').AsString;
Würde ich jetzt diesen Record zu diesem Node abfragen...

Delphi-Quellcode:
  Daten := vstKunden.GetNodeData(pNode);
  ShowMessage(Daten^.Kundenname);
  ShowMeddage(Daten^.Objektname);
wird das Ergebniss immer

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:
  Daten := vstKunden.GetNodeData(pNode.Parent);
  ShowMessage(Daten^.Kundenname);
arbeiten?
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt.
  Mit Zitat antworten Zitat
Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#36

AW: Fehler beim Programm beenden

  Alt 10. Nov 2015, 10:37
*push*
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt.
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#37

AW: Fehler beim Programm beenden

  Alt 10. Nov 2015, 10:47
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.
  Mit Zitat antworten Zitat
Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#38

AW: Fehler beim Programm beenden

  Alt 10. Nov 2015, 19:35
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:
-Kunde1
  -Objekt1
  -Objekt2
  -Objekt3
-Kunde2
  -Objekt1
  -Objekt2
...
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...

Delphi-Quellcode:
  type
    pVSTNodeData = ^rVSTNodeData;
    rVSTNodeData = record
      KundenName, ObjektName, AnlagenTyp, AnlagenBezeichnung : WideString;
      KundenNr, ObjektNr, AnlagenNr : Integer;
    end;
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.

  Objektname : array of WideString wäre.

In der Datenzuweisung mache ich ja immer

Delphi-Quellcode:
  //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';
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"

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
Angehängte Dateien
Dateityp: zip Musterprojekt.zip (2,48 MB, 1x aufgerufen)
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt.
  Mit Zitat antworten Zitat
bcvs

Registriert seit: 16. Jun 2011
668 Beiträge
 
Delphi 12 Athens
 
#39

AW: Fehler beim Programm beenden

  Alt 11. Nov 2015, 08:01
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:
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;
Dann braucht du noch eine ObjectList für die Kunden:

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:
  type
    pVSTNodeData = ^rVSTNodeData;
    rVSTNodeData = record
      Data : TObject;
    end;
Dann gehst du die zuvor befüllte KundenListe durch und baust den Inhalt des VST auf:


Delphi-Quellcode:
  //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]);
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:

Delphi-Quellcode:
  Daten := vstKunden.GetNodeDate(Node);
  if Daten^.Data is TKunde then
    // Kunde
  else
    // Objekt
  Mit Zitat antworten Zitat
Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#40

AW: Fehler beim Programm beenden

  Alt 15. Nov 2015, 18:34
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.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 4   « Erste     234   


Forumregeln

Es 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

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:22 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