You need to enable JavaScript to run this app. 基于CScrollView的IDE视图用CreateCompatibleDC双缓冲不显示字符问题咨询
优惠活动
大模型
产品
解决方案
定价
更多

基于CScrollView的IDE视图用CreateCompatibleDC双缓冲不显示字符问题咨询

双缓冲显示异常的核心原因与修复

存在两个关键逻辑错误,直接导致绘制内容不可见:

  • 内存DC未关联有效绘制位图
    调用CreateCompatibleDC仅会创建内存绘制上下文,默认选入的是1x1的单色占位位图,没有匹配你需要绘制的客户区大小。后续FillSolidRect、TextOut等操作都会因为超出占位位图的存储范围被直接丢弃,无实际绘制内容留存。
    修复方式:创建内存DC后,生成与显示DC兼容、和当前客户区大小完全匹配的位图,再选入内存DC作为绘制目标:
    // 获取客户区真实设备坐标,无需做偏移
    CRect clientRect;
    GetClientRect(&clientRect);
    
    CDC memDc;
    if (!memDc.CreateCompatibleDC(pDC)) {
        MessageBox(L"CreateCompatibleDC is failed");
        return;
    }
    // 创建与客户区等大的兼容位图
    CBitmap memBmp;
    memBmp.CreateCompatibleBitmap(pDC, clientRect.Width(), clientRect.Height());
    // 选入内存DC,保存旧GDI对象避免资源泄漏
    CBitmap* pOldBmp = memDc.SelectObject(&memBmp);
    CFont* pOldFont = memDc.SelectObject(&font);
    
  • BitBlt目标坐标与源坐标逻辑错误
    BitBlt的目标坐标是显示DC的客户区设备坐标,原点固定为客户区左上角(0,0),而非文档滚动后的偏移位置。你原代码中给BitBlt传了pos.x, pos.y作为目标坐标,所有绘制内容都会被放到客户区可视范围之外,自然无法看到。
    同时,绘制文本的坐标逻辑也需要修正:需要将文档坐标减去滚动偏移量,转换为当前可见区域内的相对坐标后,再在内存DC上绘制。
    修正后的完整OnDraw实现示例:
    void CIDEView::OnDraw(CDC *pDC) {
        CPoint const scrollPos = GetDeviceScrollPosition();
        CRect clientRect;
        GetClientRect(&clientRect);
    
        CDC memDc;
        if (!memDc.CreateCompatibleDC(pDC)) {
            MessageBox(L"CreateCompatibleDC is failed");
            return;
        }
        CBitmap memBmp;
        memBmp.CreateCompatibleBitmap(pDC, clientRect.Width(), clientRect.Height());
        CBitmap* pOldBmp = memDc.SelectObject(&memBmp);
        CFont* pOldFont = memDc.SelectObject(&font);
    
        // 填充编辑器背景
        memDc.FillSolidRect(&clientRect, RGB(255, 255, 255));
    
        // 示例文本绘制:文档坐标转换为当前可视区域的相对坐标
        memDc.TextOutW(0, 0, L"¶", 1);
    
        // 恢复GDI对象
        memDc.SelectObject(pOldFont);
        memDc.SelectObject(pOldBmp);
    
        // 一次性将内存绘制内容拷贝到显示DC的客户区原点
        pDC->BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &memDc, 0, 0, SRCCOPY);
    }
    
    优化建议:可将内存DC、内存位图设为视图类的成员变量,仅在客户区大小变更时重新创建,避免每次重绘都反复创建销毁GDI对象带来的开销。
内存占用疑问解答

你担心的20倍桌面分辨率内存占用的情况不会发生:

  • 常规双缓冲的内存位图,仅需要和当前可见的客户区大小匹配,不需要和整个文档的总大小匹配。不管文档有多少页,每次重绘时仅需绘制当前屏幕能显示的部分内容,分配的内存位图大小最多等于当前客户区的尺寸。
  • 按3840*2160分辨率、32位色深计算,单帧内存占用为3840 * 2160 * 4 ≈ 32MB,与文档总页数无关联。
  • 若需进一步降低内存占用,可仅为本次重绘的无效区域(而非整个客户区)分配对应大小的内存位图,进一步减少临时内存开销。

内容的提问来源于stack exchange,提问作者Zoltán Hegedüs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 08:15:04