使用透明/半透明窗口/图片时遇到的一些问题
2013-05-28 01:18
363 查看
最近两周使用透明、半透明窗口比较多,在此之前我写代码都借助封装好了的皮肤库,而现在都是“手写”的——石器时代大冒险,遇到了一些困难,在此做总结。
1、GDI函数对Alpha值的忽视。
GDI函数只有AlphaBlend api可以提供alpha通道的绘制,使用AlphaBlend可以实现32位位图的绘制。因为只有这个api能识别alpha通道,如果在一个MemDC上用DrawText绘制文本,这些文字区域的alpha值都为0,之后再使用AlphaBlend api把MemDC的位图拷贝到实际DC,就会导致文字区域异常,要么是透明了,要么是变成纯白色了。解决办法是:1、在能达到目的的前提下,从MemDC拷贝到实际DC时,不用AlphaBlend混合拷贝,而是使用Bitblt简单拷贝;2、1可能无法达到想要的半透明效果,那么就只能在混合拷贝之前遍历文字区域的每一个像素,把它的alpha值修改为255[可参考http://bbs.csdn.net/topics/360021944];3、最方便的做法是引入GDI+,使用CImage,GDI+的文本绘制带有Alpha属性值。
2、AlphaBlend API和透明度
Alpha通道值。0表示完全透明,255表示完全不透明。
AlphaBlend函数里的BLENDFUNCTION结构体里的SourceConstantAlpha成员,指示的是整个图片的Alpha值。0,表示源图片完全透明,255,表示使用源图片的每个像素自己的Alpha值。
AlphaBlend函数产生的图片让源、目标、SourceConstantAlpha混合。有一套复杂的计算:http://msdn.microsoft.com/en-us/library/windows/desktop/dd183393(v=vs.85).aspx
计算涉及到这么几种情况:
1、没有设置AC_SRC_ALPHA 属性,只有SourceConstantAlpha做混合;
2、设置了AC_SRC_ALPHA 属性,同时把SourceConstantAlpha设置为0xFF,这时候,只使用源图片每个像素的Alpha值做混合;
3、设置了AC_SRC_ALPHA属性,同时把SourceConstantAlpha设置为非0xFF,这时候既使用SourceConstantAlpha的值也使用源图片每个像素的Alpha值做混合。
按照MSDN公式的介绍,当SourceConstantAlpha的值为0的时候,则源DC的图片在目标DC上完全不显示了,源DC的RGB值都丢失了。当SourceConstantAlpha为255时,则使用源DC的图片的Alpha值。
当使用AlphaBlend的时候,只是把数据从一个DC拷贝到另一个DC。所以,如果是要把一个图片贴到目标DC,必须是先把图片选入到MemDC,然后再使用AlphaBlend函数把图片从MemDC拷贝到实际DC。
使用这个API,可以实现图片切换时的平缓过渡效果,上一个图片慢慢的消失,下一个图片慢慢的呈现。
3、AlphaBlend失败的可能原因
参数错误失败原因1: 如果位图的bmBitsPixel为24,那么是无法使用该函数的。
所以对于来源未知的图片,安全的做法是
BITMAP bitmapInfo;
:: GetObject(hBitMap, sizeof( BITMAP), &bitmapInfo);
if (bitmapInfo. bmBitsPixel == 24) //24位的位图就直接使用Bitblt/StretchBlt
{...........}
参数错误失败原因2:可能参数使用错了,源dc的位图跟参数里面指示源位图高度、宽度的值不相符。
绘制效果很奇怪:之前以为使用了AlphaBlend之后就没法使用Bitblt了,实际上是可以的,并不会导致alpha通道丢失。倒是这样子会有问题:通过alphablend往memdc上绘制图片,然后使用DrawText往memdc上绘制文字,最后使用alphablend把memdc的内容拷贝到实际DC,这就会导致文字变成白色的。所以,最后一步不能使用alphablend,必须使用bitblt这类函数。
4、GDI+绘制文本
GDI+的DrawString可以绘制文本,如果用GDI+绘制文本再加上使用WS_EX_LAYER属性,那么GDI+绘制的文本必须使用UpdateLayeredWindow拷贝到目标区域。不能直接在有WS_EX_LAYER属性的窗口上使用GDI+绘制,必须先绘制然后使用UpdateLayeredWindow函数拷贝。
5、使用GDI+
VS2008需要加上头文件:#include <objbase.h>
GDI+初始化:
[align=left]ULONG_PTR m_GdiToken; [/align]
[align=left]GdiplusStartupInput m_GdiInput; [/align]
[align=left]GdiplusStartup(&m_GdiToken ,&m_GdiInput ,NULL );[/align]
[align=left] GDI+销毁[/align]
[align=left]GdiplusShutdown(m_GdiToken );[/align]
6、WS_EX_LAYERED窗口无法显示
只有WS_EX_LAYERED属性,而没有调用SetLayeredWindowAttribute或者UpdateLayeredWindow函数,那将导致窗口无法显示。
7、如何绘制部分透明的窗口
1)切出部分透明的图;
2)创建有WS_EX_LAYERED属性的窗口;
3)把图片选进MemDC,使用AlphaBlend函数把图片混合拷贝到另一个MemDC;
4)由于GDI的DrawText函数会把该区域像素的alpha值清0,导致透明,所以建议使用GDI+的DrawString函数;
5)最后使用UpdateLayeredWindow把MemDC拷贝到实际DC。
8、SetLayeredWindowAttributes和UpdateLayeredWindow的区别
两者在win7以下的版本都要求必须是带有WS_EX_LAYERED属性的顶层窗口(非WS_CHILD属性的窗口),windows 8之后的版本开始支持非顶层窗口。
SetLayeredWindowAttributes函数可以实现:1、对某一个RGB值实现透明;2、可以实现对整个窗口都使用同一个透明度。
UpdateLayeredWindow函数可以实现局部半透明。而且这个函数是GDI+的函数,使用时需要初始化GDI+。
9、 UpdateLayeredWindow不支持局部更新
UpdateLayeredWindow函数包含了SetWindowPos设置窗口位置、大小的功能。这个函数不支持局部更新绘制区域。
10、不能把MAKEINTRESOURCE之后的值赋值给wstring
因为这不是一个string,如果发生赋值,会导致触发WM_PAINT消息(很莫名其妙),导致错误。
1、GDI函数对Alpha值的忽视。
GDI函数只有AlphaBlend api可以提供alpha通道的绘制,使用AlphaBlend可以实现32位位图的绘制。因为只有这个api能识别alpha通道,如果在一个MemDC上用DrawText绘制文本,这些文字区域的alpha值都为0,之后再使用AlphaBlend api把MemDC的位图拷贝到实际DC,就会导致文字区域异常,要么是透明了,要么是变成纯白色了。解决办法是:1、在能达到目的的前提下,从MemDC拷贝到实际DC时,不用AlphaBlend混合拷贝,而是使用Bitblt简单拷贝;2、1可能无法达到想要的半透明效果,那么就只能在混合拷贝之前遍历文字区域的每一个像素,把它的alpha值修改为255[可参考http://bbs.csdn.net/topics/360021944];3、最方便的做法是引入GDI+,使用CImage,GDI+的文本绘制带有Alpha属性值。
2、AlphaBlend API和透明度
Alpha通道值。0表示完全透明,255表示完全不透明。
AlphaBlend函数里的BLENDFUNCTION结构体里的SourceConstantAlpha成员,指示的是整个图片的Alpha值。0,表示源图片完全透明,255,表示使用源图片的每个像素自己的Alpha值。
AlphaBlend函数产生的图片让源、目标、SourceConstantAlpha混合。有一套复杂的计算:http://msdn.microsoft.com/en-us/library/windows/desktop/dd183393(v=vs.85).aspx
计算涉及到这么几种情况:
1、没有设置AC_SRC_ALPHA 属性,只有SourceConstantAlpha做混合;
2、设置了AC_SRC_ALPHA 属性,同时把SourceConstantAlpha设置为0xFF,这时候,只使用源图片每个像素的Alpha值做混合;
3、设置了AC_SRC_ALPHA属性,同时把SourceConstantAlpha设置为非0xFF,这时候既使用SourceConstantAlpha的值也使用源图片每个像素的Alpha值做混合。
按照MSDN公式的介绍,当SourceConstantAlpha的值为0的时候,则源DC的图片在目标DC上完全不显示了,源DC的RGB值都丢失了。当SourceConstantAlpha为255时,则使用源DC的图片的Alpha值。
当使用AlphaBlend的时候,只是把数据从一个DC拷贝到另一个DC。所以,如果是要把一个图片贴到目标DC,必须是先把图片选入到MemDC,然后再使用AlphaBlend函数把图片从MemDC拷贝到实际DC。
使用这个API,可以实现图片切换时的平缓过渡效果,上一个图片慢慢的消失,下一个图片慢慢的呈现。
3、AlphaBlend失败的可能原因
参数错误失败原因1: 如果位图的bmBitsPixel为24,那么是无法使用该函数的。
所以对于来源未知的图片,安全的做法是
BITMAP bitmapInfo;
:: GetObject(hBitMap, sizeof( BITMAP), &bitmapInfo);
if (bitmapInfo. bmBitsPixel == 24) //24位的位图就直接使用Bitblt/StretchBlt
{...........}
参数错误失败原因2:可能参数使用错了,源dc的位图跟参数里面指示源位图高度、宽度的值不相符。
绘制效果很奇怪:之前以为使用了AlphaBlend之后就没法使用Bitblt了,实际上是可以的,并不会导致alpha通道丢失。倒是这样子会有问题:通过alphablend往memdc上绘制图片,然后使用DrawText往memdc上绘制文字,最后使用alphablend把memdc的内容拷贝到实际DC,这就会导致文字变成白色的。所以,最后一步不能使用alphablend,必须使用bitblt这类函数。
4、GDI+绘制文本
GDI+的DrawString可以绘制文本,如果用GDI+绘制文本再加上使用WS_EX_LAYER属性,那么GDI+绘制的文本必须使用UpdateLayeredWindow拷贝到目标区域。不能直接在有WS_EX_LAYER属性的窗口上使用GDI+绘制,必须先绘制然后使用UpdateLayeredWindow函数拷贝。
5、使用GDI+
VS2008需要加上头文件:#include <objbase.h>
GDI+初始化:
[align=left]ULONG_PTR m_GdiToken; [/align]
[align=left]GdiplusStartupInput m_GdiInput; [/align]
[align=left]GdiplusStartup(&m_GdiToken ,&m_GdiInput ,NULL );[/align]
[align=left] GDI+销毁[/align]
[align=left]GdiplusShutdown(m_GdiToken );[/align]
6、WS_EX_LAYERED窗口无法显示
只有WS_EX_LAYERED属性,而没有调用SetLayeredWindowAttribute或者UpdateLayeredWindow函数,那将导致窗口无法显示。
7、如何绘制部分透明的窗口
1)切出部分透明的图;
2)创建有WS_EX_LAYERED属性的窗口;
3)把图片选进MemDC,使用AlphaBlend函数把图片混合拷贝到另一个MemDC;
4)由于GDI的DrawText函数会把该区域像素的alpha值清0,导致透明,所以建议使用GDI+的DrawString函数;
5)最后使用UpdateLayeredWindow把MemDC拷贝到实际DC。
8、SetLayeredWindowAttributes和UpdateLayeredWindow的区别
两者在win7以下的版本都要求必须是带有WS_EX_LAYERED属性的顶层窗口(非WS_CHILD属性的窗口),windows 8之后的版本开始支持非顶层窗口。
SetLayeredWindowAttributes函数可以实现:1、对某一个RGB值实现透明;2、可以实现对整个窗口都使用同一个透明度。
UpdateLayeredWindow函数可以实现局部半透明。而且这个函数是GDI+的函数,使用时需要初始化GDI+。
9、 UpdateLayeredWindow不支持局部更新
UpdateLayeredWindow函数包含了SetWindowPos设置窗口位置、大小的功能。这个函数不支持局部更新绘制区域。
10、不能把MAKEINTRESOURCE之后的值赋值给wstring
因为这不是一个string,如果发生赋值,会导致触发WM_PAINT消息(很莫名其妙),导致错误。
相关文章推荐
- GDI+ 为了阴影和透明,使用双层窗口遇到的一些问题
- GDI+ 为了阴影和透明,使用双层窗口遇到的一些问题
- PyQt使用中遇到的若干问题(1)(版本选择,安装,显示图片,滑动条,窗口一闪而过)
- 问题:部署到iis上后Chart图片不显示;结果:使用webchart过程中遇到的一些问题
- 使用glide框架加载图片遇到的一些问题
- 关于用c生成的dll在使用其他供应商的工具创建可执行模块时遇到的一些问题
- 来谈一下我在使用fo-dicom开源库时遇到的一些问题,这篇主要就是针对从RIS那获取worklist的,希望能帮助那些刚接触这个开源库的。
- GitHub使用elasticsearch遇到的一些问题及解决方法
- Android Studio使用过程中遇到的一些问题及解决方案
- kotlin的一些学习和使用时遇到的问题
- 使用xcode7(或是xcode6)遇到的一些问题
- 学习使用solr时遇到的一些问题,记录
- 重装系统后使用java遇到的一些小问题
- Hibernate | Spring JPA | MySQL 使用过程遇到的一些问题
- pytorch使用过程中遇到的一些问题
- [项目过程中所遇到的各种问题记录]ORM篇——使用NHibernate配置对象实体的一些小问题 22
- MySql使用过程中常常遇到的一些问题
- solr使用过程中遇到的一些问题
- 使用LWUIT中遇到的一些问题
- caffe训练图片分类遇到一些问题