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

Woosa

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

公告

View Post

Windows界面编程第三篇 异形窗体 普通版

 上一篇《Windows界面编程第二篇 半透明窗体》介绍了先使用SetWindowLong为窗体加上WS_EX_LAYERED属性,再使用SetLayeredWindowAttributes调整窗体的透明度。本篇将使用这二个函数来完成另一个实用的功能——异形窗口(异形窗体)。

异形窗口的原理很简单,首先加载一张位图画刷作窗口背景,然后设置透明色就可以使得窗口由矩形变成任意形状。这样使得窗口的显示更加美观。

    下面先简单介绍下Win32 SDK方式创建窗口的流程(按《Windows程序设计》中的大体流程):

1.设置WNDCLASS类型的变量,这个变量将描述窗口的风格、窗口消息处理函数、程序图标、光标、窗口背景画刷等待。

2.使用RegisterClass将WNDCLASS类型的变量注册下。

3.使用CreateWindow或CreateWindowEx创建窗口,这里可以设置窗口的初始位置、初始大小、扩展属性等等。

4.通过ShowWindow和UpdateWindow将窗口显示出来。

5.窗口显示完成后,在WinMain()函数中添加消息处理:   

       MSGmsg;

      while (GetMessage(&msg,NULL, 0, 0))

      {

             TranslateMessage(&msg);

             DispatchMessage(&msg);

      }

通过这五步就完成了一个窗口的创建了。

对于窗口消息函数,一般只要在WM_DESTROY消息中调用下PostQuitMessage(0);其它的消息都可以使用默认消息处理函数DefWindowProc。

对于异形窗口,可以在WM_CREATE即窗口初始化时设置好透明色就完成了窗口形状的改变,不过为了支持鼠标对窗口的拖曳,还要在WM_LBUTTONDOWN消息中加入:

PostMessage(hwnd,WM_SYSCOMMAND,SC_MOVE | HTCAPTION, 0);

这样,异形窗口就可以在屏幕上像普通窗口一样的移动了。

完整的源代码如下所示(下载地址:http://download.csdn.net/download/morewindows/4966815):

[cpp]view plaincopyprint?
  1. //   异形窗口1  窗口背景使用位图画刷再指定透明色 
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows) 
  3. #include <windows.h> 
  4.  
  5. constchar szAppName[] = "异形窗口1 MoreWindows-(http://blog.csdn.net/MoreWindows)"; 
  6.  
  7. /*
  8. * 函数名称: GetWindowSize
  9. * 函数功能: 得到窗口的宽高
  10. * hwnd      窗口句柄
  11. * pnWidth   窗口宽
  12. * pnHeight  窗口高
  13. */ 
  14. void GetWindowSize(HWND hwnd,int *pnWidth, int *pnHeight); 
  15.  
  16.  
  17. /*
  18. * 函数名称: InitBitmapWindow
  19. * 函数功能: 位图窗口初始化
  20. * hinstance 进程实例
  21. * hBitmap   位图句柄
  22. * nCmdshow  显示方式-与ShowWindow函数的第二个参数相同
  23. */ 
  24. BOOL InitBitmapWindow(HINSTANCE hinstance,HBITMAP hBitmap, int nCmdshow); 
  25.  
  26. // 位图窗口消息处理函数 
  27. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd,UINT message, WPARAM wParam,LPARAM lParm); 
  28.  
  29.  
  30. int APIENTRY WinMain(HINSTANCE hInstance, 
  31.                     HINSTANCE hPrevInstance, 
  32.                      LPSTR     lpCmdLine, 
  33.                     int       nCmdShow) 
  34. { 
  35.     //设置窗口背景画刷为图片画刷,再指定透明颜色即可以创建透明区域。 
  36.     HBITMAP  hBitmap; 
  37.     hBitmap = (HBITMAP)LoadImage(NULL,"Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); 
  38.     if (hBitmap == NULL) 
  39.     { 
  40.         MessageBox(NULL, "位图加载失败", "Error", MB_ICONERROR); 
  41.         return 0; 
  42.     } 
  43.     if (!InitBitmapWindow(hInstance, hBitmap, nCmdShow)) 
  44.         return 0; 
  45.  
  46.     MSG msg; 
  47.     while (GetMessage(&msg, NULL, 0, 0)) 
  48.     { 
  49.         TranslateMessage(&msg); 
  50.         DispatchMessage(&msg); 
  51.     } 
  52.     DeleteObject(hBitmap); 
  53.  
  54.     return msg.wParam; 
  55. } 
  56.  
  57.  
  58. BOOL InitBitmapWindow(HINSTANCE hinstance,HBITMAP hBitmap, int nCmdshow) 
  59. { 
  60.     HWND hwnd; 
  61.     WNDCLASS wndclass; 
  62.      
  63.     wndclass.style       = CS_VREDRAW | CS_HREDRAW; 
  64.     wndclass.lpfnWndProc = BitmapWindowWndPrco;  
  65.     wndclass.cbClsExtra  = 0; 
  66.     wndclass.cbWndExtra  = 0; 
  67.     wndclass.hInstance   = hinstance;    
  68.     wndclass.hIcon       = LoadIcon(NULL, IDI_APPLICATION); 
  69.     wndclass.hCursor     = LoadCursor(NULL, IDC_ARROW); 
  70.     wndclass.hbrBackground = CreatePatternBrush(hBitmap);//位图画刷 
  71.     wndclass.lpszMenuName  = NULL; 
  72.     wndclass.lpszClassName = szAppName; 
  73.      
  74.     if (!RegisterClass(&wndclass)) 
  75.     { 
  76.         MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR); 
  77.         return FALSE; 
  78.     } 
  79.  
  80.     BITMAP bm; 
  81.     GetObject(hBitmap,sizeof(bm), &bm); 
  82.     hwnd = CreateWindowEx(WS_EX_TOPMOST, 
  83.                         szAppName, 
  84.                         szAppName,  
  85.                         WS_POPUP, 
  86.                         CW_USEDEFAULT,  
  87.                         CW_USEDEFAULT,  
  88.                         bm.bmWidth,  
  89.                         bm.bmHeight, 
  90.                         NULL, 
  91.                         NULL, 
  92.                         hinstance, 
  93.                         NULL); 
  94.     if (hwnd == NULL) 
  95.         return FALSE; 
  96.      
  97.     ShowWindow(hwnd, nCmdshow); 
  98.     UpdateWindow(hwnd); 
  99.      
  100.     return TRUE; 
  101. } 
  102.  
  103. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd,UINT message, WPARAM wParam,LPARAM lParm) 
  104. { 
  105.     static HDC s_hdcMem; 
  106.     staticHBRUSH s_hBackBrush; 
  107.      
  108.     switch (message) 
  109.     { 
  110.     case WM_CREATE: 
  111.         { 
  112.             // 设置分层属性 
  113.             SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); 
  114.             // 设置透明色 
  115.             COLORREF clTransparent = RGB(0, 0, 0); 
  116.             SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY); 
  117.         } 
  118.         return 0; 
  119.  
  120.          
  121.     case WM_KEYDOWN:  
  122.         switch (wParam) 
  123.         { 
  124.         case VK_ESCAPE: //按下Esc键时退出 
  125.             SendMessage(hwnd, WM_DESTROY, 0, 0); 
  126.             return 0; 
  127.         } 
  128.         break; 
  129.      
  130.  
  131.     case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口 
  132.         PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);  
  133.         return 0; 
  134.  
  135.  
  136.     case WM_DESTROY: 
  137.         PostQuitMessage(0); 
  138.         return 0; 
  139.     } 
  140.     return DefWindowProc(hwnd, message, wParam, lParm); 
  141. } 
  142.  
  143. void GetWindowSize(HWND hwnd,int *pnWidth, int *pnHeight) 
  144. { 
  145.     RECT rc; 
  146.     GetWindowRect(hwnd, &rc); 
  147.     *pnWidth = rc.right - rc.left; 
  148.     *pnHeight = rc.bottom - rc.top; 
  149. } 
