Windows 中绘图以及Windows 的图形设备接口(GDI )
图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏幕输出。GDI负责Windows的所有图形输出,包括屏幕上输出像素、在打印机上输出硬拷贝以及绘制Windows用户界面。
应用程序可以使用GDI创建三种类型的图形输出:矢量输出、光栅图形输出和文本输出。
矢量图形输出
矢量图形输出指的是创建线条和填充图形,包括点、直线、曲线、多边形、扇形和矩形的绘制。
光栅输出
光栅图形的输出是指光栅图形函数对以位图形式存储的数据进行操作,它包括各种位图和图标的输出。在屏幕上表现为对若干行和列的像素的操作,在打印机上则是若干行和列的点阵的输出。
光栅图形输出的优点是速度很快,它是直接从内存到显存的拷贝操作。缺点是需要额外的内存空间。Windows在绘制界面时使用了大量的光栅输出。
文本输出
与DOS字符方式下的输出不同,Windows是按图形方式输出的。这样,在输出文本时,必须以逻辑坐标为单位计算文本的输出位置,而不是象DOS下以文本行为单位输出文本。这比DOS下的文本输出要难一些。
MFC中与GDI有关的类
为了支持GDI绘图,MFC提供了两种重要的类:设备上下文类,用于设置绘图属性和绘制图形;绘图对象类,封装了各种GDI绘图对象,包括画笔、刷子、字体、位图、调色板和区域。
设备上下文类
设备上下文类包括CDC和它的派生类CClientDC、CPaintDC、CWindowDC、CmeteFileDC。
CDC是设备上下文类的基类,除了一般的窗口显示外,还用于基于桌面的全屏幕绘制和非屏幕显示的打印机输出。CDC类封装了所有图形输出函数,包括矢量、光栅和文本输出。
CPaintDC用于响应窗口重绘消息(WM_PAINT)是的绘图输出。CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。CPaintDC也只能用在WM_PAINT消息处理之中。
CWindowDC用于窗口客户区和非客户区(包括窗口边框、标题栏、控制按钮等)的绘制。除非要自己绘制窗口边框和按钮(如一些CD播放程序等),否则一般不用它。
CmeteFileDC专门用于图元文件的绘制。图元文件记录一组GDI命令,可以通过这一组GDI命令重建图形输出。使用CmeteFileDC时,所有的图形输出命令会自动记录到一个与CmeteFileDC相关的图元文件中。
图形对象类
图形对象类包括CGdiObject、画笔、刷子、字体、位图、调色板、区域等。CGdiObject是图形对象类的基类,但该类不能直接为应用程序所使用。要使用GDI对象,必须使用它的派生类:画笔、刷子、字体、位图、区域等等。
使用图形对象要注意两点:
1.同其他MFC对象一样,GDI对象的创建也要分为两步:第一步,是定义一个GDI绘图对象类的实例;第二步调用该对象的创建方法真正创建对象。
2.创建对象:使用该对象,首先要调用CDC::SelectObject()将它选入到设备上下文中,同时保存原来的设置到一个GDI对象指针比如说pOldObject中。在使用完后,再用SelectObject(pOldObject)恢复原来的设置。但是,如果该设备上下文是用户自己创建的,则不必恢复原来设置,因为框架会在该设备上下文生存期结束时删除该设备上下文,同时也就删除了原来存放于该设备上下文中的绘图对象设置。
访问当前活动视图和活动文档
对于SDI程序,主框架窗口就是文档框窗,可以采用以下方法取得当前文档和视图:
取得活动文档:
CMyDocument* pDoc;
pDoc=(CMyDocument*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)
->GetActiveDocument();
或
pDoc=(CMyDocument*)((CFrameWnd*)AfxGetMainWnd());
这两者是等效的。
取得活动视图:
CMyView* pView;
pView=(CMyView*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveView();
对于MDI程序,由于子窗口才是文档框窗,因此首先要用GetActiveFrame()取得活动子框架窗口,然后通过该子窗口获取活动文档和视图:
CMDIChildWnd* pChild=(CMDIChildWnd*)((CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveFrame();
取得活动文档:
CMyDocument* pDoc=pChild->GetActiveDocument();
CMyView* pView=(CMyView*)pChild->GetActiveView();
可以把上述函数片段做成静态成员函数,比如:
static CMyDocument::GetCurrentDoc()
{
CMDIChildWnd* pChild=(CMDIChildWnd*)((CFrameWnd*)AfxGetApp()- >m_pMainWnd)->GetActiveFrame();
CMyDocument* pDoc=pChild->GetActiveDocument();
}
这样就可以通过以下方式取得活动文档(或视图):
CMyDocument::GetCurrentDoc();
注:静态成员函数调用时不需要一个具体的对象与之相关联。