2

多くのポイントを含むグラフ全体を更新しているときにパフォーマンスの問題が発生しました。グラフの再描画にかかる時間を短縮する方法があるかどうかを尋ねたいと思います。

たとえば、私のグラフには、それぞれ 1000 ポイントに相当する TAreaSeries が 100 個含まれています。これらの値は一度作成され、その後は変更されません。しかし、2 つのポイントを持つ 1 つの短い TLineSeries があり、50 ミリ秒ごとに座標を変更しながらグラフを「ジャンプ」します。プロットの小さな領域 (TLineSeries の領域内のピクセル) のみが変更されているにもかかわらず、グラフ全体 (数千のポイントを含む) が更新および再描画され、リソースの負荷が無駄になり、大幅な遅延が発生します。私の場合、2 つのポイントを持つこの TLineSeries の次と前の位置がわかっているので、グラフ全体を再描画する代わりに、TChart に事前定義されたプロット領域のみを強制的に再描画させる方法があるかどうか疑問に思いましたか?

4

1 に答える 1

2

リアルタイム アプリケーションでは、通常、こちらのリアルタイム チャートの記事で説明されている内容に従うことをお勧めします。

チャートの領域のみを再描画する限り、 InvalidateRacteを呼び出すことはできず、四角形のチャート セクションのみを再作成します。InvalidateRacteは、バッファ ビットマップ ( Chart1.Canvas.Bitmap 、 Chart1.BufferedDisplayを使用する場合) の一部を再描画するためにのみ使用できます。VCL フレームワークはそれをサポートしていません。

ここでは、最も時間のかかる作業である再作成せずに、チャートの一連の折れ線を別のチャートの上に描画するプロジェクトをダウンロードできます。バッファ ビットマップを再描画できる回数をカウントするボタンがあります。毎秒約5000を取得します。グラフを毎回再作成する必要がある場合 (例: 軸、系列、凡例など)、1 秒あたり最大 100 回取得します。プロジェクトに示されている機能は、新しい TeeChart Pro ベータ版を使用してのみ利用できます。プロジェクトのコードは次のとおりです。

type
  TSeriesAccess=class(TChartSeries);
  TChartAccess=class(TCustomTeePanel);

procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
  // Example: Modify a Line value
  Series1.YValues[10]:=350+ScrollBar1.Position;

  // Paint Line to Chart2, just to check the change (this is optional)
  Series1.Repaint;

  // Redraw Chart1 fast, just the buffer bitmap, without repainting everything:
  TChartAccess(Chart1).Paint;

  // Draw the Line over Chart1, on top of it, instead of "inside" it
  TSeriesAccess(Series1).FParent:=Chart1;
  TSeriesAccess(Series1).DrawAllValues;
  TSeriesAccess(Series1).FParent:=Chart2;
end;

// Count the number of times a Chart buffer can be redisplayed
// (without redrawing everything)
procedure TForm1.Button1Click(Sender: TObject);
var t1 : Cardinal;
    tmpCount : Integer;
begin
  tmpCount:=0;

  t1:=GetTickCount;

  // Loop for one second
  while GetTickCount-t1 < 1000 do
  begin
    TChartAccess(Chart1).Paint;
    Inc(tmpCount);
  end;

  Caption:='Redraws per second: '+IntToStr(tmpCount);
end;

もう 1 つのオプションはthisで、プロジェクトと多かれ少なかれ同じことを行う ColorLine を使用し、 Pen.Mode = pmXor を使用して塗りつぶします

プロジェクトに関しては、シリーズを更新する前にAutoRepaintを true に設定できませんでした。このコードは機能します:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
    // The 'jumping' TLineSeries will move to the right 1 point every 1 second.
    Form1.Chart1.Series[1].XValue[0]:= Form1.Chart1.Series[1].XValue[0] + 1;
    Form1.Chart1.Series[1].XValue[1]:= Form1.Chart1.Series[1].XValue[1] + 1;

    Form1.Chart1.AutoRepaint:=True;
    Form1.Chart1.Series[1].Repaint;
    Form1.Chart1.AutoRepaint:=False;
end;

また、縦線のシリーズの代わりにTColorLineToolを使用することもできます。2 番目のライン シリーズを削除し、設計時に ColorLine ツールを追加して、次のようなコードを実装する必要があります。

unit UnitTeeChartRefresh;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, TeeProcs, TeEngine, Chart, Series, StdCtrls,
  TeeGDIPlus, TeeTools;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    Series1: TAreaSeries;
    Button1: TButton;
    Timer1: TTimer;
    Label1: TLabel;
    ChartTool1: TColorLineTool;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Chart1AfterDraw(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  times_redrawn: cardinal = 0;   // A counter indicating how many times our chart was redrawn.

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
    i: integer;
begin
  //Let's add one constant TAreaSeries and one 'jumping' across the graph TLineSeries
  Randomize;
  Form1.Chart1.Axes.Left.SetMinMax(0, 10);
  Form1.Chart1.Axes.Bottom.SetMinMax(0, 20);

  for i:= 1 to 20 do
  begin
    Form1.Chart1.Series[0].AddXY(i, Random(10))
  end;

  ChartTool1.Axis:=Chart1.Axes.Bottom;
  ChartTool1.Value:=0;

  // If I enable AutoRepaint I will be able to see all changes on the whole plot in real-time
  // and have no problem.
  // But I want to manually control the refreshing process and even refresh some regions of the
  // graph separately.
  Form1.Chart1.AutoRepaint:=False;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  // This button launches the animation of the 'jumping' TLineSeries.
  Form1.Timer1.Enabled:= not Form1.Timer1.Enabled;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  // The 'jumping' TLineSeries will move to the right 1 point every 1 second.
  Form1.Chart1.AutoRepaint:=True;
  ChartTool1.Value:=ChartTool1.Value + 1;
  Form1.Chart1.AutoRepaint:=False;
end;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
begin
  times_redrawn:= times_redrawn + 1;
  Form1.Label1.Caption:= intToStr(times_redrawn);
end;

end.
于 2013-07-29T13:34:23.097 に答える