一个Win32Sdk实现的无边框窗口案例最佳实践
// WindowsProject.cpp : Defines the entry point for the application. // #include "framework.h" #include "WindowsProject.h" #include <ShObjIdl.h> #include <GdiPlus.h> #pragma comment(lib, "Gdiplus.lib") #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING]; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name ULONG_PTR gdiplusToken = 0; Gdiplus::GdiplusStartupInput gdiplusStartupInput = { 0 }; Gdiplus::GdiplusStartupOutput gdiplusStartupOutput = { 0 }; // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(::CoInitialize(NULL)); Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, &gdiplusStartupOutput); // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_WINDOWSPROJECT, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(IDC_WINDOWSPROJECT)); // Main message loop: while (GetMessageW(&msg, NULL, 0, 0)) { if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessageW(&msg); } } Gdiplus::GdiplusShutdown(gdiplusToken); ::CoUninitialize(); return (int)msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WINDOWSPROJECT)); wcex.hCursor = LoadCursorW(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); //wcex.hbrBackground = (HBRUSH)(COLOR_GRAYTEXT + 1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIconW(wcex.hInstance, MAKEINTRESOURCEW(IDI_SMALL)); return RegisterClassExW(&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 = NULL; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindowExW(0L, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } bool Maximized(HWND hwnd) { WINDOWPLACEMENT placement = { 0 }; if (!::GetWindowPlacement(hwnd, &placement)) { return false; } return placement.showCmd == SW_MAXIMIZE; } // // 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) { switch (message) { case WM_CREATE: CreateWindowExW(0L, WC_BUTTONW, L"测试", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, 100, 80, 30, hWnd, (HMENU)1001, NULL, NULL); break; case WM_COMMAND: { int wmId = LOWORD(wParam); int wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case 1001: Maximized(hWnd); break; case IDM_ABOUT: DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_ABOUTBOX), hWnd, About, 0L); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProcW(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code that uses hdc here... RECT rc = { 100,200,300,220 }; ::DrawTextW(hdc, L"hello World!", -1, &rc, 0); EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; case WM_NCHITTEST: { POINT pt = { (int)(short)LOWORD(lParam),(int)(short)HIWORD(lParam), }; const POINT& border { ::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER), ::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER), }; RECT window_rc = { 0,0,0,0 }; ::GetWindowRect(hWnd, &window_rc); enum region_mask { client = 0, left = 1 << 0, right = 1 << 1, top = 1 << 2, bottom = 1 << 3, }; const auto& result = left * (pt.x < (window_rc.left + border.x)) | right * (pt.x >= (window_rc.right - border.x)) | top * (pt.y < (window_rc.top + border.y)) | bottom * (pt.y >= (window_rc.bottom - border.y)); switch (result) { case left: return HTLEFT; case right: return HTRIGHT; case top: return HTTOP; case bottom: return HTBOTTOM; case top | left: return HTTOPLEFT; case top | right: return HTTOPRIGHT; case bottom | left: return HTBOTTOMLEFT; case bottom | right: return HTBOTTOMRIGHT; } const int& caption = ::GetSystemMetrics(SM_CYCAPTION); if (pt.y <= window_rc.top + caption) { return HTCAPTION; } } break; case WM_NCCALCSIZE: { if (wParam == TRUE) { auto& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam); RECT& rect = params.rgrc[0]; rect.top += 1; } return 0; } break; case WM_NCACTIVATE: return TRUE; break; default: return DefWindowProcW(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; }
改进版:
#include <Windows.h> #include <CommCtrl.h> #include <GdiPlus.h> #pragma comment(lib, "Gdiplus.lib") #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING] = L"测试程序"; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING] = L"WC_TESTDEMO"; // the main window class name ULONG_PTR gdiplusToken = 0; Gdiplus::GdiplusStartupInput gdiplusStartupInput = { 0 }; Gdiplus::GdiplusStartupOutput gdiplusStartupOutput = { 0 }; // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); //int APIENTRY wWinMain(HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPWSTR lpCmdLine, // int nCmdShow) { //UNREFERENCED_PARAMETER(hPrevInstance); //UNREFERENCED_PARAMETER(lpCmdLine); //UNREFERENCED_PARAMETER(::CoInitialize(NULL)); int main(int argc, char ** argv) { Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, &gdiplusStartupOutput); // TODO: Place code here. MSG msg; HACCEL hAccelTable; HINSTANCE hInstance = GetModuleHandle(NULL); int nCmdShow = SW_SHOW; // Initialize global strings //LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); //LoadStringW(hInstance, IDC_WINDOWSPROJECT, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance(hInstance, nCmdShow)) { return FALSE; } //hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(IDC_WINDOWSPROJECT)); // Main message loop: while (GetMessageW(&msg, NULL, 0, 0)) { //if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessageW(&msg); //} } Gdiplus::GdiplusShutdown(gdiplusToken); ::CoUninitialize(); return (int)msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL;// LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_WINDOWSPROJECT)); wcex.hCursor = LoadCursorW(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); //wcex.hbrBackground = (HBRUSH)(COLOR_GRAYTEXT + 1); wcex.lpszMenuName = NULL;//MAKEINTRESOURCEW(IDC_WINDOWSPROJECT); wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL;//LoadIconW(wcex.hInstance, MAKEINTRESOURCEW(IDI_SMALL)); return RegisterClassExW(&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 = NULL; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindowExW(0L, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } bool Maximized(HWND hwnd) { WINDOWPLACEMENT placement = { 0 }; if (!::GetWindowPlacement(hwnd, &placement)) { return false; } return placement.showCmd == SW_MAXIMIZE; } #define CELLSIZE 48 #define DARKCOLOR RGB(0,47,127) #define LIGHTCOLOR RGB(241,179,0) HBRUSH hbrDark = CreateSolidBrush(DARKCOLOR); HBRUSH hbrLight = CreateSolidBrush(LIGHTCOLOR); static void CustomPaint(HDC hDC, RECT* rcDirty, BOOL bErase) { int x = 0, y = 0; RECT r = { 0,0,0,0, }; HBRUSH hBrush = NULL; // Note we paint only the cells overlaping with the dirty rectangle. for (y = rcDirty->top / CELLSIZE; y <= rcDirty->bottom / CELLSIZE; y++) { for (x = rcDirty->left / CELLSIZE; x <= rcDirty->right / CELLSIZE; x++) { hBrush = ((x + y) % 2 == 0) ? hbrLight : hbrDark; SetRect(&r, x * CELLSIZE, y * CELLSIZE, (x + 1) * CELLSIZE, (y + 1) * CELLSIZE); FillRect(hDC, &r, hBrush); } } } static void CustomPaint1(HDC hDC, RECT* rcDirty, BOOL bErase) { Gdiplus::Graphics g(hDC); Gdiplus::LinearGradientBrush linGrBrush( Gdiplus::Point(0, rcDirty->bottom), Gdiplus::Point(rcDirty->right, rcDirty->bottom), Gdiplus::Color(255, 0, 0, 0), // opaque black Gdiplus::Color(255, 255, 0, 0)); // opaque red Gdiplus::REAL relativeIntensities[] = { 0.0f, 0.5f, 1.0f }; Gdiplus::REAL relativePositions[] = { 0.0f, 0.2f, 1.0f }; //linGrBrush.SetBlend(relativeIntensities, relativePositions, 3); //g.FillEllipse(&linGrBrush, 0, 30, 200, 100); //g.FillRectangle(&linGrBrush, 0, 155, 500, 30); //g.FillEllipse(&linGrBrush, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); linGrBrush.SetGammaCorrection(TRUE); g.FillRectangle(&linGrBrush, rcDirty->left, rcDirty->top, rcDirty->right, rcDirty->bottom); { } } static void CustomDoubleBuffer(PAINTSTRUCT* pPaintStruct) { int cx = pPaintStruct->rcPaint.right - pPaintStruct->rcPaint.left; int cy = pPaintStruct->rcPaint.bottom - pPaintStruct->rcPaint.top; HDC hMemDC; HBITMAP hBmp; HBITMAP hOldBmp; POINT ptOldOrigin; // Create new bitmap-back device context, large as the dirty rectangle. hMemDC = CreateCompatibleDC(pPaintStruct->hdc); hBmp = CreateCompatibleBitmap(pPaintStruct->hdc, cx, cy); hOldBmp = (HBITMAP)SelectObject(hMemDC, hBmp); // Do the painting into the memory bitmap. OffsetViewportOrgEx(hMemDC, -(pPaintStruct->rcPaint.left), -(pPaintStruct->rcPaint.top), &ptOldOrigin); //CustomPaint(hMemDC, &pPaintStruct->rcPaint, TRUE); CustomPaint1(hMemDC, &pPaintStruct->rcPaint, TRUE); SetViewportOrgEx(hMemDC, ptOldOrigin.x, ptOldOrigin.y, NULL); // Blit the bitmap into the screen. This is really fast operation and altough // the CustomPaint() can be complex and slow there will be no flicker any more. BitBlt(pPaintStruct->hdc, pPaintStruct->rcPaint.left, pPaintStruct->rcPaint.top, cx, cy, hMemDC, 0, 0, SRCCOPY); // Clean up. SelectObject(hMemDC, hOldBmp); DeleteObject(hBmp); DeleteDC(hMemDC); } // // 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) { switch (message) { case WM_CREATE: CreateWindowExW(0L, WC_BUTTONW, L"测试", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, 100, 80, 30, hWnd, (HMENU)1001, NULL, NULL); break; case WM_COMMAND: { int wmId = LOWORD(wParam); int wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case 1001: Maximized(hWnd); break; //case IDM_ABOUT: // DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_ABOUTBOX), hWnd, About, 0L); // break; //case IDM_EXIT: // DestroyWindow(hWnd); // break; default: return DefWindowProcW(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps = { 0 }; HDC hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code that uses hdc here... SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); //HBRUSH hBrushBg = CreateSolidBrush(RGB(0, 200, 0)); //FillRect(hdc, &ps.rcPaint, hBrushBg); //RECT rc = { 100,200,300,220 }; //::DrawTextW(hdc, L"hello World!", -1, &rc, 0); { CustomDoubleBuffer(&ps); } EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; case WM_NCHITTEST: { POINT pt = { (int)(short)LOWORD(lParam),(int)(short)HIWORD(lParam), }; const POINT& border{ ::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER), ::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER), }; RECT window_rc = { 0,0,0,0 }; ::GetWindowRect(hWnd, &window_rc); enum region_mask { client = 0, left = 1 << 0, right = 1 << 1, top = 1 << 2, bottom = 1 << 3, }; const auto& result = left * (pt.x < (window_rc.left + border.x)) | right * (pt.x >= (window_rc.right - border.x)) | top * (pt.y < (window_rc.top + border.y)) | bottom * (pt.y >= (window_rc.bottom - border.y)); switch (result) { case left: return HTLEFT; case right: return HTRIGHT; case top: return HTTOP; case bottom: return HTBOTTOM; case top | left: return HTTOPLEFT; case top | right: return HTTOPRIGHT; case bottom | left: return HTBOTTOMLEFT; case bottom | right: return HTBOTTOMRIGHT; } const int& caption = ::GetSystemMetrics(SM_CYCAPTION); if (pt.y <= window_rc.top + caption) { return(HTCAPTION); } return HTCLIENT; } break; case WM_NCCALCSIZE: { //if (wParam == TRUE) { // auto& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam); // RECT& rect = params.rgrc[0]; // //rect.top += 1; //} return(FALSE); } break; case WM_NCACTIVATE: return(TRUE); break; default: return(DefWindowProcW(hWnd, message, wParam, lParam)); } return(FALSE); } // 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; }
收藏的用户(0)
X
正在加载信息~
2
最新回复 (0)