【原】孙鑫VC教学 第11课 图形的保存和重绘

用户绘制图形:
      窗口重绘,会发送一个WM_PAINT消息,擦除原窗上的消息,重新绘制

    由于所有绘制图形时,所有的图形元素均可概括为几个要素(如:起点,终点,绘制类型等),可通过一个类的对象将所有图形的以上要素保存下来.由于,对象的空间未知,故可用MFC中的一个CObArray的集合类来实现.

    要注意对象与作用域(即{}之间的部分)之间的关系:当对象为局部对象时候,作用域结束时,便会自动调用对象的析构函数. 则需将对象声明为指针对象,然后通过new在堆栈中申请空间,这样对象的生命周期与程序的周期同长(除非手动调用delete)

    OnDraw为一个虚函数,为何重绘消息为WM_PAINT,其响应函数为OnPaint,却会响应虚函数OnDraw?主要是在OnPaint的父类函数调用了OnDraw.

    CPaintDC:是从CDC继承而来的,在构造函数的时候调用CWnd::BeginPaint,析构时候调用CWnd::EndPaint(具体参加MSDN),故声明CPaintDC可直接声明和使用其对象进行操作,相似的还有CClientDC.注意BeginPaint和EndPaint只能被CPaintDC及其子类调用,其他的类只能通过GetDC和ReleaseDC实现.

    在AppWizard中未将CScrollView作为基类函数时实现窗口的滚动功能:

在OnPaint函数中,在调用OnDraw函数之前调用OnPrepareDC,手动将CMyView类中的继承类由CView替换为CScrollView,并通过查找替换所有的CView.通过CScrollView::SetScrollSizes实现

映射模式的转换:(参见MSDN:Coordinate Spaces and Transformation)

坐标空间:

    Win32应用程序设计接口(API)使用四种坐标空间:世界坐标系空间,页面空间,设备空间,和物理设备空间.应用程序通过世界坐标系空间对图形输出进行旋转,斜切或者反射.

Win32API吧世界坐标系空间和页面空间称为逻辑空间;物理设备空间通常指应用程序窗口的客户区,但是它也包括整个桌面,完整的窗口(包括框架,标题栏和菜单栏)或打印机的一页或绘图仪的一页纸.物理设备的尺寸随显示器.打印机或绘图仪所设置的尺寸而变化.

    在图形中要做某个区域的局部放大,可通过设置世界坐标系空间(具体参加MSDN)

页面空间到设备空间的转换:

    页面空间到设备空间的转换是原Windows接口的一部分.这种转换确定与一特定设备描述表相关的所有图形输出的映射方式.

    所谓映射方式是指确定用于绘图操作的单位大小的一种度量转换.映射方式是一种影响几乎任何客户区绘图的设备环境属性.另外还有四种设备环境属性:窗口原点,视口原点,窗口范围,和视口范围,这四种属性与映射方式密切相关.

    页面空间到设备空间的转换所用的是两个矩形的宽与高的比率,其中页面空间中的矩形被称为窗口,设备空间中的矩形被称为视口,Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了这种转换.

    设备空间到物理空间的转换由几个独特之处:它只是限于平移,并由Windows的窗口管理部分控制,这种转换的唯一用途是确保设备空间的原点被映射到物理设备上的适当点上.没有函数能设置这种转换,也没有函数可以获取有关数据.

    一旦应用程序建立了设备描述表,并立即开始调用GDI绘图或输出函数,则运用默认页面空间到设备空间的转换和设备空间到客户区的转换(在应用程序调用SetWorldTransform函数之前,不会出现世界坐标空间到页面空间的转换).

    Windows对所有的消息(如WM_SIZE,WM_MOUSEMOVE,WM_LBUTTONDOWN),所有的非GDI函数和一些GDI函数(如GetDeviceCaps函数),永远使用设备坐标.

继续回到滚动视图的实现:

    可通过虚函数OnInitialUpdate实现(此函数在第一次调用OnDraw函数之前调用),在函数中实现SetScrollSizes函数,具体参见MSDN

注意:在画线的时候,因为GDI的函数使用的是逻辑坐标,而图形在显示的时候,Windows需要将逻辑坐标转换未设备坐标.

    当窗口发生重绘的时候,会调用OnPrepareDC函数,重新设置设备上下文属性,将视口设置未(0,-150)

    为解决窗口重绘之后,发生图形错位的现象,在绘制图形之后,保存坐标点之前,调用OnPrepareDC函数,调整显示上下文的属性,将视口的原点设置为(0,-150),这样窗口的原点也就是逻辑坐标(0,0)将别映射为设备坐标(0,-150),然后调用DPtoLP函数将设备坐标转换为逻辑坐标.

CMetaDC,CMetaDC记录绘图的过程.

    利用兼容DC(CCompatibleDC)保存图形:为了使兼容DC得到当前客户区的大小,可创建兼容位图CCompatibleBitmap

CClientDC dc(this);

if(!m_dcCompatible.m_hDC)

{

    m_dcCompatible.CreateCompatibleDC(&dc);

    CRect rect;

    GetClientDC(&rect);

    CBitmap bitmap;

    bitmap.CreateCompatibleBitmap(&dc,rect.width(),rect.Height());

    m_dcCompatible.SelectObject(&bitmap);

    m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);

}

dc.Ellipse(&rect);

CMyView::OnDraw(...)

{

   CRect rect;

   GetClientDC(&rect);

  

}

    由于CreateCompatibleBitmap返回的位图对象只包含相应设备描述表中的位图信息头,不包含颜色表和象素数据块.因此,选入该位图对象的设备描述表不能像选入普通位图对象的设备描述表一样应用,必须在SelectObject函数之后,调用BitBlt将原始设备描述表的颜色表及象素数据块拷贝到兼容设备描述表.

你可能感兴趣的:(VC)