1。由于每次调用OnMouseMove函数都绘制一个椭圆,如何清除前面绘制的椭圆只保留最后一次画的椭圆呢?
2。另外如何使椭圆内部填充色为无色以便不遮盖背景?谢谢!

解决方案 »

  1.   

    1. Invalidate2.NULL_BRUSH or HOLLOW_BRUSH
      

  2.   

    1.绘制之前执行清除背景
     RedrawWindow();
     Invalidate(0);2.你不填充颜色不就是无色吗(看你用什么函数绘制椭圆的)
      

  3.   

    用CRgn::CreateRoundRectRgn来绘制是不填充的
      

  4.   

    zhucde:本人使用Ellipse绘制椭圆。如何使内部不填充颜色呢?
      

  5.   

    dc.SelectObject(::GetStockObject(NULL_BRUSH)); 
    或者:
    dc.SelectStockObject(NULL_BRUSH);//选入空刷子
    ....
    dc.Ellipse(10,10,200,200);
      

  6.   

    画刷,2.NULL_BRUSH  or  HOLLOW_BRUSH
      

  7.   

    是呀,CPen用来画线,CBrush用来填充,如果你不像填充图形。可以将当前设备环境的刷子设为
    NULL_BRUSH方法就是:pDC->SelectStockObject(NULL_BRUSH);
    //pDC 为当前设备环境的指针
      

  8.   

    谢谢各位!
    我的第二个问题已经解决了。
    可是第一个问题还没解决:
    由于每次调用OnMouseMove函数都绘制一个椭圆,如何清除前面绘制的椭圆只保留最后一次画的椭圆呢?
      

  9.   


    调用Invalidate();CWnd::Invalidate
    void Invalidate( BOOL bErase = TRUE );ParametersbEraseSpecifies whether the background within the update region is to be erased.
      

  10.   

    鼠标消息中不要绘制,将点的信息保存后刷新(Invalidate(TRUE)或者InvalidateRect),在OnDraw中绘制。这样可能导致闪烁,解决方法是双缓冲。
      

  11.   

    有一点不清楚,麻烦各位高手解释一下:
    1。OnPaint 函数的执行是靠什么来驱动的?是不是每个很短的时间自动调用的?
    2。如果给InvalidateRec函数制定某一个Rec,它是通过调用OnPaint来刷新这个Rec的吗?
       执行InvalidateRec之后是不是就执行OnPaint呢?谢谢!
      

  12.   

    还真是挺麻烦的。Mackz(在相互) 的点子,你要好好分析一下。
    画椭圆无外乎就是两点,而鼠标点上的时候,这是一个起始点。记录下来。 当鼠标移动的时候,记录当前点。然后调用invalidata(), 这样会自动触发ondraw,然后再ondraw中 利用这两点画椭圆。
      

  13.   

    1。OnPaint 函数的执行是靠什么来驱动的?是不是每个很短的时间自动调用的?
    //不是,OnPaint是在窗体变化的时候由于发送了WM_PAINT才发生OnPaint的,比如移动窗体,有窗体从上面移动过,或者最大最小化等等。
    2。如果给InvalidateRec函数制定某一个Rec,它是通过调用OnPaint来刷新这个Rec的吗?
       执行InvalidateRec之后是不是就执行OnPaint呢?
    //InvalidateRec就是让OnPaint刷新这一个局部,不会对整个窗体重绘。
    //InvalidateRec相当于传递一个矩形和一个WM_PAINT消息。
      

  14.   

    把代码发给你:http://blog.csdn.net/precipitant/archive/2006/09/17/1232563.aspx
      

  15.   

    非常感谢wf520pb!!也感谢塞北的雪,不过我现在的问题不是不会画椭圆不过第二个问题还有一点疑问:
    你说:InvalidateRec相当于传递一个矩形和一个WM_PAINT消息。也就是调用InvalidateRec之后就执行OnPaint,可是我在OnPaint函数中有绘制其他区域的代码,那不也就把其他区域也刷新了吗?另外,OnPaint函数并没有要绘制的矩形这样一个参数啊?是无参函数谢谢!
      

  16.   

    wf520pb怎么不来回答呢?塞北的雪:恕我愚昧,你说的我不知所云啊,GetUpdateRect
      

  17.   

    最后一个问题:InvalidateRec与OnPaint函数在执行时的关系
      

  18.   

    搞定这个问题就结帖了:如何只刷新窗体的某一个区域而不刷新其他呢?由于我的所有绘制代码都在OnPaint中,如何让他们互不影响呢?希望有同志来回答,实在没有人回答的话,我也会按时结帖,把分数给大家。
      

  19.   

    The invalidated areas accumulate in the update region until the region is processed when the next WM_PAINT message occurs or until the region is validated by using the ValidateRect or ValidateRgn function. The system sends a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window. 
      

  20.   

    假设你是在OnLButtonUp里画图:
    void CXXX::OnLButtonUp()
    {
    // 先刷
    InvalidateRect();
    // 再画
    DrawEllipse();
    }
    参数省略
      

  21.   

    这个帖子比较热门啊,看下来发现搂主对于GDI机制还是不很了解,其实一般入门的书都会提到:WM_PAINT消息中,需要通过BeginPaint/EndPaint来取得一个绘图结构PAINTSTRUCT,这里面就包含了无效区域,也就是InvalidateRect里面的矩形。
    但是由于WM_PAINT消息是系统发送的,不是简单的在Invalidate之后就会有WM_PAINT消息,如果连续发送多个Invalidate或者InvalidateRect,可能只会有一个WM_PAINT消息,因此无效矩形是通过计算后包含了最大的无效区域。还有一个函数GetClipRgn,可以更精确地得到无效区域。
    GDI本身具有的优化使得你在无效矩形之外绘制的图形不会显示出来,但是绘制的代码还是运行了,所以为了提高绘制效率,可以在绘制之前判断是否在无效矩形里面,以决定是否重新绘制。下面给个例子说明“在无效矩形之外绘制的图形不会显示出来”:
    视图类中建立一个成员变量,初始化为FALSE:
    BOOL m_bUpdate;
    建立一个菜单项Test,在视图中响应:
    void C...View::OnTest()
    {
    // TODO: 在此添加命令处理程序代码
    m_bUpdate = TRUE;
    InvalidateRect(CRect(100, 100, 130, 130));}
    在OnDraw中:
    void C...View::OnDraw(CDC* pDC)
    {
    C...Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
    return; // TODO: 在此处为本机数据添加绘制代码
    pDC->FillSolidRect(0, 0, 200, 200, RGB(100, 100, 100));
    if (m_bUpdate)
    {
    pDC->Ellipse(90, 90, 150, 150);
    }
    }你会看到,点击菜单后,灰色背景中是一个白色矩形而不是圆形。然后如果你改变窗口大小,或者切换窗口,那么就会变成灰色背景中一个白色圆形,因为这时候系统刷新了窗口区域,整个客户区都无效了。
      

  22.   

    非常感谢Mackz详细的讲解!正是我所需要的答案。晚上回去想想,要下班了。
      

  23.   

    实在对不起这几天出差没过来看。
    我感觉有那么点儿意思,但是恕我愚昧还没看懂。
    1。你说“GDI本身具有的优化使得你在无效矩形之外绘制的图形不会显示出来,但是绘制的代码还是运行了”,这样说来,刷新局部跟刷新整个客户区域还是没什么区别啊。当你点击Test之后,m_bUpdate = TRUE;以后刷新整个客户区还是执行了绘制椭圆的代码啊
    2。我碰到一个与之有关的问题:有两个矩形区域,比如(0,0,50,50)和(100,0,150,50),里面都绘制有东西,当用Invalidate刷新第一个区域时,对第二个区域没有影响(只有第一个区域有闪烁),但是当刷新第二个区域时,第一个区域也有闪烁。我发现刷新的时候似乎是按照从客户区的左上角沿x、y方向刷新的,由于第二个区域的x坐标比第一个大,刷新它时必然要先刷新它前面的区域,是这样吗?非常感谢Mackz!!!
      

  24.   

    1 是的,我的意思就是这样,这只是个例子说明问题,绘制椭圆的代码无论是否刷新整个客区,在m_bUpdate为TRUE之后都是执行了的,但是在局部刷新的时候,只有被刷新的矩形部分更新了显示,刷新矩形之外的区域没有更新显示;
    2 不是的。如果你明白了我的例子,应该可以理解这一点。
      

  25.   

    Mackz:
    我在这儿等着你回来,等着你回来,把那问题解 ^_^
      

  26.   

    你想要的就是橡皮筋效果,在交互式程序设计里必倍的技术,源码你在网上搜一下就有,我只说个大概的思路:
    首先你用了某一种颜色画前一个椭圆,记录这个椭圆的位置.
    然后你在第2次画的时候需要画2个椭圆.
    先把画笔改为反色绘制,pDC->SetROP2(R2_NOT); 然后在记录的位置绘制一个椭圆,这时你绘制的椭圆会和背景色一致,巧妙的覆盖了你前面画出来的椭圆.
    然后你再在新的坐标绘制一个你需要的椭圆就行了.
      

  27.   

    其实刷新的问题,楼上的都说清除了,你如果还是不能理解,请多写下这方面的程序,然后结合<<Windows程序设计>><<Windows图像编程>>就可以了.而且要了解这些知识,最直接有效的就是查看MSDN和里面提供的范例.
      

  28.   

    这么给你说,刷新整个区域和刷新局部区域,如果你在OnDraw函数内的绘制代码,不加判断的话,是没有任何区别的.他默认只对windows自己的控件有优化效果.为了提高程序的执行效率,你应该在代码开始处调用pDC->GetClipBox(rect);
    然后,凡是你绘制的东西的边界矩形和这个rect相交的,就绘制,不相交的,不用理会.
      

  29.   

    LiveALearn(研究GDI),你的GDI研究的很牛啊!谢了
    我试试看吧
    你说的“代码开始处调用pDC->GetClipBox(rect)”是在InvalidateRec后还是在OnPaint的开始处?
    还有,如何解释这个现象呢:我碰到一个与之有关的问题——有两个矩形区域,比如(0,0,50,50)和(100,0,150,50),里面都绘制有东西,当用Invalidate刷新第一个区域时,对第二个区域没有影响(只有第一个区域有闪烁),但是当刷新第二个区域时,第一个区域也有闪烁。我发现刷新的时候似乎是按照从客户区的左上角沿x、y方向刷新的,由于第二个区域的x坐标比第一个大,刷新它时必然要先刷新它前面的区域,请问是这样吗?
      

  30.   

    刷新矩形之外的区域没有更新显示,就是这样,上面这个GDI兄请运行我的例子试试。这就是GDI的内部优化的作用。
      

  31.   

    pDC->GetClipBox(rect);是在OnPaint的开始处进行调用.Mackz(在相互)说的是在刷新时GDI内部的优化作用,但是你忽略了一点.我们绘制的矢量图单元往往不是一句pDC->Ellipse();就完了.而且当界面上出现了大量的矢量图单元时,依赖GDI自身的优化无意义.正确的优化方法应该是和当前刷新矩形相交的地方,执行绘制代码,不相交的地方,多余代码坚决不执行.(这在大型矢量图无极缩放的时候效果明显)
      

  32.   

    那么请问如何解释下面的现象(没有使用pDC->GetClipBox(rect)):有两个矩形区域,比如(0,0,50,50)和(100,0,150,50),里面都绘制有东西,当用Invalidate刷新第一个区域时,对第二个区域没有影响(只有第一个区域有闪烁),但是当刷新第二个区域时,第一个区域也有闪烁。注意这两个区域的位置关系是:第二个区域在第一个区域的右边如果像你说的那样,刷新第一个区域时也会导致第二个区域闪烁。因为第一个区域的绘制代码也执行了。可是为什么不是这样的呢?这个是我在程序中看到的现象
      

  33.   

    GDI同志说的没错,我这个例子说明的是GDI内部有优化,不是说自己不要优化,我上面也说到:所以为了提高绘制效率,可以在绘制之前判断是否在无效矩形里面,以决定是否重新绘制。
      

  34.   

    非常感谢两位的热心。代码:
    void CMatchDlg::OnMouseMove(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    if(rbuttondown)//右键按下
    {
    CRect rc2(281, 560, 591, 670);
    CRect rc3(641, 560, 951, 670);
    InvalidateRect(rc2, TRUE);
    InvalidateRect(rc3, TRUE);
    }
    CDialog::OnMouseMove(nFlags, point);
    }
    我删掉了中间一些不重要的代码。大致是这样
    麻烦分析一下原因
      

  35.   

    Mackz(在相互)同志,你说帮我看代码,我在等你哦
    等到秋风起,秋叶落成堆。