Windows SDK 实现不规则窗口
不规则窗口在程序界面设计中能提供非常好的用户体验,以下是我程序运行时的效果图:
以下是代码,注意需要修改一些简单的位置,如资源ID,项目的头文件,图片资源等,这些是根据你创建的win32程序的项目名改变的,我的项目名为RgnWindow.
// RgnWindow.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "RgnWindow.h" #include <comdef.h> #define ULONG_PTR ULONG #include <gdiplus.h> using namespace Gdiplus; #pragma comment(lib, "gdiplus.lib") //注意,要保证vc路径的lib中,能够找到这个文件 #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name GdiplusStartupInput m_gdiplusStartupInput; ULONG_PTR m_pGdiToken; HWND g_hWnd = 0; Image *g_pImageBack=0; //透明度颜色混合选项 BLENDFUNCTION g_Blend; //背景图的宽度和高度 int g_BakWidth, g_BakHeight; // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); BOOL ImageFromIDResource(UINT nID, LPCTSTR sTR, Image * & pImg); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); void Update(); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_RGNWINDOW, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RGNWINDOW)); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } GdiplusShutdown(m_pGdiToken); return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // // COMMENTS: // // This function and its usage are only necessary if you want this code // to be compatible with Win32 systems prior to the 'RegisterClassEx' // function that was added to Windows 95. It is important to call this function // so that the application will get 'well formed' small icons associated // with it. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDC_RGNWINDOW)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_RGNWINDOW); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); //hWnd=CreateWindowEx(WS_EX_TOPMOST|WS_EX_LAYERED|WS_EX_TOOLWINDOW, szWindowClass,NULL,WS_POPUP|WS_SYSMENU, // 0,0,300,400,NULL,NULL,hInstance,NULL); if (!hWnd) { return FALSE; } //初始化 g_Blend.SourceConstantAlpha = int(0 * 2.55);//1~255 g_Blend.BlendOp=0; //theonlyBlendOpdefinedinWindows2000 g_Blend.BlendFlags=0; //nothingelseisspecial... g_Blend.AlphaFormat=1; //... g_Blend.SourceConstantAlpha=255;//AC_SRC_ALPHA DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE); //设置成工具窗口,无标题栏 SetWindowLong(hWnd, GWL_STYLE, dwExStyle ^ WS_EX_TOOLWINDOW); //设置成层次窗口 dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); //if((dwExStyle & WS_EX_LAYERED) != WS_EX_LAYERED) // SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle|WS_EX_TOPMOST|WS_EX_LAYERED); //加载图像 //ImageFromIDResource(IDR_CLOCK, L"PNG", g_pImageBack); g_pImageBack = Image::FromFile(_T("D://launcher//bx.png")); ImageType t = g_pImageBack->GetType(); //bkImg.FromFile(); g_BakWidth = g_pImageBack->GetWidth(); g_BakHeight = g_pImageBack->GetHeight(); g_hWnd=hWnd; //::SetWindowPos(g_hWnd, HWND_TOPMOST,0,0,g_BakWidth,g_BakHeight,SWP_NOSIZE|SWP_NOMOVE); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); Update(); return TRUE; } // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // // WM_COMMAND - process the application menu // WM_PAINT - Paint the main window // WM_DESTROY - post a quit message and return // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... Update(); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_LBUTTONDOWN: //禁止显示移动矩形窗体框 ::SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,TRUE,NULL,0); //非标题栏移动整个窗口 ::SendMessage(hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // Message handler for about box. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } BOOL ImageFromIDResource(UINT nID, LPCTSTR sTR, Image * & pImg) { HINSTANCE hInst = hInst;//GetResourceInstance(); HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type if (!hRsrc) return FALSE; // load resource into memory DWORD len = SizeofResource(hInst, hRsrc); BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc); if (!lpRsrc) return FALSE; // Allocate global memory on which to create stream HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len); BYTE* pmem = (BYTE*)GlobalLock(m_hMem); memcpy(pmem,lpRsrc,len); IStream* pstm; CreateStreamOnHGlobal(m_hMem,FALSE,&pstm); // load from stream pImg=Gdiplus::Image::FromStream(pstm); // free/release stuff GlobalUnlock(m_hMem); pstm->Release(); FreeResource(lpRsrc); return TRUE; } void Update() { HDC hdcTemp= ::GetDC(g_hWnd); HDC hdcMemory=CreateCompatibleDC(hdcTemp); HBITMAP hBitMap=CreateCompatibleBitmap(hdcTemp, g_BakWidth, g_BakHeight); SelectObject(hdcMemory, hBitMap); HDC hdcScreen=::GetDC (g_hWnd); RECT rct; ::GetWindowRect(g_hWnd, &rct); POINT ptWinPos={rct.left,rct.top}; Graphics graph(hdcMemory); Point points[] = { Point(0, 0), Point(g_BakWidth, 0), Point(0, g_BakHeight) }; graph.DrawImage(g_pImageBack, points, 3); POINT ptDst; ptDst.x = rct.left; ptDst.y = rct.top; SIZE size={g_BakWidth, g_BakHeight}; POINT pt; pt.x = 0; pt.y = 0; //设置成层次窗口 DWORD dwExStyle = GetWindowLong(g_hWnd,GWL_EXSTYLE); if((dwExStyle & WS_EX_LAYERED) != WS_EX_LAYERED) {//WS_EX_LAYERED是0x00080000 SetWindowLong(g_hWnd, GWL_EXSTYLE,dwExStyle^WS_EX_LAYERED); } //更新窗口 if (!UpdateLayeredWindow( g_hWnd, hdcScreen, &ptWinPos, &size, hdcMemory, &pt, 0, &g_Blend, 2)) { DWORD dwError = ::GetLastError(); printf("failed"); } //释放资源 graph.ReleaseHDC(hdcMemory); ::DeleteObject(hBitMap); ::DeleteDC(hdcMemory);; ::ReleaseDC(g_hWnd, hdcTemp); ::ReleaseDC(g_hWnd, hdcScreen); }