为什么“先用pDC对象从mPointOrign点绘制一条线到mPointOld点,这相当于擦除了之前的线。”
时间: 2024-02-28 20:54:40 浏览: 47
这是因为在MFC框架下,绘制图形是通过GDI(图形设备接口)实现的。每次绘制都会将图形绘制在设备上,如果想要擦除之前的图形,需要将设备上的图形擦除掉。
在这段代码中,使用pDC对象从mPointOrign点绘制一条线到mPointOld点,实际上是在设备上绘制了一条白色的线,将之前的线覆盖掉,从而实现了擦除旧线的效果。然后再使用pDC对象从mPointOrign点绘制一条线到point点,就相当于在设备上绘制了一条新的线,从而实现了画出新线的效果。
需要注意的是,在每次绘制之前,需要将pDC对象的绘图颜色设置为白色,这样才能擦除之前的线。具体代码如下:
```
CPen pen(PS_SOLID, 1, RGB(255, 255, 255)); // 创建一个白色画笔
pDC->SelectObject(&pen); // 选择该画笔
pDC->MoveTo(mPointOrign); // 设置起点
pDC->LineTo(mPointOld); // 绘制白色线,相当于擦除旧线
```
这样就可以实现擦除旧线并画出新线的效果了。
相关问题
解释pDC.MoveTo(mPointOrign); pDC.LineTo(mPointOld);//擦旧线 pDC.MoveTo(mPointOrign); pDC.LineTo(point);//画新线
这段代码是在MFC框架下绘制图形的代码。其中,pDC是一个指向CDC对象的指针,表示绘图设备的上下文。MoveTo()和LineTo()是CDC类的成员函数,分别用于设置绘图起点和绘制直线。
这段代码的作用是:先用pDC对象从mPointOrign点绘制一条线到mPointOld点,这相当于擦除了之前的线。然后再从mPointOrign点绘制一条线到point点,这相当于画了一条新线。这样就实现了在画布上擦除旧线并画出新线的效果。
其中,mPointOrign是线条的起点坐标,mPointOld是上一条线的终点坐标,point是本次绘制的终点坐标。这段代码需要在OnMouseMove()等事件处理函数中调用,以响应用户的鼠标移动事件,实现动态绘图的效果。
使用MFC完成手动绘制点、手绘线、折线、圆的代码
以下是使用MFC完成手动绘制点、手绘线、折线、圆的代码:
首先在类视图中创建一个新的View类,例如CMyDrawView。
在CMyDrawView.h文件中添加如下代码:
```cpp
class CMyDrawView : public CView
{
protected: // 仅从序列化创建
CMyDrawView() noexcept;
DECLARE_DYNCREATE(CMyDrawView)
// 特性
public:
CMyDrawDoc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
// 实现
public:
virtual ~CMyDrawView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
private:
CPoint m_ptStart; // 起点
CPoint m_ptEnd; // 终点
BOOL m_bDrawing; // 是否正在绘制
int m_nShape; // 绘制的形状:0-点,1-线,2-折线,3-圆
CArray<CPoint, CPoint&> m_arrPoints; // 折线的点集合
};
#ifndef _DEBUG // MyDrawView.cpp 中的调试版本
inline CMyDrawDoc* CMyDrawView::GetDocument() const
{ return reinterpret_cast<CMyDrawDoc*>(m_pDocument); }
#endif
```
在CMyDrawView.cpp文件中添加如下代码:
```cpp
// CMyDrawView
IMPLEMENT_DYNCREATE(CMyDrawView, CView)
BEGIN_MESSAGE_MAP(CMyDrawView, CView)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
// CMyDrawView 构造/析构
CMyDrawView::CMyDrawView() noexcept
{
m_bDrawing = FALSE;
m_nShape = 0;
}
CMyDrawView::~CMyDrawView()
{
}
BOOL CMyDrawView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
// CMyDrawView 绘制
void CMyDrawView::OnDraw(CDC* pDC)
{
CMyDrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// 绘制折线
if (m_nShape == 2)
{
if (m_arrPoints.GetSize() > 0)
{
POINT* pPoints = new POINT[m_arrPoints.GetSize()];
for (int i = 0; i < m_arrPoints.GetSize(); i++)
{
pPoints[i] = m_arrPoints.GetAt(i);
}
pDC->Polyline(pPoints, m_arrPoints.GetSize());
delete[] pPoints;
}
}
// 绘制圆
if (m_nShape == 3)
{
int nRadius = (int)sqrt((double)((m_ptStart.x - m_ptEnd.x) * (m_ptStart.x - m_ptEnd.x) + (m_ptStart.y - m_ptEnd.y) * (m_ptStart.y - m_ptEnd.y)));
pDC->Ellipse(m_ptStart.x - nRadius, m_ptStart.y - nRadius, m_ptStart.x + nRadius, m_ptStart.y + nRadius);
}
}
// CMyDrawView 消息处理程序
void CMyDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bDrawing = TRUE;
m_ptStart = point;
m_ptEnd = point;
// 绘制点
if (m_nShape == 0)
{
CDC* pDC = GetDC();
pDC->SetPixel(m_ptStart, RGB(0, 0, 0));
ReleaseDC(pDC);
}
CView::OnLButtonDown(nFlags, point);
}
void CMyDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bDrawing)
{
CDC* pDC = GetDC();
pDC->SetROP2(R2_NOTXORPEN);
// 擦除之前的绘制
if (m_nShape == 1 || m_nShape == 2 || m_nShape == 3)
{
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
}
// 更新终点
m_ptEnd = point;
// 绘制线
if (m_nShape == 1)
{
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
}
// 绘制折线
if (m_nShape == 2)
{
if (m_arrPoints.GetSize() > 0)
{
pDC->MoveTo(m_arrPoints.GetAt(m_arrPoints.GetSize() - 1));
pDC->LineTo(m_ptEnd);
}
else
{
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
}
}
// 绘制圆
if (m_nShape == 3)
{
pDC->Ellipse(m_ptStart.x - abs(m_ptStart.x - m_ptEnd.x), m_ptStart.y - abs(m_ptStart.x - m_ptEnd.x), m_ptStart.x + abs(m_ptStart.x - m_ptEnd.x), m_ptStart.y + abs(m_ptStart.x - m_ptEnd.x));
}
pDC->SetROP2(R2_COPYPEN);
ReleaseDC(pDC);
}
CView::OnMouseMove(nFlags, point);
}
void CMyDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bDrawing = FALSE;
// 绘制线
if (m_nShape == 1)
{
CDC* pDC = GetDC();
pDC->MoveTo(m_ptStart);
pDC->LineTo(m_ptEnd);
ReleaseDC(pDC);
}
// 绘制折线
if (m_nShape == 2)
{
m_arrPoints.Add(point);
}
// 绘制圆
if (m_nShape == 3)
{
Invalidate();
}
CView::OnLButtonUp(nFlags, point);
}
#ifdef _DEBUG
void CMyDrawView::AssertValid() const
{
CView::AssertValid();
}
void CMyDrawView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMyDrawDoc* CMyDrawView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDrawDoc)));
return (CMyDrawDoc*)m_pDocument;
}
#endif //_DEBUG
```
接下来在CMyDrawDoc.cpp文件中添加如下代码:
```cpp
// CMyDrawDoc
IMPLEMENT_DYNCREATE(CMyDrawDoc, CDocument)
BEGIN_MESSAGE_MAP(CMyDrawDoc, CDocument)
END_MESSAGE_MAP()
// CMyDrawDoc 构造/析构
CMyDrawDoc::CMyDrawDoc() noexcept
{
}
CMyDrawDoc::~CMyDrawDoc()
{
}
BOOL CMyDrawDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
return TRUE;
}
// CMyDrawDoc 序列化
void CMyDrawDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
#ifdef _DEBUG
void CMyDrawDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CMyDrawDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
```
最后,在MainFrm.cpp文件中添加如下代码:
```cpp
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_COMMAND(ID_DRAW_POINT, OnDrawPoint)
ON_COMMAND(ID_DRAW_LINE, OnDrawLine)
ON_COMMAND(ID_DRAW_POLYLINE, OnDrawPolyline)
ON_COMMAND(ID_DRAW_CIRCLE, OnDrawCircle)
END_MESSAGE_MAP()
// CMainFrame 构造/析构
CMainFrame::CMainFrame() noexcept
{
// TODO: 在此添加成员初始化代码
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 如果在此处添加任何特定于应用程序的代码,
// 将该代码放置于最终应该出现的位置
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return TRUE;
}
// CMainFrame 消息处理程序
void CMainFrame::OnDrawPoint()
{
CMyDrawView* pView = (CMyDrawView*)GetActiveView();
if (pView != NULL)
{
pView->m_nShape = 0;
}
}
void CMainFrame::OnDrawLine()
{
CMyDrawView* pView = (CMyDrawView*)GetActiveView();
if (pView != NULL)
{
pView->m_nShape = 1;
}
}
void CMainFrame::OnDrawPolyline()
{
CMyDrawView* pView = (CMyDrawView*)GetActiveView();
if (pView != NULL)
{
pView->m_nShape = 2;
pView->m_arrPoints.RemoveAll();
}
}
void CMainFrame::OnDrawCircle()
{
CMyDrawView* pView = (CMyDrawView*)GetActiveView();
if (pView != NULL)
{
pView->m_nShape = 3;
}
}
```
现在可以在菜单栏上添加四个按钮,分别对应绘制点、线、折线和圆的功能。当用户选择其中一个按钮时,就改变视图中的m_nShape变量,使之对应相应的绘制形状。当用户开始绘制时,OnLButtonDown()函数将启动绘制过程,并在OnMouseMove()函数中更新绘制结果。当用户完成绘制时,OnLButtonUp()函数将完成绘制。
注意:本示例只支持绘制单个圆形。如果需要绘制多个圆形,可以用一个CArray来存储所有的圆心和半径。