在 WM_PAINT 处理程序中找出哪个区域正在被 InvalidateRgn 无效
Find out in WM_PAINT handler which region is being invalidated by InvalidateRgn
我的任务是创建带有背景刻度和指针的指标。当指针移动时,我想在原来的地方重画一部分背景,然后再画一个新的指针。
指针形状定义为多边形,我从中创建了一个 GDI+ 区域。
所以我有 2 个区域对象:旧的和新的。
我每 50 毫秒调用一次以下例程:
procedure TForm1._timerTick(Sender: TObject);
var
g: TGPGraphics;
mx: TGPMatrix;
hr: HRGN;
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
hr := _oldRegion.GetHRGN(g);
try
InvalidateRgn(Handle, hr, False); //Restore background
finally
DeleteObject(hr);
end;
hr := _newRegion.GetHRGN(g);
try
InvalidateRgn(Handle, hr, False); //Draw new region
finally
DeleteObject(hr);
end;
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 也会被调用两次,从而导致四次操作而不是两次。
有什么方法可以在 Paint 方法内部的 Windows 级别找出哪个区域正在失效?
在您的 WM_PAINT
处理程序中,您可以使用:
GetUpdateRect()
or GetUpdateRgn()
, or GetClipBox()
or GetClipRgn()
, on the HDC
that BeginPaint()
returns (in VCL, GetClipBox()
is wrapped by the TCanvas.ClipRect
属性 便于阅读)。
输出时BeginPaint()
填写的PAINTSTRUCT.rcPaint
成员。这是与 GetUpdateRect()
returns.
相同的矩形
任何一种方法都会给你一个 update/clipping 区域,在这个区域中 HDC
需要被绘制。您在该区域之外所做的任何绘图都将被丢弃。因此,您可以将其用作优化,以免浪费精力绘制任何可能会被丢弃的东西。
If I perform InvalidateRgn
twice, then Paint will also be called twice resulting in four operations instead of two.
不正确。 Window 失效被缓存和合并,直到 window 被实际绘制和验证。您可以根据需要多次调用 InvalidateRect()
/InvalidateRgn()
,并且 window 不会被绘制,直到您 return 控制消息循环,所以 WM_PAINT
message can then be generated (unless you force a paint by calling UpdateWindow()
or RedrawWindow()
). WM_PAINT
is a low-priority message, it is only generated by the message queue when the window has a non-empty Update Region and no other higher-priority messages are pending. The window is not validated until WM_PAINT
is processed (unless you force it by calling ValidateRect()
/ValidateRgn()
). See Invalidating and Validating the Update Region 在 MSDN 上获取更多详细信息。
我的任务是创建带有背景刻度和指针的指标。当指针移动时,我想在原来的地方重画一部分背景,然后再画一个新的指针。
指针形状定义为多边形,我从中创建了一个 GDI+ 区域。
所以我有 2 个区域对象:旧的和新的。
我每 50 毫秒调用一次以下例程:
procedure TForm1._timerTick(Sender: TObject);
var
g: TGPGraphics;
mx: TGPMatrix;
hr: HRGN;
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
hr := _oldRegion.GetHRGN(g);
try
InvalidateRgn(Handle, hr, False); //Restore background
finally
DeleteObject(hr);
end;
hr := _newRegion.GetHRGN(g);
try
InvalidateRgn(Handle, hr, False); //Draw new region
finally
DeleteObject(hr);
end;
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 也会被调用两次,从而导致四次操作而不是两次。
有什么方法可以在 Paint 方法内部的 Windows 级别找出哪个区域正在失效?
在您的 WM_PAINT
处理程序中,您可以使用:
GetUpdateRect()
orGetUpdateRgn()
, orGetClipBox()
orGetClipRgn()
, on theHDC
thatBeginPaint()
returns (in VCL,GetClipBox()
is wrapped by theTCanvas.ClipRect
属性 便于阅读)。输出时
BeginPaint()
填写的PAINTSTRUCT.rcPaint
成员。这是与GetUpdateRect()
returns. 相同的矩形
任何一种方法都会给你一个 update/clipping 区域,在这个区域中 HDC
需要被绘制。您在该区域之外所做的任何绘图都将被丢弃。因此,您可以将其用作优化,以免浪费精力绘制任何可能会被丢弃的东西。
If I perform
InvalidateRgn
twice, then Paint will also be called twice resulting in four operations instead of two.
不正确。 Window 失效被缓存和合并,直到 window 被实际绘制和验证。您可以根据需要多次调用 InvalidateRect()
/InvalidateRgn()
,并且 window 不会被绘制,直到您 return 控制消息循环,所以 WM_PAINT
message can then be generated (unless you force a paint by calling UpdateWindow()
or RedrawWindow()
). WM_PAINT
is a low-priority message, it is only generated by the message queue when the window has a non-empty Update Region and no other higher-priority messages are pending. The window is not validated until WM_PAINT
is processed (unless you force it by calling ValidateRect()
/ValidateRgn()
). See Invalidating and Validating the Update Region 在 MSDN 上获取更多详细信息。