`
devgis
  • 浏览: 138073 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

使用分层窗口及透明png图片实现一个异形窗口

 
阅读更多

搞Windows程序的人尽皆知分层窗口能够实现很多不错的效果,之前看过一些异形窗口的实现,所以就手痒也想自己搞一个玩一玩。自己动手实现过程才发现还是有不少问题的。

基本思路是:
1.将窗口扩展属性设置为分层属性WS_EX_LAYERED。
2.选一张透明的png图片,并将其加载进来。
3.创建与窗口兼容的内存设备上下文,以及兼容位图,将兼容位图选入兼容设备上下文。
4.将png图片绘制到内存设备上下文中。
5.设置BLENDFUNCTION结构,调用UpdateLayeredWindow。


第一步设置窗口的分层属性比较简单:

windowStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
windowStyle = windowStyle | WS_EX_LAYERED;
SetWindowLong(hWnd, GWL_EXSTYLE, windowStyle);


第二步是将png图片加载到程序中,ATL的CImage和GDI+的Image这两个类比较常用。使用CImage直接通过Load方法加载绝对路径图片或者内存中的图片,我这里就是使用CImage类实现。代码:

//CImage类方式加载图片
CImage img;
img.Load(TEXT("绝对路径png图片")); //将图片与类关联起来

然后是使用Image类方式:

//Image类方式加载图片
Image* pImage = Image::FromFile(_T("绝对路径png图片"));


第三步比较繁琐点。加载了图片后就需要创建一个位图句柄HBITMAP,创建位图句柄有两种方式:CreateCompatibleBitmap和CreateDIBSection这两个函数。先介绍下这两个函数。

HBITMAP CreateCompatibleBitmap( HDC hdc, // handle to DC
int nWidth, // width of bitmap, in pixels
int nHeight // height of bitmap, in pixels);
复制代码
HBITMAP CreateDIBSection( HDC hdc, // handle to DC
    CONST BITMAPINFO *pbmi, // bitmap data
    UINT iUsage, // data type indicator
    VOID **ppvBits, // bit values
    HANDLE hSection, // handle to file mapping object
    DWORD dwOffset // offset to bitmap bit values
);
复制代码

首先看看CreateCompatibleBitmap函数的代码:

//CreateCompatibleBitmap函数创建
        hdc = GetDC(hWnd); //hWnd为需要分层窗口的句柄
        hdcMem = CreateCompatibleDC(hdc); //创建与hdc相兼容的内存句柄
        hBitmap = CreateCompatibleBitmap(hdc, sz.cx, sz.cy); //创建与hdc相兼容的位图句柄
        SelectObject(hdcMem,(HGDIOBJ)hBitmap); //将位图选入内存句柄作为画板   

然后是使用CreateDIBSection函数的代码:

复制代码
//CreateDIBSection函数创建
        hdc = GetDC(hWnd);
        hdcMem = CreateCompatibleDC(hdc);

        BITMAPINFO bitmapinfo;
        bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bitmapinfo.bmiHeader.biBitCount = 32;
        bitmapinfo.bmiHeader.biHeight = sz.cy;
        bitmapinfo.bmiHeader.biWidth = sz.cx;
        bitmapinfo.bmiHeader.biPlanes = 1;
        bitmapinfo.bmiHeader.biCompression=BI_RGB;
        bitmapinfo.bmiHeader.biXPelsPerMeter=0;
        bitmapinfo.bmiHeader.biYPelsPerMeter=0;
        bitmapinfo.bmiHeader.biClrUsed=0;
        bitmapinfo.bmiHeader.biClrImportant=0;
        bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biBitCount / 8;

        hBitmap = ::CreateDIBSection(hdcMem,&bitmapinfo, 0,NULL, 0, 0);
        SelectObject(hdcMem,(HGDIOBJ)hBitmap);    
复制代码


第四步,将png图片绘制到内存设备上下文中。这一步根据前面加载图片的两种方式对应不同的绘制函数。

CImage类方式代码:

//CImage类方式代码
//将img关联的png图片绘制到内存句柄中
img.Draw(hdcMem, 0, 0, sz.cx, sz.cy, 0, 0, sz.cx, sz.cy);
//hdcMem为内存兼容句柄,之后四个参数表明了在内存兼容句柄中绘制的位置,最后四个参数表示了img关联的png图片的位置

然后是Image类方式处理代码:

//Image类方式代码
Graphics g(hMemDC);
g.DrawImage( pImage, 0, 0);


第五步:设置BLENDFUNCTION结构,调用UpdateLayeredWindow。

设置BLENDFUNCTION结构代码如下:

BLENDFUNCTION  bf;
bf.AlphaFormat = AC_SRC_ALPHA;//源位图具有Alpha通道
bf.BlendFlags = 0;//必须为0
bf.BlendOp = AC_SRC_OVER;//
bf.SourceConstantAlpha = 255;//设置透明度

然后就是调用UpdateLayeredWindow函数了

UpdateLayeredWindow(hWnd, hdc, NULL, &sz, hdcMem, &pt, NULL, &bf, ULW_ALPHA);

看看MSDN对UpdateLayeredWindow函数的介绍:

复制代码
BOOL UpdateLayeredWindow(
    HWND hwnd,//需要分层的窗口句柄
    HDC hdcDst, //需要分层窗口设备句柄
    POINT *pptDst,//窗口位置不发生变化可以设置为NULL
    SIZE *psize,//窗口大小不发生变化可以设置为NULL
    HDC hdcSrc,//绘制源的设备句柄
    POINT *pptSrc,//
    COLORREF crKey,//指定一个透明色,使用ULW_COLORKEY标志时有效,也就是说crKey为白色时候,那么位图上所有白色的地方均为透明,其他地方不透明
    BLENDFUNCTION *pblend,//之前介绍过了
    DWORD dwFlags//ULW_ALPHA使用Alpha通道,ULW_COLORKEY使用crKey作为透明色,ULW_OPAQUE不透明
);
复制代码

这样异形窗口就算完成了。


整理以下代码如下:

复制代码
LONG windowStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
windowStyle = windowStyle | WS_EX_LAYERED;
SetWindowLong(hWnd, GWL_EXSTYLE, windowStyle);

CImage img;
img.Load(TEXT("png图片"));

SIZE sz;//图片大小
sz.cx = img.GetWidth();
sz.cy = img.GetHeight();

SetWindowPos(hWnd, NULL, 0, 0, sz.cx, sz.cy, SWP_NOREDRAW);//将窗口大小设置为图片大小使之相互合适

HDC hdc = GetDC(hWnd);//获取窗口设备句柄
HDC hdcMem = CreateCompatibleDC(hdc);//创建一个与hdc相兼容的内存设备句柄
HBITMAP    hBitmap = CreateCompatibleBitmap(hdc, sz.cx, sz.cy);
SelectObject(hdcMem,(HGDIOBJ)hBitmap);
img.Draw(hdcMem, 0, 0, sz.cx, sz.cy, 0, 0, sz.cx, sz.cy);

POINT pt;
pt.x = 0;
pt.y = 0;

BLENDFUNCTION  bf;
bf.AlphaFormat = AC_SRC_ALPHA;
bf.BlendFlags = 0;
bf.BlendOp = AC_SRC_OVER;
bf.SourceConstantAlpha = 255;

UpdateLayeredWindow(hWnd, hdc, NULL, &sz, hdcMem, &pt, NULL, &bf, ULW_ALPHA);
ReleaseDC(hWnd, hdc);
复制代码


说说遇到的问题,最开始就碰到了一个问题发现png图片没有办法产生异形的效果,然后才发现原来我使用的png图片不是透明png图片。

当png透明图片问题解决后,发现窗口出现后,本来那个应该是透明的地方却是白色不透明的了。这个问题网上也是有介绍的,我在这里得到了答案。下面我把原因重新贴一下:

PNG图片的透明背景总是一片白色,后来才发现这其实是微软GDI+的设计问题,PNG图片是ARGB,使用GDI+载入图片的时候,GDI+会默认已经进行了预剩运算(PARGB),即每象素的实际值是已经和ALPHA值按比例相乘的结果,实际上它根本就没有做预乘,在使用透明图片的象素ALPHA通道的时候,CImage内部正是调用的AlphaBlend,没有预乘的图当作预乘的图片处理的结果就是这相当于一张和纯白背景进行了预剩,所以图象总是出现白色背景。

下面给出解决这个问题的代码,代码来源这里,处理还是比较简单的:

复制代码
if (pImage->GetBPP() == 32) //确认该图像包含Alpha通道
   {
       for (inti=0; i<pImage->GetWidth();i++)
       {
            for(int j=0; j<pImage->GetHeight(); j++)
            {
                byte*pByte = (byte*)pImage->GetPixelAddress(i, j);
                pByte[0]= pByte[0] * pByte[3]/ 255;
                pByte[1]= pByte[1] * pByte[3]/ 255;
                pByte[2]= pByte[2] * pByte[3]/ 255;
            }
       }
   }
复制代码

这样异形窗口也算是完成了,但是这样生成的exe文件需要依赖外部的png图片,所以我应该把那张png图片放到资源文件中,然后直接生成的exe就包含了那张png图片。这就涉及到了如何从资源中加载图片的问题。

分享到:
评论

相关推荐

    PNG分层窗口.rar

    2. 图层管理:创建多个窗口或控件,每个对应一个PNG图层,通过调整窗口的Z轴顺序实现前后层次。 3. 透明度处理:设置窗口或控件的透明度属性,使其能够显示PNG的透明效果。 4. 事件响应:处理用户的交互事件,如点击...

    透明异形窗口实现总结

    综上所述,透明异形窗口的实现涉及多个层次和技术,包括设置窗口风格、使用图形库绘制形状、利用分层窗口特性和DWM服务。通过深入理解这些技术并熟练运用,开发者可以创造出独特且富有吸引力的用户界面,提升软件的...

    VC利用GDI+采用分层窗体实现PNG透明窗体

    本主题将深入探讨如何使用Visual C++ (VC++) 和GDI+库来实现一个基于分层窗体(Layered Window)的PNG透明窗体。这在需要在视频或其他背景上显示具有自定义透明度的窗口时非常有用,例如制作桌面小工具或软件界面。 ...

    e语言-易语言PNG分层窗口

    在这个易语言PNG分层窗口源码例程中,开发者结合了易语言的编程语法和GdiPlus类,利用GdiPlus对PNG图像的支持,实现了窗口的背景为PNG图片,并且具备分层透明的效果。PNG格式的图像支持透明度,这使得窗口背景可以有...

    易语言源码易语言PNG分层窗口源码.rar

    "易语言PNG分层窗口源码"是一个关于易语言的项目,主要涉及到如何在易语言中处理PNG图像并实现分层窗口的功能。下面将详细阐述这一知识点。 PNG(Portable Network Graphics)是一种无损压缩的位图格式,支持透明度...

    VC++界面编程之--使用分层窗口实现界面皮肤

    使用分层界面来实现界面皮肤的好处是:可以保证图片边缘处理不失真,且能用于异形窗口上,如一些不规则的窗口,你很难用SetWindowRgn来达到理想效果。 在很多情况下,界面的漂亮与否,取决于PS的制作及创意,而界面...

    易语言调用API函数实现分层透明窗口

    实践是最好的老师,尝试自己动手实现一个简单的透明窗口程序,将帮助你更好地理解和掌握这一技术。 最后,不要忘记在代码中添加注释,以便于自己和其他人理解代码的功能和逻辑。这不仅有助于提高代码的可读性,也...

    易语言PNG分层窗口

    易语言PNG分层窗口源码,PNG分层窗口,SetAlpha,GetGraphics,GetBitmap,GetMDC,Init,Update,destroy,Paint,PtInRcf,WndProc,MouseMove,MouseUp,MouseDown,图形_九宫绘图,GetWindowRect,GetDC,CreateCompatibleDC,...

    易语言PNG分层窗口源码

    易语言PNG分层窗口源码例程程序结合易语言GdiPlus类.ec模块,调用API函数实现分层透明窗口。 点评:易语言PNG分层窗口源码是易语言支持PNG应用例程。 @易语言难学吗。

    桌面时钟 (基于分层窗口,Layered window)

    标题中的“桌面时钟(基于分层窗口,Layered window)”是指一个应用程序,它使用Windows操作系统中的分层窗口技术来创建一个具有特殊效果的桌面时钟,如半透明或透明背景。这种技术允许开发者创建出更加吸引人的...

    基于分层窗口创建的GIF图片显示

    在IT领域,创建一个能够显示透明动态GIF图片的工具是一项常见的需求,尤其在桌面应用或者个性化软件中。"基于分层窗口创建的GIF图片显示"这一技术就是解决此类问题的一种方法。在这个主题中,我们将深入探讨如何利用...

    GDI+分层窗口

    ### GDI+分层窗口在VS2010下的...综上所述,利用GDI+和VS2010可以实现较为复杂的分层窗口功能,如加载PNG图片并将其绘制到窗口上,以及动态调整窗口的透明度等。这对于开发具有良好用户体验的应用程序来说非常有用。

    delphi 实现多个浮动透明窗口

    例如,可以使用 GDI+ 或者 VCL 的图形组件来绘制图标,或者通过调整窗口透明度和位置来实现淡入淡出效果。 7. **代码示例**: 在 Delphi 代码中,创建透明窗口的示例可能如下: ```delphi type TMyFloatingForm ...

    delphi PNG透明窗体 控件不透明

    在Delphi编程中,创建一个PNG透明窗体并让其上的控件保持不透明是一项具有挑战性的任务。PNG格式支持半透明(阿尔法通道),这使得背景可以透过控件显示出来,但默认情况下,Delphi的VCL框架并不直接支持这种效果。...

    桌面钟表 (layered window 分层窗口)

    1. **创建分层窗口**:使用`CreateWindowEx`函数,设置WS_EX_LAYERED样式,创建一个分层窗口。这个窗口可以被设置为不接受鼠标或键盘输入,以便它仅仅作为一个显示元素。 2. **设置透明度**:通过`...

    Duilib实现异形窗口

    异形窗口的实现 基本思路是: 1.将窗口扩展属性设置为分层属性WS_EX_LAYERED。 2.选一张透明的png图片,并将其加载进来。 3.创建与窗口兼容的内存设备上下文,以及兼容位图,将兼容位图选入兼容设备上下文。 4.将png...

    visual c++创建分层窗口.zip

    分层窗口(Layered Windows)是一种特殊的窗口类型,它允许窗口部分透明或者拥有自定义的Alpha通道,从而实现更加精致的视觉效果。下面我们将深入探讨如何在VC++中利用这些技术。 首先,让我们了解一些关键的文件在...

    易语言-易语言PNG分层窗口

    总结来说,易语言PNG分层窗口源码是一个演示如何在易语言中创建具有PNG背景和分层透明效果的窗口的示例程序。它结合了易语言的GdiPlus类和EC模块,以及Windows API函数,展示了易语言在图形图像处理上的强大能力。...

    HTMLayout分层窗口.rar

    4. 窗口透明度和可见性控制:学习如何改变窗口的透明度和显示状态,实现窗口的动态效果。 5. 源码结构解析:分析源码的模块化设计,理解类和函数的作用,以便于复用和扩展。 六、实战应用 除了理论学习,实际动手...

Global site tag (gtag.js) - Google Analytics