搞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 DCCONST BITMAPINFO *pbmi, // bitmap dataUINT iUsage, // data type indicatorVOID **ppvBits, // bit valuesHANDLE hSection, // handle to file mapping objectDWORD 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,//窗口位置不发生变化可以设置为NULLSIZE *psize,//窗口大小不发生变化可以设置为NULLHDC 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图片。这就涉及到了如何从资源中加载图片的问题。

做了一个Demo,下载地址:地址1

DUILIB异形窗口实现相关推荐

  1. Duilib异形窗口

    源码下载:https://gitee.com/Ailsc/Duilib.git 一步搞定:指定窗口属性layered="true",之后按照正常的UI布局即可. <Windo ...

  2. duilib 子窗口位置_duilib绝对定位与相对定位

    前言 duilib中窗口,布局,控件等在屏幕上的显示位置都是按照配置好的xml文件规则显示的,每个显示元素的位置大小也需要显式指定,才能呈现出更好看的界面效果,显示元素的位置有两种配置规则,即绝对位置 ...

  3. QT窗口:透明与半透明、不规则异形窗口、控件透明与半透明、不规则异形按钮

    目录 1.不规则异形窗口和控件的代码原理 2.主窗口全透明 3.主窗口半透明(以白里透红为例) 4.不规则异形窗口 5.不规则异形按钮 6.使用样式表实现透明与半透明 1.不规则异形窗口和控件的代码原 ...

  4. mfc异形窗口的创建

    在OnInitDialog进行窗体形状的设置 BOOL CTestWindowDlg::OnInitDialog() {CDialog::OnInitDialog();// 设置此对话框的图标.当应用 ...

  5. WPF 制作高性能的透明背景异形窗口(使用 WindowChrome 而不要使用 AllowsTransparency=True)

    在 WPF 中,如果想做一个背景透明的异形窗口,基本上都要设置 WindowStyle="None".AllowsTransparency="True" 这两个 ...

  6. [MFC] WS_EX_LAYERED 实现透明异形窗口(酷狗歌词、360加速球、窗口边缘阴影)

    关键词:WS_EX_LAYERED. UpdateLayeredWindow PC应用不少都有透明的异形窗口  比如以下程序的效果: 酷狗音乐播放器的歌词窗口(窗口除了歌词内容 其他都是透明的) 36 ...

  7. wpf异形按钮_WPF Window异形窗口演示

    我们先通过简单的效果展示,切换展示不同图片: 我们先定义图片资源文件,我们可以在window资源中定义,下面的在app.xaml文件来定义: xmlns="http://schemas.mi ...

  8. duilib 子窗口位置_duilib入门简明教程 -- 界面布局(9)

    上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...

  9. duilib : 模态窗口

    void CMainDlg::DoTask() { CTaskDlg * pDlg = NULL; pDlg = new CTaskDlg(XML_FILE_NAME_TASK_DLG, WND_CL ...

最新文章

  1. 2021全国高校计算机能力挑战赛(初赛)Java试题三
  2. 我国北斗卫星导航系统在轨卫星已达39颗
  3. jquery Ajax 通过jsonp的方式跨域提交表单
  4. 设计模式复习-享元模式
  5. unix中的grep家族
  6. Redis在生产中不得不重视的几个运维问题
  7. mysql 查询某个字段SQL语句【mysql语句】
  8. ASP游戏工作室网站源码v1.0
  9. SpringMvc表单使用
  10. [Python] Python学习笔记之常用模块总结[持续更新...]
  11. java爬取_java实现爬取知乎用户基本信息
  12. QTP 10.0 破解版下载安装超详细教程
  13. html音乐播放器怎么有黑边框,播放不能满屏有黑边怎么办,怎么剪切视频黑边,剪切黑边...
  14. 大学算法分析与设计复习总结
  15. 名帖148 行书《兰亭八柱帖》第六册:于敏中补戏鸿堂刻柳公权书兰亭诗阙笔册
  16. 批量将word转换成excel格式的方法
  17. HTML基础知识(一) 网页简介
  18. 湖南师范大学计算机专业研究生读几年,湖南师范大学计算机专业在职研究生培养方式是怎样的?...
  19. c语言txt文件写入数学,文本文件输入文件.txt中存有一个学生的学号,性别,年龄,数学,语文,英语三门课的成绩....
  20. 有哪些鲜为人知,但是很有意思的网站?

热门文章

  1. 2022T电梯修理考试题模拟考试平台操作
  2. 前端开发:Vue项目报错Unknown custom element:XXX - did you register the component correctly…的解决方法丨蓄力计划
  3. 平摊分析(后续持续更新)
  4. 飞书开放平台-查询已读消息示例
  5. 锐志51开发板原理图1,实物图,LED,蜂鸣器(定时器),按键(按键中断)
  6. [02-14] 绿色免费软件更新
  7. jquery竖向走马灯_根本不用插件,实现jQuery横/纵向走马灯
  8. 关于THC/THC.h: No such file or directory解决办法
  9. php 易宝支付,【图片】易宝支付PHP版测试、懂的进【php吧】_百度贴吧
  10. 激光钢网正确保养方法-清洗