最近一个作业,是MFC画直线。主要功能是三个:
1.可以指定线的颜色:红色,绿色和蓝色。
2.有四种画直线的方法。第一种用的是:SetROP2(R2_COPYPEN)
第二种用的是:SetROP2(R2_NOT)
第三种用的是:SetROP2(R2_XORPEN)
第四种用的是:SetROP2(R2_XORPEN)
3.可以指定线的宽度:2pt 4pt 8pt.
一开始写程序的时候,没有用memory DC来画,于是在画线的过程中会产生闪烁这个问题。
这个程序主要部分有两个:一个是OnPaint()函数,一个是DrawTempLine()函数。
OnPaint()函数主要是将松开鼠标左键后的终点和起始点的那条直接画出来,这个直线当然不会只是一条。因为松开鼠标后,可以继续画其他的直线。
DrawTempLine()函数:主要是将鼠标在移动的过程中产生的线画出来。当鼠标放开之后,只会得到最后那条直线。
接下来,就是memDC解决闪烁问题。
当我们添加WM_ERASEBKGND后,在OnPain()函数中用memDC来画直线的话,然后在mousemove这个操作中,RedrawWindow()是不起作用的,而且还会增加闪烁现象。
于是,在DrawTempLine()函数中也用memDC来画直线。
代码贴出来:
void CChildView::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
CDC mDC;
mDC.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
CBitmap *pOldBmp = mDC.SelectObject(&bitmap);
mDC.FillSolidRect(&rect, RGB(255, 255, 255));
CPen *pOldPen=NULL;
INT_PTR n = m_lines.GetSize();
for (int i=0; i<n; i++)
{
CPen pen(PS_SOLID, m_lines[i].width , m_lines[i].color);
mDC.SelectObject(pen);
mDC.MoveTo(m_lines[i].start);
mDC.LineTo(m_lines[i].end);
}
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &mDC, 0, 0, SRCCOPY);
mDC.SelectObject(pOldBmp);
mDC.SelectObject (pOldPen);
}
void CChildView::DrawTempLine(CPoint point, BOOL bFirst)
{
CClientDC dc(this);
CRect rect;
GetClientRect(&rect);
CDC mDC;
mDC.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
CBitmap *pOldBmp = mDC.SelectObject(&bitmap);
//mDC.FillSolidRect(&rect, dc.GetBkColor ());
mDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, SRCCOPY); //这是关键的地方
//CPen *pOldPen=NULL;
CPen pen;
if (m_selMethod == ID_METHOD1)
{
pen.CreatePen(PS_SOLID, m_width, m_color);
mDC.SetROP2(R2_COPYPEN);
}
else if (m_selMethod == ID_METHOD2)
{
pen.CreatePen(PS_SOLID, m_width, m_color);
mDC.SetROP2(R2_NOT);
}
else if (m_selMethod == ID_METHOD3)
{
pen.CreatePen(PS_SOLID, m_width, m_color);
mDC.SetROP2(R2_XORPEN);
}
else if (m_selMethod == ID_METHOD4)
{
pen.CreatePen(PS_SOLID, m_width, 0xffffff & ~m_color);
mDC.SetROP2(R2_XORPEN);
}
CPen *pOldPen =mDC.SelectObject(&pen);
if (!bFirst)
{
mDC.MoveTo(m_tmpLine.start);
mDC.LineTo(m_tmpLine.end);
}
m_tmpLine.end = point;
mDC.MoveTo(m_tmpLine.start);
mDC.LineTo(m_tmpLine.end);
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &mDC, 0, 0, SRCCOPY);
mDC.SelectObject(pOldBmp);
mDC.SelectObject (pOldPen);
}
在DrawTempLine()函数中。
mDC.BitBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, SRCCOPY); //这是关键的地方
按照平时的写程式的方式,会将memDC在放回到dc上面去。
但是在这里,如果DrawTempLine()函数也是先创建一个memDC,在这个上面进行画直线,然后放回到dc上去,在鼠标移动进行画线的时候,客户区上原来已经画好的直线是不会出现的,只会在鼠标放开之后,才会出现。
于是:咱们换个角度去想问题。我在鼠标移动,DrawTempLine的时候,将此时客户区背景以及上面已经有的东西,整个截取下来,当作DrawTempLine()的memDC,在上面进行画直线,画完之后,再讲memDC放回到原来的dc上去。这样的话,就不会出现遮盖原来的直线的问题。而且也不会闪烁了。
就这个样子。不好意思,表达能力有限