AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

TDBChart mit Queries in Thread füttern

Ein Thema von Medium · begonnen am 29. Feb 2012 · letzter Beitrag vom 2. Mär 2012
Antwort Antwort
Medium

Registriert seit: 23. Jan 2008
3.631 Beiträge
 
Delphi 2007 Enterprise
 
#1

TDBChart mit Queries in Thread füttern

  Alt 29. Feb 2012, 14:33
Aloah

Ich habe ein TDBChart, dass mir Messwerte aus einer Datenbank grafisch darstellen soll. Dieses Chart soll ca. jede Sekunde aktualisiert werden, und zeigt immer Werte der letzten paar Minuten an. In der Datenbank stehen jedoch ziemlich viele Werte (eine Tabelle mit den Daten von ~20 Messstellen, auch solchen die in der Vergangenheit gemessen wurden - nicht nur die anzuzeigenden).

Zunächst habe ich die AutoUpdate-Property vom Chart verwendet, jedoch werden die Abfragen mittlerweile etwas träge, so dass es die Bedienbarkeit des UI beeinträchtigt. Also wollte ich gerne das Abfragen in einen Thread auslagern, da das Refresh der Queries hier der Flaschenhals ist.

Problem ist: Das Chart bleibt seit dem einfach leer! Die Series werden nicht gezeichnet, obwohl laut Steema Doku die verwendete Methode "TLineSeries.CheckDataSource" auch die Aktualisierung des Charts auslösen sollte.

Auf die relevanten Teile eingedampfter Code:
Delphi-Quellcode:
unit _frmCurves;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, TeeProcs, TeEngine, Chart, DBChart, Contnrs, DB, MemDS,
  DBAccess, Uni, Series;

type
  TUpdateProc = procedure of Object;

  TCurveUpdateThread = class(TThread)
  protected
    procedure Execute; override;
  public
    Con: TUniConnection;
    Queries: TObjectList;
    UpdateProc: TUpdateProc;
    constructor Create(aConnection: TUniConnection);
    destructor Destroy; override;
    function AddQuery: TUniQuery;
  end;

  TfrmCurves = class(TForm)
    Chart: TDBChart;
  private
    { Private-Deklarationen }
    UThread: TCurveUpdateThread;
    Series: TObjectList;
    procedure Updated;
  public
    { Public-Deklarationen }
    procedure ShowData(aTitle: String; aDuration: Integer; aLabels: array of String; aUnits: array of String);
    constructor CreateCustom(aParent: TWinControl; aLeft, aTop, aWidth, aHeight: Integer);
  end;

implementation

uses
  DateUtils;

{$R *.dfm}

{ TfrmCurves }

constructor TfrmCurves.CreateCustom(aParent: TWinControl; aLeft, aTop, aWidth, aHeight: Integer);
begin
  inherited Create(nil);
  Doublebuffered := true;

  UThread := TCurveUpdateThread.Create(frmAnwahl.Con);
  UThread.UpdateProc := Updated;

  Series := TObjectList.Create;
  Series.OwnsObjects := false;
end;

procedure TfrmCurves.Updated;
var
  i: Integer;
begin
  for i := 0 to Series.Count-1 do
    (Series[i] as TLineSeries).CheckDataSource;
end;

procedure TfrmCurves.ShowData(aTitle: String; aDuration: Integer; aLabels, aUnits: array of String);
var
  i: Integer;
  q: TUniQuery;
begin
  for i := 0 to High(aLabels) do
  begin
    q := UThread.AddQuery;
    with q do
    begin
      SQL.Text := 'SELECT * FROM messwerte WHERE mstelle=:ms AND mtime > DATE_SUB(NOW(), INTERVAL :st MINUTE) ORDER BY mtime';
      ParamByName('ms').AsString := aLabels[i];
      ParamByName('st').AsInteger := aDuration;
      Open;
      (FieldByName('mtime') as TDateTimeField).DisplayFormat := 'hh:mm:ss';
    end;
    Series.Add(TLineSeries.Create(nil));
    with Series[i] as TLineSeries do
    begin
      Chart.AddSeries(Series[i] as TLineSeries);
      DataSource := q;
      XValues.ValueSource := 'mtime';
      YValues.ValueSource := 'mwert';
      XLabelsSource := 'mtime';
      XValues.DateTime := true;
      Title := aLabels[i] + ' ('+aUnits[i]+')';
    end;
  end;
  Show;
  UThread.Resume;