//   异形窗口1  窗口背景使用位图画刷再指定透明色
//By MoreWindows-(http://blog.csdn.net/MoreWindows)
#include <windows.h>

const char szAppName[] = "异形窗口1 MoreWindows-(http://blog.csdn.net/MoreWindows)";

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


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

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


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    //设置窗口背景画刷为图片画刷,再指定透明颜色即可以创建透明区域。
	HBITMAP  hBitmap;
	hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
	if (hBitmap == NULL)
	{
		MessageBox(NULL, "位图加载失败", "Error", MB_ICONERROR);
		return 0;
	}
	if (!InitBitmapWindow(hInstance, hBitmap, nCmdShow))
		return 0;

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

	return msg.wParam;
}


BOOL InitBitmapWindow(HINSTANCE hinstance, HBITMAP hBitmap, 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 = CreatePatternBrush(hBitmap);//位图画刷
	wndclass.lpszMenuName  = NULL;
	wndclass.lpszClassName = szAppName;
	
	if (!RegisterClass(&wndclass))
	{
		MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR);
		return FALSE;
	}

	BITMAP bm;
	GetObject(hBitmap, sizeof(bm), &bm);
	hwnd = CreateWindowEx(WS_EX_TOPMOST,
						szAppName,
						szAppName, 
						WS_POPUP,
						CW_USEDEFAULT, 
						CW_USEDEFAULT, 
						bm.bmWidth, 
						bm.bmHeight,
						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;
	static HBRUSH s_hBackBrush;
	
	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);
		}
		return 0;

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

	case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口
		PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0); 
		return 0;


	case WM_DESTROY:
		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;
}

运行结果如下:

现在总结下异形窗口的创建,先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。为了支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理,使得异形窗口可以像普通窗口一样在屏幕上移动。

本篇程序中的异形窗口的大小是无法设置的,只能和位图一样。下一篇《Windows界面编程第四篇 异形窗体 高富帅版》将介绍窗口大小可以指定的异形窗口。欢迎继续浏览。

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

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