首页 > 代码库 > Windows界面编程第四篇 异形窗体(转)
Windows界面编程第四篇 异形窗体(转)
原文转自 http://blog.csdn.net/morewindows/article/details/8451638
上一篇《Windows界面编程第三篇 异形窗体 普通版》介绍了异形窗口(异形窗体)的创建,其主要步骤为——先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。并且为了使异形窗口支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理。
然后在下图中有非常相似的两个异形窗体,只不过,左边的异形窗体小,右边的异形窗体大。这个可以怎么实现了?
先通过其它软件来缩放位图,然后再让程序加载这种方式来指定异形窗口的大小。这种方法虽然可以完成任务,但毕竟太OUT了。
由《Windows界面编程第一篇位图背景与位图画刷》可以想到不用位图画刷,而直接在窗口背景绘制时使用StretchBlt来缩放位图至窗口大小,这样就可以达到指定窗口大小的功能。
由于异形窗口运行后无法通过鼠标来动态调整窗口大小,因此可以窗口初始化时就可以先缩放位图并加载到一个缓冲HDC中,然后再在窗口背景绘制时使用BitBlt来贴图。这种做法只需要缩放位图一次,在每次背景绘制时只须拷贝位图,对程序的效率会有提高。下面给出完整源代码(下载地址:http://download.csdn.net/download/morewindows/4966819)
// 异形窗口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界面编程第五篇 静态控件背景透明化》将介绍如何为静态框设置透明背景。
Windows界面编程第四篇 异形窗体(转)