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

MFC MDI程序中擦除红色线条时如何保留原有黑色线条?

解决MFC MDI中擦除红色线条不影响黑色线条的问题

你的问题出在使用R2_NOT这个ROP模式上,它的作用是反转目标区域的每个像素颜色,这直接导致两个核心问题:

  • 如果背景不是纯白色,红色线条反转后会变成奇怪的颜色(比如你看到的绿色/青色);
  • 黑色线条所在的像素也会被反转,直接把黑色变成白色,自然就被误擦除了。

而且你当前直接在DC上绘制/擦除的方式,没有利用MFC的重绘机制,窗口一旦重绘(比如最小化恢复、拖动窗口),红色线条就会消失,这也不是MFC绘图的正确姿势。

最优解决方案:利用重绘机制控制线条显示

MFC的视图绘图应该依赖OnDraw函数,通过状态变量来控制是否绘制红色线条,步骤如下:

  1. 添加状态变量
    在你的CScrRulerView类中添加一个成员变量,用来标记是否显示红色线条:
private:
    bool m_bShowRedLine = false; // 默认不显示红色线条
  1. 处理按钮点击事件
  • 绘制按钮的点击逻辑:
void CScrRulerView::OnDrawButtonClicked() {
    m_bShowRedLine = true;
    InvalidateRect(nullptr); // 触发视图重绘
}
  • 删除按钮的点击逻辑:
void CScrRulerView::OnDeleteButtonClicked() {
    m_bShowRedLine = false;
    InvalidateRect(nullptr); // 触发视图重绘
}
  1. 修改OnDraw函数
    在OnDraw中先绘制固定的黑色线条,再根据状态变量决定是否绘制红色线条:
void CScrRulerView::OnDraw(CDC* pDC) {
    CScrRulerDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // 先绘制固定的黑色线条(替换成你实际的黑色线条绘制代码)
    CPen blackPen(PS_SOLID, 1, RGB(0, 0, 0));
    CPen* pOldBlackPen = pDC->SelectObject(&blackPen);
    CRect rulerRectBlack(...); // 你的黑色线条区域
    pDC->MoveTo(rulerRectBlack.left, rulerRectBlack.top);
    pDC->LineTo(rulerRectBlack.right, rulerRectBlack.bottom);
    pDC->SelectObject(pOldBlackPen);

    // 根据状态绘制红色线条
    if (m_bShowRedLine) {
        CPen redPen(PS_SOLID, 1, RGB(255, 0, 0));
        CPen* pOldRedPen = pDC->SelectObject(&redPen);
        CRect rulerRectRed(...); // 你的红色线条区域
        pDC->MoveTo(rulerRectRed.left, rulerRectRed.top);
        pDC->LineTo(rulerRectRed.right, rulerRectRed.bottom);
        pDC->SelectObject(pOldRedPen);
    }
}

备选方案:用R2_XORPEN实现即时擦除(不推荐)

如果因为特殊需求必须直接在DC上擦除,可以使用R2_XORPEN模式:

  • 绘制红色线条时用R2_XORPEN,此时线条是红色与背景的异或结果;
  • 擦除时再用同样的画笔和R2_XORPEN绘制一次,异或两次就会恢复原来的像素,不会影响黑色线条(前提是两次绘制的区域完全一致)。

修改你的DrawLine函数:

void CScrRulerView::DrawLine(CDC* pDC, CRect rulerRect, bool bDraw) {
    int nPrevMode;
    CPen pen(PS_SOLID,1,RGB(255,0,0));
    CPen* pPenOld = pDC->SelectObject (&pen);
    nPrevMode = pDC->SetROP2(R2_XORPEN);
    
    // 不管是绘制还是擦除,都执行一次LineTo,XOR两次就恢复原像素
    pDC->MoveTo(rulerRect.left,rulerRect.top);
    pDC->LineTo(rulerRect.right,rulerRect.bottom);
    
    pDC->SelectObject(pPenOld);
    pDC->SetROP2(nPrevMode);
}

但这种方法有明显弊端:如果两次绘制之间背景区域被其他操作修改过(比如窗口被遮挡后恢复),擦除时就会得到错误的颜色,所以还是优先推荐重绘机制的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:26:01