需要知道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);
}
效果: