Win32多行编辑控件缩放因子变化但文本大小未改变的问题
Win32 C++多行编辑控件缩放因子变化但文本大小不变问题
我正在开发一款Win32 C++应用,使用了多行编辑控件。已设置ES_EX_ZOOMABLE扩展样式,按住Ctrl键滚动鼠标滚轮时,通过Edit_GetZoom确认缩放因子确实变化,但控件内的文本大小始终保持不变。
缩放前:
缩放后:
创建编辑控件的代码
g_editControlHandle = CreateWindowEx( 0, L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL, 0, 0, 0, 0, hwnd, editControlId, g_mainWindowClass.hInstance, nullptr ); constexpr auto extendedStyles = ES_EX_ALLOWEOL_ALL | ES_EX_CONVERT_EOL_ON_PASTE | ES_EX_ZOOMABLE; SendMessage(g_editControlHandle, EM_SETEXTENDEDSTYLE, extendedStyles, extendedStyles); SetWindowSubclass(g_editControlHandle, FNEditControlProc, static_cast<int>(ChildId::EditControl), 0);
获取缩放因子的代码
void UpdateZoomStatus() { int numerator; int denominator; Edit_GetZoom(g_editControlHandle, &numerator, &denominator); const auto zoom = static_cast<int>(static_cast<double>(numerator) / static_cast<double>(denominator) * 100.0); std::wstringstream zoomText; zoomText << zoom << L"%"; SendMessage(g_statusBarHandle, SB_SETTEXT, MAKEWPARAM(static_cast<WORD>(StatusBarField::Zoom), 0), reinterpret_cast<LPARAM>(zoomText.str().data())); }
编辑控件的子类过程
LRESULT CALLBACK FNEditControlProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam, [[maybe_unused]] UINT_PTR uIdSubclass, [[maybe_unused]] DWORD_PTR dwRefData) { if (uMsg == WM_CHAR && !g_insertMode) { if (!(wParam == VK_RETURN || wParam == VK_BACK || wParam == VK_DELETE || wParam == VK_TAB)) { // 如果选中文本长度为0,用输入字符替换光标处字符;否则替换选中的文本 DWORD selectionStart; DWORD selectedEnd; SendMessage(hWnd, EM_GETSEL, reinterpret_cast<WPARAM>(&selectionStart), reinterpret_cast<LPARAM>(&selectedEnd)); if (const auto selectionLength = selectedEnd - selectionStart; selectionLength == 0) { const auto caretIndex = Edit_GetCaretIndex(hWnd); const auto textLength = Edit_GetTextLength(hWnd); if (caretIndex < static_cast<DWORD>(textLength)) { auto text = new WCHAR[2]; text[0] = static_cast<WCHAR>(wParam); text[1] = L'\0'; SendMessage(hWnd, EM_SETSEL, caretIndex, caretIndex + 1); SendMessage(hWnd, EM_REPLACESEL, true, reinterpret_cast<LPARAM>(text)); } else { return DefSubclassProc(hWnd, uMsg, wParam, lParam); } } else { SendMessage(hWnd, EM_REPLACESEL, true, reinterpret_cast<LPARAM>(&wParam)); } return 0; } } const auto result = DefSubclassProc(hWnd, uMsg, wParam, lParam); if (uMsg == WM_KEYDOWN) { switch (wParam) { case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT: { PostMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(static_cast<int>(ChildId::EditControl), FNN_SEL_CHANGE), MAKELPARAM(hWnd, 0)); break; } case VK_INSERT: { g_insertMode = !g_insertMode; UpdateInsertModeStatus(); break; } default: { break; } } } if (uMsg == WM_MOUSEWHEEL) { UpdateZoomStatus(); } return result; }
问题原因及解决方案
核心原因
- 扩展样式设置方式错误,直接覆盖所有扩展样式可能丢失系统默认必要样式,导致缩放逻辑异常
- 编辑控件默认使用的位图字体无法被缩放
- 未确保所有与缩放相关的内部消息都能正常传递到控件原始过程
修复步骤
修正扩展样式设置逻辑
不要直接覆盖所有扩展样式,应基于现有样式叠加需要的选项:DWORD currentExStyle = SendMessage(g_editControlHandle, EM_GETEXTENDEDSTYLE, 0, 0); DWORD targetStyles = ES_EX_ALLOWEOL_ALL | ES_EX_CONVERT_EOL_ON_PASTE | ES_EX_ZOOMABLE; SendMessage(g_editControlHandle, EM_SETEXTENDEDSTYLE, targetStyles, currentExStyle | targetStyles);设置可缩放的TrueType字体
创建控件后为其指定支持缩放的字体(如Segoe UI):HFONT hFont = CreateFontW( 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI" ); SendMessage(g_editControlHandle, WM_SETFONT, reinterpret_cast<WPARAM>(hFont), TRUE);确保子类过程不干扰缩放消息
当前子类过程中仅处理WM_CHAR和WM_KEYDOWN,未拦截缩放相关消息,这部分无需修改,但要保证所有未自定义处理的消息都通过DefSubclassProc传递给原始控件过程。
内容的提问来源于stack exchange,提问作者Dave F
相关产品推荐
相关产品推荐

