TChart automatisch erstellen?

Rund um die LCL und andere Komponenten
Antworten
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

TChart automatisch erstellen?

Beitrag von Timm Thaler »

Sorry, ich habe gerade und schon seit Tagen eine Denkblockade.

Ich möchte auf einem Formular untereinander 5 Liniendiagramme (chart1 bis 5) darstellen. In jedes Diagramm sollen 6 Datenreihen (line1 bis line30) über der Zeit aufgetragen werden. Bisher bin ich soweit, dass ich die Diagramme mit Skalen angelegt habe.

Aber: Muss ich jetzt wirklich von Hand 30 mal TLineSeries auf dem Formular erstellen und 30 mal TUserDefinedChartSource anlegen? Und wenn ich dann den Datenreihen individuell Farben geben und mit GetChartDataItem() Werte zuweisen will, muss ich dann jedesmal per if elseif selektieren, welche der Datenreihen gerade gemeint ist? Das würde ja in exzessive Abfragefolgen ausarten?

Meine Daten liegen als wert[1..Kanal, 1..Messwert] of real vor. Die Farbe der Datenreihen liegt als col[1..Kanal] vor, der Name als name[1..Kanal], die Zeit als ttim[1..Messwert]. Ich dachte, ich kann jetzt sowas machen wie:

for i := 1 to 5 // Diagramm
for k := 1 to 6 // Reihe im Diagramm
kanal := (i - 1) * 5 + k
erstelle TLineSeries[kanal] auf Diagramm i // 30 Reihen
weise TLineSeries[kanal] Name aus name[kanal] zu
färbe TLineSeries mit col[kanal]

und dann die Messwerte mit GetChartDataItem(TLineSeries)
kanal := Nummer von TLineSeries
übergebe TLineSeries wert[kanal, Messwert]

wenn Benutzer Messreihen abwählt oder selektiert
unterdrücke TLineSeries[kanal]
weise TLineSeries[kanal] Liniendicke 3 zu

Kurz: Ich bräuchte irgendwas wie ein array of TLineSeries[1..Kanal] anstelle die alle von Hand zu erstellen und per if elseif zu selektieren. Geht das? Und wie geht das?

Die Tutorials waren bisher wenig hilfreich dafür, weil die immer davon ausgehen, dass man nur wenige Datenreihen hat und die von Hand anlegt. Genau darüber will ich ja hinaus.

Die Alternative wäre halt, den Kram wie bisher in Basic selbst zu zeichnen, aber ich dachte, wenn es schon diese schönen Charts gibt...

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: TChart automatisch erstellen?

Beitrag von wp_xyz »

Ungetestet, aber sinngemäß:

Code: Alles auswählen

const
  MaxChart = 5;
  MaxKanal = 30;
  MaxSeriesProChart = MaxChart div MaxKanal;
 
type
  TForm1 = class(TForm)
    procedure Formcreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    FCharts: array[1..MaxChart] of TChart;
    FLineSeries: array[1..MaxKanal] of TLineSeries;
    FSources: array[1..MaxKanal] of TUserDefinedChartSource;   
    procedure GetChartData(ASource: TUserDefinedChartSource;
      AIndex: Integer; var AItem: TChartDataItem);
  public
    procedure WaehleMessreihe(AKanal: Integer);
  end;
 
procedure TForm1.FormCreate(Sender: TObject);
var
  i, j, kanal: Integer;
