请见delphi的源码: procedure TWinControl.PaintHandler(var Message: TWMPaint); var I, Clip, SaveIndex: Integer; DC: HDC; PS: TPaintStruct; begin DC := Message.DC; if DC = 0 then DC := BeginPaint(Handle, PS); 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); //很显然是先画窗口再画控件。 finally if Message.DC = 0 then EndPaint(Handle, PS); end; end; 至于控件的重画顺序,如下源码: procedure TWinControl.PaintControls(DC: HDC; First: TControl); var I, Count, SaveIndex: Integer; FrameBrush: HBRUSH; begin if DockSite and UseDockManager and (DockManager <> nil) then DockManager.PaintSite(DC); if FControls <> nil then begin I := 0; if First <> nil then begin I := FControls.IndexOf(First); if I < 0 then I := 0; end; Count := FControls.Count; while I < Count do //是根据form的controls[i]属性的顺序重画的。 begin ... end; ... end; ... end; 而form的control是个控件数组,其顺序就是在设计时VCL控件放置在窗口上的顺序,而非其TabOrder。
TabIndex: Integer; const Rect: TRect; Active: Boolean);
beginend;
procedure TWinControl.PaintHandler(var Message: TWMPaint);
var
I, Clip, SaveIndex: Integer;
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC;
if DC = 0 then DC := BeginPaint(Handle, PS);
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); //很显然是先画窗口再画控件。
finally
if Message.DC = 0 then EndPaint(Handle, PS);
end;
end;
至于控件的重画顺序,如下源码:
procedure TWinControl.PaintControls(DC: HDC; First: TControl);
var
I, Count, SaveIndex: Integer;
FrameBrush: HBRUSH;
begin
if DockSite and UseDockManager and (DockManager <> nil) then
DockManager.PaintSite(DC);
if FControls <> nil then
begin
I := 0;
if First <> nil then
begin
I := FControls.IndexOf(First);
if I < 0 then I := 0;
end;
Count := FControls.Count;
while I < Count do //是根据form的controls[i]属性的顺序重画的。
begin
...
end;
...
end;
...
end;
而form的control是个控件数组,其顺序就是在设计时VCL控件放置在窗口上的顺序,而非其TabOrder。
procedure x.onpaint..
{
dosomething...
}
我有这样的代码!procedure TForm1.RefreshPgControl(APageControl: TPageControl);
var
iActiveIndex: Integer;
rRect: TRect;
sCaption : String;
begin
iActiveIndex := APageControl.ActivePageIndex;
rRect := APageControl.TabRect(iActiveIndex);
sCaption := APageControl.Pages[iActiveIndex].Caption;
APageControl.Canvas.Font:= APageControl.Font;
APageControl.Canvas.Font.Color := clBlue;
APageControl.Canvas.Brush.Color := clBtnFace;
APageControl.Canvas.TextOut(rRect.Left + 6, rRect.Top + 2, sCaption);
end;
这个代码只是把参数的pagecontrol的活动页的caption字体画为蓝色!通过按钮调用是没问题的!
procedure TForm1.WndProc(var Message: TMessage);
begin
inherited;
if Message.Msg = WM_PAINT then
RefreshPgControl(PageControl1);
end;
本意是想在窗体重绘的时候,重新刷新pagecontrol的caption字体颜色,可就是不行!
望高手指点!
begin
inherited;
if Message.Msg = WM_PAINT then
RefreshPgControl(PageControl1);
end;procedure TForm1.RefreshPgControl(APageControl: TPageControl);
var
iActiveIndex: Integer;
rRect: TRect;
sCaption : String;
begin
iActiveIndex := APageControl.ActivePageIndex;
rRect := APageControl.TabRect(iActiveIndex);
sCaption := APageControl.Pages[iActiveIndex].Caption;
APageControl.Canvas.Font:= APageControl.Font;
APageControl.Canvas.Font.Color := clBlue;
APageControl.Canvas.Brush.Color := clBtnFace;
APageControl.Canvas.TextOut(rRect.Left + 6, rRect.Top + 2, sCaption);
end;感觉有几个问题:1. 代码未判断WM_PAINT消息的接收对象
2. PageControl的WM_PAINT消息不一定要经过其属主窗口
3. 如果WM_PAINT消息是POST的,可以在消息队列中检索到,Application是入口
4. 如果自己画,必须在画完后通知操作系统,并终止后续事件,但未看到对应的代码
多谢你的回答,我会往这个方向寻找答案!
如果可以,希望你能指条捷径!
而用ondrawtab事件的话,那必须把ownerdraw置为true才行啊!但这样的话,看起来效果不好,tab标签和下面的tssheet衔接不协调。还有想请教:子类化pagecontrol如何实现?谢谢!
有多种组件可以取代PageControl,而且界面非常美观。Jedi是由Delphi开发者建立的一个套件集,用于强化VCL:
http://delphi-jedi.org/子类化PageControl并不复杂,但是是没必要