再问关于透明panel 的问题

mdejtod 2009-05-05 03:38:22
RT。。。 上次问了,没解决,再开一贴
重写了 CreateParams事件
procedure CreateParams(var Params: TCreateParams);
begin
params.ExStyle:=params.ExStyle+ws_ex_transparent
end;
拦截了WM_EraseBkgnd 消息,设置了父控件的 control style
是可以实现 panel透明,但是在上面放一个image ,移动image 控件时,背景无法擦除。只有让窗体重画才能刷新,。。有没有什么别的办法可以让它自己刷新,而不用手动刷新窗体
也加了 WM_NCPAINT,WMWindowPosChanging,WMWindowPosChanged 等消息的拦截,在这些事件里重画,在设计期效果不错,移动panel时,可以看到被panel 挡住的其它控件,
但就是无法刷新它自己,找了好多代码,也都是这种情况!!!
另外,rzpanel 可以透明,但是当切换背景图片或隐藏显示panel时,它闪烁很厉害,不知道有哪位能解决!!!
...全文
587 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
边缘998 2009-05-06
  • 打赏
  • 举报
回复
transparent能不能实现?不行的话,用API去画了
mdejtod 2009-05-06
  • 打赏
  • 举报
回复
我要晕了,看不到回复,电脑问题?
JPEXE 2009-05-06
  • 打赏
  • 举报
回复
透明效果会大大降低性能,这是肯定的,窗体缩放时会体现得更明显.
beiguofengguang 2009-05-06
  • 打赏
  • 举报
回复
关注
JPEXE 2009-05-06
  • 打赏
  • 举报
回复
楼主不排斥的话,很多第三方界面组件都有透明Panel,比如SUIPack.你也可以去学学它们的源码.
mdejtod 2009-05-06
  • 打赏
  • 举报
回复
谢谢三国,这段代码是写在哪里的?onpaint 中么?
刚刚没看到回复
mdejtod 2009-05-06
  • 打赏
  • 举报
回复
高人都不愿意出现?莫非此题无解?
散尽一千多分了
sanguomi 2009-05-06
  • 打赏
  • 举报
回复
先来谈谈闪烁产生的原因

原因一:
如果熟悉显卡原理的话,调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕
上只是写到了显存里,而显卡每隔一段时间把显存的内容输出到屏幕上,这就是刷新周期。

一般显卡的刷新周期是 1/80秒左右,具体数字可以自己设置的。

这样问题就来了,一般画图都是先画背景色,然后再把内容画上去,如果这两次操作不在同一个
刷新周期内完成,那么给人的视觉感受就是,先看到只有背景色的图像,然后看到画上内容的图像,
这样就会感觉闪烁了。

解决方法:尽量快的输出图像,使输出在一个刷新周期内完成,如果输出内容很多比较慢,那么采用
内存缓冲的方法,先把要输出的内容在内存准备好,然后一次输出到显存。要知道一次API调用一般可以
在一个刷新周期内完成。

对于GDI,用创建内存DC的方法就可以了

原因二:

复杂的界面有多层窗口组成,当windows在窗口改变大小的时候是先重画父窗口,然后重画子窗口,子父
窗口重画的过程一般无法在一个刷新周期内完成,所以会呈现闪烁。

我们知道父窗口上被子窗口挡住的部分其实没必要重画的

解决方法:给窗口加个风格 WS_CLIPCHILDREN ,这样父窗口上被子窗口挡住的部分就不会重画了。

如果同级窗口之间有重叠,那么需要再加上 WS_CLIPSIBLINGS 风格

原因三:

有时候需要在窗口上使用一些控件,比如IE,当你的窗口改变大小的时候IE会闪烁,即使你有了WS_CLIPCHILDREN
也没用。原因在于窗口的类风格有CS_HREDRAW 或者 CS_VREDRAW,这两个风格表示窗口在宽度或者高度变化的时候
重画,但是这样就会引起IE闪烁

解决方法:注册窗口类的时候不要使用这两个风格,如果窗口需要在改变大小的时候重画,那么可以在WM_SIZE的时候
调用RedrawWindow。

原因四:

界面上窗口很多,而且改变大小时很多窗口都要移动和改变大小,如果使用MoveWindow或者SetWindowPos两个API来
改变窗口的大小和位置,由于他们是等待窗口重画完成后才返回,所以过程很慢,这样视觉效果就可能会闪烁。

解决方法:

