17.3 应用序列化
要在Sketcher应用程序中实现序列化,必须在CSketcherDoc类中实现Serialize()函数,以便这个函数可以处理该类的所有数据成员。对于指定可能要包括在文档中的对象的每个类,都需要添加序列化。开始在应用程序类中添加序列化之前,应当对Sketcher程序做一些小的修改,以记录用户对草图文档所做的修改。虽然这并非完全必要,但是强烈建议这样做,因为这能够防止程序在没有保存修改的情况下关闭文档。
17.3.1 记录文档修改(1)
已经有一种机制用于记录文档的修改;它使用CSketcherDoc的一个继承成员SetModifiedFlag()。每次修改文档时都调用这个函数,可以把文档已被修改的事实记录在文档类对象的数据成员中。如果试图在没有保存已修改文档的情况下退出应用程序,就会自动显示一个提示消息。SetModifiedFlag()函数的参数是一个BOOL型的值,默认值是TRUE。如果偶尔要说明文档未被修改,那么可以用参数FALSE调用这个函数。
修改文档对象中草图的情况只有4种:
调用CSketcherDoc的成员AddElement()添加新元素。
调用CSketcherDoc的成员DeleteElement()删除元素。
调用文档对象的SendToBack()函数
移动元素。
这4种情况都容易处理。需要做的仅仅是针对这些操作中所涉及的每个函数添加对SetModified- Flag()的调用。AddElement()的定义出现在CSketcherDoc类定义中。可以把这个定义扩展为:
- void AddElement(std::shared_ptr<CElement>& pElement) // Add an element to the list
- {
- m_Sketch.push_back(pElement);
- UpdateAllViews(nullptr, 0, pElement.get()); // Tell all the views
- SetModifiedFlag(); // Set the modified flag
- }
DeleteElement()函数的定义也在CSketcherDoc定义中。应当在这个定义中添加一行如下所示的代码:
- void DeleteElement(std::shared_ptr<CElement>& pElement)
- {
- m_Sketch.remove(pElement);
- UpdateAllViews(nullptr, 0, pElement.get()); // Tell all the views
- SetModifiedFlag(); // Set the modified flag
- }
SendToBack()函数也需要添加这行代码:
- void SendToBack(std::shared_ptr<CElement>& pElement)
- {
- if(pElement)
- {
- m_Sketch.remove(pElement); // Remove the element from the list
- m_Sketch.push_back(pElement); // Put a copy at the end of the list
- SetModifiedFlag(); // Set the modified flag
- }
- }
在视图对象中,移动元素的操作出现在由WM_MOUSEMOVE消息处理程序调用的MoveElement()成员中,但是只有在按下鼠标左按钮时才能修改文档。如果右击鼠标,那么元素将返回其原来的位置,所以只需要在OnLButtonDown()函数中添加对文档的SetModifiedFlag()函数的调用,如下所示:
- void CSketcherView::OnLButtonDown(UINT nFlags, CPoint point)
- {
- CClientDC aDC(this); // Create a device context
- OnPrepareDC(&aDC); // Get origin adjusted
- aDC.DPtoLP(&point); // convert point to Logical
- CSketcherDoc* pDoc = GetDocument(); // Get a document pointer
- if(m_MoveMode)
- { // In moving mode, so drop the element
- m_MoveMode = false; // Kill move mode
- auto pElement(m_pSelected); // Store selected address
- m_pSelected = nullptr; // De-select the element
- pDoc->UpdateAllViews(nullptr, 0, pElement.get()); // Redraw all the views
- pDoc->SetModifiedFlag(); // Set the modified flag
- }
- // Rest of the function as before...
- }