如何防止控件重画而造成的抖动!(100分)

  • 主题发起人 主题发起人 midi
  • 开始时间 开始时间
M

midi

Unregistered / Unconfirmed
GUEST, unregistred user!
我想实现一幅图从中间向两边拉开的效果,编写了以下的语句。(抄来的)
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if (image1.Left>0) then // 或其它的值。
begin
image1.Left:=image1.Left-1;
image1.Width:=image1.Width+2;
end
else
timer1.Enabled:=false;
end;

一个图形控件,一为timer控件。timer控件每执行一次,图形就闪烁一次,
怎样解决这个总是呢!
希望能提供部分源程!
十分感谢!
 
如果构件的 ComponentStyle 属性没有包含 csOpaque 旗帜的话,调用
Invalidate方法时 会导致构件的背景先被擦掉再重绘。如果你在 Paint 方法中绘制
背景,那你应该在构件的建构函式中加上:

ComponentStyle := ComponentStyle + [csOpaque];

Max Nilson的回答:
引起闪动另一个原因可能是 WM_ERASEBKGND 讯息的处理。当 VCL 控制项
收到一个 WM_ERASEBKGND讯息时,它会将构件的背景擦掉然後配置成预设的颜色。如
果你的元件衍生自TWinControl,而且构件的颜色与背景颜色不同(例如图形),每
次重画以前都会将构件先清成背景颜色再重绘,这就是造成闪动的原因了!

解决的方法不难,你必须告诉 Windows 你要自行解决『所有的』绘图动
作。不过有一个前提是,你一定要确定你的 Paint 方法将整个构件都画过,如果你
漏了什麽地方忘了画,那个节的数据会由乱数组成,你能想见这情况吗?使用这个方
法可以加速你的构件绘制动作(稍微快一点点),因为少了一个填满背景颜色的动
作。
type
TMyComponent = class (TWinControl)
...
protected
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message
WM_ERASEBKGND;
...
end;
procedure TBMyComponent.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
// 不要重绘背景,这会造成构件闪动
Message.Result := 0
end;

 
最好用copyrect函数可以有效必免抖动。
 
何苦!

先把Image放好,在上面盖两个Panel,

一个居左,一个居右,

然后在OnTimer事件里把这两个Panel的宽度递减

试试看!
 
>>包含 xxx 旗帜
2 www:
你老兄是台湾人吧?还是台湾佬的书看太多了?
 
刚才试了一下我的方法,效果还不错~~
 
to 蚯蚓:
我不是台湾人,刚才是从网上剪了一段下来。
 
其实用canvas.StretchDraw就可以了,不要操作image控件的属性.
 
可以把图形装载到一个image1(TImage,且image1.visible=false)里,
再在Timer里调用copyrect(每次copy区域当然不一样),从image1里
copy到form1.canvas里。

我试过在24位真彩800x600下全屏,timer.interval=1,显示图片没有
闪烁。我的cpu是Pentium233。
 
timer.interval=1
同timer.interval=50效果是一样的。
Delphi的timer最小单位是 20毫秒。
 
我知道timer.interval=1即每秒18.2次,
我是想说明用timer方式的最快的情形。
 
各位:
能不能给点例程,我初学DELPHI在多媒体中的编程,请大家多多帮忙!!
 
用StretchDraw来实现:
var bmp:tbitmap; //2个全局变量
bmpw:integer;

procedure TForm1.Button1Click(Sender: TObject); //按button1后开始
begin
bmp:=tbitmap.Create;
bmp.LoadFromFile('c:/windows/安装程序.bmp');
bmpw:=4; //初始宽度为4
timer1.Enabled:=true; //打开timer1
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var tmpbmp:tbitmap;
rect:trect;
begin
rect.Left:=(width-bmpw) div 2;
rect.right:=rect.left+bmpw;
rect.top:=(height-bmp.Height) div 2;
rect.Bottom:=rect.top+bmp.height;
canvas.StretchDraw(rect,bmp);
inc(bmpw,4);
if bmpw>=bmp.width then timer1.enabled:=false; //全部展开后关闭timer1
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
bmp.free; //记住释放bmp
end;
 
再试一试copyrect:
加两个控件:TTimer和TImage。
var
x1,x2:integer;//全局变量

form1的create事件:

procedure TForm1.FormCreate(Sender: TObject);
begin
form1.WindowState :=wsMaximized;
image1.AutoSize :=true;
image1.Visible :=false;
image1.Picture.Bitmap.LoadFromFile('c:/windows/clouds.bmp');
timer1.Interval :=1;
timer1.Enabled :=true;
x1:=image1.Width div 2;
x2:=image1.Width div 2;
end;

timer事件:
procedure TForm1.Timer1Timer(Sender: TObject);
var sr,dr:trect;
begin
x1:=x1-3;
x2:=x2+3;//加减多少自己决定
if x1<0 then
begin
timer1.Enabled:=false;
x1:=0;
end;
dr:=rect(x1,0,x2,image1.Height-1);
sr:=dr;
Form1.Canvas.CopyRect(dr,IMAGE1.Canvas ,sr);
end;
 
谢谢大家的帮忙。
liuge兄的方法最符合要求,但cakk兄又提供了一种新的方法。
www的蚯蚓兄的讨论也让我受益不少,在此一并感谢!
midi
 

Similar threads

D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
I
回复
0
查看
621
import
I
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
后退
顶部