vc怎么实现窗体透明呢?

菜鸟二号 2010-11-22 01:51:42
想大家都见过那种透明的窗体,例如:QQ的透明设置,千千静听的透明,....高级的如:win7的透明窗体...。
也许我们最先联想到的函数有SetLayeredWindowAttributes和UpdateLayeredWindow
先不说这两个函数的限制有多大,就拿毛玻璃透明来说,我想用这两个函数就很难实现了。
因此,不能纠结在这两个函数上,而是要了解其内部原理。可是其原理是什么呢?我就不得而知了...
我曾想过,透明的话,要获取背景然后和窗体进行透明融合计算,不过这种即使能勉强做好,估计也很占cpu,而且要时时更新(不知道背景是否变,所以要实时的重新计算),这显然不可取...
因此,我想知道的是,这个透明是怎么实现的呢?换言之,窗体应该只是一个矩形,而呈现在桌面这个更大的矩形里(我的想法),只是存在图层的差异,那是否是要像素从最底层的图层一直计算到最高的图层,最终在显示出来,如果是要怎么做呢?
由于对windows窗体理解不深,如果发现有言误之处还望指出,谢谢大家

还是总结一下吧,怎么不用上述的两个函数来实现窗体透明呢?如果大牛你知道,还望告知小虾,谢谢~\(≧▽≦)/~啦啦啦,再同时,分不是问题,问题如题
...全文
1136 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq5069099 2012-08-10
  • 打赏
  • 举报
回复
这个我知道,可以加我QQ
hiho_honey 2012-08-10
  • 打赏
  • 举报
回复
我也正遇到一个需要部分透明的问题, PNG图像是解决不了问题的, 刚开始可能会给你通透的效果, 但是一旦移动窗口, 你会发现原先被"透明"而看到的别的窗口内容, 已变成你的窗口的背景的一部分, 跟着一块移动. 需要自己解决刷新的问题, 但想要获取新位置的背景, 难度相当大, 也可能是无解的.
后来我改用穿透色来实现, 虽然显示效果就比PNG差得多, 但是至少可以应付一下.
菜鸟二号 2010-11-25
  • 打赏
  • 举报
回复
如果哪天你有同样的问题看到该贴,或者有什么好方法或者问题,可以联系本人(Q,501219511),或者登陆myccode.com留言,因为结贴时问题并未解决,也许真的很难,等待时间吧...
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 a316586261 的回复:]
LZ,借地问个问题
UpdateLayeredWindow 内部如何实现?
直接用GDI+画透明图片上去就可以透明
[/Quote]

这也是我想知道的哦,其内部是什么原理呢?
仅仅GDI+画图片是不可能实现的
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
谢谢13楼详细的回答,不过那些我都知道,我想了解的是其大概的原理,不过你的回答还是相当有用的
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 wangbo56916860 的回复:]
引用楼主 hkf314 的回复:
那是否是要像素从最底层的图层一直计算到最高的图层,最终在显示出来


不用从最底层融合到最高层吧,第n层就是n层和n-1 层的融合,n-1 是 n-1 和n-2 融合出来的。

SetLayeredWindowAttributes 我个人认为就是设置了一个标志量,当第n层的标志位表示
需要融合时,就与第n-1 层进行像素的融合。
[/Quote]

如果透明窗口下还一个或多个透明窗体呢?
至善者善之敌 2010-11-23
  • 打赏
  • 举报
回复
学习,我只知道是ALPHA起了作用!导致上层图片可以融合到下面的图片层,就是一个通道的问题!
wangbo56916860 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用楼主 hkf314 的回复:]
那是否是要像素从最底层的图层一直计算到最高的图层,最终在显示出来
[/Quote]

不用从最底层融合到最高层吧,第n层就是n层和n-1 层的融合,n-1 是 n-1 和n-2 融合出来的。

SetLayeredWindowAttributes 我个人认为就是设置了一个标志量,当第n层的标志位表示
需要融合时,就与第n-1 层进行像素的融合。
jtll521 2010-11-23
  • 打赏
  • 举报
回复
使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。


  SetLayeredWindowAttributes的函数原型如下:

BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window
COLORREF crKey, // specifies the color key
BYTE bAlpha, // value for the blend function
DWORD dwFlags // action
);


Windows NT/2000/XP: Included in Windows 2000 and later.
Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的)
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.


  一些常量:


WS_EX_LAYERED = 0x80000;
LWA_ALPHA = 0x2;
LWA_COLORKEY=0x1;

  其中dwFlags有LWA_ALPHA和LWA_COLORKEY

  LWA_ALPHA被设置的话,通过bAlpha决定透明度.

  LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示.

  要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000).

  例子代码:

  在OnInitDialog()加入:

//加入WS_EX_LAYERED扩展属性
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
 typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
 MYFUNC fun = NULL;
 //取得SetLayeredWindowAttributes函数指针
 fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
 if(fun)fun(this->GetSafeHwnd(),0,128,2);
 FreeLibrary(hInst);
}

  稍加修改还可以作出淡出淡入的效果. 注意第三个参数(128)不要取得太小了,为0的话就完全透明,看不到了。

  如何使框架窗口的图标为动画显示

  可以用TIMER,但是TIMER不能有效的定时。因为TIMER发送的是窗口消息,当窗口忙于处理键盘、鼠标等消息时就不能及时处理TIMER,会使间隔时间变得很长 。

  可以考虑用一个单独得TIMER线程,用Sleep()定时来解决此问题。


UINT Timer(LPVOID param)
{
 HWND hWnd=(HWND)param;
 while(1)
 {
  Sleep(ms);
  PostMessage(hWnd,CH_PICTURE,NULL,NULL)
 }
}

  Sleep(ms)后发送自定义消息。消息处理函数就选择某一个ICON或BITMAP来显示。如 :


MyBotton.SetBitmap((HBITMAP)Bitmap[i]);

  Bitmap是一个位图数组,存放有j个位图。消息处理函数运行一次,i就累加一次,当i==j时,i就回到0;
a316586261 2010-11-23
  • 打赏
  • 举报
回复
LZ,借地问个问题
UpdateLayeredWindow 内部如何实现?
直接用GDI+画透明图片上去就可以透明
手机写程序 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hkf314 的回复:]
引用 5 楼 eyey1 的回复:

SetLayeredWindowAttributes用LWA_ALPHA就可以实现半透明,不知道你说的毛玻璃是什么.
SetLayeredWindowAttributes和UpdateLayeredWindow不是纯软件的做法,如果你更换显卡,效果很明显.
我觉得没有理由小看SetLayeredWindowAttributes和UpdateLayere……
[/Quote]
原理就像你说的,用alpha融合和背景计算,但利用了GPU的计算能力, 对没有GPU的电脑(比如集成显卡)使用纯软件的方法,CPU的loading就会加重.
如何利用GPU可能你要自己查资料了,可能GPU提供的功能不止alpha融合这么简单,可能还有图层的功能,不了解.
SetLayeredWindowAttributes没有公开源码,以上仅是猜测.
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 psbeond 的回复:]
自己几乎没办法实现。不要在这上面浪费时间了。就连SetLayeredWindowAttributes和UpdateLayeredWindow都有很多问题,比如与正在播放的视频进行混合就没有实现。虽然微软管理显示是分层的,但你拿不到层的信息。你后面覆盖的那一层,不一定是窗口,你也不可能知道它是否改变了外观。
[/Quote]
谢谢你的忠告哦,不过不试永远都不知道哦,失败也没事哦,当学习了,O(∩_∩)O~
psbeond 2010-11-23
  • 打赏
  • 举报
回复
自己几乎没办法实现。不要在这上面浪费时间了。就连SetLayeredWindowAttributes和UpdateLayeredWindow都有很多问题,比如与正在播放的视频进行混合就没有实现。虽然微软管理显示是分层的,但你拿不到层的信息。你后面覆盖的那一层,不一定是窗口,你也不可能知道它是否改变了外观。
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 wangbo56916860 的回复:]
只是两个位图的操作你认为时间会是多少呢? 不是你的 从 0 层 到 n 层。
[/Quote]
获取桌面的像素可以很快,但是像素计算和再次生成bits,这样整个过程的时间不容忽视,而且最重要的要实时更新,也许你认为不会慢,你可以试着挪动一个透明的窗体,其CPU使用率会攀升不少,他们使用的方法至少要比我们好吧,你可以想一下这样做出来会如何。0->n层是针对系统来说,而并非一个程序。
wangbo56916860 2010-11-23
  • 打赏
  • 举报
回复
o(︶︿︶)o 唉 我也不知道了 。 一起见证 NB 答案的到来
wangbo56916860 2010-11-23
  • 打赏
  • 举报
回复
只是两个位图的操作你认为时间会是多少呢? 不是你的 从 0 层 到 n 层。
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 wangbo56916860 的回复:]
引用 24 楼 hkf314 的回复:

引用 23 楼 wangbo56916860 的回复:
如果你自己想做融合的话,你只需要完成你自己的第n层和n-1层的融合就足够了吧。如果n-1层以下你都要自己做? 有几个问题。第一,你如何获得每一层,如何知道那个窗口在第几层? 第二,你如何保证在你融合之后,第x层刷新了,但是你取到的是旧图像,你融合到最后的图像是和操作系统不同步的啊?第三就是效率问……
[/Quote]

这个我已经说过了,你觉得可行性呢?如果背景有某个窗口刷新?总之吧,单靠这个是不妥的,有方法如DX的显存操作,我会试的,总之要搞定它,谢谢大家的回答,完成了就结贴给分
wangbo56916860 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 hkf314 的回复:]

引用 23 楼 wangbo56916860 的回复:
如果你自己想做融合的话,你只需要完成你自己的第n层和n-1层的融合就足够了吧。如果n-1层以下你都要自己做? 有几个问题。第一,你如何获得每一层,如何知道那个窗口在第几层? 第二,你如何保证在你融合之后,第x层刷新了,但是你取到的是旧图像,你融合到最后的图像是和操作系统不同步的啊?第三就是效率问题了,你怎么解决啊.

这就是我要问的了……
[/Quote]
既然你这么问了,我就猜猜吧,嘎嘎。隐藏你的当前窗口,GetDC(NULL) 直接获得当前桌面,匹配你窗口的前一位置和大小,获取图像,通过混合的方式,和你的图像进行操作,显示窗口。
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 jameshooo 的回复:]
VISTA/WIN7的毛玻璃效果可是跟SetLayeredWindowAttributes/UpdateLayeredWindow毫无关系的,它只跟DWM相关,并以桌面主题的方式提供,任何一个具有边框的普通窗口都自动具备毛玻璃效果。

一旦DWM激活,整个桌面就是一个全屏的3D窗口,所有应用程序的窗口DC不再是真正的屏幕DC,而是一个3D纹理表面(这一点微软有文章介绍,跟DC相关的API都被重……
[/Quote]

谢谢你的回答,这个也许就是实现的方法
菜鸟二号 2010-11-23
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 wangbo56916860 的回复:]
如果你自己想做融合的话,你只需要完成你自己的第n层和n-1层的融合就足够了吧。如果n-1层以下你都要自己做? 有几个问题。第一,你如何获得每一层,如何知道那个窗口在第几层? 第二,你如何保证在你融合之后,第x层刷新了,但是你取到的是旧图像,你融合到最后的图像是和操作系统不同步的啊?第三就是效率问题了,你怎么解决啊.
[/Quote]
这就是我要问的了,呵呵,就是怎么获得呢?
加载更多回复(12)

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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