高分求助 TGraphicControl继承写一个组件当组件多或者尺寸太大时闪烁太强烈??(300分)

  • 主题发起人 主题发起人 明天0
  • 开始时间 开始时间

明天0

Unregistered / Unconfirmed
GUEST, unregistred user!
我从TGraphicControl继承写一个组件 来实现像图层一样 显示图片, 可以拖动,运行时
可以拖动改变大小,而且能透明显示图片.当组件多或者尺寸太大时闪烁太强烈.
我尝试从TCustomContro继承,虽然解决了闪烁的问题,但新的问题又出现了.就是
移动时背景不能自动刷新,本来透明显示的图片就不能透明了.
大家有什么好的解决办法没有.
讲一下方法、给一个实例 也行。
我感激不尽。
 
TGraphicControl.Parent.DoubleBuffered := true;
 
我已经尝试过了 但是虽然解决了闪烁的问题,但新的问题又出现了.就是
本来透明显示的图片就不能透明显示了.
 
你怎么实现透明显示的,是这样吗?
Fpicture.Bitmap.TransparentMode := tmAuto;
Fpicture.Bitmap.TransparentColor := Fpicture.BitMap.canvas.pixels[5,5];
Fpicture.Bitmap.Transparent := true;
 
改用窗口控件继承立刻可以减小闪烁,或打开双缓冲。
 
我已经尝试过了 但是虽然解决了闪烁的问题,但新的问题又出现了.就是
本来透明显示的图片就不能透明显示了.我想找一个办法两个问题都解决。
既不闪烁 移动时又能透明显示图片。
 
这就更简单了。
在你控件的设置图片方法里写:
if 对象.Assign(Value) then
begin
fGraphic:=Value;
if fTransparent then
fGraphic.Transparent:=True;
end;

 
各位大侠 你们的方法是对的
但是我透明图片的实现方法是 首先抓取parent 的Hdc 然后截取组件对应位置的图片
为背景和要显示的图片处理后显示出来。
如果parent的双缓冲打开的话,抓取背景就会把 组件 自己的也会 抓取出来。
透明 怎么解决啊大家有什么好办法吗
 
可否把你的代码贴出来?至少把
--------------------------
“首先抓取parent 的Hdc 然后截取组件对应位置的图片
为背景和要显示的图片处理后显示出来。”
--------------------------
的实现过程帖出来。
 
>>但是我透明图片的实现方法是 首先抓取parent 的Hdc 然后截取组件对应位置的图片
>>为背景和要显示的图片处理后显示出来。

没必要~~~~
TGraphicControl.paint时Canvas里已经有背景了(由parent的WM_ERASEBKGND消息与这个graphiccontrol前面的control.paint共同完成的)
 
Pearl说的有理,你直接在TGraphicControl.paint中用canvas.draw(x,y,Fpicture.Bitmap)就可以了,在设置
Fpicture.Bitmap.TransparentMode := tmAuto;
Fpicture.Bitmap.TransparentColor := Fpicture.BitMap.canvas.pixels[5,5];
Fpicture.Bitmap.Transparent := true;
之后该图就是透明的,而不必“截取组件对应位置的图片为背景和要显示的图片处理后显示出来。”
 
大家说的有道理。
我“截取组件对应位置的图片为背景和要显示的图片处理后显示出来。”
原因是
Fpicture.Bitmap.TransparentMode := tmAuto;
Fpicture.Bitmap.TransparentColor := Fpicture.BitMap.canvas.pixels[5,5];
Fpicture.Bitmap.Transparent := true;
方法获得的透明图片不平滑,边缘有锯齿,对于不是单纯颜色的图片就无能为力了。
我的方法是 截取parent 的hdc 为背景图片 ,和一张 黑白两种颜色的图片作为遮罩 图片
、一张前景图片 结合。能实现 任意颜色的图片 的任意 形状的边缘平滑透明。
大家有什么更好的方法吗?能告诉我吗?
 
>>我的方法是 截取parent 的hdc 为背景图片
根本没必要截取呀, TGraphicControl.Paint时Canvas上已经有背景了。如果你愿意, 直接用"一张 黑白两种颜色的图片作为遮罩 图片
、一张前景图片 结合"画在Canvas上就可以了。

另外:
黑白图片(2色)作为mask, 画出来的图也有锯齿的, 除非你的图片里没有斜线。
 
》》“如果你愿意, 直接用"一张 黑白两种颜色的图片作为遮罩 图片、一张前景图片
结合"画在Canvas上就可以了。”
我的方法 必需要 三张图片 才行呀
一张 作为背景、一张 为 蔗罩图片 ,一张为前景
请问两张图片 一张 遮罩 一张前景 怎么做呀 能否告诉我呀
>>黑白图片(2色)作为mask, 画出来的图也有锯齿的, 除非你的图片里没有斜线。
我没有讲明白 我的 mask 图片不是2位的是24位的 边缘有羽化的 可以产生半透明的效果
有斜边也不会有锯齿的
 
我被你搞糊涂了。 一张mask, 一张前景, 还有一张在GraphicControl.Canvas上(就是背景)不是三张吗?
 
