MFC MDI程序中擦除红色线条时如何保留原有黑色线条?
解决MFC MDI中擦除红色线条不影响黑色线条的问题
你的问题出在使用R2_NOT这个ROP模式上,它的作用是反转目标区域的每个像素颜色,这直接导致两个核心问题:
- 如果背景不是纯白色,红色线条反转后会变成奇怪的颜色(比如你看到的绿色/青色);
- 黑色线条所在的像素也会被反转,直接把黑色变成白色,自然就被误擦除了。
而且你当前直接在DC上绘制/擦除的方式,没有利用MFC的重绘机制,窗口一旦重绘(比如最小化恢复、拖动窗口),红色线条就会消失,这也不是MFC绘图的正确姿势。
最优解决方案:利用重绘机制控制线条显示
MFC的视图绘图应该依赖OnDraw函数,通过状态变量来控制是否绘制红色线条,步骤如下:
- 添加状态变量
在你的CScrRulerView类中添加一个成员变量,用来标记是否显示红色线条:
private: bool m_bShowRedLine = false; // 默认不显示红色线条
- 处理按钮点击事件
- 绘制按钮的点击逻辑:
void CScrRulerView::OnDrawButtonClicked() { m_bShowRedLine = true; InvalidateRect(nullptr); // 触发视图重绘 }
- 删除按钮的点击逻辑:
void CScrRulerView::OnDeleteButtonClicked() { m_bShowRedLine = false; InvalidateRect(nullptr); // 触发视图重绘 }
- 修改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
相关产品推荐
相关产品推荐

