Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende (https://www.delphipraxis.net/202162-komponente-zur-laufzeit-um-eigenschaft-erweitern-fehler-bei-programmende.html)

DieDolly 3. Okt 2019 23:11


Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ich versuche gerade ein TChart während der Laufzeit um eine Eigenschaft zu erweitern.
Das klappt auch und ich kann die Eigenschaft auch beschreiben. Aber beim Programmende gibt es eine wenig aussagekräftige AV. Was mache ich falsch?
SeriesGroup ist ein einfacher Enum.

Delphi-Quellcode:
 TCustomSeriesClass = class(TCustomSeries)
 public
  SeriesGroup: TSeriesGroup;
 end;

procedure CreateSeries(const SeriesType: TCustomSeriesClass; const SeriesGroup: TSeriesGroup; const Name: string; const Color: Integer);
var
 CustomSeries: TCustomSeriesClass;
begin
 CustomSeries := TCustomSeriesClass(TAreaSeries.Create(FormMain.Chart1));

 CustomSeries.Name := Name;
 CustomSeries.SeriesGroup := SeriesGroup;
.......

DieDolly 4. Okt 2019 00:11

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ich glaube du hast mich falsch verstanden.
Das was du als nicht zu TChart gehörig ansiehst habe ich hinzugefügt.

Zitat:

es ist nichts davon zu erkennen, dass die Klasse FMXTee.Chart.TChart um eine Eigenschaft erweitert wird.
?
Delphi-Quellcode:
TCustomSeriesClass = class(TCustomSeries)
 public
  SeriesGroup: TSeriesGroup;
 end;
Zitat:

Die Methode CreateSeries() erweckt den Anschein, dass sie zu der Klasse TCustomSeriesClass gehören könnte, was eben nicht der Fall ist.
Um sowas kümmer ich mich später. Das ist gerade nicht wichtig.

Es funktioniert und ich kann TCustomSeries um die Eigenschaft SeriesGroup erweitern! Der Code lässt sich kompilieren und ausführen.
Aber beim Programmende bekomme ich eine AV.

hoika 4. Okt 2019 05:14

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Hallo,
sicher, dass die AV wegen Deiner Ableitung kommt?
Clear mal die Series vor dem Programmende.

Zitat:

gut möglich beim Hinzufügen eines Graphen
Nein, es knallt ja beim Programmende ...

Lemmy 4. Okt 2019 08:41

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Zitat:

Zitat von DieDolly (Beitrag 1449013)
Ich glaube du hast mich falsch verstanden.
Das was du als nicht zu TChart gehörig ansiehst habe ich hinzugefügt.

Zitat:

es ist nichts davon zu erkennen, dass die Klasse FMXTee.Chart.TChart um eine Eigenschaft erweitert wird.
?
Delphi-Quellcode:
TCustomSeriesClass = class(TCustomSeries)
 public
  SeriesGroup: TSeriesGroup;
 end;

nein, Du hast eine neue Ableitung von TCustomSeries erstellt und dort ein neues "Feld" dazu gemacht. Die anderen von TCustomSeries abgeleiteten KLassen kennen deswegen aber noch lange nicht diese EIgenschaft, eben weil die weiterhin von TCustomSeries abgeleitet sind und nicht von TCustomSeriesClass.

Anschließend machst Du nen Hardcast - und stellst fest, dass das ziemlich lange gut geht. Insofern hast Du eigentlich Pech, dass dir die Anwendung nicht gleich um die Ohren fliegt bei der Zuweisung.

MyRealName 4. Okt 2019 09:08

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Was der Lemmy sagen will ist, dass auch wenn Du diese Klasse definiert hast, TChart die nicht kennt und trotzdem nur eine TAriaSeries erstellt oder so. Aber eben nicht deine neu definierte abgeleitete Klasse. Und dann einen Typecast drauf zu machen, ändert die Klasse nicht, der Speicher für deine zusätzliche Variable "SeriesGroup" wurde ja nicht erzeugt und beim TypeCast dann aber beschrieben. Das heisst, du kritzelst in einem Bereich des Speichers rum, der nicht zur Komponente gehört und das knallt dann irgendwann mal.

dummzeuch 4. Okt 2019 09:17

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Wird denn das neue Feld SeriesGroup auch irgendwo initialisiert? Ich sehe nur Code, der es verwendet.

Gausi 4. Okt 2019 09:31

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ich selbst habe damit noch nicht gearbeitet, aber wäre das nicht ein Fall für eine Helferklasse bzw. class helper, anstatt eine neue Klasse abzuleiten?

Wenn ich das Konzept der class helper richtig verstanden habe, ist das genau für das da, was du anscheinend erreichen willst ...

hoika 4. Okt 2019 09:56

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Hallo,
Zitat:

initialisiert?
CustomSeries := TCustomSeriesClass(TAreaSeries.Create(FormMain.Chart1));

Oha, jetzt sehe ich da ja den harten Type Cast.
Das geht glaube ich so nicht ...

Müsste es nicht so heißen?

CustomSeries := TCustomSeriesClass.Create(FormMain.Chart1);

DieDolly 4. Okt 2019 13:26

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Zitat:

Zitat von hoika (Beitrag 1449051)
Hallo,
Zitat:

initialisiert?
CustomSeries := TCustomSeriesClass(TAreaSeries.Create(FormMain.Chart1));

Oha, jetzt sehe ich da ja den harten Type Cast.
Das geht glaube ich so nicht ...

Müsste es nicht so heißen?

CustomSeries := TCustomSeriesClass.Create(FormMain.Chart1);

Wenn man nur TCustomSeriesClass.Create nimmt stzatt TAreaSeries, dann bekommt man nicht den Chart den man erstellen möchte.

Zitat:

Zitat von Gausi (Beitrag 1449048)
Ich selbst habe damit noch nicht gearbeitet, aber wäre das nicht ein Fall für eine Helferklasse bzw. class helper, anstatt eine neue Klasse abzuleiten?

Wenn ich das Konzept der class helper richtig verstanden habe, ist das genau für das da, was du anscheinend erreichen willst ...

Die Series haben viele Properties. Aber eine fehlt mir und genau die möchte ich hinzufügen.

So?
Delphi-Quellcode:
 TCustomSeriesClass = class helper for TCustomSeries
 public
  class var SeriesGroup: TSeriesGroup;
 end;
Und überall dann nur noch die Chart-eigene Klasse TCustomSeries verwenden?

Gausi 4. Okt 2019 13:58

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Class var ist da vermutlich falsch, eher so
Delphi-Quellcode:
TCustomSeriesClass = class helper for TCustomSeries
 public
   SeriesGroup: TSeriesGroup;
 end;
Und ja, falls ich das Konzept richtig verstanden habe, dann erhalten dadurch überall in deinem Projekt alle Objekte vom Typ TCustomSeries die Eigenschaft SeriesGroup.

DieDolly 4. Okt 2019 14:04

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ohne class var funktioniert es nicht.
Aber das ist alles irgendwie noch komisch. Ich erzeuge 3 Series mit 3 unterschiedlichenj SeriesGroup-Typen.

Wenn ich den ordinalen Wert von SeriesGroup der Series abfrage, kommt immer 3 raus (das Enum ist 3 groß)
Delphi-Quellcode:
ShowMessage(Ord(TCustomSeries(Chart1.Series[0]).SeriesGroup).ToString);
Egal ob Series 0, 1 oder 2. Ord(SeriesGroup) ist immer 3, obwohl ich jeder Series ein anderes Enum zuweise.

Delphi-Quellcode:
procedure CreateSeries(const SeriesType: TCustomSeries; const SeriesGroup: TSeriesGroup; const Name: string; const Color: Integer);
var
 CustomSeries: TCustomSeries;
begin
 if Assigned(FormMain.Chart1.FindComponent(Name)) then
  Exit;

 if SeriesType = TCustomSeries(TAreaSeries) then
  CustomSeries := TCustomSeries(TAreaSeries.Create(FormMain.Chart1))
 else if SeriesType = TCustomSeries(TLineSeries) then
  CustomSeries := TCustomSeries(TLineSeries.Create(FormMain.Chart1))
 else if SeriesType = TCustomSeries(TBarSeries) then
  CustomSeries := TCustomSeries(TBarSeries.Create(FormMain.Chart1))
 else
  CustomSeries := nil;

 if CustomSeries = nil then
  Exit;

 CustomSeries.Name := Name;
 CustomSeries.SeriesGroup := SeriesGroup;
.....
Hier habe ich es mal mit einer ziemlich bösen Lösung versucht. Ausnutzung des Tag-Properties
Delphi-Quellcode:
TCustomSeriesClass = class helper for TCustomSeries
 public
  function GetSeriesGroup: TSeriesGroup;
  procedure SetSeriesGroup(const SeriesGroup: TSeriesGroup);
 end;

implementation

{TCustomSeriesClass}

function TCustomSeriesClass.GetSeriesGroup: TSeriesGroup;
begin
 Result := TSeriesGroup(Self.Tag);
end;

procedure TCustomSeriesClass.SetSeriesGroup(const SeriesGroup: TSeriesGroup);
begin
 Self.Tag := Ord(SeriesGroup);
end;

// Setzen
CustomSeries.SetSeriesGroup(SeriesGroup);
// Holen
SeriesGroup := TCustomSeries(Chart1.Series[0]).GetSeriesGroup);

