楼主的意思可能是想从一个不带TCanvas的类继承,创建新的有TCanvas的控件吧。
------------------------------------------------------
VCL建立TCanvas的标准方法:
Windows Message: WM_PAINT -> WMPaint(var Message : TWMPaint) -> PaintHandler -> PaintWindow(DC HDC) -> Paint
------------------------------------------------------
要自己从一个不带TCanvas的控件上继承,而又希望用TCanvas,标准的方法为(可从TControl开始继承):
1.创建TCanvas
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor TMyControl.Destroy;
begin
if CaptureControl = Self then SetCaptureControl(nil);
FCanvas.Free;
inherited Destroy;
end;
2.响应WM_PAINT
{ 不带缓冲的绘制方法 }
procedure TMyControl.WMPaint( var Message : TWMPaint );
var
PS : TPaintStruct;
DC : HDC;
begin
PaintHandler(Message); // 通过PaintHandler开始绘制
end;
{ 带缓冲的绘制方法 }
procedure TMyControl.WMPaint( var Message : TWMPaint );
var
DC, MemDC: HDC;
MemBitmap, OldBitmap: HBITMAP;
PS: TPaintStruct;
begin
DC := GetDC(0); // 取DC
// 创建绘制缓冲区
MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
ReleaseDC(0, DC);
MemDC := CreateCompatibleDC(0);
// 指定对MemDC缓制到缓冲区上
OldBitmap := SelectObject(MemDC, MemBitmap);
try
// 开始绘制
DC := BeginPaint(Handle, PS);
// 擦清缓冲上的内容
Perform(WM_ERASEBKGND, MemDC, MemDC);
// 绘制内容
PaintHandler(Message);
// 将缓冲区上复制到界面上
BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY);
// 绘制结束
EndPaint(Handle, PS);
finally
// 恢复MemDC
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
// 释放缓冲区
DeleteObject(MemBitmap);
end;
end;
3.PaintHandler用于根据控件的状态决定绘制边框等操作
procedure TMyControl.PaintHandler(var Message: TWMPaint);
var
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC;
if DC = 0 then DC := BeginPaint(Handle, PS);
try
PaintWindow(DC);
finally
if Message.DC = 0 then EndPaint(Handle, PS);
end;
end;
4.创建TCanvas准备绘制
procedure TMyControl.PaintWindow(DC: HDC);
FCanvas : TCanvas;
begin
FCanvas.Lock;
try
FCanvas.Handle := DC;
try
TControlCanvas(FCanvas).UpdateTextFlags;
Paint;
finally
FCanvas.Handle := 0;
end;
finally
FCanvas.Unlock;
end;
end;
5.绘制
procedure TMyControl.Paint;
begin
// 绘制
end;
------------------------------------------------------
一个简单的实现方法:
1.创建TCanvas
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor TMyControl.Destroy;
begin
if CaptureControl = Self then SetCaptureControl(nil);
FCanvas.Free;
inherited Destroy;
end;
2.响应WM_PAINT
procedure TMyControl.WMPaint( var Message : TWMPaint );
var
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC;
if DC = 0 then DC := BeginPaint(Handle, PS);
FCanvas.Lock;
try
FCanvas.Handle := DC;
try
TControlCanvas(FCanvas).UpdateTextFlags;
Paint;
finally
FCanvas.Handle := 0;
end;
finally
begin
if Message.DC = 0 then EndPaint(Handle, PS);
FCanvas.UnLock;
end;
end;
end;
------------------------------------------------------
Invalidate实际上封装了Windows GDI API内的InvalidateRect方法来重绘整个控件区域,基本上等价于GDI API的InvalidateRect(Handle, BoundsRect, true);
要提高控件的重绘速度,就应该确定哪些区域需要重新绘制,再主动调用InvalidateRect来进行,而尽量少用或不用Invalidate或Repint.