我的任务是创建一个带有背景刻度和指针的指示器。当指针移动时,我想在其先前位置重新绘制背景的一部分,然后绘制一个新的指针。
指针形状定义为我从中创建了GDI +区域的多边形。
所以我有2个区域对象:旧的和新的。
每隔50毫秒,我会调用以下例程:
procedure TForm1._timerTick(Sender: TObject);
var
g: TGPGraphics;
mx: TGPMatrix;
begin
if _newRegion <> nil then _newRegion.Free();
if _oldRegion <> nil then _oldRegion.Free();
_newRegion := _baseRegion.Clone();
_oldRegion := _baseRegion.Clone();
mx := TGPMatrix.Create();
try
mx.RotateAt(_angle, MakePoint(250.0, 120.0));
_oldRegion.Transform(mx);
mx.Reset();
Inc(_angle);
if _angle >= 360 then _angle := 0;
mx.RotateAt(_angle, MakePoint(250.0, 120.0));
_newRegion.Transform(mx);
finally
mx.Free();
end;
g := TGPGraphics.Create(Canvas.Handle);
try
InvalidateRgn(Handle, _oldRegion.GetHRGN(g), False); //Restore background
InvalidateRgn(Handle, _newRegion.GetHRGN(g), False); //Draw new region
finally
g.Free();
end;
end;
正如您所看到的,我没有两次调用InvalidateRgn
更好的主意:一次用于后台还原,一次用于指针绘制。
WM_PAINT处理程序如下所示:
procedure TForm1.Paint();
var
g: TGPGraphics;
mx: TGPMatrix;
brs: TGPSolidBrush;
begin
inherited;
g := TGPGraphics.Create(Canvas.Handle);
mx := TGPMatrix.Create();
brs := TGPSolidBrush.Create(MakeColor(255, 255, 0));
try
if _fullDraw then begin
_fullDraw := False;
end
else begin
g.IntersectClip(_oldRegion);
end;
g.DrawImage(_img, 0, 0);
if _newRegion <> nil then begin
g.ResetClip();
g.FillRegion(brs, _newRegion);
end;
finally
brs.Free();
mx.Free();
g.Free();
end;
end;
它总是执行两个操作:恢复背景并绘制指针。
如果我执行两次InvalidateRgn
,那么Paint也将被调用两次,从而导致四个操作而不是两个操作。
是否有某种方法可以在Windows级别的Paint方法内找出哪个区域无效?
在WM_PAINT
处理程序内部,您可以使用以下任何一种:
GetClipBox()
返回的GetClipBox()
上的GetClipRgn()
或GetClipRgn()
。
HDC
在输出时填写的BeginPaint()
成员。
两种方法都将为您提供一个需要绘制HDC的剪切区域。您在该裁剪区域之外所做的任何绘图都将被丢弃。因此,您可以将此作为一种优化,以免浪费精力绘画任何将被丢弃的东西。