在MFC中用双缓冲绘制橡皮线,新画的总是覆盖了原来画的(就是一新画的时候原来的就消失了)
下面是我写的简易代码这个鼠标移动的主要就是给OnDraw函数传坐标void CTwoBufferView::OnMouseMove(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
if (chek)//鼠标按下的时候开始作图
{
cend=point;
Invalidate(false);
}
CView::OnMouseMove(nFlags, point);}这是OnDraw函数的代码void CTwoBufferView::OnDraw(CDC* pDC)
{
   CTwoBufferDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   // TODO: add draw code for native data here
   CRect rect;
   GetClientRect(&rect);
  //创建一个用于绘图的内存设备环境
  memDc.CreateCompatibleDC(pDC);
  //建立一个与屏幕显示兼容的位图,
  memBmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
  CBitmap *pOldBit= memDc.SelectObject(&memBmp);
  memDc.FillSolidRect(0,0,rect.Width(), rect.Height(),RGB(255,255,255));
 //创建画笔
  CPen m_pen;
  m_pen.CreatePen(PS_SOLID, 5, RGB(0,123,0));
  SelectObject(memDc,m_pen);
 //开始画图
  memDc.MoveTo(cbgin);
  memDc.LineTo(cend);
  //将内存设备环境上的图拷贝到屏幕上显示
  pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDc, 0, 0, SRCCOPY);
  //绘图完成后清理
  memBmp.DeleteObject();
  memDc.DeleteDC();
}
//都是全局变量
CBitmap memBmp;
CDC memDc;高手请给解答。。是不是要用个数组把画过的保存起来 然后在循环的输出?

解决方案 »

  1.   

    这是肯定的啊
    新绘制后进入OnDraw()函数后坐标参数都改变了
    可以把以前的坐标保存起来
      

  2.   

    没有代码,自己动手丰衣足食
    可以参考下思路:typedef struct
    {
    CPoint begin;
    CPoint end;
    }POINTS;
    #define MAX_NUM  100//最大数目自己定义
    POINTS pt[MAX_NUM];
    int count;//记录已经绘制了多少个矩形,初始化时count=0;
    鼠标点击时:pt[count].begin=?;pt[count].end=?;count++;
    绘制时:用一个循环来for(int i=0;i<count;i++){……}
    大致思路就是这样,自己写吧
      

  3.   

    有一个方法
    OnDraw中只做一件事,BitBlt,就是拷贝内存dc到屏幕dc上去,
    绘图操作(不在Ondraw中)都画在内存DC上。
      

  4.   


    //鼠标左键按下的时候
    void CTwoBufferView::OnLButtonDown(UINT nFlags, CPoint point) 
    {
      // TODO: Add your message handler code here and/or call default
       pt[count].begin=point;
       pt[count].cend=point;
       count++;
       chek=true;//鼠标按下
       CView::OnLButtonDown(nFlags, point);
    }
    鼠标移动的时候void CTwoBufferView::OnMouseMove(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    if (chek)//鼠标按下的时候开始作图
    {
    pt[count].cend=point;
            count++;
    Invalidate(false);
    }
    CView::OnMouseMove(nFlags, point);
    }OnDraw函数void CTwoBufferView::OnDraw(CDC* pDC)
    {
     CTwoBufferDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
     CRect rect;
     GetClientRect(&rect);
    //创建一个用于绘图的内存设备环境
     memDc.CreateCompatibleDC(pDC);
    //建立一个与屏幕显示兼容的位图,
      memBmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
      CBitmap *pOldBit= memDc.SelectObject(&memBmp);
      memDc.FillSolidRect(0,0,rect.Width(), rect.Height(),RGB(255,255,255));
    //创建一画笔
      CPen m_pen;
      m_pen.CreatePen(PS_SOLID, 1, RGB(255,0,0));
      SelectObject(memDc,m_pen);
     for(int i=0;i<count;i++)
     {
         memDc.MoveTo(pt[count].begin);
         memDc.LineTo(pt[count].cend);
     }
      //将内存设备环境上的图拷贝到屏幕上显示
      pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDc, 0, 0, SRCCOPY);
      //绘图完成后的清理
      memBmp.DeleteObject();
      memDc.DeleteDC();
    }
    没有效果你看怎么回事?。
      

  5.   

    绘图操作都画在内存DC上怎么操作呀? 我不就是画在内存DC上吗而且它也是全局的变量呀。
      

  6.   

    你在::OnMouseMove中count++肯定出错啊
    count是记录绘制矩形的个数
    在绘制一个矩形时鼠标一直在移动count一直在加
    自己好好理解下这个过程
      

  7.   

    我是画直线count去掉了还是没有效果 代码和我上面的基本一样。。
      

  8.   

    我自己试了一下,可以的啊:
    看代码:// 1View.h : CMy1View 类的接口
    //
    #pragma once
    typedef struct
    {
    CPoint begin;
    CPoint end;
    }PTS;
    #define MAX 100
    class CMy1View : public CView
    {
    protected: // 仅从序列化创建
    CMy1View();
    DECLARE_DYNCREATE(CMy1View)// 属性
    public:
    CMy1Doc* GetDocument() const;// 操作
    public:// 重写
    public:
    virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    protected:
    virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);// 实现
    public:
    virtual ~CMy1View();
    #ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
    #endifprotected:// 生成的消息映射函数
    protected:
    DECLARE_MESSAGE_MAP()
    public:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    private:
    PTS pt[MAX];
    int count;
    public:
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    private:
    BOOL m_IsLButtonDown;
    };#ifndef _DEBUG  // 1View.cpp 中的调试版本
    inline CMy1Doc* CMy1View::GetDocument() const
       { return reinterpret_cast<CMy1Doc*>(m_pDocument); }
    #endif
    // 1View.cpp : CMy1View 类的实现
    //#include "stdafx.h"
    #include "1.h"#include "1Doc.h"
    #include "1View.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    // CMy1ViewIMPLEMENT_DYNCREATE(CMy1View, CView)BEGIN_MESSAGE_MAP(CMy1View, CView)
    // 标准打印命令
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
    ON_WM_CREATE()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    END_MESSAGE_MAP()// CMy1View 构造/析构CMy1View::CMy1View()
    : m_IsLButtonDown(FALSE)
    {
    // TODO: 在此处添加构造代码
    count=0;}CMy1View::~CMy1View()
    {
    }BOOL CMy1View::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式 return CView::PreCreateWindow(cs);
    }// CMy1View 绘制void CMy1View::OnDraw(CDC* pDC)
    {
    CMy1Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
    return;
    for(int i=0;i<count;i++)
    {
    //MessageBox(_T("HHH"));
    pDC->MoveTo(pt[i].begin);
    pDC->LineTo(pt[i].end);
    }
    // TODO: 在此处为本机数据添加绘制代码
    }
    // CMy1View 打印BOOL CMy1View::OnPreparePrinting(CPrintInfo* pInfo)
    {
    // 默认准备
    return DoPreparePrinting(pInfo);
    }void CMy1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: 添加额外的打印前进行的初始化过程
    }void CMy1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: 添加打印后进行的清理过程
    }
    // CMy1View 诊断#ifdef _DEBUG
    void CMy1View::AssertValid() const
    {
    CView::AssertValid();
    }void CMy1View::Dump(CDumpContext& dc) const
    {
    CView::Dump(dc);
    }CMy1Doc* CMy1View::GetDocument() const // 非调试版本是内联的
    {
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMy1Doc)));
    return (CMy1Doc*)m_pDocument;
    }
    #endif //_DEBUG
    // CMy1View 消息处理程序int CMy1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CView::OnCreate(lpCreateStruct) == -1)
    return -1; // TODO:  在此添加您专用的创建代
    return 0;
    }void CMy1View::OnLButtonDown(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    this->m_IsLButtonDown=TRUE;
    pt[count].begin=point; CView::OnLButtonDown(nFlags, point);
    }void CMy1View::OnLButtonUp(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    count++;
    this->m_IsLButtonDown=FALSE;
    CView::OnLButtonUp(nFlags, point);
    }void CMy1View::OnMouseMove(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if(m_IsLButtonDown)
    {
    pt[count].end=point;
    Invalidate();
    }
    CView::OnMouseMove(nFlags, point);
    }
    不知道是不是这样的简单画线
      

  9.   


    小修改了下代码已经可以画来了。。但是线条粗的时候拖动鼠标效果不是很理想。线条会有点闪、拖动鼠标时两条线的交叉会有白色点。。
    代码如下:鼠标移动  ---void CTwoBufferView::OnMouseMove(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    if (chek)//鼠标按下的时候开始作图
    {
                    CClientDC pDC(this);
    int nOldDrawMode = pDC.SetROP2(R2_NOTXORPEN);/*R2_NOT*//*R2_XORPEN*/
    CPen cpen(PS_SOLID, 5, RGB(0,123,0));
    pDC.SelectObject(&cpen);
    pDC.MoveTo(cbgin);
    pDC.LineTo(cend);
    cend=point;
                    pDC.MoveTo(cbgin);
    pDC.LineTo(cend);
    pDC.SelectObject(&cpen);
    pt[count].cend=point;
    }
    CView::OnMouseMove(nFlags, point);
    }
    //鼠标左键按下的时候
    void CTwoBufferView::OnLButtonDown(UINT nFlags, CPoint point) 
    {
       // TODO: Add your message handler code here and/or call default
       pt[count].begin=point;
       pt[count].cend=point;
       cbgin=point;//原点坐标
       cend=point;//当前坐标
       chek=true;//鼠标按下
       CView::OnLButtonDown(nFlags, point);
    }
    //鼠标左键弹起了的时候
    void CTwoBufferView::OnLButtonUp(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
        chek=false;
        Invalidate(false); //刷新
        count++;        //弹起来的时候数量加一 表明已经画好一个线段
        CView::OnLButtonUp(nFlags, point);
    }void CTwoBufferView::OnDraw(CDC* pDC)
    {
    CTwoBufferDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    MyDraw(pDC); //调用自定义函数

    void CTwoBufferView::MyDraw(CDC *pDC)
    {
            CRect rect;
    GetClientRect(&rect);
    //创建一个用于绘图的内存设备环境
    memDc.CreateCompatibleDC(pDC);
    //建立一个与屏幕显示兼容的位图,
    memBmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    CBitmap *pOldBit= memDc.SelectObject(&memBmp);
    memDc.FillSolidRect(0,0,rect.Width(), rect.Height(),RGB(255,255,255));
    //创建一画笔
    CPen m_pen;
    m_pen.CreatePen(PS_SOLID, 5, RGB(0,123,0));
    SelectObject(memDc,m_pen);
    for(int i=0;i<count;i++)
    {
    memDc.MoveTo(pt[i].begin);
    memDc.LineTo(pt[i].cend);
    }
    //将内存设备环境上的图拷贝到屏幕上显示
    pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDc, 0, 0, SRCCOPY);
    //绘图完成后的清理
    memBmp.DeleteObject();
            memDc.DeleteDC();
    }
    //定义的结构体等。。
    #define MAX_NUM 100
    typedef struct POINTS
    {
    CPoint begin;
    CPoint cend;
    };
    POINTS pt[MAX_NUM];
      

  10.   

    因为你每次都把位图重新创建,所以会把原来的绘图给擦除,你既然是全局的memBmp,只需要创建一次,并选入DC,以后就不用再创建并选入了,只需要绘图然后Biblt就行;
      

  11.   

    我把它们提到初始化中? 还有我两条线交叉的时候会有白色的是因为我显示鼠标移动的轨迹用了SetROP2(R2_NOTXORPEN) 有没有什么更好的办法呀 鼠标轨迹用双缓冲显示不是太好把。。系统的画图程序是怎么处理的呀    CRect rect;
        GetClientRect(&rect);
        //创建一个用于绘图的内存设备环境
        memDc.CreateCompatibleDC(pDC);
        //建立一个与屏幕显示兼容的位图,
        memBmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
        CBitmap *pOldBit= memDc.SelectObject(&memBmp);
        memDc.FillSolidRect(0,0,rect.Width(), rect.Height(),RGB(255,255,255));
      

  12.   

    绘图程序有几个要点:
      1.在 OnDraw/OnPaint 等函数中使用双缓冲的方式绘制全部数据,这是为了保证被别的窗体挡住或从最小化恢复后能正确显示。
      2.在 MouseMove 等函数中只绘制真正需要的数据,而不要通过调用 Invalidate 全部重绘的方式。这样代码虽然简单,但往往会出现闪烁或效率低。  另外,微软的 AllVCLanguageSamples.zip 例子程序里有个叫 drawcli 的,是一个简单的绘图程序,可以参考做为例子。
      

  13.   

    我把代码调整了下什么都画不出来了 怎么回事啊....我看了半天了没有看出来int CTwoBufferView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
    if (CView::OnCreate(lpCreateStruct) == -1)
    return -1;

    // TODO: Add your specialized creation code here
    CRect rect;
    GetClientRect(&rect);
    //创建一个用于绘图的内存设备环境
    memDc.CreateCompatibleDC(&pDC);
    //建立一个与屏幕显示兼容的位图,
    memBmp.CreateCompatibleBitmap(&pDC, rect.Width(), rect.Height());
    CBitmap *pOldBit= memDc.SelectObject(&memBmp);
    memDc.FillSolidRect(0,0,rect.Width(), rect.Height(),RGB(255,255,255));
    return 0;
    }
    void CTwoBufferView::OnMouseMove(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    if (chek)//鼠标按下的时候开始作图
    {
    pt[count].cend=point;
    Invalidate();
    }
    CView::OnMouseMove(nFlags, point);
    }void CTwoBufferView::OnDraw(CDC* pDC)
    {
    CTwoBufferDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    MyDraw(pDC);
    }
    void CTwoBufferView::MyDraw(CDC *pDC)
    {
            CRect rect;
    GetClientRect(&rect);
    //创建一画笔
    CPen m_pen;
    m_pen.CreatePen(PS_SOLID,5, RGB(123,255,0));
    SelectObject(memDc,m_pen);
    for(int i=0;i<count;i++)
    {
    memDc.MoveTo(pt[i].begin);
    memDc.LineTo(pt[i].cend);
    }
    //将内存设备环境上的图拷贝到屏幕上显示
    pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDc, 0, 0, SRCCOPY);
    //绘图完成后的清理在析构函数
    }
    CTwoBufferView::~CTwoBufferView()
    {
        memBmp.DeleteObject();
        memDc.DeleteDC();
    }