Gausi 4. Okt 2019 14:37

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ok, habe grade gelernt, dass Class helper keine neuen Felder hinzufügen können, sondern nur Methoden ... dann fällt das natürlich raus. https://www.delphipraxis.net/172414-class-helper.html :?

class var ist ja im Grunde nur eine globale Variable, die aber nur innerhalb der Klasse sichtbar ist. Wenn du mehrere Instanzen hast, und dieser Class Var etwas zuweist, dann gilt diese Zuweisung auch für alle anderen Instanzen dieser Klasse.

Dann fällt mir nur noch ein, eine Ableitung von TChart zu erstellen, wodrin du das dann verwenden kannst. Oder halt mit Tag rumwerkeln ...

DieDolly 4. Okt 2019 14:39

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ein property sollte man eigentlich nicht missbrauchen. Aber in diesem Fall werde ich es sonst eh nicht nutzen.

Funktioniert jetzt :thumb:

Neutral General 4. Okt 2019 14:41

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ich versteh nicht was das Problem ist einfach eine Ableitung von TAreaSeries zu machen? :gruebel:
Das ist sowohl die einfachste als auch sauberste Lösung.

DieDolly 4. Okt 2019 17:14

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Bin für Vorschläge immer offen. Wenn du weißt wie man das hier einbaut, immer her damit
Delphi-Quellcode:
procedure CreateSeries(const SeriesType: TCustomSeries; const SeriesGroup: TSeriesGroup; const Name: string; const Color: Integer);
var
 CustomSeries: TCustomSeries;
