zoukankan      html  css  js  c++  java
  • C++ GDI图形设备接口

    一、概念

    1. GDI:(Graphics Device Interfase)图形设备接口,是一个应用程序与输出设备之间的中介。

    一方面,GDI向应用程序提供一个与设备无关的编程环境,另一方面,它又以设备相关的格式和具体的设备打交道。
    2. DC:(Device Context)设备描述表,是一种Windows数据结构。包括了与一个设备的绘制属性相关的信息。所有的绘制操作通过一个设备描述表进行,绘制线条、形状和文本的Windows API 函数都与DC有关。

    二、 在Windows Application程序中画线

    1. 定义两个全局变量用于记录鼠标按下的(x,y)坐标。
           int nOrginX;  int nOrginY;
    2. 响应鼠标按下和鼠标抬起的消息:
           在Swich中加入case WM_LBUTTONDOWN:     

                                   case WM_LBUTTONUP:
    3. 在鼠标按下时记录鼠标按下的(x,y)坐标,查MSDN得知WM_LBUTTONDOWNlParam的低字存放x坐标,高字存放y坐标,将其取出存入nOrginX,nOrginY。
                        case WM_LBUTTONDOWN:  

                                  nOrginX=lParam & 0x0000ffff;  

                                  nOrginY=lParam >> 16 & 0x0000ffff;  

                                  break;

    4. 在鼠标抬起时画线:
                        case WM_LBUTTONUP:  

                                 HDC hdc;  

                                 hdc=GetDC(hwnd);  

                                 PAINTSTRUCT ps; 

                                 ::MoveToEx(hdc,nOrginX,nOrginY,NULL);  

                                 ::LineTo(hdc,LOWORD(lParam),HIWORD(lParam) );  

                                 ::ReleaseDC(hwnd,hdc);

    三、在MFC程序中画线

    1. 在CxxxView中响应鼠标按下和鼠标抬起的消息(因为只有CxxxView中才能接收到鼠标消息):
    使用ClassWizard加入WM_LBUTTONDOWN,WM_LBUTTONUP的消息响应函数OnLButtonDown, OnLButtonUp。
    2. 在CxxxView中添加成员变量CPoint m_ptOrigin,用于记录鼠标按下的(x,y)坐标。
    CPoint是一个用于描述点的简单的类,它有两个成员变量可以存放点的(x,y)坐标。
    3. 在鼠标按下时记录该点的坐标:
    m_ptOrigin =point;

    其中point是调用OnLButtonDown传入的鼠标按下的点的坐标。
    4. 在鼠标抬起时画线:
     CClientDC dc(this);
     dc.MoveTo(m_ptOrigin);  dc.LineTo(point);
    其中CClientDC 是一个CDC的子类,在它的构造函数中调用了GetDC,析构函
    数中调用了ReleaseDC,简化了用户的操作。 

    四、 实现橡皮筋功能

    1.再定义一个成员变量,用于记录鼠标抬起的点,以便擦线。
    CPoint m_ptEnd;
    2. 在鼠标按下时记录该点的坐标:  

    m_ptOrigin=m_ptEnd=point;
    3.使用ClassWizard加入WM_MOUSEMOVE的消息响应函数OnMouseMove。
    在鼠标移动时判断鼠标左鍵是否按下,如果按下,就不断地擦去上一条线,画出鼠标按下点到鼠标移动的当前点之间线。 

    if(MK_LBUTTON & nFlags) 
    { 
    CClientDC dc(this);  
    dc.SetROP2(R2_NOT);  
    dc.MoveTo(m_ptOrigin);  
    dc.LineTo(m_ptEnd);  
    dc.MoveTo(m_ptOrigin); 
    dc.LineTo(point);  
    m_ptEnd=point; 
    }   
    

      

    其中:

    if (MK_LBUTTON & nFlags) 是判断鼠标左鍵是否按下。在调用OnMouseMove时,不仅为用户传来了坐标信息,还把鼠标左鍵是否按下,Shift鍵是否按下(详细信息可查MSDN)等信息放在UINT nFlags中传入OnMouseMove,用户可以检查相应位是否为1来判断相应键是否按下。
    dc.SetROP2(R2_NOT); 该句设置逆转当前屏幕颜色的绘图模式。这种模式下,在屏幕上首次画出的线的是可见的,但在同一位置再画一遍时,线就不见了。这样可以方便的实现不断画线、擦线的效果。

    五、 生成自定义的笔和刷子

    1. Windows的GDI对象:CGDIObject
    (1). CPen :用来画线及绘制有形边框的工具,可以指定它的颜色及宽度,并且可以指定它的线型(实线、点线、虚线等)。  

    (2).CBrush :对区域内部填充颜色。
    (3).CFont :字体是一种具有某种风格和尺寸的所有字符的完整集合。
    (4).CBitmap:位图是一种位矩阵,每一个显示象素都对应于其中的一个或多个位,可以利用位图来表示图象,也可以利用它来创建刷子。
    (5).CRgn :区域是由多边形、椭圆或二者组合形成的一种范围,可以利用它来进行填充、裁剪以及点中测试。 
    当用户生成一个GDI对象时,它是不会生效的。必须用SelectObject将该GDI对象选入设备描述表,它才会在以后的绘制操作中生效。SelectObject函数会返回指向前一次被选对象的指针。

    2 自定义画笔
    CPen 类提供构造函数用于产生Cpen可以定义笔的线型、线宽和颜色。

    CPen( int nPenStyle, int nWidth, COLORREF crColor );

    程序中,生成了一个实线,宽度为6,颜色为黑色的笔。要注意的是,有的线型只在线宽小于1时才有效。 

    CPen newpen(PS_SOLID ,6,RGB(255,0,0));

     dc.SelectObject(&newpen);

    3 自定义刷子:
    CBrush 提供用于产生刷子的构造函数:

    CBrush( COLORREF crColor );

    CBrush( int nIndex, COLORREF crColor );

    CBrush( CBitmap* pBitmap );

    (1). CBrush( COLORREF crColor );

    它可以产生某种颜色的实心刷子,下面的代码产生了一个红色的实心刷子。

    CBrush br(RGB(255,0,0));

    dc.SelectObject(&br);

    (2) CBrush( int nIndex, COLORREF crColor );

    它可以产生某种剖面线的刷子,下面的代码产生了一个红色的剖面线刷子。 CBrush br(HS_FDIAGONAL,RGB(255,0,0));

    dc.SelectObject(&br);

    (3)CBrush( CBitmap* pBitmap );

    它可以产生位图刷子。

     CBitmap bmp;

    bmp.LoadBitmap(IDB_BITMAP1);

    CBrush br(&bmp); 

    dc.SelectObject(&br);

    这段代码首先装入了一幅位图(先在资源中添加一个位图资源,其ID指定为IDB_BITMAP1),再根据这幅位图产生了一个位图刷子。

    六、绘图操作

    CDC类
    在选择了画笔和刷子后就可以利用Windows的作图函数进行作图了

    基本的画线函数有以下几种 

    CDC::MoveTo( int x, int y ); 改变当前点的位置 
    CDC::LineTo( int x, int y ); 画一条由当前点到参数指定点的线 
    CDC::SetPixel(CPoint, CPen);画点
    CDC::BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 画弧线CDC::BOOL Polyline( LPPOINT lpPoints, int nCount ); 将多条线依次序连接 
    
    
    基本的作图函数有以下几种: 
    CDC::BOOL Rectangle( LPCRECT lpRect ); 矩形 
    CDC::RoundRect( LPCRECT lpRect, POINT point ); 圆角矩形 
    CDC::Draw3dRect( int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight ); 3D边框 
    CDC::Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 扇形
    CDC::Ellipse( LPCRECT lpRect ); 椭圆形 
    CDC::Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 
    CDC::Polygon( LPPOINT lpPoints, int nCount ); 多边形。

    对于矩形,圆形或类似的封闭曲线,系统会使用画笔绘制边缘,使用刷子填充内部。如果你不希望填充或是画出边缘,你可以选入空(NULL_PEN)笔或空(NULL_BRUSH)刷子。 在窗口中绘制设备相关位图,图标,设备无关位图。

    在Windows中可以将预先准备好的图像复制到显示区域中,这种内存拷贝执行起来是非常快的。在Windows中提供了两种使用图形拷贝的方法:通过设备相关位图(DDB)和设备无关位图(DIB)。DDB可以用MFC中的CBitmap来表示。通过CDC::BitBlt把内存中绘制图形复制到屏幕上(StretchBlt可以进行缩放) 光栅操作的类型,可取以下值: 

    BLACKNESS 输出区域为黑色 DSTINVERT 反色输出区域

    MERGECOPY 在源和目的间使用AND操作

    MERGEPAINT 在反色后的目的和源间使用OR操作 NOTSRCCOPY 将反色后的源拷贝到目的区 PATINVERT 源和目的间进行XOR操作 SRCAND 源和目的间进行AND操作  SRCCOPY 复制源到目的区

    SRCINVERT 源和目的间进行XOR操作 SRCPAINT 源和目的间进行OR操作 WHITENESS 输出区域为白色  下面用代码演示这种方法:

    CXXXView::OnDraw(CDC* pDC)

     { 

    CDC memDC;//定义一个兼容DC 

    memDC.CreateCompatibleDC(pDC);//创建DC 

    CBitmap bmpDraw; 

    bmpDraw.LoadBitmap(ID_BMP);//装入DDB 

    CBitmap* pbmpOld=memDC.SelectObject(&bmpDraw);//保存原有DDB,并选入新DDB入DC  pDC->BitBlt(0,0,20,20,&memDC,0,0,SRCCOPY);//将源DC中(0,0,20,20)复制到目的DC(0,0,20,20)
    pDC->BitBlt(20,20,40,40,&memDC,0,0,SRCAND);//将源DC中(0,0,20,20)和目的DC(20,20,40,40)区域进行AND操作 

    memDC.SelectObject(pbmpOld);//选入原DDB


    图标的操作
    CWinApp::LoadIcon( UINT nIDResource )或CWinApp::LoadStandardIcon( LPCTSTR lpszIconName ) 装入,用CDC::DrawIcon绘制。用DestroyIconq清除图标 设备无关位图。

    DIB操作
    MFC没有提供DIB操作的类,我们需要自己读取位图文件中的头信息和数据,用StretchDIBits绘制。位图文件结构 JPG PNP GIF 


    BITMAPFILEHEADER结构
    BITMAPINFOHEADER结构
    调色板信息
    数据

    多边形和剪贴区域
    CreateRectRgn 由矩形创建一个多边形  CreateEllipticRgn 由椭圆创建一个多边形 

    CreatePolygonRgn 创建一个有多个点围成的多边形  PtInRegion 某点是否在内部  CombineRgn 两个多边形相并 

    EqualRgn 两个多边形是否相等  

    Windows中的映射模式
    1、Windows定义映射模式的目的,以下几个方面:

    a、不同人的使用习惯。不同国家的,不同地区,以及不同的人因为习惯喜欢用不同的度量单位,有的人人喜欢用英寸,而有的人喜欢用公制中的厘米,毫米等。其他的人又喜欢用另外一些单位。

    b、使软件与硬件向分离开来。让开发的软件能够最大限度的与硬件无关。 c、提供逻辑和物理的一种转换。就相当于银行的利率。

    2、默认的映射模式

    默认的映射模式使MM_TEXT,它使以象素为单位的。X轴向左为正,Y轴向下为正。默认的坐标原点在左上角。

    3、固定比例映射模式固定比例的映射模式有MM_LOMETRIC、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH、MM_TWIPS种。它们默认的坐标原点都使在左上角。其区别在于每一个逻辑单位对应的物理大小不一样。所对用的逻辑单位分别为0.1毫米,0.01毫米,0.01英寸,0.001英寸,1/1440英寸(0.0007英寸)。

    4、可变比例映射模式

    对于可变比例的映射模式用户可以自己定义一个逻辑单位代表的大小,其大小可以任意。也可以让这个大小随环境改变而改变。有MM_ISOTROPIC,MM_ANISOTROPIC这两种映射模式。其逻辑单位的大小等于视口范围和窗口范围的比值。两者的不同在于前者要求X轴和Y轴的度量单位必须相同,而后者没有这样的限制。

    七、Windows中的几种坐标体系

    1、屏幕坐标
    屏幕坐标描述物理设备(显示器、打印机等)的一种坐标体系,坐标原点在屏幕的左上角,X轴向右为正,Y轴向下为正。度量单位是象素。原点、坐标轴方向、度量单位都是不能够改变的。

    2、设备坐标(又称物理坐标)
    设备坐标是描述在屏幕和打印机显示或打印的窗体的一种坐标体系。默认的坐标原点是在其客户区的左上角。X轴向右为正,Y轴向下为正。度量单位为象素。原点和坐标轴方向可以改变,但是度量单位不可以改变。

    3、逻辑坐标
    逻辑坐标是在程序中控制显示,打印使用的坐标体系。该坐标系与定义的映射模式密切相关。默认的映射模式是MM_TEXT。我们可以通过设置不同的映射模式来改变该坐标体系的默认行为。

    例:逻辑坐标和设备坐标之间的转换

    void CMapModeView::OnPaint() 
    {
    CPaintDC dc(this);//获取设备类的设置
    CPoint ptOrgView,ptOrgWindow;
    CSize sizeView,sizeWindow;
    CString strMsg;
    ptOrgView=dc.GetViewportOrg();//获取视口原点
    ptOrgWindow=dc.GetWindowOrg();//获取窗口原点
    sizeView=dc.GetViewportExt();//获取视口范围
    sizeWindow=dc.GetWindowExt();//获取窗口范围
    strMsg.Format(_T("Viewport Extent:(%d,%d),	Viewport Org:(%d,%d)	Window Extent:(%d,%d	Window Org(%d,%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y); TRACE("%s
    ",strMsg); //设置映射模式以及原点
    dc.SetMapMode(MM_TEXT);//设置映射模式
    dc.SetWindowOrg(100,100);//设置窗口的坐标原点
    dc.SetViewportOrg(200,200);//设置视口的坐标原点
    dc.SetWindowExt(5,10);//改语句仅对可变比例映射模式有效
    dc.SetViewportExt(1,1); 
    ptOrgView=dc.GetViewportOrg();
    ptOrgWindow=dc.GetWindowOrg();
    sizeView=dc.GetViewportExt();
    sizeWindow=dc.GetWindowExt();
    strMsg.Format(_T("Viewport Extent:(%d,%d),	Viewport Org:(%d,%d)	Window Extent:(%d,%d)	Window Org(%d%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y);
    TRACE("%s
    ",strMsg);  
    //将点(300,400)从逻辑坐标体系映射到设备坐标体系。
    CPoint ptMap;
    ptMap=CPoint(300,400);
    dc.LPtoDP(&ptMap);
    strMsg.Format(_T("The Orginal Point(In LP):CPoint(300,400),Convert to DP is:CPoint(%d,%d)"), ptMap.x,ptMap.y);
    TRACE("%s
    ",strMsg);
    //将点(300,400)从设备坐标体系映射到逻辑坐标体系 ptMap=CPoint(300,400); dc.DPtoLP(&ptMap); 
    strMsg.Format(_T("The Orginal Point(In DP):CPoint(300,400),Convert to LP is:CPoint(%d%d)"), ptMap.x,ptMap.y);
    TRACE("%s
    ",strMsg);
    }

    发布于CSDN: 2015-05-11

  • 相关阅读:
    ThreadLocal内存泄漏真因探究(转)
    JAVA设计模式工厂模式
    java设计模式单例模式
    Java-Socket
    Java-Queue总结
    Java-Reentrantlock
    Java-Iterator遍历集合
    安装和启动docker
    C# System.Reflection.Assembly动态加载资源文件
    C#调用 kernel32.dll
  • 原文地址:https://www.cnblogs.com/arxive/p/11747990.html
Copyright © 2011-2022 走看看