2016-06-07 30 views
1

如果光標在圖表上,我想顯示當前鼠標位置上所有系列的值。正是因爲它顯示在圖中:TeeChart:在當前鼠標位置顯示系列值的快速方法

Target Display

爲了完成這個行爲我用了一個TAnnotationToolOnMouseMove事件。此外,我使用TCursorToolStyle := cssVerticalFollowMouse := True在當前的斜線位置繪製垂直線。不幸的是,這個解決方案非常慢如果系列計數大於10,則用戶已經可以觀察到註釋在鼠標之後延遲約500ms。在我這個問題的調查中,我發現了MouseMoveEvent的這部分是瓶頸:

chtMain : TChart; 
FValAnno : TAnnotationTool; 
... 
TfrmMain.chtMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer) 
var 
    HasData : Boolean; 
    AnnoLst : TStrings; 
begin 
    ... 
    if HasData then 
    Self.FValAnno.Text := AnnoLst.Text 
    else 
    Self.FValAnno.Text := 'No data'; 
    // 
    if (X < Self.chtMain.Width - Self.FValAnno.Width - 5) then 
    Self.FValAnno.Shape.Left := X + 10 
    else 
    Self.FValAnno.Shape.Left := X - Self.FValAnno.Width - 15; 
    // 
    if (Y < Self.chtMain.Height - Self.FValAnno.Height - 5) then 
    Self.FValAnno.Shape.Top := Y + 10 
    else 
    Self.FValAnno.Shape.Top := Y - Self.FValAnno.Height - 15; 
    // 
    if (FX >= Self.chtMain.BottomAxis.IStartPos) and 
    (FX <= Self.chtMain.BottomAxis.IEndPos) and 
    (FY >= Self.chtMain.LeftAxis.IStartPos) and 
    (FY <= Self.chtMain.LeftAxis.IEndPos) then 
    Self.FValAnno.Active := True 
    else 
    Self.FValAnno.Active := False; 
    ... 
end; 

如果我使用垂直線上面的代碼和500ms左右光標後的註釋運行在一系列計數爲100.系列計數越高,延遲越大。另一方面,如果我不使用註釋代碼,那麼垂直線只會延遲大約100ms。

有沒有其他的工具可以用TChart組件更快地完成這個工作?還是有什麼我可以用來提高速度的屬性?

在此先感謝您的支持!

編輯:示例代碼重現此問題

  1. 創建一個新的VCL項目
  2. 降一TChart組件和形式
  3. 上的複選框創建FORMCREATE的形式和MouseMoveEvent爲圖表
  4. 切換到代碼視圖的插入以下代碼:

代碼:

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, 
    VCLTee.TeEngine, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart, VCLTee.TeeTools, 
    Vcl.StdCtrls; 

type 
    TForm1 = class(TForm) 
    chtMain: TChart; 
    chkAnno: TCheckBox; 
    procedure FormCreate(Sender: TObject); 
    procedure chtMainMouseMove(Sender: TObject; Shift: TShiftState; X, 
     Y: Integer); 
    private 
    FCursor : TCursorTool; 
    FAnno : TAnnotationTool; 
    public 
    { Public-Deklarationen } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

uses 
    VCLTee.Series, 
    System.DateUtils; 

const 
    ARR_MAXS : array[0..3] of Double = (12.5, 25.8, 2.8, 56.7); 

procedure TForm1.chtMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); 

    function GetXValueIndex(const ASerie: TChartSeries; const AX: Double): Integer; 
    var 
    index: Integer; 
    begin 
    for index := 0 to ASerie.XValues.Count - 1 do 
    begin 
     if ASerie.XValue[index] >= AX then 
     Break; 
    end; 
    // 
    Result := index - 1; 
    end; 

var 
    Idx, I : Integer; 
    CursorX, 
    CursorY, 
    Value  : Double; 
    Serie  : TChartSeries; 
    LegendTxt : string; 
    AnnoLst : TStrings; 
    HasData : Boolean; 
    ShownDate : TDateTime; 
