WinAPI C语言创建RichEdit时修改行距及相关问题咨询
问题解决与代码修正
核心错误:误用普通EDIT控件而非RichEdit控件
你代码中创建的是普通EDIT控件(类名"EDIT"),而普通EDIT控件不支持PARAFORMAT2结构和EM_SETPARAFORMAT消息,这是行距修改无效的根本原因。必须将控件类名改为RichEdit对应的类名:
- ANSI版本:
"RichEdit20A" - 宽字符版本:
"RichEdit20W"
LoadLibrary("riched20.dll")的必要性
是必要的。RichEdit控件的窗口类并非系统默认注册,必须先加载riched20.dll(或更高版本如riched32.dll、msftedit.dll)才能完成类注册,否则CreateWindowEx创建RichEdit控件会失败。建议保存模块句柄并在程序退出时释放,避免内存泄漏:
HMODULE hRichEdit = LoadLibrary("riched20.dll"); // ... 程序逻辑 ... FreeLibrary(hRichEdit);
行距修改函数(LSpaceA、LSpaceB)修正
要正确设置行距,需结合bLineSpacingRule和dyLineSpacing,同时确保dwMask覆盖必要的格式位。建议先获取当前段落格式再修改,避免丢失原有设置:
修正后的LSpaceA(固定行距示例)
void LSpaceA() { PARAFORMAT2 pf2 = {0}; pf2.cbSize = sizeof(PARAFORMAT2); // 先获取当前段落格式 SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2); pf2.dwMask |= PFM_LINESPACING; // 设置为固定行距(LS_EXACT),dyLineSpacing为像素值 pf2.bLineSpacingRule = LS_EXACT; pf2.dyLineSpacing = 40; // 固定40像素行距 SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); }
修正后的LSpaceB(多倍行距示例)
void LSpaceB(HWND hwnd, int spaceFactor) { PARAFORMAT2 pf = {0}; pf.cbSize = sizeof(PARAFORMAT2); SendMessage(hwnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_LINESPACING; // 设置为多倍行距(LS_MULTIPLE),spaceFactor为1/20点的倍数(如40=2倍行距) pf.bLineSpacingRule = LS_MULTIPLE; pf.dyLineSpacing = spaceFactor; SendMessage(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); }
bLineSpacingRule常用取值说明:
LS_SINGLE(0):单倍行距LS_ONEHALF(1):1.5倍行距LS_DOUBLE(2):双倍行距LS_EXACT(4):固定行距,dyLineSpacing为像素值LS_MULTIPLE(5):多倍行距,dyLineSpacing为1/20点的倍数(例如20=1倍,30=1.5倍)
完整修正后的测试代码
#include <stdio.h> #include <windows.h> #include <richedit.h> #define ID_EDIT 1 #define ID_BUTTON 2 HWND hEdit, hButton; HINSTANCE hInstance; HMODULE hRichEdit; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); char sbuf[900]; void MkBuf() { char sta[300]; int ii; _strcpy_s(sbuf, sizeof(sbuf), ""); for(ii=0; ii<6; ii++){ _snprintf_s(sta, sizeof(sta), _TRUNCATE, "%dth line Test WinApi Test WinApi Test WinApi Test WinApi Test WinApi\r\n", 1+ii); _strcat_s(sbuf, sizeof(sbuf), sta); } } void LSpaceA() { PARAFORMAT2 pf2 = {0}; pf2.cbSize = sizeof(PARAFORMAT2); SendMessage(hEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2); pf2.dwMask |= PFM_LINESPACING; pf2.bLineSpacingRule = LS_EXACT; pf2.dyLineSpacing = 40; SendMessage(hEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); } void LSpaceB(HWND hwnd, int spaceFactor) { PARAFORMAT2 pf = {0}; pf.cbSize = sizeof(PARAFORMAT2); SendMessage(hwnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); pf.dwMask |= PFM_LINESPACING; pf.bLineSpacingRule = LS_MULTIPLE; pf.dyLineSpacing = spaceFactor; SendMessage(hwnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hRichEdit = LoadLibrary("riched20.dll"); if (!hRichEdit) { MessageBox(NULL, "Failed to load riched20.dll", "Error", MB_ICONERROR); return 1; } WNDCLASSEX wc = {0}; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = "EditorWindowClass"; RegisterClassEx(&wc); HWND hwnd = CreateWindowEx(0, "EditorWindowClass", "Text Editor", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL); // 创建RichEdit20A控件(ANSI版本) hEdit = CreateWindowEx(0, "RichEdit20A", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE, 0, 0, 800, 500, hwnd, (HMENU)ID_EDIT, hInstance, NULL); hButton = CreateWindowEx(0, "BUTTON", "Change Line Spacing", WS_CHILD | WS_VISIBLE, 10, 510, 150, 30, hwnd, (HMENU)ID_BUTTON, hInstance, NULL); MkBuf(); SetWindowText(hEdit, sbuf); LSpaceA(); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } FreeLibrary(hRichEdit); return (int)msg.wParam; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: if (LOWORD(wParam) == ID_BUTTON) { LSpaceB(hEdit, 40); // 设置2倍行距(40=2*20) } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }
VS编译兼容性说明
将strcpy、sprintf、strcat替换为安全版本_strcpy_s、_snprintf_s、_strcat_s,即可在Visual Studio中正常编译。
内容的提问来源于stack exchange,提问作者land cc
相关产品推荐
相关产品推荐

