zoukankan      html  css  js  c++  java
  • mFC 橡皮线

    一般都用GDI实现:

    void CXiangpijinView::OnMouseMove(UINT nFlags, CPoint point) 
    {
        // TODO: Add your message handler code here and/or call default
        
        CView::OnMouseMove(nFlags, point);
        if (Lbrndown)
        {
    
    
              CClientDC dc(this);
             int oldmode=dc.SetROP2(R2_NOTXORPEN);
             CPen pen(PS_SOLID, 2.0, RGB(255,0,0)), *oldpen;
             oldpen = dc.SelectObject(&pen);
             
             dc.MoveTo(m_ptOrigin);
             dc.LineTo(m_ptEnd);
             
             m_ptEnd=point;
             
             dc.MoveTo(m_ptOrigin);
             dc.LineTo(m_ptEnd);
             
             dc.SelectObject(oldpen);
             dc.SetROP2(oldmode);
             ReleaseDC(&dc);
            
    
        }
        
    }
    
    void CXiangpijinView::OnLButtonDown(UINT nFlags, CPoint point) 
    {
        // TODO: Add your message handler code here and/or call default
        
        CView::OnLButtonDown(nFlags, point);
        Lbrndown=true;
        m_ptOrigin = m_ptEnd = point; 
    }

    主要得益于GDI支持SetROP2,绘图模式。

    nDrawMode Specifies the new drawing mode. It can be any of the following values:

    R2_BLACK   Pixel is always black.

    R2_WHITE   Pixel is always white.

    R2_NOP   Pixel remains unchanged.

    R2_NOT   Pixel is the inverse of the screen color.

    R2_COPYPEN   Pixel is the pen color.

    R2_NOTCOPYPEN   Pixel is the inverse of the pen color.

    R2_MERGEPENNOT   Pixel is a combination of the pen color and the inverse of the screen color (final pixel = (NOT screen pixel) OR pen).

    R2_MASKPENNOT   Pixel is a combination of the colors common to both the pen and the inverse of the screen (final pixel = (NOT screen pixel) AND pen).

    R2_MERGENOTPEN   Pixel is a combination of the screen color and the inverse of the pen color (final pixel = (NOT pen) OR screen pixel).

    R2_MASKNOTPEN   Pixel is a combination of the colors common to both the screen and the inverse of the pen (final pixel = (NOT pen) AND screen pixel).

    R2_MERGEPEN   Pixel is a combination of the pen color and the screen color (final pixel = pen OR screen pixel).

    R2_NOTMERGEPEN   Pixel is the inverse of the R2_MERGEPEN color (final pixel = NOT(pen OR screen pixel)).

    R2_MASKPEN   Pixel is a combination of the colors common to both the pen and the screen (final pixel = pen AND screen pixel).

    R2_NOTMASKPEN   Pixel is the inverse of the R2_MASKPEN color (final pixel = NOT(pen AND screen pixel)).

    R2_XORPEN   Pixel is a combination of the colors that are in the pen or in the screen, but not in both (final pixel = pen XOR screen pixel).

    R2_NOTXORPEN   Pixel is the inverse of the R2_XORPEN color (final pixel = NOT(pen XOR screen pixel)).

    原理:R2_NOTXORPEN画出来的颜色与R2_XORPEN相反,R2_XORPEN是屏幕颜色和画笔颜色的异或。OnMouseMove第一次被调用时,还没画线,所以屏幕的颜色是白色的,R2_XORPEN是当前画笔的颜色取反,那么R2_NOTXORPEN就是当前画笔颜色了。就是说第一次画的线是画笔的颜色。

    第二次调用OnMouseMove时,m_ptOrigin和m_ptEnd两个点还没变,所以可以用这两个点再画线,将第一次画的线覆盖掉,变成画布的颜色,然后在新的point点和m_ptOrigin之间重新画线,颜色为画笔颜色。在旧的直线上面画线,因为线本来有颜色,所以R2_XORPEN(屏幕的颜色==画笔颜色)就会变成黑色(1 xor 1=0,0 xor 0=0),取反,即R2_NOTXORPEN为白色,就是画布的颜色,看起来就像消失了一样,其实只不过是线变成白色了(如果画笔不是白色,比如使用你系统设置了护眼配色,客户区变成不伤眼的浅绿色,这样显示出来的颜色还是白色,而不是客户区的颜色)。旧的直线删除了,就可以在新的点point上再次画线了。

    注意:如果背景色是白色,那么画出来的线就是画笔的颜色,如果不是白色,线的颜色为笔色与屏幕颜色异或再取反的颜色。

    同理只需替换绘图函数就可可以实现矩形、椭圆的橡皮筋效果。

    而GDI+不支持SetRop2,

    好像说是因为SetRop2只针对光栅,而GDI+不只是用于光栅,要支持打印机等原因。不懂。

    一般来说,新的库应该有方法来取代SetRopt2原来的功能。

    这就使得画橡皮条非常困难,网上提供了一些方法以及问题:

    1/ 使用DllImport,导入SetRop2  : 结合GDI绘图,这违背了GDI+删去SetRop2的本意。

    2/ 更新从起始点到结束点的整个块状区域 : 我觉得为了一条线而刷新整个区域是很愚蠢的事情,虽然可以使用双缓冲等等技术

    3/ 使用一个ErasePen和一个DrawPen,ErasePen和背景同色 : 这个方法很有问题,当和其他线条相交时会擦去原来的线条

    不知道为什么要把SetRop2去掉。

    我自己实现的使用双缓冲来实现橡皮条

    void CXiangpijinView::OnDraw(CDC* pDC)
    {
        CXiangpijinDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        // TODO: add draw code for native data here
    
        GetClientRect(&rc);
        Graphics Gp(pDC->m_hDC);
        SolidBrush mybrush(Color( 135 ,135,135));
        Gp.FillRectangle(&mybrush,0,0,rc.Width(),rc.Height());
        Gp.ReleaseHDC(hMemDC);
        
        HBITMAP hBitmap,hOldBitmap;    
        //建立一个屏幕设备环境句柄    
        hMemDC=CreateCompatibleDC(pDC->m_hDC);
        //建立一个与屏幕设备环境句柄兼容、与鼠标指针所在窗口的区域等大的位图
        hBitmap=CreateCompatibleBitmap(pDC->m_hDC,rc.Width(),rc.Height());
        //把新位图选到内存设备描述表中
        hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);
        //把屏幕设备描述表拷贝到内存设备描述表中    
        BitBlt(hMemDC,0,0,rc.Width(),rc.Height(),pDC->m_hDC,0,0,SRCCOPY);
    
    }
    void CXiangpijinView::OnMouseMove(UINT nFlags, CPoint point) 
    {
        // TODO: Add your message handler code here and/or call default
        
        CView::OnMouseMove(nFlags, point);
        if (Lbrndown)
        {
    
    
            BitBlt(GetDC()->m_hDC,0,0,rc.Width(),rc.Height(),hMemDC,0,0,SRCCOPY);
       Graphics Gp3(GetDC()->m_hDC);
            Pen mypen(Color(0,255,0),2.0);
       Gp3.DrawLine(&mypen,m_ptOrigin.x,m_ptOrigin.y,point.x,point.y);  
         Gp3.ReleaseHDC(GetDC()->m_hDC);
    } } void CXiangpijinView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CView::OnLButtonDown(nFlags, point); Lbrndown=true; m_ptOrigin = m_ptEnd = point; } void CXiangpijinView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CView::OnLButtonUp(nFlags, point); //把新的DC拷贝到hMemDC BitBlt(hMemDC,0,0,rc.Width(),rc.Height(),GetDC()->m_hDC,0,0,SRCCOPY); }

    主要原理是绘图前把屏幕DC内容拷贝到兼容的内存位图中,绘图时把兼容dC 上的内容拷贝到屏幕,然后在在当前DC上绘图,一次绘制结束再把 DC上拷贝到兼容DC上。


    常用绘图操作

     m_map = new Bitmap(rc.Width(),rc.Height());  

    Pen mypen(Color(0,255,0),2.0);  

    m_Gpp = new Graphics(m_map);  

    m_Gpp->DrawEllipse(&mypen,po.X,po.Y,8.0,8.0);

    Graphics Gp3(GetDC()->m_hDC);  

    Gp3.DrawImage(m_map,0,0);

     Gp3.ReleaseHDC(GetDC()->m_hDC);

  • 相关阅读:
    ArcGIS Engine常用网址
    【转载】C# 跨线程调用控件
    win7电脑更新显卡不兼容,造成电脑开机黑屏
    js 字符串时间比较大小
    jquery 实现 table搜索功能
    php抓取网页数据遇到的问题
    php根据修改时间删除指定目录下文件
    ubuntu18.10安装redis遇到问题
    DEV通过FindFilterText自动检索gridview内容
    dev gridview 设置分组
  • 原文地址:https://www.cnblogs.com/Yogurshine/p/3729787.html
Copyright © 2011-2022 走看看