zoukankan      html  css  js  c++  java
  • WM_PAINT在微软官方定义中,wParam和lParam都没有使用,所以就被Delphi给重定义了这个消息,还增加了DC(Delphi可任意改写消息的结构)

    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第一次会发给父控件,然后依次重绘TCustomControl子控件,但是每个TCustomControl子控件都会通过inherited把消息传回来,当第一次传回来的时候,这个消息的DC就应该不是0了。

  • 相关阅读:
    字的传送
    mov 寄存器,段寄存器
    c语言中利用三维数组计算成绩总分数
    python中break语句
    c语言中求课程总分、平均分。学生总分及平均分
    python中assert语句
    python中random模块引入随机数
    python中实现列表的倒序排列
    c语言中求两个矩阵的乘积
    python的严格缩进可以避免else悬挂
  • 原文地址:https://www.cnblogs.com/findumars/p/5183638.html
Copyright © 2011-2022 走看看