You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

问题原因及解决方案

核心原因

  1. 扩展样式设置方式错误,直接覆盖所有扩展样式可能丢失系统默认必要样式,导致缩放逻辑异常
  2. 编辑控件默认使用的位图字体无法被缩放
  3. 未确保所有与缩放相关的内部消息都能正常传递到控件原始过程

修复步骤

  1. 修正扩展样式设置逻辑
    不要直接覆盖所有扩展样式,应基于现有样式叠加需要的选项:

    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);
    
  2. 设置可缩放的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);
    
  3. 确保子类过程不干扰缩放消息
    当前子类过程中仅处理WM_CHAR和WM_KEYDOWN,未拦截缩放相关消息,这部分无需修改,但要保证所有未自定义处理的消息都通过DefSubclassProc传递给原始控件过程。

内容的提问来源于stack exchange,提问作者Dave F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 01:19:53