• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

Woosa

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。
  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

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

 上一篇《Windows界面编程第三篇 异形窗体 普通版》介绍了异形窗口(异形窗体)的创建,其主要步骤为——先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。并且为了使异形窗口支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理。

然后在下图中有非常相似的两个异形窗体,只不过,左边的异形窗体小,右边的异形窗体大。这个可以怎么实现了?

先通过其它软件来缩放位图,然后再让程序加载这种方式来指定异形窗口的大小。这种方法虽然可以完成任务,但毕竟太OUT了。

由《Windows界面编程第一篇位图背景与位图画刷》可以想到不用位图画刷,而直接在窗口背景绘制时使用StretchBlt来缩放位图至窗口大小,这样就可以达到指定窗口大小的功能。

由于异形窗口运行后无法通过鼠标来动态调整窗口大小,因此可以窗口初始化时就可以先缩放位图并加载到一个缓冲HDC中,然后再在窗口背景绘制时使用BitBlt来贴图。这种做法只需要缩放位图一次,在每次背景绘制时只须拷贝位图,对程序的效率会有提高。下面给出完整源代码(下载地址:http://download.csdn.net/download/morewindows/4966819)

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

/*
 * 函数名称: GetWindowSize
 * 函数功能: 得到窗口的宽高
 * hwnd      窗口句柄
 * pnWidth   窗口宽
 * pnHeight  窗口高
*/
void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);


/*
 * 函数名称: InitBitmapWindow
 * 函数功能: 位图窗口初始化
 * hinstance 进程实例
 * nWidth    窗口宽
 * nHeight   窗口高
 * nCmdshow  显示方式-与ShowWindow函数的第二个参数相同
*/
BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow);

// 位图窗口消息处理函数
LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm);

          
HBITMAP  g_hBitmap;
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    //先创建一个无背影画刷窗口,
	//然后在WM_CREATE中并指定透明颜色, 缩放位图后加载至s_hdcMem中.
	//最后在WM_ERASEBKGND中用s_hdcMem贴图即可
	g_hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	if (g_hBitmap == NULL)
	{
		MessageBox(NULL, "位图加载失败", "Error", MB_ICONERROR);
		return 0;
	}

	// 设置异形窗口大小
	BITMAP bm;
	GetObject(g_hBitmap, sizeof(bm), &bm);
	int nWindowWidth = bm.bmWidth;
	int nWindowHeight = bm.bmHeight + 100; //拉高100高度

	if (!InitBitmapWindow(hInstance, nWindowWidth, nWindowHeight, nCmdShow))
		return 0;

	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	DeleteObject(g_hBitmap);

	return msg.wParam;
}


BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow)
{
	HWND hwnd;
	WNDCLASS wndclass;
	
	wndclass.style       = CS_VREDRAW | CS_HREDRAW;
	wndclass.lpfnWndProc = BitmapWindowWndPrco;	
	wndclass.cbClsExtra  = 0;
	wndclass.cbWndExtra  = 0;
	wndclass.hInstance   = hinstance;	
	wndclass.hIcon       = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor     = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//窗口背影画刷为空
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;
	
	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR);
		return FALSE;
	}
	
	hwnd = CreateWindowEx(WS_EX_TOPMOST,
						szAppName,
						szAppName, 
						WS_POPUP,
						CW_USEDEFAULT, 
						CW_USEDEFAULT, 
						nWidth, 
						nHeight,
						NULL,
						NULL,
						hinstance,
						NULL);
	if (hwnd == NULL)
		return FALSE;
	
	ShowWindow(hwnd, nCmdshow);
	UpdateWindow(hwnd);
	
	return TRUE;
}

LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm)
{
	static HDC s_hdcMem; //放置缩放后的位图
	
	switch (message)
	{
	case WM_CREATE:
		{
			// 设置分层属性
 			SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
			// 设置透明色
			COLORREF clTransparent = RGB(0, 0, 0);
 			SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);
			
			//   缩放位图
			// 加载位图到hdcTemp中
			HDC hdc = GetDC(hwnd);
			HDC hdcTemp = CreateCompatibleDC(hdc);
			SelectObject(hdcTemp, g_hBitmap);

			// 得到窗口大小
			int nWidth, nHeight;
			GetWindowSize(hwnd, &nWidth, &nHeight);

			// 创建与窗口大小相等且能容纳位图的HDC - s_hdcMem
			s_hdcMem = CreateCompatibleDC(hdc);
			HBITMAP hbmp = CreateCompatibleBitmap(hdc, nWidth, nHeight);
			SelectObject(s_hdcMem, hbmp);

			// 将原位图缩放到窗口大小
			BITMAP bm;
			GetObject(g_hBitmap, sizeof(bm), &bm);
			StretchBlt(s_hdcMem, 0, 0, nWidth, nHeight, hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
			
			// 释放资源
			DeleteDC(hdcTemp);
			ReleaseDC(hwnd, hdc);
		}
		return 0;

		
	case WM_KEYDOWN: 
		switch (wParam)
		{
		case VK_ESCAPE: //按下Esc键时退出
			SendMessage(hwnd, WM_DESTROY, 0, 0);
			return TRUE;
		}
		break;
	

	case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口
		PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0); 
		return TRUE;
				
	case WM_ERASEBKGND: //在窗口背景中直接贴图
		{
			HDC hdc = (HDC)wParam;
			int nWidth, nHeight;
			GetWindowSize(hwnd, &nWidth, &nHeight);
			BitBlt(hdc, 0, 0, nWidth, nHeight, s_hdcMem, 0, 0, SRCCOPY);
			return TRUE;
		}

	case WM_DESTROY:
		DeleteDC(s_hdcMem);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParm);
}


void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight)
{
	RECT rc;
	GetWindowRect(hwnd, &rc);
	*pnWidth = rc.right - rc.left;
	*pnHeight = rc.bottom - rc.top;
}

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

最后总结一下异形窗口的“三要素”:

1.WS_EX_LAYERED属性

2.以位图为窗口背景(自贴图或位图画刷)

3.指定透明色

本文配套程序下载地址为:http://download.csdn.net/download/morewindows/4966819

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

posted on 2013-03-15 20:10  Woosa  阅读(410)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3