begin
  for i:=1 to MaxKanal do begin   
    // Chart erzeugen
    FCharts[i] := TChart.Create(self);
    FCharts[i].Parent := self// oder was auch immer der Container sein soll, in dem die Charts sitzen
    FCharts[i].Height := Height div MaxKanal;
    if i = MaxKanal then
      FCharts[i].Align := alClient else
      FCharts[i].Align := alTop;
 
    for j := 1 to MaxSeriesProKanal do begin
      kanal := (i - 1) * MaxChart + k;
 
      // ChartSources erzeugen
      FSources[kanal] := TUserDefinedChartSource.Create(self);
      FSources[kanal].PointsCount := Messwert;   //Anzahl der Datenpunkte in diesem Kanal
      FSources[kanal].OnGetChartDataItem := @GetChartData;
      FSources[kanal].Tag := kanal;  // Kanal im Tag speichern, damit die Source den Kanal finden kann
 
      // LineSeries erzeugen
      FLineSeries[kanal] := TLineSeries.Create(FCharts[i]);
      FLineSeries[kanal].SeriesColor := col[kanal];
      FLineSeries[kanal[.Title := name[kanal];
      FLineSeries[kanal].Source := FSources[kanal]
      FCharts[i].AddSeries(FLineSeries[kanal]);
  end;
end;
 
// Charts automatisch in der Höhe anpassen, falls sich die Fenstergröße ändert.
procedure TForm1.FormResize(Sender: TObject);
var
  h: Integer;
begin
  h := ClientHeight div MaxChart;
  for i:= 2 to MaxChart-1 do
    FCharts[i].Height := h;
  // Der letzte Chart, FCharts[MaxChart], ist client-aligned und passt seine Höhe automatisch an.
end;
 
procedure TForm1.GetChartData(ASource: TUserDefinedChartSource;
  AIndex: Integer; var AItem: TChartDataItem);
var
  kanal: Integer;
begin
  // Wir brauchen hier den Kanal-Index, um den Datenwert zu finden. Da die UserDefinedChartSource dies
  // normalerweise nicht weiß, wurde oben der Kanal-Index in der Wald-und-Wiesen-Eigenschaft "Tag"
  // gespeichert.
  kanal := ASource.Tag;
  AItem.X := ttim[AIndex+1]// Bei TAChart beginnt Indiziert bei 0, bei dir bei 1
  AItem.Y := wert[kanal, AIndex+1];
end;
 
// Series auswählen. Die gewählte Series wird mit Linienbreite 3 dargestellt.
procedure TForm1.WaehleMessreihe(AKanal: Integer);
var
  kanal: Integer;
begin
  for kanal:=1 to MaxKanal do
    FLineSeries[kanal].LinePen.Width := 1;
  FLineSeries[AKanal].LinePen.Width := 3;
end;


Ich hoffe das stimmt so in etwa (ich mag mir gerade keine Testanwendung zusammenklicken). Falls du Probleme hast, melde dich wieder und lade das, was du schon hast, hier hoch (nur pas, lfm, lpi und lpr-Dateien, alles in einem zip zusammengeschnürt); wenn möglich, lasse nicht-relevante Teile weg, aber das Programm muss kompilierbar bleiben und laufen.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: TChart automatisch erstellen?

Beitrag von Timm Thaler »

Danke! Also war meine Idee mit dem Array of Sources und Lines schonmal zielführend.

Ich hab das jetzt mal umgesetzt. Um die Aktualisierung nach neuen Daten zu erreichen, rufe ich noch FSources[i].Reset; auf. Achso, FSources[kanal].PointsCount habe ich durch PointsNumber ersetzt, ersteres gibt es nicht.

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: TChart automatisch erstellen?

Beitrag von wp_xyz »

Jetzt habe ich doch noch die Generierung von Dummy-Daten dazugemacht und alles getestet - das lauffähige Projekt ist im Anhang. Es gab ja noch einiges auszubessern, nicht nur die Eigenschaft PointsNumber...

Das Problem bei dir ist wahrscheinlich dasselbe wie bei meinen Tests: offenbar wurden nicht alle Series und Sources erzeugt. Der Fehler war in der Zeile "kanal := (i - 1) * MaxChart + j": hier muss es MaxSeriesProChart heißen (statt MaxChart) - jeder Chart enthält MaxSeriesproChart Kanäle, nicht MaxChart Kanäle -, denn sonst wird der letzte Kanal in einem Chart vom ersten Kanal des nächsten Charts überschrieben, und es werden ingesamt zuwenig Kanäle angelegt.

[EDIT]
Die Beschreibung dieses Problems ist in dem vorigen Beitrag inzwischen nicht mehr vorhanden: Es geht um einen Absturz, wenn alle Sources von 1 bis MaxKanal durchlaufen werden.
Dateianhänge
chart-runtime-multi.zip
(3.52 KiB) 68-mal heruntergeladen

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: TChart automatisch erstellen?

Beitrag von Timm Thaler »

wp_xyz hat geschrieben:Die Beschreibung dieses Problems ist in dem vorigen Beitrag inzwischen nicht mehr vorhanden: Es geht um einen Absturz, wenn alle Sources von 1 bis MaxKanal durchlaufen werden.


Ähm ja, das war mir so peinlich, dass ich es gelöscht habe: Ich habe zwar munter auf die Sources zugegriffen, aber ich habe vorher das Create gar nicht aufgerufen. Dann kann das ja nicht gehen. Und nicht aufgerufen habe ich es, weil ich es in eine eigene Init-Prozedur gepackt habe, die muss man dann aber auch anspringen.

Und da das spät in der Nacht war dachte ich nicht, dass jemand die Fehlerbeschreibung überhaupt gelesen hat.

Also bei mir funktioniert es soweit.

wp_xyz
Beiträge: 4888
Registriert: Fr 8. Apr 2011, 09:01

Re: TChart automatisch erstellen?

Beitrag von wp_xyz »

Das muss dir nicht peinlich sein, das ist jedem schon mal passiert. Ich habe das [EDIT] nur angefügt, weil der Zusammenhang nicht klar war.

Es freut mich, dass es geht.

creed steiger
Beiträge: 957
Registriert: Mo 11. Sep 2006, 22:56

Re: TChart automatisch erstellen?

Beitrag von creed steiger »

Leicht OT:
TAChart ist ein feines Stück Software das viele Möglichkeiten bietet, aber deshalb auch ein bissl komplex ist ;)

Umso glücklicher bin ich das wp_xyz im deutschen sowie im englischen Forum so kompetente Hilfe bietet.

Danke wp_xyz.

Mathias
Beiträge: 6193
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TChart automatisch erstellen?

Beitrag von Mathias »

TAChart ist ein feines Stück Software das viele Möglichkeiten bietet, aber deshalb auch ein bissl komplex ist

So wie es scheint, ist TChart die komplexeste Komponente die ich kenne.

Umso glücklicher bin ich das wp_xyz im deutschen sowie im englischen Forum so kompetente Hilfe bietet.

Da war ich auch schon mehrmals froh. :wink:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten