WM_PAINT는 마이크로소프트의 공식 정의에서 wParam과 lParam을 모두 사용하지 않았기 때문에 델파이에 의해 이 메시지를 다시 정의했고 DC(Delphi는 메시지를 임의로 바꿀 수 있는 구조를 추가했다. 앞의 4바이트만 메시지로 유지하면 되고 마이크로소프트가 정의한 모든 필요한 정보를 휴대하면 된다)

7132 단어
LRESULT CALLBACK WindowProc(
  HWND hwnd, 
  UINT  uMsg, 
  WPARAM wParam, 
  LPARAM lParam     
);


Parameters
wParam
This parameter is not used.
lParam
This parameter is not used.
Delphi에서 핸들을 제거한 후 재정의하기
  TWMPaint = packed record
    Msg: Cardinal;
    DC: HDC;
    Unused: Longint;
    Result: Longint;
  end;

테스트 결과 크기는 16:
procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(TWMPaint)));
end;

재정의된 활용 과정은 다음과 같습니다.
procedure TWinControl.WMPaint(var Message: TWMPaint);
var
  DC, MemDC: HDC;
  MemBitmap, OldBitmap: HBITMAP;
  PS: TPaintStruct;
begin
  if not FDoubleBuffered or (Message.DC <> 0) then //        DC,         
  begin
    if not (csCustomPaint in ControlState) and (ControlCount = 0) then //   Windows    ,          0,       。
      inherited //   1,     Windows      ,         ,     ,    BeginPaint  ?
    else
      PaintHandler(Message); //   2,     Delphi     ,  BeginPaint
  end
  else
  begin
    DC := GetDC(0); //   3,       DC,     ,  BeginPaint
    MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
    ReleaseDC(0, DC);
    MemDC := CreateCompatibleDC(0);
    OldBitmap := SelectObject(MemDC, MemBitmap);
    try
      DC := BeginPaint(Handle, PS);
      Perform(WM_ERASEBKGND, MemDC, MemDC);
      Message.DC := MemDC; //           
      WMPaint(Message); //     DC,     Message.DC := 0;
      BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY);
      EndPaint(Handle, PS);
    finally
      SelectObject(MemDC, OldBitmap);
      DeleteDC(MemDC);
      DeleteObject(MemBitmap);
    end;
  end;
end;

전송 계속:
procedure TWinControl.PaintHandler(var Message: TWMPaint);
var
  I, Clip, SaveIndex: Integer;
  DC: HDC;
  PS: TPaintStruct;
begin DC := Message.DC; //          (        ),                 ,           DC   。        ,      ,Message.DC        。fixme       if DC = 0 then DC := BeginPaint(Handle, PS); //   DC   ,     (        ,     ) try
    if FControls = nil then PaintWindow(DC) else
    begin
      SaveIndex := SaveDC(DC);
      Clip := SimpleRegion;
      for I := 0 to FControls.Count - 1 do
        with TControl(FControls[I]) do
          if (Visible or (csDesigning in ComponentState) and
            not (csNoDesignVisible in ControlStyle)) and
            (csOpaque in ControlStyle) then
          begin
            Clip := ExcludeClipRect(DC, Left, Top, Left + Width, Top + Height);
            if Clip = NullRegion then Break;
          end;
      if Clip <> NullRegion then PaintWindow(DC);
      RestoreDC(DC, SaveIndex);
    end;
    PaintControls(DC, nil); //       DC      finally
    if Message.DC = 0 then EndPaint(Handle, PS);
  end;
end;

procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
  if Message.DC <> 0 then //   ,  DC  ,      (    )
  begin
    Canvas.Lock;
    try Canvas.Handle := Message.DC; //       ,DC       Canvas  ,       DC   try
        Paint;
      finally Canvas.Handle := 0; end;
    finally
      Canvas.Unlock;
    end;
  end;
end;

procedure TCustomControl.WMPaint(var Message: TWMPaint);
begin
  Include(FControlState, csCustomPaint);
  inherited;
  Exclude(FControlState, csCustomPaint);
end;

procedure TWinControl.WMPrintClient(var Message: TWMPrintClient);
begin
  with Message do
    if Result <> 1 then
      if ((Flags and PRF_CHECKVISIBLE) = 0) or Visible then
        PaintHandler(TWMPaint(Message))
      else
        inherited
    else
      inherited;
end;

TWinControl에 여러 TCustomControl 하위 컨트롤이 포함되어 있는 실험을 다시 수행합니다.WM_PAINT는 처음으로 부모 컨트롤러에 보내고 TCustom Control 하위 컨트롤러를 순서대로 다시 그립니다. 그러나 모든TCustom Control 하위 컨트롤러는 inherited를 통해 메시지를 전송합니다. 처음 전송했을 때 이 메시지의 DC는 0이 아니었을 것입니다.

좋은 웹페이지 즐겨찾기