一、概念

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),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d\tWindow Org(%d,%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y); TRACE("%s\n",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),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d)\tWindow Org(%d%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y);
TRACE("%s\n",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\n",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\n",strMsg);
}

发布于CSDN: 2015-05-11

C++ GDI图形设备接口的更多相关文章

  1. 图形设备接口(GDI)

    图形设备接口(GDI,Graphics Device Interface)负责在显示器和打印机上显示图形.GDI 是由几百个函数和一些相关的数据类型.宏和结构构成的.Windows 98/NT 中的图 ...

  2. OSG图形设备接口GraphicsContext

    1.图形设备与相机 在Camera类的成员函数中,setGraphicContext()函数的工作是设置相机对应的图形设备对象,换句话说,下面要介绍的GraphicsContext类就是图形设备对象的 ...

  3. 第四章 Windows的图形设备接口及Windows绘图 P83 4-6

    实验(实习)名称  图形程序设计及其应用  实验(实习)日期 一.实验目的 1.熟悉图形设备接口的概念及其应用. 二.实验内容及步骤  实验任务 1.熟悉基于图形应用的程序设计: 2.掌握刷新技术及其 ...

  4. Windows的图形设备接口与Windows绘图

    本次学习目标 理解DC, 映像模式, 坐标系统, 窗口和视口; 学习获取绘图工具(画笔/画刷)的句柄, 设置颜色, 能定义映像模式; 会使用常用的绘图函数. 编写程序: 在屏幕上出现一个圆心沿正弦曲线 ...

  5. C#多线程及GDI(Day 23)

       又来到了总结知识的时间了,今天又学了一些新的知识,是多线程和GDI的一些运用. 理论: 在学习多线程之前,首先要了解一下什么是进程? 进程:(关键字Process)进程是一个具有一定独立功能的程 ...

  6. 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记1——创建窗口&GDI

    第1章 创建窗口 步骤: 窗口类的设计 窗口类的注册 窗口的正式创建 窗口的显示与更新 消息循环体系 窗口过程函数处理消息 1. 设计:使用WNDCLASSEX结构体,这里注意的是C++中的结构体中的 ...

  7. HANDLE HINSTANCE HWND CWnd CDC

    HANDLE HINSTANCE HWND CWnd CDC 句柄:   柄,把柄 例如一个锅的手柄,你只要抓住了它,你就可以很好地操作那个锅,不过很明显你只能通过锅的手柄来做一些诸如炒菜之类的事,你 ...

  8. MFC学习(七) 单文档程序

    1 MFC单文档程序的主要类 (1)文档类(Document) 即应用程序处理的数据对象,文档一般从 MFC 中 CDocument 中派生.CDocument 类用于相应数据文件的读取以及存储 Cv ...

  9. [译]NeHe教程 - 创建一个OpenGL窗体

    原文: Setting Up An OpenGL Window 欢迎阅读我的OpenGL教程.我是一个热爱OpenGL的普通码农!我第一次听到OpenGL是在3Dfx刚发布他们给Voodoo I显卡的 ...

随机推荐

  1. 201871010132——张潇潇《面向对象程序设计JAVA》第二周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  2. windows 上robot framework 读取sqlite3提示:OperationalError: unable to open database file错误

    原因:路径写的不正确. 正确的写法:'D:/Python27/163/demo.db' 或者 r 'E:\\rf-demos-master\\DatabaseDemo\\demo.db' Connec ...

  3. CF308C-Sereja and Brackets-(线段树+括号匹配)

    题意:给出一段括号,多次询问某个区间内能匹配多少括号. 题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val. 当前结点的val=左儿子的val+右儿子的val+min ...

  4. Python进阶-III 函数装饰器(Wrapper)

    1.引入场景: 检查代码的运行时间 import time def func(): start = time.time() time.sleep(0.12) print('看看我运行了多长时间!') ...

  5. git crate&query&delete tag(九)

    root@vmuer-VirtualBox:/opt/myProject# git log --pretty=oneline0169b7a1c4bccb47e76711f353fd8d3864bde9 ...

  6. Android 开发基础入门篇: Android Studio 导入工程

    最简单的方式 等待加载完就好了

  7. svn Server authz 配置示例(文件夹权限配置)

    [aliases] [groups] admin = jiangzhehao technology = chenlei,liulei,xunzheng,qiaomingjie sales = chen ...

  8. Hadoop集群上搭建Ranger

    There are two types of people in the world. I hate both of them. Hadoop集群上搭建Ranger 在搭建Ranger工程之前,需要完 ...

  9. 二叉树遍历(前序、中序、后序)-Java实现

    一.前序遍历 访问顺序:先根节点,再左子树,最后右子树:上图的访问结果为:GDAFEMHZ. 1)递归实现 public void preOrderTraverse1(TreeNode root) { ...

  10. 规范化使用MySQL

    如何更规范化使用MySQL 如何更规范化使用MySQL 背景:一个平台或系统随着时间的推移和用户量的增多,数据库操作往往会变慢:而在Java应用开发中数据库更是尤为重要,绝大多数情况下数据库的性能决定 ...