哦,好罢。不过太基础的东西可能需要你自己看书解决了。
不论你怎么处理,图象都是存在于内存的是不是,假如,我有了背景和切出来的前景
画面,在静止时,可以简单地将两者叠加,所谓的闪烁是不存在的,对不对。
但是,当画面进行移动时,由于 onPaint 不能没有延时地同步将两者出现或图片比较
大时,就会出现两种闪烁,不同步闪烁和延时闪烁,加上重画的速率没有办法控制,
问题就更严重。怎么解决。
这里耗用资源是肯定的了,但我们可以解决它。
在 Windows 中,我们看到的图形,被叫做 图形用户界面,Microsoft 为解决显示闪烁
的问题,提出了 CompatibleDC 的概念,这个 DC ,可以在显示器上出现,也可以在内
存中出现,只要你调用 CreateCompatibleDC(@dc) 的函数,最著名的例子是桌面属性
选项里的 "移动时显示窗口内容"。工作原理是当应用程序发现显示在桌面上的界面被
移动时,并不重画它,而是重画内存中的另一个界面,画完了,使用一个叫做 BitBlt
的函数,将内存中的界面翻转到桌面上。于是,即便你的机器性能很差,可能看到一
跳一跳的,但整体内容却是完整且不闪烁的。
利用这个原理,我们可以处理你碰到的问题了:
如果画面被移动,我们在内存中不但重新 Mask 前景,拼合前景和背景,我们还在内存
中创建 CompatibleDC ,先将合成的图形画到内存 DC 上,这时它有闪烁也没关系,因
为我们看不见,等到画完了,我们一次性地将内存中的 DC 翻转到桌面上来,然后内存
中根据是否移动继续合成,合成后再翻转到桌面上...如此反复,就解决了你的问题。
 
非常感谢各位给我的回答
可是我还是不能理解各位所说的 问题没有解决
我把代码贴出来:
大家看一下,给我指点一下:
如下
TGraphicControl继承的组件的
paint 事件的代码

forebmp 为前景图片
fmaskbmp 为掩模 图片 是一个 24 位的图片
var
tmpbk,tmpt:tbitmap;//tmpbk为临时存储背景
begin
inherited paint;
canvas.Lock ;
if forebmp.Empty then exit;
tmpbk:=tbitmap.Create ;
tmpbk.Width:=width;
tmpbk.Height:=height;
tmpbk.PixelFormat:=pf24bit;

tmpt:=tbitmap.Create ;
tmpt.Width:=parent.Width ;
tmpt.Height:=parent.Height;
tmpt.Canvas.Handle :=getdc(parent.Handle);//获得parent的hdc
//拷贝tmpt到tmpbk
tmpbk.Canvas.CopyRect(rect(0,0,tmpbk.Width ,tmpbk.height),tmpbk.canvas,boundsrect);
ReleaseDC(parent.Handle ,tmpt.Canvas.Handle );
tmpt.Free ;
if (not fmaskbmp.Empty) then //掩模图片是否为空
copymask(forebmp,fmaskbmp,tmpbk,canvas)//合成前景、背景图片 根据掩模图片
else
canvas.StretchDraw(rect(0,0,width,height),forebmp);
canvas.Unlock ;
end;

问题是
1。当parent.DoubleBuffered:=true;时移动 , 背景没有刷新
如设为False 则 移动时会有闪烁
2。 tmpt.Canvas.Handle :=getdc(parent.Handle);//获得parent的hdc
tmpbk.Canvas.CopyRect(rect(0,0,tmpbk.Width ,tmpbk.height),tmpbk.canvas,boundsrect);
这种方法得到的背景图片 连上面的顶级(像winamp) 窗体也会 抓到
请大家帮助我呀!
 
var
tmpbk:tbitmap;//tmpbk为临时存储背景
// **** tmpt没有用, 去掉
begin
// **** inherited paint; 这句去掉
canvas.Lock ;
if forebmp.Empty then exit;
tmpbk:=tbitmap.Create ;
tmpbk.Width:=width;
tmpbk.Height:=height;
tmpbk.PixelFormat:=pf24bit;
bitblt(tmpbk.canvas.handle, 0, 0, width, height, canvas.handle, 0, 0, SRCCOPY);
{ 所有关于tmpt的操作换成上面一句就够了
tmpt:=tbitmap.Create ;
tmpt.Width:=parent.Width ;
tmpt.Height:=parent.Height;
tmpt.Canvas.Handle :=getdc(parent.Handle);//获得parent的hdc
//拷贝tmpt到tmpbk
tmpbk.Canvas.CopyRect(rect(0,0,tmpbk.Width ,tmpbk.height),tmpbk.canvas,boundsrect);
ReleaseDC(parent.Handle ,tmpt.Canvas.Handle );
tmpt.Free ; }
if (not fmaskbmp.Empty) then //掩模图片是否为空
copymask(forebmp,fmaskbmp,tmpbk,canvas)//合成前景、背景图片 根据掩模图片
else
canvas.StretchDraw(rect(0,0,width,height),forebmp);
canvas.Unlock ;
tmpbk.free; // 漏了这句
end;

一些题外话:
不建议用TBitmap来保存图像处理的中间结果, 因为效率很低。 尽量直接用CreateCompatibleBitmap和CreateCompatibleDC来复制中间结果。
 
谢谢 大家给我的解答
特别是 [:)]Pearl.
问题已经解决
就是速度很慢
分数已经分给大家
 
后退
顶部