看完了《Microsoft Visual C++ windows applications by example 》第一个例子,做下总结。
今天的感想:(1)CObject很好很强大。(2)MSDN上的解释是很好的,不过貌似英文转成中文再加上自己的理解就完全不对了。-_-! (3) GDI容易资源泄漏,以后得看看GDI+
//*********************************************************************
1. 在《Microsoft Visual C++ windows applications by example 》pdf第128页的例子(在RingView.cpp中为View添加消息映射和处理)中:
光标必须指在MESSAGEMAP代码段(BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间),代码属性窗口才会出现“消息”选项。
2. 虚拟键码VK_PRIOR对应的是PAGEUP而不是向上方向键, (向上键是VK_UP)。同样VK_NEXT对应的是PAGEDOWN。
3. Ring程序中使用的是MDI,在编辑Menu资源时有IDR_MAINFRAME和IDR_RINGTYPE两个默认的MENU,其中IDR_RINGTYPE才是ringview对应的子窗口所对应的menu,应该修改这个menu。如果在IDR_MAINFRAME上修改是不对的。
4. 资源编辑器中的toolbar的按钮图标之间的分隔符:最后一个按钮图标是新建按钮图标的位置(类似于MENU编辑器),选中那个按钮图标后即可用画笔等工具对图标进行修改。将按钮图标用鼠标左键向右拖动大约半个图标的距离即可在图表前面添加一个分隔符,向左拖动则可将原有分隔符去掉。
5. Menu item前面的小圆点(radio)是通过响应该menu item的UPDATE_COMMAND_UI事件进行设置的,通过回调函数参数*pCmdUI调用SetRadio方法:pCmdUI->SetRadio(BOOL)
6. 为按钮添加消息处理函数的两种方法:(1)在资源编辑器中右键对应的按钮选择“添加消息处理函数”,选择消息处理函数所在的类(如doc类)。 (2)手动在MESSAGEMAP代码段的代码属性中添加对特定的按钮资源ID的COMMAND消息的响应。
7. 创建了CPen和CBrush等CGdiObject对象后绘画时应将其选入DC:
pDC->selectobject(&pen);
pDC->selectobject(&brush);
如果想用空画笔或空画刷则选中NULL_BRUSH(相当于HOLLOW——BRUSH)和NULL_PEN。
CObject的析构函数是纯虚函数;virtual ~CObject() = 0;
CGdiObject直接派生于CObject,其中有BOOL CGdiObject::DelectObject()方法用于释放资源。但是为保证资源释放成功GDI对象必须不被DC选中,所以使用GDI对象后应该将其选出DC。
有人说:“CBrush,CPen,CFont,CBitmap都是从CGdiObject类派生的,CGdiObject的析构函数中会调用DeleteObject,所以在对象销毁前自己用代码DeleteObject是多余的。”还有人说,“用CPen::CreatePen()来初始化的才需要”??
MSDN中相关的的说明:
对于CPen的说明
When an application no longer requires a given pen, it should call the CGdiObject::DeleteObject member function or destroy the CPen object so the resource is no longer in use. An application should not delete a pen when the pen is selected in a device context.
我的理解是:“在程序中,类似CPen这样的对象在不用的时候应该手动调用CGdiObject::DeleteObject来释放资源。”
MSDN对于CGdiObject::DeleteObject()的说明:
CGdiObject::DeleteObject() Deletes the attached Windows GDI object from memory by freeing all system storage associated with the Windows GDI object. The storage associated with the CGdiObject object is not affected by this call. An application should not call DeleteObject on a CGdiObject object that is currently selected into a device context.
When a pattern brush is deleted, the bitmap associated with the brush is not deleted. The bitmap must be deleted independently.
我的理解:”该函数作用是释放资源,但是不会改变资源内存的内容。不要在资源被选入DC时调用。”
以此,合理的做法如下:
void CRingView::OnDraw(CDC* pDC)
{
CRingDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
PointArray& pointArray = pDoc->GetPointArray();
ColorArray& colorArray = pDoc->GetColorArray();
int iSize = (int)pointArray.GetSize();
for (int iIndex = 0; iIndex<iSize; ++iIndex)
{
CPoint point = pointArray[iIndex];
COLORREF color = colorArray[iIndex];
CPen pen(PS_SOLID,0,BLACK);
CBrush brush(color);
//将临时的CPen和CBrush选入DC,通过返回值保存原来的GDI对象
CPen* pOldPen = pDC->SelectObject(&pen);
CBrush* pOldBrush = pDC->SelectObject(&brush);
//使用含有pen和brush的DC进行画图
pDC->Ellipse(point.x-RADIUS,point.y-RADIUS,point.x+RADIUS,point.y+RADIUS);
//重新载入原来的GDI对象使得临时GDI对象不再被引用而可以销毁
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
//调用DeleteObject释放pen和brush的资源
pen.DeleteObject();
brush.DeleteObject();
}
}
最后一点:为了避免临时资源的频繁创建和释放,可以改成全局资源,在程序销毁时统一释放。
PS: 去VC目录里翻了下MFC源代码WinGDI.cpp,当中只有DeleteObject的定义,并没有析构函数的定义。AFXWIN.H中也仅仅是有声明没定义。貌似MFC的源码是半开源的?有人能找到~CGdiObject()的函数体吗?Help!!!