在Win32API窗体下实现透明背景

Win32 专栏收录该内容
2 篇文章 0 订阅
    前面拜读过本站无数高手的许多好文章,受益非浅,首先向各位大侠致敬!今天编程偶有小得,不敢独享,特拿出来与各位共享,希望对某些朋友有些许帮助。
  透明窗体的问题相信大家已经很熟悉了,前面的几期在线杂志也有几篇详尽的教程,总结一下就是通过SetWindowRgn这个函数来实现,具体的裁切框用CRgn来生成,比较简单的 象圆,椭圆,圆角窗口等CRgn类都提供了相应的生成方法,我们如果想根据自己的图片来生成裁切框前面的朋友提到的方法是首先生成一个矩形裁切框,然后扫描图片,根据象素点的颜色与掩码颜色的匹配与否,对裁切框进行删减(生成一个新的,然后XOR),对于这种方法我就不详细描述了,有需要的朋友请查阅以前的文章,我首先说一下我遇到的不足之处:
  如果我的窗体支持Resize,那么我调整大小的过程中,要不停的计算裁切框(要逐点扫描象素,并对裁切框进行操作),计算量相当大,特别当窗体比较大的时候更是如此,会造成窗体的闪烁。
  我查阅相关资料得到另一种实现方法,简单实用,那就是利用 SetLayeredWindowAttributes 这个函数,相信许多朋友都见过Microsoft对他的描述但用过的并不多,要用它,要安装最新的SDK,否则会出现没有定义的错误。小弟懒得下载,下面的介绍采用了一般API调用的格式。如果你已经有最新的SDK,那你的程序可以变得更加简练!
首先介绍一下这个函数: 

BOOL SetLayeredWindowAttributes(
    HWND hwnd,     // 应用目标窗口的句柄
    COLORREF crKey, // 掩码的颜色,可以用RGB(r,g,b)来指定
    BYTE bAlpha,     // 掩码颜色部分的Alpha值,0是全透明,255是完全不透明
    DWORD dwFlags     // 透明方式
);  

要说名的是这个函数只在Windows2000及以上版本才支持。MSDN对要求的描述如下 
<Requirements>
Windows NT/2000/XP: Included in Windows 2000 and later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

  还有就是这个函数对于有标题框的窗体支持不好,就是它裁切的只是客户区域,好在我们要制作透明窗体的场合一般用不到标题框下面就说名例程的制作过程。(我旨在说明这种透明窗体的思路及函数的用法,所以代码非常简单,并且没有必要的错误验证机制,希望大家谅解) 
建立一张用于在窗体上绘制的背景图片,把要裁切的部分用一种颜色标记出来,我们叫它MaskColor,我的图片如下:



我的MaskColor = 0xFF00,也就是 RGB(0,255,0). 
建立一个基于对话框的工程,修改对话框资源的属性,主要修改两个地方。一是指定没有TitleBar,二是指定BorderStyle为None.这样才能保证出来的窗体符合你的要求 
把图片加入资源,付ID = IDB_BACKGROUND 
下面就开始写代码了,呵呵,看下面的代码这么长。是不是头有点大呀,别急,这些多半都是工程向导自动生成的,我加的都已经注解上了,并用黄色表示没有几行的。要不然我怎么敢向各位吹嘘这个实现方法简单呢。 
a.首先我们给窗体添加两个成员变量: 
  CBitmap * m_oldBitmap; //指向内存DC原来的 Bitmap
  CDC m_DC;              //用于存放背景图片的内存DC

b.在窗体的OnInitDialog()函数中做一番初始化: 
BOOL CTransWindowDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);         // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标
    ///
    //段会锋添加的代码
    //实现背景图以及窗口透明
    //调用背景图片
    CBitmap bitmap;
    BITMAP bitInfo;
    bitmap.LoadBitmap(IDB_BACKGROUND);
    //得到图片大小并调整窗口大小适应图片
    bitmap.GetBitmap(&bitInfo);
    CRect rect;
    GetWindowRect(&rect);
    rect.right = rect.left + bitInfo.bmWidth;
    rect.bottom = rect.top + bitInfo.bmHeight;
    MoveWindow(rect);
    //创建并保存DC
    m_DC.CreateCompatibleDC(GetDC());
    m_oldBitmap = m_DC.SelectObject(&bitmap);
    //设置窗口掩码颜色和模式
    //首先获得掩码颜色
    COLORREF maskColor = m_DC.GetPixel(0,0);
    
    #define LWA_COLORKEY  0x00000001
    #define WS_EX_LAYERED  0x00080000
    
    typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)(HWND hWnd, 
                    COLORREF crKey, 
                    BYTE bAlpha, 
                    DWORD dwFlags);
    
    lpfnSetLayeredWindowAttributes SetLayeredWindowAttributes;
    
    HMODULE hUser32 = GetModuleHandle("user32.dll");
    SetLayeredWindowAttributes = (lpfnSetLayeredWindowAttributes)GetProcAddress(hUser32,
        "SetLayeredWindowAttributes");

    SetWindowLong(GetSafeHwnd(), 
                  GWL_EXSTYLE, 
                  GetWindowLong(GetSafeHwnd(), 
                  GWL_EXSTYLE) | WS_EX_LAYERED);

    SetLayeredWindowAttributes(GetSafeHwnd(),
                   maskColor, 
                   255, 
                   LWA_COLORKEY);

    FreeLibrary(hUser32);
        
    return TRUE;  // 除非设置了控件的焦点,否则返回 TRUE
}

就像注释的那样,我们首先把图片Load进来,然后把m_DC创建一个与窗口DC兼容的DC,并把刚才Load进来的图片绑定到该内存DC上,并用m_oldBitmap 记录下原有Bitmap,用户最后释放。 
c.向OnPaint中添加代码,用于把背景图片绘制到窗口上: 
void CTransWindowDlg::OnPaint() 
{
  if (IsIconic())
  {
      //这里是MFC的框架代码,为了减少篇幅省略…
  }
  else
  {
      
      //段会锋修改的代码,用于绘制背景图片
      //CDialog::OnPaint();
      CDC * pDC = this->GetDC();
      CRect rect;
      GetWindowRect(&rect);
      pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_DC,0,0,SRCCOPY);
      
  }
}

d.到这里我们要的功能就已经能够实现了,但是好的程序员绝对不应该忘记释放资源,你也一样,一定没有忘记在程序结束时释放资源,呵呵,我们可以写到析构函数中,我们也可放到OnClose()函数中,都一样,我采用了后一种:添加函数并添加释放资源的代码 
void CTransWindowDlg::OnClose()
{
    
    //段会锋添加的代码
    //释放资源
    CBitmap * bitmap = m_DC.SelectObject(m_oldBitmap);
    m_DC.DeleteDC();
    bitmap->DeleteObject();
    
    CDialog::OnClose();
}

e.现在好了,运行一下吧,真爽,就这么几行代码搞定了一个漂亮的窗口。是不是很有成就感?呵呵。又看了几次真的美滋滋的。不好发现问题了,怎么程序运行的时候开始有一下闪烁呢?哦,是清空背景的时候画了一下,没关系,让我们干掉它。添加WM_EraseBkgnd事件的响应函数,把原来的注释掉直接返回True,再运行一下看看吧?怎么样,满意了吗? 
BOOL CTransWindowDlg::OnEraseBkgnd(CDC* pDC)
{
    
    //段会锋编辑的代码
    //防止开始绘制的一下闪烁
    //return CDialog::OnEraseBkgnd(pDC);
    return true;
    
    
}

f.好了,我已经非常满意了,要休息一下了,但我怎么关闭这个窗口呢?糟糕,非要我用Alt+F4不成?算了再多用一下功,写个双击事件好了: 
void CTransWindowDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
  ///
  //段会锋添加的代码,双击窗口关闭Windows
  this->PostMessage(WM_CLOSE);
  ///

  CDialog::OnLButtonDblClk(nFlags, point);
}

  呵呵,本文旨在说明透明窗体的思路及函数用法,抛砖引玉,相信大家一定有好多更好的创意通过这个思路实现,比如,可以添加Resize功能呀,使掩码不完全透明甚至是渐隐呀等等,总之创意无限,等待着大家的发掘!
  本文不完整之处是没有实现拖动,要添加请参阅前面朋友的相关文章,再此对所有把编程经验和心得拿出来与大家共享的朋友致意最崇高的敬意,并号召大家积极向前面的朋友学习!但愿我的努力能够为你提供点点帮助,那我就无比欣慰了,如有任何问题或疑问请 Email: duanoldfive@sohu.com,或者QQ:86685028)






最新评论 [发表评论] [文章投稿]  查看所有评论  推荐给好友  打印 

对话框上的控件如Edit Control属于子窗口
WS_EX_TRANSPARENT不支持
( sheismylife 发表于 2004-11-23 10:40:00)

请问,如果要透明和不透明的内容是动态的,那又应该如何实现,例如,如果我要在一个透明窗体上画图,窗体是透明的,但画的东西不透明。 ( cyvk 发表于 2004-7-5 15:42:00)

你这个程序不能运行呀,,怎么回事啊 ( bapldc 发表于 2004-6-13 21:16:00)

此法可以将对话框上的Edit Box透明吗?我试了不行,不知何故!另:我已安装了最新的SDK,也在VC6的TOOLS-OPTION中添加了INCLUDE、LIBRARY目录,但编译时还是提示未定义? ( xmxjh 发表于 2004-6-13 0:58:00)

在OnPaint里面至少要执行一次BeginPaint和EndPaint,否则窗口会不断地收到WM_PAINT消息,出现死循环 ( duxiuxing 发表于 2004-6-10 10:39:00)

我这里运行只能看到背景,但所有控制都不可见,如winterain所说加上CDialog::OnPaint()后,确实可见控制,但效果很差! ( xander 发表于 2004-6-9 15:05:00)

很好,但是  OnPaint  里的CDialog::OnPaint();不应该被注释掉,不然程序无法正常运行!
  • 1
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

Windows应用程序接口(API)是可视化编程工具功能的扩充和延伸。本书通过大量实例,介绍了如何Visual Basic程序设计中使用 Win32 API函数,内容包括:API函数的声明和参数传送、资源文件、窗口、Windows消息控制、设备环境(DC)、GDI对象、光标、位图与光栅运算、字体与文本、多媒体程序设计、注册表、进程通信等。本书是Visual Basic较为深入的内容,提供了大量的软件开发中十分重要而用Visual Basic无法实现的功能,可供具有Visual Basic程序设计基础和一定实践经验,需要进一步深入了解Visual Basic,进行较高层次软件开发的高级用户使用;也可供 C/C++或 Delphi程序员参考。 第1章 概述 1.1 静态链接与动态链接库 1.1.1 静态链接 1.1.2 动态链接库 1.1.3 动态链接库与API函数 1.2VisualBasicWindows 1.2.1 VisualBasicWindows的基本特性 1.2.2Windows窗口 1.3Win32API简介 1.3.1 窗口管理函数 1.3.2 图形设备接口 1.3.3 系统服务 1.3.4 其他函数 1.4 VisualBasic中使用动态链接库 1.4.1 声明 1.4.2VisualBasic6.0中的API函数声明 1.5 API文本浏览器 1.5.1 API浏览器的使用 1.5.2 把声明.常量或类型拷贝到VisualBasic代码中 1.6 API调用举例 1.6.1 调用API绘图函数 1.6.2 文本输出 1.6.3 环境设置 1.7 句柄 1.7.1 什么是句柄 1.7.2 窗口句柄 1.7.3 设备环境句柄 1.8 如何找到所需要的API2Win32API函数调用 2.1 字符集 2.1.1 Win32API使用的字符集 2.1.2VisualBasic与字符集 2.2 字符串参数的传送 2.2.1 VisualBasic字符串与API字符串 2.2.2 字符串数据的传送 2.2.3 系统平台与字符串传送 2.3 Any类型数据的传送 2.4 数组与自定义类型数据的传送 2.4.1 数组的传送 2.4.2 自定义类型数据的传送 2.5 其他数据的传送 2.5.1 数值数据的传送 2.5.2 变体与对象 2.5.3 指针与属性 2.6 API函数调用总结 2.6.1 数据类型转换 2.6.2 含有API函数的应用程序的调试 第3章 资源文件 3.1 资源文件的建立 3.1.1 资源的定义 3.1.2 编译源资源文件 3.2 与使用资源文件有关的函数 3.2.1 由VisualBasic提供的函数 3.2.2API函数sndPlaySound 3.3 VisualBasic应用程序中使用资源文件 第4章 窗体与窗口 4.1 窗体标题栏的控制 4.1.1 使标题栏闪烁 4.1.2 隐藏/显示标题栏 4.1.3 禁用最大化.最小化和关闭按钮 4.1.4 移动没有标题栏的窗体 4.2 改变窗体形状 4.2.1 圆形或椭圆形窗体 4.2.2 多边形窗体 4.3 浮动窗体透明窗体 4.3.1 浮动窗体 4.3.2 透明窗体 4.4 动态打开和关闭窗口 第5章Windows消息系统 5.1 基本概念 5.1.1 什么是消息 5.1.2 消息的控制 5.2VisualBasic事件与Windows消息 5.2.1 从消息到事件 5.2.2 预定义窗口程序 5.3 回调函数 5.4 增强窗口程序的功能 5.4.1 工作原理 5.4.2 程序举例 5.5 鼠标与键盘类消息 5.5.1 鼠标类消息与键盘类消息 5.5.2 WM_NCHITTEST消息 5.6 消息的截获与处理 5.6.1 截获单个窗口消息 5.6.2 截获多个窗口消息 5.7 常用Windows消息详解 5.8 窗口消息举例 第6章 控件消息 6.1 消息的发送 6.1.1 与发送消息有关的函数 6.1.2 用消息函数发送消息 6.2 编辑控件消息 6.2.1 编辑控件的通知消息 6.2.2 编辑控件消息 6.2.3 程序举例 6.3 列表框消息 6.3.1 列表框消息的分类 6.3.2 列表框消息 6.3.3 列表框消息举例 6.4 组合框消息 6.4.1 组合框消息 6.4.2 组合框消息举例 6.5 按钮控件消息 6.5.1 常用按钮控件消息 6.5.2 程序举例 第7章 设备环境(DC) 7.1 剪裁与坐标转换 7.1.1 剪裁 7.1.2 坐标转换 7.2 使用设备环境 7.2.1 设备环境的属性和分类 7.2.2 VisualBasic中使用设备环境 7.3 设备环境与窗口 7.3.1 设备环境的获取和释
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值