如果光標在圖表上,我想顯示當前鼠標位置上所有系列的值。正是因爲它顯示在圖中:TeeChart:在當前鼠標位置顯示系列值的快速方法
爲了完成這個行爲我用了一個TAnnotationTool
和OnMouseMove
事件。此外,我使用TCursorTool
與Style := cssVertical
和FollowMouse := 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組件更快地完成這個工作?還是有什麼我可以用來提高速度的屬性?
在此先感謝您的支持!
編輯:示例代碼重現此問題
- 創建一個新的VCL項目
- 降一TChart組件和形式
- 上的複選框創建FORMCREATE的形式和MouseMoveEvent爲圖表
- 切換到代碼視圖的插入以下代碼:
代碼:
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]
我不觀察到任何差別,是否使用位置註釋代碼或另一個。
我不認爲你顯示的代碼是延遲的原因。註釋位置的兩個「if」和相關設置不應占用任何重要時間(但爲什麼在最後一次提到'FY'而不是'Y')?)。最後一個'if'也一樣。但是將底層數據的值傳遞給AnnoLst可能需要一些時間,但是您沒有表現出來,因此無法評估。 –
所以,請在代碼中填寫'AnnoLst'。 –
'FY'是我改變它的一個錯誤。我在鼠標移動事件中對所有內容進行了計時,並且數據 - > AnnoLst部分花費了不可測量的時間。當我忽略上面的代碼時,我只觀察到了不同。也許你是對的它不是上面的代碼不會造成滯後,而是'TChart'組件的後端。我會在可以評估行爲的問題中舉一些例子。 – FlorianSchunke