TBarSeries dynamisch erzeugen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
heheracer
Beiträge: 54
Registriert: Mo 17. Nov 2014, 16:45

TBarSeries dynamisch erzeugen

Beitrag von heheracer »

Hi,

ich bin gerade etwas mit Diagrammen rumspielen und möchte jetzt eine beliebige Anzahl von Funktionen darstellen. Wichtig dabei ist, dass man diese zur Laufzeit erzeugen kann.

Bisher sieht der Code so aus:

Code: Alles auswählen

implementation
 
var
  Chart_Series: array of TBarSeries;
 
{$R *.lfm}
 
{nicht relevanter Code}
 
procedure TFCollatz.MenuItem_LoadNewClick(Sender: TObject);
var
  tf: textfile;
  filename: string;
  c, n: QWord;
  i: word;
begin
  filename := InputBox('New Graph', 'Filename:', '');
  if fileexists(filename)
  then begin
    i := length(Chart_Series);
    setlength(Chart_Series, i + 1);
    Chart_Series[i] := TBarSeries.Create(Chart); //mit Self als Owner geht auch nicht
    assignfile(tf, filename);
    reset(tf);
    repeat
      readln(tf, c);
      readln(tf, n);
      Chart_Series[i].AddXY(c, n);
    until eof(tf);
    closefile(tf);
  end;
end;


Allerdings werden die Graphen nicht angezeigt. Fehlermeldungen gibt es nicht, aber es passiert nichts.

Vielen Dank im Voraus :)

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

Re: TBarSeries dynamisch erzeugen

Beitrag von wp_xyz »

Es fehlt noch das Einfügen der Series in den Chart: Chart.AddSeries.

Code: Alles auswählen

  Chart.AddSeries(Chart_Series[i])

Es ist übrigens nicht nötig, die Series in einem eigenen Array zu speichern, der Chart macht das automatisch und stellt dafür die Liste Chart.Series[] zur Verfügung, die Anzahl der vorhandenen Series erhältst du über Chart.SeriesCount. Da Chart.Series[] jedoch für alle Series-Typen geeignet sein muss, wird jede Series nur in der primitivsten Seriesklasse gespeichert. Durch eine Typumwandlung zur TBarSeries kommst du aber an die BarSeries-Eigenschaften heran.

Hier ist dein Code etwas umgeschrieben, so wie ich es machen würde:

Code: Alles auswählen

procedure TFCollatz.MenuItem_LoadNewClick(Sender: TObject);
var
  tf: textfile;
  filename: string;
  c, n: QWord;  // warum so groß? Integer sollte es auch tun...
  barseries: TBarSeries;
begin
  filename := InputBox('New Graph', 'Filename:', '');
  if fileexists(filename)
  then begin
    barseries := TBarSeries.Create(Chart);
    barseries.SeriesColor := clRed;  // Farbe für die Series
    barseries.Title := filename;  // Dateiname als Legendentext
    Chart.AddSeries(barseries);
    barseries.DisableRedrawing// verhindert das Neuzeichnen des Chart nach Hinzufügen jedes Datenpunkts --> schneller
    assignfile(tf, filename);
    reset(tf);
    repeat
      readln(tf, c);
      readln(tf, n);
      barseries.AddXY(c, n);
    until eof(tf);
    closefile(tf);
    barseries.EnableRedrawing  // Chart-Neuzeichnen wieder aktivieren
  end;
end;

Wenn du später die Series mit dem Index i wieder benötigst, geht das - ohne dein Chart_Series[]-Array - über

Code: Alles auswählen

var
  barseries: TBarSeries;
....
  barseries := TBarSeries(Chart.Series[i]);
// oder falls auch andere Seriestypen enthalten sind:
  if Chart.Series[i] is TBarSeries then barseries := TBarSeries(Chart.Series[i]);

Achja, das noch: Wenn die x-Werte nicht äquidistant sind, werden die Balken unterschiedlich breit. Falls dich das stört, setze oben barseries.BarWidthPercent := bwPercentMin.

Und abschließend möchte ich noch auf die beiden BarSeries-Tutorials hinweisen (allerdings nur englisch):

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

Re: TBarSeries dynamisch erzeugen

Beitrag von Mathias »

So kann ich Balken Serien hinzufügen, welche auch angezeigt werden.


Code: Alles auswählen

var
  Chart_Series: array of TBarSeries;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  l, i: integer;
begin
  l := Length(Chart_Series);
  SetLength(Chart_Series, l + 1);
  Chart_Series[l] := TBarSeries.Create(Self);
  Chart_Series[l].BarBrush.Color := l * 1000;
  Chart_Series[l].Name := 'Test' + IntToStr(l);
  for i := 0 to 10 do begin
    Chart_Series[l].AddXY(Random, Random);
  end;
  Chart1.AddSeries(Chart_Series[l]); // Dies ist relevant
end
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: TBarSeries dynamisch erzeugen

Beitrag von wp_xyz »

Setze mal als Owner der Series nicht das Formular ein, sondern den Chart. Der Chart sorgt mit Hilfe seiner SeriesList selbst dafür, dass die Series aufgeräumt wird. Da kracht es dann, wenn das Formular das selbst nochmals macht. Strenggenommen ist das so nicht ganz in Ordnung, aber meine Vorgänger werden sich dabei schon etwas gedacht haben...

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

Re: TBarSeries dynamisch erzeugen

Beitrag von Mathias »

Setze mal als Owner der Series nicht das Formular ein, sondern den Chart.

Wen du mich meinst, ich hatte mit SetLength einen Fehler, ich hatte das +1 am falschen Ort.
Aber mit Char anstelle Self geht es auch.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: TBarSeries dynamisch erzeugen

Beitrag von wp_xyz »

Ah, um so besser, wenn ich mich geirrt habe. Ich dachte allerdings, es hätten hier mal diesen Fall (Series-Owner = Formular) gegeben.

Antworten