在 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 处理程序中,您可以使用:

任何一种方法都会给你一个 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 上获取更多详细信息。