需要知道GetDC与BeginPaint的区别,这里有一篇不错的文章。
简洁的就是说:BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。
如果用GetDC的话,窗口会一直在重绘,可以在WM_PAINT消息里加上断点即可知道
那么如何将位图渲染到控件里呢,我们需要用到DefSubclassProc(hwnd, uMsg, wParam, lParam);
这是默认的消息出来函数,因为是用来子类控件的消息事件,所以是DefSubclassProc。
在子类回调函数里的WM_PAINT添加DefSubclassProc即可。
下面的完整代码;
// WindowsProject49.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "WindowsProject49.h" #include <Richedit.h> #include <commctrl.h> #pragma comment(lib, "comctl32.lib") #define MAX_LOADSTRING 100 #define EDIT_CLASS RICHEDIT_CLASS #define mb_err(x) MessageBox(NULL, TEXT(x), TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK) #define main_edit 101 // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING]; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING] = L"Sample Window Class"; // the main window class name HWND hedit = NULL; HBITMAP hBitmap = NULL; // 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); LRESULT CALLBACK main_edit_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. // Initialize global strings LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDC_WINDOWSPROJECT49, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT49)); MSG msg; // Main message loop: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // FUNCTION: MyRegisterClass() // // PURPOSE: Registers the window class. // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW 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(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 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) { hInst = hInstance; // Store instance handle in our global variable HWND hWnd = CreateWindowEx( 0, // Optional window styles. szWindowClass, // Window class L"Learn to Program Windows", // Window text WS_OVERLAPPEDWINDOW, // Window style // Size and position CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, // Parent window NULL, // Menu hInstance, // Instance handle NULL // Additional application data ); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); 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) { switch (message) { case WM_CREATE: { hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), L"C:\\Users\\strives\\Desktop\\small.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); LoadLibrary(L"Riched20.dll"); hedit = CreateWindowEx(0, EDIT_CLASS, NULL, WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_HSCROLL, 0, 0, 100, 100, hWnd, NULL, GetModuleHandle(NULL), NULL); if (main_edit_proc != NULL) SetWindowSubclass(hedit, main_edit_proc, main_edit, 1); if (hedit == NULL) mb_err("Could not create edit control."); else { SendMessage(hedit, EM_SETBKGNDCOLOR, 0, RGB(40, 40, 40)); CHARFORMAT2 format; memset(&format, 0, sizeof format); format.cbSize = sizeof(CHARFORMAT2); format.dwMask = CFM_COLOR | CFM_FACE; format.crTextColor = RGB(255, 0, 255); memcpy(format.szFaceName, L"Consolas", sizeof(L"Consolas")); if (SendMessage(hedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&format) == 0) { mb_err("Failed to set font."); } if (SendMessage(hedit, EM_SETTEXTMODE, TM_PLAINTEXT, 0) != 0) { mb_err("EM_SETTEXTMODE returned non-zero value"); } //did not set the yHeight, so need to get it (from default) SendMessage(hedit, EM_GETCHARFORMAT, NULL, (LPARAM)&format); RECT rect; SendMessage(hedit, EM_GETRECT, 0, (LPARAM)&rect); rect.left = format.yHeight / 4; SendMessage(hedit, EM_SETRECT, 0, (LPARAM)&rect); } break; } case WM_COMMAND: { int wmId = LOWORD(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: { PAINTSTRUCT ps; HDC hdc; BITMAP bitmap; HDC hdcMem; HGDIOBJ oldBitmap; hdc = BeginPaint(hWnd, &ps); if (hdc == NULL) __debugbreak(); hdcMem = CreateCompatibleDC(hdc); oldBitmap = SelectObject(hdcMem, hBitmap); GetObject(hBitmap, sizeof(bitmap), &bitmap); BitBlt(hdc, 200, 200, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, oldBitmap); DeleteDC(hdcMem); EndPaint(hWnd, &ps); break; }*/ case WM_DESTROY: PostQuitMessage(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; } LRESULT CALLBACK main_edit_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { switch (uMsg) { case WM_SETCURSOR: { POINT pos; GetCursorPos(&pos); HWND cur_hwnd = WindowFromPoint(pos); if (cur_hwnd == hwnd) SetCursor(LoadCursor(NULL, IDC_ARROW)); else SendMessage(cur_hwnd, WM_SETCURSOR, 0, 0); return 0; } case WM_PAINT: { DefSubclassProc(hwnd, uMsg, wParam, lParam); HDC hdc; BITMAP bitmap; HDC hdcMem; HGDIOBJ oldBitmap; hdc = GetDC(hwnd); if (hdc == NULL) __debugbreak(); hdcMem = CreateCompatibleDC(hdc); oldBitmap = SelectObject(hdcMem, hBitmap); GetObject(hBitmap, sizeof(bitmap), &bitmap); BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); SelectObject(hdcMem, oldBitmap); DeleteDC(hdcMem); ReleaseDC(hwnd, hdc); return 0; } case WM_NCDESTROY: RemoveWindowSubclass(hwnd, &main_edit_proc, main_edit); break; } return DefSubclassProc(hwnd, uMsg, wParam, lParam); }
效果:
原文:https://www.cnblogs.com/strive-sun/p/11778590.html