TChart automatisch erstellen?
-
- 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?
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...
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...
Re: TChart automatisch erstellen?
Ungetestet, aber sinngemäß:
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.
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.
-
- 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?
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.
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.
Re: TChart automatisch erstellen?
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.
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
-
- 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?
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.
Re: TChart automatisch erstellen?
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.
Es freut mich, dass es geht.
-
- Beiträge: 957
- Registriert: Mo 11. Sep 2006, 22:56
Re: TChart automatisch erstellen?
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.
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.
-
- Beiträge: 6194
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: TChart automatisch erstellen?
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.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot