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

解决方案 »

  1.   

    关注中,不过我的程序是用 PNG 图片实现透明的
      

  2.   


    使用png少不了用UpdateLayeredWindow函数的
    O(∩_∩)O~,谢谢你的回答
      

  3.   

    SetLayeredWindowAttributes用LWA_ALPHA就可以实现半透明,不知道你说的毛玻璃是什么.
    SetLayeredWindowAttributes和UpdateLayeredWindow不是纯软件的做法,如果你更换显卡,效果很明显.
    我觉得没有理由小看SetLayeredWindowAttributes和UpdateLayeredWindow.自己计算alpha值,用ddraw等画上去并不见的高明,我觉得微软自己也会这些.
      

  4.   

    lz去看看WPF是不是你想要的吧.
      

  5.   

    如果你用过WIN7,或者迅雷7,你就知道了,那两个函数确实很强大的,可是想知道具体原理,而并非用法
      

  6.   

    SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^WS_EX_LAYERED); 
    SetLayeredWindowAttributes(this->m_hWnd,0,128,2); 
      

  7.   

    原理就像你说的,用alpha融合和背景计算,但利用了GPU的计算能力, 对没有GPU的电脑(比如集成显卡)使用纯软件的方法,CPU的loading就会加重.
    如何利用GPU可能你要自己查资料了,可能GPU提供的功能不止alpha融合这么简单,可能还有图层的功能,不了解.
    SetLayeredWindowAttributes没有公开源码,以上仅是猜测.
      

  8.   

    LZ,借地问个问题
    UpdateLayeredWindow 内部如何实现?
    直接用GDI+画透明图片上去就可以透明
      

  9.   

    使用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;
      

  10.   


    不用从最底层融合到最高层吧,第n层就是n层和n-1 层的融合,n-1 是 n-1 和n-2 融合出来的。SetLayeredWindowAttributes 我个人认为就是设置了一个标志量,当第n层的标志位表示
    需要融合时,就与第n-1 层进行像素的融合。
      

  11.   

    学习,我只知道是ALPHA起了作用!导致上层图片可以融合到下面的图片层,就是一个通道的问题!
      

  12.   


    这也是我想知道的哦,其内部是什么原理呢?
    仅仅GDI+画图片是不可能实现的
      

  13.   

    n-1 层是 n-1 和n-2  融合过的。 n 层和 n-1 层融合 就相当于 n 和 n-1 ,n-2 一起融合了也就是说 n 层和 n-1 层融合就足够了
      

  14.   

    VISTA/WIN7的毛玻璃效果可是跟SetLayeredWindowAttributes/UpdateLayeredWindow毫无关系的,它只跟DWM相关,并以桌面主题的方式提供,任何一个具有边框的普通窗口都自动具备毛玻璃效果。一旦DWM激活,整个桌面就是一个全屏的3D窗口,所有应用程序的窗口DC不再是真正的屏幕DC,而是一个3D纹理表面(这一点微软有文章介绍,跟DC相关的API都被重写了,一旦DWM激活,获取的窗口DC被重定向到一个D3D表面,GDI绘制的所有内容都是动态纹理的一部分),整个桌面中的所有窗口就是由这些纹理贴图而成,窗口内容的变化也被捕获以便DWM重新渲染。这种做法的好处是:VISTA下的ALT-TAB进行3D窗口切换效果很容易实现;窗口缩略图的内容能跟原始窗口内容实时同步。这些特性在GDI时代是无法实现的。SetLayeredWindowAttributes/UpdateLayeredWindow跟3D没有关系,是纯软件方式实现的,仅仅是把窗口当作一个有ALPHA通道的图层来处理,它利用窗口的Z序,桌面会正确地把普通窗口和这些图层混合渲染。为了效率,分层窗口被约束成必须是一个静态的图片,或者拥有固定的ALPHA值,桌面渲染这些图层的效率达到了极致,纯软件混合的速度几乎赶上了硬件。但限制也是很强的,跟渲染相关的窗口消息被禁止了,保留的是鼠标、键盘、命中测试等低功耗消息。
      

  15.   

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

  16.   

    既然你这么问了,我就猜猜吧,嘎嘎。隐藏你的当前窗口,GetDC(NULL) 直接获得当前桌面,匹配你窗口的前一位置和大小,获取图像,通过混合的方式,和你的图像进行操作,显示窗口。
      

  17.   

    o(︶︿︶)o 唉 我也不知道了 。  一起见证 NB 答案的到来
      

  18.   

    获取桌面的像素可以很快,但是像素计算和再次生成bits,这样整个过程的时间不容忽视,而且最重要的要实时更新,也许你认为不会慢,你可以试着挪动一个透明的窗体,其CPU使用率会攀升不少,他们使用的方法至少要比我们好吧,你可以想一下这样做出来会如何。0->n层是针对系统来说,而并非一个程序。
      

  19.   

    自己几乎没办法实现。不要在这上面浪费时间了。就连SetLayeredWindowAttributes和UpdateLayeredWindow都有很多问题,比如与正在播放的视频进行混合就没有实现。虽然微软管理显示是分层的,但你拿不到层的信息。你后面覆盖的那一层,不一定是窗口,你也不可能知道它是否改变了外观。
      

  20.   

    如果哪天你有同样的问题看到该贴,或者有什么好方法或者问题,可以联系本人(Q,501219511),或者登陆myccode.com留言,因为结贴时问题并未解决,也许真的很难,等待时间吧...
      

  21.   

    我也正遇到一个需要部分透明的问题, PNG图像是解决不了问题的, 刚开始可能会给你通透的效果, 但是一旦移动窗口, 你会发现原先被"透明"而看到的别的窗口内容, 已变成你的窗口的背景的一部分, 跟着一块移动. 需要自己解决刷新的问题, 但想要获取新位置的背景, 难度相当大, 也可能是无解的. 
    后来我改用穿透色来实现, 虽然显示效果就比PNG差得多, 但是至少可以应付一下.