首页 > 代码库 > 一行代码设置TForm颜色的前世今生

一行代码设置TForm颜色的前世今生

来自万一的帖子:
http://www.cnblogs.com/del/archive/2008/04/27/1173658.html
的确做到了一行代码设置颜色的TForm控件。真实的情况是,VCL框架在这个过程中做了大量的工作,经过多次消息的发送,才达到了目的,大致顺序如下:

procedure TForm1.Button4Click(Sender: TObject);begin  Self.Color := clRed;end;procedure TControl.SetColor(Value: TColor);begin  if FColor <> Value then  begin    FColor := Value;    FParentColor := False;    Perform(CM_COLORCHANGED, 0, 0); // 第一个消息  end;end;procedure TCustomForm.CMColorChanged(var Message: TMessage);begin  inherited;  if FCanvas <> nil then FCanvas.Brush.Color := Color; // 说到底,还是通过FCanvas.Brush起作用,类属性Color只是表象end;procedure TWinControl.CMColorChanged(var Message: TMessage);begin  inherited;  FBrush.Color := FColor;  NotifyControls(CM_PARENTCOLORCHANGED); // 第二个消息,组建消息并传播,通知子控件,但没有任何子控件响应end;procedure TControl.CMColorChanged(var Message: TMessage);begin  Invalidate;end;procedure TWinControl.Invalidate;begin  // 注意,第二个参数即WParam是0,即要求API使自己失效,而不是仅仅做一个通知作用。  Perform(CM_INVALIDATE, 0, 0); // 第三个消息end;procedure TWinControl.CMInvalidate(var Message: TMessage);var  I: Integer;begin  if HandleAllocated then  begin    if Parent <> nil then      Parent.Perform(CM_INVALIDATE, 1, 0); // 第四个消息,递归,先通知父类。Form1的Parent是Application,它没有响应。    if Message.WParam = 0 then    begin      // API,第二个参数为NULL的话,则重画整个客户区;第三个参数TRUE则背景重绘。      InvalidateRect(FHandle, nil, not (csOpaque in ControlStyle)); // 总算初步达到目的,使Form1失效,后面还要自绘      { Invalidate child windows which use the parentbackground when themed }      if ThemeServices.ThemesEnabled then        for I := 0 to ControlCount - 1 do          if csParentBackground in Controls[I].ControlStyle then // important            Controls[I].Invalidate;    end;  end;end;

以上过程使Form1的画板失效(说到底,还是通过Form1.FCanvas.Brush起作用,类属性Color只是表象),接下去还要用TForm的函数自绘:

TForm继承自TWinControl,而不是TCustomControl,而且响应WM_PAINT消息并覆盖了WMPaint函数,所以Windows会把WM_PAINT直接发给Form1:
TCustomForm.WMPaint(var Message: TWMPaint);
TWinControl.WMPaint(var Message: TWMPaint);
TWinControl.PaintHandler(var Message: TWMPaint);
TCustomForm.PaintWindow

一行代码设置TForm颜色的前世今生