TControl的显示函数(5个非虚函数,4个虚函数)和三个例子的执行过程(包括SetParent的例子)

时间:2022-08-11 17:59:06

// 9个显示函数
procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual; // 虚函数,important 根据父控件
// 手法:固定不变的模式,或者简单调用,或者简单设置标志位,就不是虚函数。
procedure Show; // 设置自己和所有祖先的visible标识
procedure Hide; // 简单设置visible标识,与祖先无关
procedure Refresh; // 简单调用Repaint虚函数,但Refresh本身不是虚函数。一般应该使用它,因为可以获得更多的无关性。
procedure SendToBack;
procedure BringToFront; // 图形控件也要用此能力啊,所以在TControl就已经定义了


// 这三个函数,被TWinControl覆盖。即使使用,也是被inherited使用。
// 而图形控件都没有覆盖着三个函数,因此会经常用到它们。摆明了就是给图形控件用的。
// fixme 有空试试把它们都放到图形控件里去
procedure Repaint; virtual; // 虚函数,取得父控件的DC,重画父控件的所有子控件。被TWinControl覆盖。
procedure Invalidate; virtual; // 虚函数,调用非虚函数类函数InvalideControl,把自己需要重画的部分算清楚。被TWinControl覆盖。
{ 递归调用Parent的update,否则什么都不做。意思是,自己更新了,那么父控件也要更新。}
procedure Update; virtual; // 虚函数,通知父控件自己更新了。而父控件的Update是可以被改写的,这样就达到了目的。被TWinControl覆盖。

{
看一下VCL的源码,就不难发现了。
Paint是TCustomForm的Protected方法,实际就是调用OnPaint事件。
Invalidate是TWinControl的方法,主要是发送一个CM_INVALIDATE消息,对控件的值作有效性判断。
Update(其实)也是TWinControl的方法,是通过调用Win32API函数重画窗口。
Repaint是TControl的虚方法,在TWinControl中override,程序只有2行,就是(1)Invalidate;(2)Update
Refresh是TControl的方法,程序只有1句:Repaint.
所以ReFresh和RePaint对于TWinControl的子类来说是等价的(除非又重载过),但是应该说Refresh是更规范的用法。
至于Invalidate的Update一般是没有单独使用的必要的。
}

function TControl.GetDeviceContext(var WindowHandle: HWnd): HDC;
begin
if Parent = nil then
raise EInvalidOperation.CreateFmt(SParentRequired, [Name]);
Result :
= Parent.GetDeviceContext(WindowHandle);
SetViewportOrgEx(Result, Left, Top,
nil);
IntersectClipRect(Result,
0, 0, Width, Height);
end;

procedure TControl.InvalidateControl(IsVisible, IsOpaque: Boolean);
var
Rect: TRect;

function BackgroundClipped: Boolean;
var
R: TRect;
List: TList;
I: Integer;
C: TControl;
begin
Result :
= True;
List :
= FParent.FControls;
I :
= List.IndexOf(Self);
while I > 0 do
begin
Dec(I);
C :
= List[I];
with C do
if C.Visible and (csOpaque in ControlStyle) then
begin
IntersectRect(R, Rect, BoundsRect);
if EqualRect(R, Rect) then Exit;
end;
end;
Result :
= False;
end;

begin
if (IsVisible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
Parent.HandleAllocated
then
begin
Rect :
= BoundsRect;
InvalidateRect(Parent.Handle, @Rect,
not (IsOpaque or
(csOpaque
in Parent.ControlStyle) or BackgroundClipped));
end;
end;

procedure TControl.Invalidate;
begin
InvalidateControl(Visible, csOpaque
in ControlStyle);
end;

procedure TControl.Hide;
begin
Visible :
= False;
end;

procedure TControl.Show;
begin
if Parent <> nil then Parent.ShowControl(Self);
if not (csDesigning in ComponentState) or
(csNoDesignVisible
in ControlStyle) then Visible := True;
end;

procedure TControl.Update;
begin
if Parent <> nil then Parent.Update; // 图形控件没法刷新自己,让父控件去刷新
end;

procedure TControl.Refresh;
begin
Repaint;
end;

procedure TControl.Repaint;
var
DC: HDC;
begin
if (Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
Parent.HandleAllocated
then
if csOpaque in ControlStyle then
begin
DC :
= GetDC(Parent.Handle);
try
IntersectClipRect(DC, Left, Top, Left
+ Width, Top + Height);
Parent.PaintControls(DC, Self);
finally
ReleaseDC(Parent.Handle, DC);
end;
end else
begin
Invalidate;
Update;
end;
end;

PaintControls的意思是,重绘所有图形子控件

--------------------------------------------------------------------------------

例子1:可以看到Image1.的绘制过程

image1.Refresh;

例子2:

Image1.Hide;

例子3:

var
Image2 : TImage;
begin
Image2 := TImage.Create(self);
Image2.Left := 100;
Image2.Top := 50;
Image2.Picture.LoadFromFile('c:\pic.jpg');
Image2.Parent := Form1;
end;