begin
 if Assigned(FormMain.Chart1.FindComponent(Name)) then
  Exit;

 if SeriesType = TCustomSeries(TAreaSeries) then
  CustomSeries := TCustomSeries(TAreaSeries.Create(FormMain.Chart1))
 else if SeriesType = TCustomSeries(TLineSeries) then
  CustomSeries := TCustomSeries(TLineSeries.Create(FormMain.Chart1))
 else if SeriesType = TCustomSeries(TBarSeries) then
  CustomSeries := TCustomSeries(TBarSeries.Create(FormMain.Chart1))
 else
  CustomSeries := nil;

 if CustomSeries = nil then
  Exit;

 CustomSeries.Name := Name;
 CustomSeries.SetSeriesGroup(SeriesGroup);
 CustomSeries.ParentChart := FormMain.Chart1;

 CustomSeries......
end;

Neutral General 4. Okt 2019 17:35

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Ich hab mal was zusammengebaut:
Delphi-Quellcode:
TDollyAreaSeries = class(TAreaSeries)
private
  FSeriesGroup: TSeriesGroup;
public
  property SeriesGroup: TSeriesGroup read FSeriesGroup write FSeriesGroup;
  constructor Create(AOwner: TComponent; ASeriesGroup: TSeriesGroup); reintroduce;
