Canvas.textout 在新系列可见后不显示文本
Canvas.textout doesn´t show text after a new series is made visible
所以我正在做的是在 teechart 图表上使用以下代码在 onmousemove 事件中显示鼠标指针的 x 和 y 值:
oscilografia.Repaint;
if ((x>236) and (x<927)) and ((y>42) and (y<424)) then
begin
oscilografia.Canvas.Brush.Style := bsSolid;
oscilografia.Canvas.Pen.Color := clBlack;
oscilografia.Canvas.Brush.Color := clWhite;
oscilografia.Canvas.TextOut(x+10,y,datetimetostr(oscilografia.Series[0].XScreenToValue(x))+','+FormatFloat('#0.00',oscilografia.series[0].YScreenToValue(y)));
edit1.Text:=inttostr(x)+' '+inttostr(y);
end;
代码工作正常,但是当我通过在图例上选择另一个系列使其可见时出现问题:canvas.textout 创建的框中的文本不再显示。
框仍然跟随鼠标,但没有任何文字。所以我想要一个解决方案。
基本问题归结为绘画的工作原理。 Windows 没有持久绘图表面。您在 window 上绘制的内容将在下次系统需要重新绘制时被覆盖。
您需要安排所有绘画都是为了响应 WM_PAINT
消息。在 Delphi 术语中,这通常意味着您会将绘画代码放在重写的 Paint
方法中。
所以基本流程是这样的:
- 导出图表控件的子class,并在其中class 覆盖
Paint
。调用继承的 Paint
方法,然后执行您的代码以显示所需的文本。
- 在您的
OnMouseMove
事件处理程序中,如果您检测到鼠标坐标文本需要更新,请在图表上调用 Invalidate
。
- 对
Invalidate
的调用会将 window 标记为脏,并且当下一个绘制周期发生时,将执行 Paint
中的代码。
- 此外,当发生任何其他强制绘制循环的事情时,例如对图表的其他修改,您的绘制代码将再次执行。
请注意,作为 sub-classing 的替代方法,您可以使用 TChart
事件 OnAfterDraw
。但我不是 TChart
方面的专家,所以不确定。不过,要点正如我上面所述。
来自 , I see you followed this example.
请注意,它没有绘制任何矩形;它只绘制文本,所以我不确定你的鼠标后面是什么框。
另请注意示例调用 Invalidate
,作为 David Heffernan suggested in 。
在下面找到同一示例的修改版本,在文本前绘制一个矩形。
procedure TForm1.FormCreate(Sender: TObject);
begin
Series1.FillSampleValues(10);
Chart1.View3D := False;
end;
procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var tmpL,tmpL2,ClickedValue : Integer;
tmpWidth, tmpHeight: Integer;
tmpText: string;
begin
clickedvalue := -1;
tmpL2:= -1;
With Chart1 do
begin
If (Series1.Clicked(X, Y) <> -1) And (not OnSeriesPoint) Then
begin
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Color := clBlack;
Canvas.Brush.Color := clWhite;
tmpText:=FormatFloat('#.00',Series1.XScreenToValue(x))+','+FormatFloat('#.00',Series1.YScreenToValue(y));
tmpWidth:=Canvas.TextWidth(tmpText)+10;
tmpHeight:=Canvas.TextHeight(tmpText);
Canvas.Rectangle(x+5, y, x+tmpWidth, y+tmpHeight);
Canvas.TextOut(x+10,y,tmpText);
OnSeriesPoint := True;
ClickedValue:= Series1.Clicked(x,y);
End;
//Repaint Chart to clear Textoutputted Mark
If (ClickedValue=-1) And (OnSeriesPoint) Then
begin
OnSeriesPoint := False;
Invalidate;
End;
tmpL := Chart1.Legend.Clicked(X, Y);
If (tmpL <> -1) And ((tmpL <> tmpL2) Or (not OnLegendPoint)) Then
begin
repaint;
Canvas.Brush.Color := Series1.LegendItemColor(tmpL);
Canvas.Rectangle( X, Y, X + 20, Y + 20);
Canvas.Brush.Color := clWhite;
Canvas.TextOut(x+15,y+7,FormatFloat('#.00',Series1.XValues.Items[Series1.LegendToValueIndex(tmpl)]));
tmpL2 := tmpL;
OnLegendPoint := True;
End;
If (tmpL2 = -1) And (OnLegendPoint) Then
begin
OnLegendPoint := False;
Invalidate;
End;
End;
End;
所以我正在做的是在 teechart 图表上使用以下代码在 onmousemove 事件中显示鼠标指针的 x 和 y 值:
oscilografia.Repaint;
if ((x>236) and (x<927)) and ((y>42) and (y<424)) then
begin
oscilografia.Canvas.Brush.Style := bsSolid;
oscilografia.Canvas.Pen.Color := clBlack;
oscilografia.Canvas.Brush.Color := clWhite;
oscilografia.Canvas.TextOut(x+10,y,datetimetostr(oscilografia.Series[0].XScreenToValue(x))+','+FormatFloat('#0.00',oscilografia.series[0].YScreenToValue(y)));
edit1.Text:=inttostr(x)+' '+inttostr(y);
end;
代码工作正常,但是当我通过在图例上选择另一个系列使其可见时出现问题:canvas.textout 创建的框中的文本不再显示。
框仍然跟随鼠标,但没有任何文字。所以我想要一个解决方案。
基本问题归结为绘画的工作原理。 Windows 没有持久绘图表面。您在 window 上绘制的内容将在下次系统需要重新绘制时被覆盖。
您需要安排所有绘画都是为了响应 WM_PAINT
消息。在 Delphi 术语中,这通常意味着您会将绘画代码放在重写的 Paint
方法中。
所以基本流程是这样的:
- 导出图表控件的子class,并在其中class 覆盖
Paint
。调用继承的Paint
方法,然后执行您的代码以显示所需的文本。 - 在您的
OnMouseMove
事件处理程序中,如果您检测到鼠标坐标文本需要更新,请在图表上调用Invalidate
。 - 对
Invalidate
的调用会将 window 标记为脏,并且当下一个绘制周期发生时,将执行Paint
中的代码。 - 此外,当发生任何其他强制绘制循环的事情时,例如对图表的其他修改,您的绘制代码将再次执行。
请注意,作为 sub-classing 的替代方法,您可以使用 TChart
事件 OnAfterDraw
。但我不是 TChart
方面的专家,所以不确定。不过,要点正如我上面所述。
来自
请注意,它没有绘制任何矩形;它只绘制文本,所以我不确定你的鼠标后面是什么框。
另请注意示例调用 Invalidate
,作为 David Heffernan suggested in
procedure TForm1.FormCreate(Sender: TObject);
begin
Series1.FillSampleValues(10);
Chart1.View3D := False;
end;
procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var tmpL,tmpL2,ClickedValue : Integer;
tmpWidth, tmpHeight: Integer;
tmpText: string;
begin
clickedvalue := -1;
tmpL2:= -1;
With Chart1 do
begin
If (Series1.Clicked(X, Y) <> -1) And (not OnSeriesPoint) Then
begin
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Color := clBlack;
Canvas.Brush.Color := clWhite;
tmpText:=FormatFloat('#.00',Series1.XScreenToValue(x))+','+FormatFloat('#.00',Series1.YScreenToValue(y));
tmpWidth:=Canvas.TextWidth(tmpText)+10;
tmpHeight:=Canvas.TextHeight(tmpText);
Canvas.Rectangle(x+5, y, x+tmpWidth, y+tmpHeight);
Canvas.TextOut(x+10,y,tmpText);
OnSeriesPoint := True;
ClickedValue:= Series1.Clicked(x,y);
End;
//Repaint Chart to clear Textoutputted Mark
If (ClickedValue=-1) And (OnSeriesPoint) Then
begin
OnSeriesPoint := False;
Invalidate;
End;
tmpL := Chart1.Legend.Clicked(X, Y);
If (tmpL <> -1) And ((tmpL <> tmpL2) Or (not OnLegendPoint)) Then
begin
repaint;
Canvas.Brush.Color := Series1.LegendItemColor(tmpL);
Canvas.Rectangle( X, Y, X + 20, Y + 20);
Canvas.Brush.Color := clWhite;
Canvas.TextOut(x+15,y+7,FormatFloat('#.00',Series1.XValues.Items[Series1.LegendToValueIndex(tmpl)]));
tmpL2 := tmpL;
OnLegendPoint := True;
End;
If (tmpL2 = -1) And (OnLegendPoint) Then
begin
OnLegendPoint := False;
Invalidate;
End;
End;
End;