使用以下API来处理窗口移动,BeginDeferWindowPos, DeferWindowPos,EndDeferWindowPos
先调用 BeginDeferWindowPos 设定需要移动的窗口的个数
使用DeferWindowPos,来移动窗口,这个API并不真的造成窗口移动
EndDeferWindowPos 一次性完成所有窗口的大小和位置的改变。

有个地方要特别注意,要仔细计算清楚要移动多少个窗口,BeginDeferWindowPos设定
的个数一定要和实际的个数一致,否则在Win9x下,如果实际移动的窗口数多于调用BeginDeferWindowPos
时设定的个数,可能会造成系统崩溃。在Windows NT系列下不会有这样的问题。

这是别人写的,
sanguomi 2009-05-06
  • 打赏
  • 举报
回复


procedure DrawParentBackground(Control: TControl; DC: HDC; R: PRect = nil; bDrawErasebkgnd: Boolean = False);
var
SaveIndex: Integer;
MemDC: HDC;
MemBmp: HBITMAP;
begin
if R <> nil then
begin
MemDC := CreateCompatibleDC(DC);
MemBmp := CreateCompatibleBitmap(DC, Control.Width, Control.Height);
SelectObject(MemDC, MemBmp);
try
with Control.BoundsRect.TopLeft do
SetWindowOrgEx(MemDC, X, Y, nil);
if bDrawErasebkgnd then
Control.Parent.Perform(WM_ERASEBKGND, Integer(MemDC), Integer(MemDC));
Control.Parent.Perform(WM_PAINT, Integer(MemDC), Integer(MemDC));
with Control.BoundsRect.TopLeft do
BitBlt(DC, R^.Left, R^.Top, R^.Right - R^.Left, R^.Bottom - R^.Top, MemDC, X + R^.Left, Y + R^.Top, SRCCOPY);
finally
DeleteObject(MemBmp);
DeleteDC(MemDC);
end;
Exit;
end;
SaveIndex := SaveDC(DC);
try
with Control.BoundsRect.TopLeft do
SetWindowOrgEx(DC, X, Y, nil);
if bDrawErasebkgnd then
Control.Parent.Perform(WM_ERASEBKGND, Integer(DC), Integer(DC));
Control.Parent.Perform(WM_PAINT, Integer(DC), Integer(DC));
finally
RestoreDC(DC, SaveIndex);
end;
end;

画背景时, 取透明
wudiralfzt2008 2009-05-06
  • 打赏
  • 举报
回复
ding
7年 2009-05-06
  • 打赏
  • 举报
回复
不懂帮顶。
sparklerl 2009-05-06
  • 打赏
  • 举报
回复
Mark

up
不得闲 2009-05-06
  • 打赏
  • 举报
回复
可以获得父背景,画到Canvas上来,然后再绘制Canvas
mdejtod 2009-05-06
  • 打赏
  • 举报
回复
采用拷贝目标区域内的画布的方法是可以,不过效果不太好
现在暂时只能用这种方法,至少可以解决闪烁问题,谢谢各位
xzhifei 2009-05-06
  • 打赏
  • 举报
回复
从TWinContrl继承下来的控件,所谓的透明都是将覆盖的区域复制一份,然后画到当前控件上的。
beeone 2009-05-05
  • 打赏
  • 举报
回复
顶下,
mdejtod 2009-05-05
  • 打赏
  • 举报
回复
好的,谢谢三国.....
刷新FORM是可以,不过就算是局部刷新这个PANEL,效果也不好,就是整个PANEL在闪....
sanguomi 2009-05-05
  • 打赏
  • 举报
回复
有很多东西不知道怎么表达.
sanguomi 2009-05-05
  • 打赏
  • 举报
回复
ws_ex_transparent 这个属性一开,会很闪的,具体原因我也不知道, 自己找了很久才发现,后来我从来不用这属性了
我都是在拦截WM_EraseBkgnd消息的时候,用自己的代码设置控制透明 ,现在的界面大部分都不会闪了,只有一俩个还很闪
最近为这个鬼问题搞很久了,

移动image 控件时,背景无法擦除。只有让窗体重画才能刷新
------------------------
你先让panl1透明了,但是你的PANL是从TWINCONTROL继承过来,本来IMAGE重绘时,是会从PANL取背景的,但是你让PANL透明了,IMAGE1当然是取FORM的背景了, 所以要FORM刷新才会有用

我这里另外还有些代码,不知道对楼主有参考没,晚上再贴,在另外个笔记本上,我的主要是子控件重绘的时候
sanguomi 2009-05-05
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 mathsfan 的回复:]
双缓冲开起来呢?
[/Quote]
那东西没点用 
加载更多回复(4)

5,391

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