begin 
    // 
    if not Self.chkAnno.Checked then 
    begin 
    // 
    FAnno.Text := Format('Position:'#13#10' X: %d'#13#10' Y: %d', [X, Y]); 
    end 
    else 
    begin 
    // 
    if (Self.chtMain.SeriesCount < 1) then 
    begin 
     // 
     if Assigned(Self.FAnno) then 
     Self.FAnno.Active := False; 
     Exit; 
    end; 
    // 
    Self.chtMain.Series[0].GetCursorValues(CursorX, CursorY); 
    // 
    AnnoLst := TStringList.Create; 
    try 
     // 
     ShownDate := 0; 
     HasData := False; 
     for I := 0 to Self.chtMain.SeriesCount - 1 do 
     begin 
     // 
     Serie := Self.chtMain.Series[I]; 
     // 
     Idx := GetXValueIndex(Serie, CursorX); 

     if Serie.XValue[Idx] > ShownDate then 
     begin 
      // 
      LegendTxt := DateTimeToStr(Serie.XValue[Idx]); 
      if (AnnoLst.Count > 0) and 
      (ShownDate > 0) then 
      AnnoLst[0] := LegendTxt 
      else if AnnoLst.Count > 0 then 
      AnnoLst.Insert(0, LegendTxt) 
      else 
      AnnoLst.Add(LegendTxt); 
      HasData := True; 
      ShownDate := Serie.XValue[Idx]; 
     end; 
     // 
     LegendTxt := Format('Serie: %d', [I]); 
     if Length(LegendTxt) <= 25 then 
      LegendTxt := Format('%-25s', [LegendTxt]) 
     else 
      LegendTxt := Format('%s...', [LegendTxt.Substring(0, 22)]); 
     // 
     Value  := Serie.YValue[Idx] * Abs(ARR_MAXS[I]); 
     LegendTxt := Format('%s: %3.3f %s', [LegendTxt, Value, 'none']); 
     AnnoLst.Add(LegendTxt); 
     end; 

     FAnno.Text := AnnoLst.Text; 
    finally 
     FreeAndNil(AnnoLst); 
    end; 
    end; 

    if (X < Self.chtMain.Width - Self.FAnno.Width - 5) then 
    Self.FAnno.Shape.Left := X + 10 
    else 
    Self.FAnno.Shape.Left := X - Self.FAnno.Width - 15; 
    // 
    if (Y < Self.chtMain.Height - Self.FAnno.Height - 5) then 
    Self.FAnno.Shape.Top := Y + 10 
    else 
    Self.FAnno.Shape.Top := Y - Self.FAnno.Height - 15; 
    // 
    if (X >= Self.chtMain.BottomAxis.IStartPos) and 
    (X <= Self.chtMain.BottomAxis.IEndPos) and 
    (Y >= Self.chtMain.LeftAxis.IStartPos) and 
    (Y <= Self.chtMain.LeftAxis.IEndPos) then 
    Self.FAnno.Active := True 
    else 
    Self.FAnno.Active := False; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    Idx, J : Integer; 
    Serie : TFastLineSeries; 
    Start : TDateTime; 
    Value : Double; 
begin 
    // 
    Self.chtMain.View3D     := False; 
    Self.chtMain.Align      := alClient; 
    Self.chtMain.BackColor     := clWhite; 
    Self.chtMain.Color      := clWhite; 
    Self.chtMain.Gradient.Visible   := False; 
    Self.chtMain.Legend.LegendStyle  := lsSeries; 
    Self.chtMain.Zoom.Allow    := False; 
    Self.chtMain.AllowPanning    := pmNone; 
    Self.chtMain.BackWall.Color   := clWhite; 
    Self.chtMain.BackWall.Gradient.Visible := False; 

    Self.chtMain.LeftAxis.Automatic  := False; 
    Self.chtMain.LeftAxis.Minimum   := 0; 
    Self.chtMain.LeftAxis.Maximum   := 2; 
    Self.chtMain.LeftAxis.Increment  := 0.1; 
    Self.chtMain.LeftAxis.Visible   := True; 
    Self.chtMain.LeftAxis.AxisValuesFormat := '#,##0.## LV'; 
    // 
    Self.chtMain.BottomAxis.DateTimeFormat := 'dd.mm.yyyy hh:mm:ss'; 
    Self.chtMain.BottomAxis.Increment  := 1/6; 
    Self.chtMain.BottomAxis.Automatic  := True; 
    Self.chtMain.BottomAxis.LabelsSize  := 32; 
    Self.chtMain.BottomAxis.LabelsMultiLine := True; 
    Self.chtMain.MarginBottom    := 6; 
    Self.chtMain.BottomAxis.Title.Caption := 'Date'; 
    Self.chtMain.BottomAxis.Visible   := False; 


    FAnno := Self.chtMain.Tools.Add(TAnnotationTool) as TAnnotationTool; 
    FAnno.Active := False; 
    FAnno.Shape.CustomPosition := True; 

    FCursor := Self.chtMain.Tools.Add(TCursorTool) as TCursorTool; 
    FCursor.FollowMouse := True; 
    FCursor.Style := cssVertical; 

    Randomize; 
    Start := Now; 
    for Idx := 0 to 3 do 
    begin 
    // 
    Serie := Self.chtMain.AddSeries(TFastLineSeries) as TFastLineSeries; 
    Serie.FastPen := True; 
    Serie.ShowInLegend := False; 
    Serie.XValues.DateTime := True; 
    Serie.VertAxis := aLeftAxis; 
    Serie.ParentChart := Self.chtMain; 

    for J := 1 to 1000 do 
    begin 
     // 
     Value := Random * ARR_MAXS[Idx] * 1.8; 
     Serie.AddXY(IncSecond(Start, J), Value/ARR_MAXS[Idx]); 
    end; 
    end; 
end; 

end. 
  • 按[F9]
  • 我不觀察到任何差別,是否使用位置註釋代碼或另一個。

    +0

    我不認爲你顯示的代碼是延遲的原因。註釋位置的兩個「if」和相關設置不應占用任何重要時間(但爲什麼在最後一次提到'FY'而不是'Y')?)。最後一個'if'也一樣。但是將底層數據的值傳遞給AnnoLst可能需要一些時間,但是您沒有表現出來,因此無法評估。 –

    +0

    所以,請在代碼中填寫'AnnoLst'。 –

    +0

    'FY'是我改變它的一個錯誤。我在鼠標移動事件中對所有內容進行了計時,並且數據 - > AnnoLst部分花費了不可測量的時間。當我忽略上面的代碼時,我只觀察到了不同。也許你是對的它不是上面的代碼不會造成滯後,而是'TChart'組件的後端。我會在可以評估行爲的問題中舉一些例子。 – FlorianSchunke

    回答

    1

    TCursorToolFullRepaint屬性(false默認情況下)使用XOR畫它,因此全圖並不需要被重新繪製每次更新其位置。這很快。

    但是,TAnnotationTool不包含這種可能性,因此,當您更新FAnnot文本或位置時,您正在強制重繪圖表,並且有許多點會使處理速度變慢。

    您可以使用TLabel組件代替使用TAnnotationTool來繪製文本。

    +0

    我以前試過,但沒有顯示。現在我發現了爲什麼:我忘了叫'lblAnno.BringToFront' ......謝謝 – FlorianSchunke

    相關問題