现在我自己写了一个控件。
Tmycontrol=class(TCustomControl)
private
FMemoryBitmap: array [0..1] of TBitmap;
FTopImg:array [0..1] of TBitmap;
FBottomImg:array [0..1] of TBitmap;
FMiddleImg:array [0..1] of TBitmap;
FOwnerForm:TForm;
FSpetPos:Integer;
protected
procedure Paint; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property OwnerForm:TForm read FOwnerForm write FOwnerForm;
property SpetPos:Integer read FSpetPos write FSpetPos;
end;
然后Create和paint时间重写如下constructor Tmycontrol.Create(AOwner: TComponent);
var
I:Integer;
begin
inherited;
FOwnerForm:=nil; //
FSpetPos:=75; FMemoryBitmap[0]:=TBitmap.Create;
FMemoryBitmap[1]:=TBitmap.Create; FTopImg[0]:=TBitmap.Create;
FTopImg[1]:=TBitmap.Create;
FTopImg[0].Handle:=LoadBitmap(hInstance,'LeftBarTop0'); //LeftBarTop0 BITMAP "image\leftbar_top0.bmp" 黑色
FTopImg[1].Handle:=LoadBitmap(hInstance,'LeftBarTop1');//灰色 FBottomImg[0]:=TBitmap.Create;
FBottomImg[1]:=TBitmap.Create;
FBottomImg[0].Handle:=LoadBitmap(hInstance,'LeftBarBottom0');
FBottomImg[1].Handle:=LoadBitmap(hInstance,'LeftBarBottom1'); FMiddleImg[0]:=TBitmap.Create;
FMiddleImg[1]:=TBitmap.Create;
FMiddleImg[0].Handle:=LoadBitmap(hInstance,'LeftBarMiddle0');
FMiddleImg[1].Handle:=LoadBitmap(hInstance,'LeftBarMiddle1');
FMemoryBitmap[0].Width:=FTopImg[0].Width;
FMemoryBitmap[0].Height:=1; for I:=0 to FTopImg[0].Width-1 do
FMemoryBitmap[0].Canvas.Pixels[I,0]:=
FTopImg[0].Canvas.Pixels[I,FTopImg[0].Height-1]; FMemoryBitmap[1].Width:=FTopImg[1].Width;
FMemoryBitmap[1].Height:=1;
for I:=0 to FTopImg[1].Width-1 do
FMemoryBitmap[1].Canvas.Pixels[I,0]:=
FTopImg[1].Canvas.Pixels[I,FTopImg[1].Height-1];
//change Cursor
Cursor:=crSizeWE;
// Self.Width
Width:= FTopImg[0].Width;
if FOwnerForm<>nil then
FOwnerForm:=nil;
end;paintprocedure Tmycontrol.Paint;
var
Idx:Integer;
begin
if (FOwnerForm<>nil) then
begin
Idx:=ord(FOwnerForm.Active);// Idx:=1
Canvas.StretchDraw(ClientRect,FMemoryBitmap[Idx]);
Canvas.Draw(0,0,FTopImg[Idx]);
Canvas.Draw(0,Height-FBottomImg[Idx].Height,FBottomImg[Idx]);
Canvas.Draw(0,FSpetPos,FMiddleImg[Idx]);
end;
end;现在就出现一个问题,也就是我用到这个控件的窗体在失焦和获得焦点切换的时候,说白了就是2个窗体一个点一下的情况,控件的某些地方就会出现白色的条,未被填充,瞬间,因为上面的LoadBitmap的图片都是灰黑色的,所以瞬间的白条很刺眼。
我感觉应该是paint语句中
Idx:=ord(FOwnerForm.Active);// Idx:=1
Canvas.StretchDraw(ClientRect,FMemoryBitmap[Idx]);
Canvas.Draw(0,0,FTopImg[Idx]);
Canvas.Draw(0,Height-FBottomImg[Idx].Height,FBottomImg[Idx]);
Canvas.Draw(0,FSpetPos,FMiddleImg[Idx]);
这里的问题,可是要怎么写才能不闪出白条呢?有没有高手来解决?
Tmycontrol=class(TCustomControl)
private
FMemoryBitmap: array [0..1] of TBitmap;
FTopImg:array [0..1] of TBitmap;
FBottomImg:array [0..1] of TBitmap;
FMiddleImg:array [0..1] of TBitmap;
FOwnerForm:TForm;
FSpetPos:Integer;
protected
procedure Paint; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property OwnerForm:TForm read FOwnerForm write FOwnerForm;
property SpetPos:Integer read FSpetPos write FSpetPos;
end;
然后Create和paint时间重写如下constructor Tmycontrol.Create(AOwner: TComponent);
var
I:Integer;
begin
inherited;
FOwnerForm:=nil; //
FSpetPos:=75; FMemoryBitmap[0]:=TBitmap.Create;
FMemoryBitmap[1]:=TBitmap.Create; FTopImg[0]:=TBitmap.Create;
FTopImg[1]:=TBitmap.Create;
FTopImg[0].Handle:=LoadBitmap(hInstance,'LeftBarTop0'); //LeftBarTop0 BITMAP "image\leftbar_top0.bmp" 黑色
FTopImg[1].Handle:=LoadBitmap(hInstance,'LeftBarTop1');//灰色 FBottomImg[0]:=TBitmap.Create;
FBottomImg[1]:=TBitmap.Create;
FBottomImg[0].Handle:=LoadBitmap(hInstance,'LeftBarBottom0');
FBottomImg[1].Handle:=LoadBitmap(hInstance,'LeftBarBottom1'); FMiddleImg[0]:=TBitmap.Create;
FMiddleImg[1]:=TBitmap.Create;
FMiddleImg[0].Handle:=LoadBitmap(hInstance,'LeftBarMiddle0');
FMiddleImg[1].Handle:=LoadBitmap(hInstance,'LeftBarMiddle1');
FMemoryBitmap[0].Width:=FTopImg[0].Width;
FMemoryBitmap[0].Height:=1; for I:=0 to FTopImg[0].Width-1 do
FMemoryBitmap[0].Canvas.Pixels[I,0]:=
FTopImg[0].Canvas.Pixels[I,FTopImg[0].Height-1]; FMemoryBitmap[1].Width:=FTopImg[1].Width;
FMemoryBitmap[1].Height:=1;
for I:=0 to FTopImg[1].Width-1 do
FMemoryBitmap[1].Canvas.Pixels[I,0]:=
FTopImg[1].Canvas.Pixels[I,FTopImg[1].Height-1];
//change Cursor
Cursor:=crSizeWE;
// Self.Width
Width:= FTopImg[0].Width;
if FOwnerForm<>nil then
FOwnerForm:=nil;
end;paintprocedure Tmycontrol.Paint;
var
Idx:Integer;
begin
if (FOwnerForm<>nil) then
begin
Idx:=ord(FOwnerForm.Active);// Idx:=1
Canvas.StretchDraw(ClientRect,FMemoryBitmap[Idx]);
Canvas.Draw(0,0,FTopImg[Idx]);
Canvas.Draw(0,Height-FBottomImg[Idx].Height,FBottomImg[Idx]);
Canvas.Draw(0,FSpetPos,FMiddleImg[Idx]);
end;
end;现在就出现一个问题,也就是我用到这个控件的窗体在失焦和获得焦点切换的时候,说白了就是2个窗体一个点一下的情况,控件的某些地方就会出现白色的条,未被填充,瞬间,因为上面的LoadBitmap的图片都是灰黑色的,所以瞬间的白条很刺眼。
我感觉应该是paint语句中
Idx:=ord(FOwnerForm.Active);// Idx:=1
Canvas.StretchDraw(ClientRect,FMemoryBitmap[Idx]);
Canvas.Draw(0,0,FTopImg[Idx]);
Canvas.Draw(0,Height-FBottomImg[Idx].Height,FBottomImg[Idx]);
Canvas.Draw(0,FSpetPos,FMiddleImg[Idx]);
这里的问题,可是要怎么写才能不闪出白条呢?有没有高手来解决?
BufferedGraphicsContext _bufferedGraphicsContext
BufferedGraphicsContext是类,提供创建图形缓冲区的方法,该缓冲区可用于双缓冲。而后者是它的实例的名称。
BufferedGraphics _bufferedGraphics
BufferedGraphics是类,为双缓冲提供图形缓冲区。而后者是它的实例的名称,是否明白中文解释的意思不重要,重要的是找到例子或使用方法。
获取当前的BufferedGraphicsContext
_bufferedGraphicsContext = BufferedGraphicsManager.Current
BufferedGraphicsManager提供对应用程序域的主缓冲图形上下文对象的访问。而Current就是获取当前应用程序域的BufferedGraphicsContext,这个对象实例交给
_bufferedGraphicsContext设置,可以在构造函数时设置
_bufferedGraphicsContext.MaximumBuffer = new Size(this.Width + 1, this.Height + 1);
_bufferedGraphics = _bufferedGraphicsContext.Allocate(this.CreateGraphics(), ClientRectangle);
MaximumBuffer是用来设置要使用的缓冲区的最大大小,如果缓冲区过小,而要画的内容过大,就不能完全展示内容了
Allocate使用指定的 System.Drawing.Graphics 的像素格式,创建指定大小的图形缓冲区。注意大小的变化时应该及时同步缓冲区大小,在OnSizeChanged事件上面设置
_bufferedGraphicsContext.MaximumBuffer = new Size(this.Width + 1, this.Height + 1);
if (_bufferedGraphicsContext != null)
_bufferedGraphicsContext.Dispose();
_bufferedGraphics = _bufferedGraphicsContext.Allocate(this.CreateGraphics(),
ClientRectangle);
因为源控件的大小发生变化后,而缓冲区不同了,所画的内容也将会不用的。OnPaint方法的调用
protected override void OnPaint(PaintEventArgs e)
{
DoSomePaintAction(_bufferedGraphics.Graphics);
_bufferedGraphics.Render(e. Graphics);
}
Render将图形缓冲区的内容写入指定的 System.Drawing.Graphics 对象。
而_bufferedGraphics.Graphics是一个Graphics的实例,DoSomePaintAction所做的动作就像平常的Paint一样,最后_bufferedGraphics.Render可以由缓冲区做的处理都反映到当前的Graphics实例上面。重要链接资源
下面的链接地址,介绍了一个DoubleBuffer的应用例子,说明得很深刻,有很好的借鉴作用。
http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx
解决了一部分问题,新问题又发现了,
在窗体resize,也就是我拖动窗体大小的时候,因为我这个控件有点儿类似于scrollbar,所以一拖动窗体大小,就出现大白块,汗,哈哈,郁闷
这里的持久化是什么东西?
private
m_bmpBuffer: TBitmap;
//.... end;procedure OnPaint;
begin
if not Assigned(m_bmpBuffer) then
begin
m_bmpBuffer = TBitmap.Create;
m_bmpBuffer.Width := Self.Width;
m_bmpBuffer.Height:= Self.Height; // Draw image on buffer(如果图像不经常变的话,可以这么做,如果变换,就把end这个放到下面或者在需要变的时候自己画)
with m_bmpBuffer.Canvas do
begin
Draw(0,0,FTopImg[Idx]);
Draw(0,Height-FBottomImg[Idx].Height,FBottomImg[Idx]);
Draw(0,FSpetPos,FMiddleImg[Idx]);
//....
end;
end; // Transfer to screen DC
Bitblt(Self.Canvas.Handle, 0, 0, Self.Width, Self.Height,
m_bmpBuffer.Canvas.Handle, 0, 0, SRCCOPY);
end;
就是具有将自己保存起来,以后有能恢复。简单的说,就是具有将自己的信息写到文件中,以后能读出来再恢复成原来状态。所有从TPersist继承下来的类,都具有持久化。