end;

TDollyLineSeries = class(TLineSeries)
private
  FSeriesGroup: TSeriesGroup;
public
  property SeriesGroup: TSeriesGroup read FSeriesGroup write FSeriesGroup;
  constructor Create(AOwner: TComponent; ASeriesGroup: TSeriesGroup); reintroduce;
end;

// etc. für jede Series Art die du brauchst...

constructor TDollyAreaSeries.Create(AOwner: TComponent; ASeriesGroup: TSeriesGroup);
begin
  inherited Create(AOwner);
  FSeriesGroup := ASeriesGroup;
end;

// Genauso für die anderen Ableitungen...

...

// Der Übergabeparameter SeriesType von CreateSeries ist irgendwie komisch..
// Du übergibst eine Instanz um dann zu gucken was die Instanz für eine Klasse hat und dann noch eine Instanz zu erstellen?
// Und der Vergleich ist auch seltsam - klappt das so überhaupt?
// Ich würde eher sowas vorschlagen:

type
  TDollySeriesType = (stArea, stLine, stBar);

procedure CreateSeries(const SeriesType: TDollySeriesType; const SeriesGroup: TSeriesGroup; const Name: string; const Color: Integer);
var
 CustomSeries: TCustomSeries;
begin
 if Assigned(FormMain.Chart1.FindComponent(Name)) then
  Exit;
 
 CustomSeries := nil;
 case SeriesType of
   stArea: CustomSeries := TDollyAreaSeries.Create(FormMain.Chart1, SeriesGroup);
   stLine: CustomSeries := TDollyLineSeries.Create(FormMain.Chart1, SeriesGroup);
   stBar: CustomSeries := TDollyBarSeries.Create(FormMain.Chart1, SeriesGroup);
 end;

 if CustomSeries = nil then
  Exit;

 CustomSeries.Name := Name;
 CustomSeries.ParentChart := FormMain.Chart1;

 CustomSeries.Dark3D := True;
 CustomSeries.Color := Color;
 CustomSeries.ColorEachLine := True;
 CustomSeries.ClickableLine := False;
 CustomSeries.ClickTolerance := 5;
 CustomSeries.DrawStyle := dsCurve;
 CustomSeries.LinePen.Width := 2;

 if SeriesType <> stBar then
  begin
   CustomSeries.Pointer.Visible := True;
   CustomSeries.Pointer.Style := psCircle;
   CustomSeries.Pointer.Size := 5;
   CustomSeries.Pointer.InflateMargins := True;
   CustomSeries.Pointer.Frame.Visible := True;
   CustomSeries.Pointer.Shadow.Visible := False;

   CustomSeries.Marks.Visible := True;
   CustomSeries.Marks.Arrow.Style := psSolid;
   CustomSeries.Marks.UseSeriesTransparency := False;

   CustomSeries.AreaLinesPen.Visible := False;
  end;

 CustomSeries.Transparency := 60;

 CustomSeries.OnGetMarkText := FormMain.GetMarkText;
 CustomSeries.OnClickPointer := FormMain.ClickPointer;
end;

DieDolly 4. Okt 2019 17:49

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Was mit der Lösung dann aber nicht mehr funktioniert ist
Delphi-Quellcode:
TCustomSeries(Series).GetSeriesGroup;
. Oder überhaupt an SeriesGroup ran zu kommen ohne den Typ des Series zu wissen.

Neutral General 4. Okt 2019 17:57

AW: Komponente zur Laufzeit um Eigenschaft erweitern, Fehler bei Programmende
 
Dann mach ein Interface mit der SeriesGroup Property, implementier es in deinen Ableitungen und benutz das Interface um auf die Property zuzugreifen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz