找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 679|回复: 3

Windows界面编程第四篇 异形窗体 高富帅版

[复制链接]

52

主题

62

回帖

0

积分

版主

积分
0
发表于 2013-10-6 23:09:10 | 显示全部楼层 |阅读模式
上一篇《Windows界面编程第三篇 异形窗体 普通版》介绍了异形窗口(异形窗体)的创建,其主要步骤为??先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。并且为了使异形窗口支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理。
然后在下图中有非常相似的两个异形窗体,只不过,左边的异形窗体小,右边的异形窗体大。这个可以怎么实现了?


[attachment=1116]






先通过其它软件来缩放位图,然后再让程序加载这种方式来指定异形窗口的大小。这种方法虽然可以完成任务,但毕竟太OUT了。
由《Windows界面编程第一篇位图背景与位图画刷》可以想到不用位图画刷,而直接在窗口背景绘制时使用StretchBlt来缩放位图至窗口大小,这样就可以达到指定窗口大小的功能。
由于异形窗口运行后无法通过鼠标来动态调整窗口大小,因此可以窗口初始化时就可以先缩放位图并加载到一个缓冲HDC中,然后再在窗口背景绘制时使用BitBlt来贴图。这种做法只需要缩放位图一次,在每次背景绘制时只须拷贝位图,对程序的效率会有提高。
  1. //   异形窗口2  在WM_ERASEBKGND消息中自贴图
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)
  3. #include <windows.h>
  4. const char szAppName[] = "异形窗口2 MoreWindows-(http://blog.csdn.net/MoreWindows)";
  5. /*
  6. * 函数名称: GetWindowSize
  7. * 函数功能: 得到窗口的宽高
  8. * hwnd      窗口句柄
  9. * pnWidth   窗口宽
  10. * pnHeight  窗口高
  11. */
  12. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);
  13. /*
  14. * 函数名称: InitBitmapWindow
  15. * 函数功能: 位图窗口初始化
  16. * hinstance 进程实例
  17. * nWidth    窗口宽
  18. * nHeight   窗口高
  19. * nCmdshow  显示方式-与ShowWindow函数的第二个参数相同
  20. */
  21. BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow);
  22. // 位图窗口消息处理函数
  23. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm);
  24.          
  25. HBITMAP  g_hBitmap;
  26. int APIENTRY WinMain(HINSTANCE hInstance,
  27.                      HINSTANCE hPrevInstance,
  28.                      LPSTR     lpCmdLine,
  29.                      int       nCmdShow)
  30. {
  31.     //先创建一个无背影画刷窗口,
  32.     //然后在WM_CREATE中并指定透明颜色, 缩放位图后加载至s_hdcMem中.
  33.     //最后在WM_ERASEBKGND中用s_hdcMem贴图即可
  34.     g_hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  35.     if (g_hBitmap == NULL)
  36.     {
  37.         MessageBox(NULL, "位图加载失败", "Error", MB_ICONERROR);
  38.         return 0;
  39.     }
  40.     // 设置异形窗口大小
  41.     BITMAP bm;
  42.     GetObject(g_hBitmap, sizeof(bm), &bm);
  43.     int nWindowWidth = bm.bmWidth;
  44.     int nWindowHeight = bm.bmHeight + 100; //拉高100高度
  45.     if (!InitBitmapWindow(hInstance, nWindowWidth, nWindowHeight, nCmdShow))
  46.         return 0;
  47.     MSG msg;
  48.     while (GetMessage(&msg, NULL, 0, 0))
  49.     {
  50.         TranslateMessage(&msg);
  51.         DispatchMessage(&msg);
  52.     }
  53.     DeleteObject(g_hBitmap);
  54.     return msg.wParam;
  55. }
  56. BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow)
  57. {
  58.     HWND hwnd;
  59.     WNDCLASS wndclass;
  60.    
  61.     wndclass.style       = CS_VREDRAW | CS_HREDRAW;
  62.     wndclass.lpfnWndProc = BitmapWindowWndPrco;   
  63.     wndclass.cbClsExtra  = 0;
  64.     wndclass.cbWndExtra  = 0;
  65.     wndclass.hInstance   = hinstance;   
  66.     wndclass.hIcon       = LoadIcon(NULL, IDI_APPLICATION);
  67.     wndclass.hCursor     = LoadCursor(NULL, IDC_ARROW);
  68.     wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//窗口背影画刷为空
  69.     wndclass.lpszMenuName  = NULL;
  70.     wndclass.lpszClassName = szAppName;
  71.    
  72.     if (!RegisterClass(&wndclass))
  73.     {
  74.         MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR);
  75.         return FALSE;
  76.     }
  77.    
  78.     hwnd = CreateWindowEx(WS_EX_TOPMOST,
  79.                         szAppName,
  80.                         szAppName,
  81.                         WS_POPUP,
  82.                         CW_USEDEFAULT,
  83.                         CW_USEDEFAULT,
  84.                         nWidth,
  85.                         nHeight,
  86.                         NULL,
  87.                         NULL,
  88.                         hinstance,
  89.                         NULL);
  90.     if (hwnd == NULL)
  91.         return FALSE;
  92.    
  93.     ShowWindow(hwnd, nCmdshow);
  94.     UpdateWindow(hwnd);
  95.    
  96.     return TRUE;
  97. }
  98. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm)
  99. {
  100.     static HDC s_hdcMem; //放置缩放后的位图
  101.    
  102.     switch (message)
  103.     {
  104.     case WM_CREATE:
  105.         {
  106.             // 设置分层属性
  107.              SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
  108.             // 设置透明色
  109.             COLORREF clTransparent = RGB(0, 0, 0);
  110.              SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);
  111.             
  112.             //   缩放位图
  113.             // 加载位图到hdcTemp中
  114.             HDC hdc = GetDC(hwnd);
  115.             HDC hdcTemp = CreateCompatibleDC(hdc);
  116.             SelectObject(hdcTemp, g_hBitmap);
  117.             // 得到窗口大小
  118.             int nWidth, nHeight;
  119.             GetWindowSize(hwnd, &nWidth, &nHeight);
  120.             // 创建与窗口大小相等且能容纳位图的HDC - s_hdcMem
  121.             s_hdcMem = CreateCompatibleDC(hdc);
  122.             HBITMAP hbmp = CreateCompatibleBitmap(hdc, nWidth, nHeight);
  123.             SelectObject(s_hdcMem, hbmp);
  124.             // 将原位图缩放到窗口大小
  125.             BITMAP bm;
  126.             GetObject(g_hBitmap, sizeof(bm), &bm);
  127.             StretchBlt(s_hdcMem, 0, 0, nWidth, nHeight, hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  128.             
  129.             // 释放资源
  130.             DeleteDC(hdcTemp);
  131.             ReleaseDC(hwnd, hdc);
  132.         }
  133.         return 0;
  134.         
  135.     case WM_KEYDOWN:
  136.         switch (wParam)
  137.         {
  138.         case VK_ESCAPE: //按下Esc键时退出
  139.             SendMessage(hwnd, WM_DESTROY, 0, 0);
  140.             return TRUE;
  141.         }
  142.         break;
  143.    
  144.     case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口
  145.         PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
  146.         return TRUE;
  147.                
  148.     case WM_ERASEBKGND: //在窗口背景中直接贴图
  149.         {
  150.             HDC hdc = (HDC)wParam;
  151.             int nWidth, nHeight;
  152.             GetWindowSize(hwnd, &nWidth, &nHeight);
  153.             BitBlt(hdc, 0, 0, nWidth, nHeight, s_hdcMem, 0, 0, SRCCOPY);
  154.             return TRUE;
  155.         }
  156.     case WM_DESTROY:
  157.         DeleteDC(s_hdcMem);
  158.         PostQuitMessage(0);
  159.         return 0;
  160.     }
  161.     return DefWindowProc(hwnd, message, wParam, lParm);
  162. }
  163. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight)
  164. {
  165.     RECT rc;
  166.     GetWindowRect(hwnd, &rc);
  167.     *pnWidth = rc.right - rc.left;
  168.     *pnHeight = rc.bottom - rc.top;
  169. }
复制代码

运行程序将得到如文章中每一张图右边所示的异形窗口。

最后总结一下异形窗口的“三要素”:
1.WS_EX_LAYERED属性
2.以位图为窗口背景(自贴图或位图画刷)
3.指定透明色




当窗口的背景用彩色图片来装饰时,其它控件如果还是用灰色的背景会显的比较不谐调,《Windows界面编程第五篇 静态控件背景透明化》将介绍如何为静态框设置透明背景。

本章源代码回复可见!!
[attachment=1117]




1

主题

23

回帖

0

积分

新手上路

积分
0
发表于 2013-10-15 09:15:21 | 显示全部楼层
学学                                   

0

主题

7

回帖

0

积分

新手上路

积分
0
发表于 2013-11-22 17:18:13 | 显示全部楼层
Windows界面编程第四篇 异形窗体 高富帅版正是我想要的。

0

主题

6

回帖

0

积分

新手上路

积分
0
发表于 2013-11-27 15:01:11 | 显示全部楼层
求给力,求解释
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

果子博客
扫码关注微信公众号

Archiver|手机版|小黑屋|风叶林

GMT+8, 2026-2-1 15:15 , Processed in 0.069150 second(s), 21 queries .

Powered by 风叶林

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表