end;

{ TCurveUpdateThread }

function TCurveUpdateThread.AddQuery: TUniQuery;
begin
  result := TUniQuery.Create(nil);
  result.Connection := Con;
  Queries.Add(result);
end;

constructor TCurveUpdateThread.Create(aConnection: TUniConnection);
begin
  inherited Create(true);
  Con := TUniConnection.Create(nil);
  Con.ProviderName := aConnection.ProviderName;
  Con.Database := aConnection.Database;
  Con.Username := aConnection.Username;
  Con.Password := aConnection.Password;
  Con.Server := aConnection.Server;
  Con.Port := aConnection.Port;
  Con.Connect;
  Queries := TObjectList.Create;
  Queries.OwnsObjects := false;
end;

destructor TCurveUpdateThread.Destroy;
var
  i: Integer;
begin
  for i := 0 to Queries.Count-1 do Queries[i].Free;
  Queries.Clear;
  Queries.Free;
  Con.Disconnect;
  Con.Free;
  inherited;
end;

procedure TCurveUpdateThread.Execute;
var
  i: Integer;
begin
  repeat
    for i := 0 to Queries.Count-1 do
      (Queries[i] as TUniQuery).Refresh;
    Synchronize(UpdateProc);
    Sleep(1000);
  until Terminated;
end;

end.
Die UpdateProc wird durchlaufen, und CheckDataSource fehlerfrei abgearbeitet. Lasse ich mir in der UpdateProc die RecordCounts der Queries anzeigen, sind diese auch >0 (und korrekt). Mein Chart bleibt aber einfach leer.
Lasse ich den Thread weg, und stelle statt dessen TDBChart.AutoUpdate auf true (und trage ein UpdateInterval ein), bekomme ich wie gewohnt meine Daten, und diese auch korrekt. Nur eben leider mit sehr ruckeliger Bedienung. (Die Felder mstelle und mtime in der Tabelle sind bereits indiziert.)
Erstellt werden diese Formulare durch "TfrmCurves.CreateCustom().ShowData();", und von da an werden sie von aussen nicht mehr angefasst. Es finden also keine Quergriffe aus anderen Teilen des Projektes statt.


Wo könnte ich hier ansetzen? (Das sind so Momente, wo sich Sourcecode von Fremdkomponenten prima machen würde...)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.631 Beiträge
 
Delphi 2007 Enterprise
 
#2

AW: TDBChart mit Queries in Thread füttern

  Alt 2. Mär 2012, 10:49
*lupf*
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#3

AW: TDBChart mit Queries in Thread füttern

  Alt 2. Mär 2012, 10:58
Ich hatte vor Jahren mal so ein Problem und habe die Series dann per Hand befüllt. Auch sonst ist mir damals aufgefallen, das das 'AutoUpdate' vom TeeChart irgendwie nicht durchdacht ist. So wie eigentlich das ganze Teil nicht sonderlich gut programmiert ist.

Aber egal, es funktioniert ja, man muss nur hier und da mal gegentreten.

Also: Thread feuert ein Event (oder verschickt ne Message) und im Hauptprogramm wird dann die Series upgedated.

So als Optimierungspotential: Es ändern sich ja nur neue Werte, also reicht es, die Query so zu schreiben, nur die neusten Daten geliefert werden. Dann schmeißt Du in der Series die hinteren weg und hängst die paar neuen Daten einfach ran. Das sollte dann schnell genug sein.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.631 Beiträge
 
Delphi 2007 Enterprise
 
#4

AW: TDBChart mit Queries in Thread füttern

  Alt 2. Mär 2012, 11:40
Hm, schade, aber vielen Dank für den Erfahrungswert! Dann wird das wohl doch etwas umständlicher als gehofft, zumal ich nicht immer jedes Leseintervall immer genau einen neuen Wert pro Series dazu bekomme. Also muss ein kleines "Management" rein, dass erkennt, wie viele neue Werte da sind, und... naja, das ist jetzt mein Bier

Best Fishes!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 03:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf