ReleaseCapture();//прекратить перехват сообщений от мыши
if (m_pTempElement)
{
delete m_pTempElement;
m_pTempElement=nullptr;
}
33. Проверьте работу программы.
34. Ответьте на контрольные вопросы и подготовьте отчет по работе.
Контрольные вопросы
1. Назначение функции SETROP2.
2. Назначение параметра nFlags обработчика события WM_ MOUSE_ MOVE.
3. Объясните механизм позднего связывания
4. В каких случаях имеет смысл использовать виртуальные методы?
5. Как в данной работе производится удаление старых элементов?
6. Назначение метода InflateRect класса CRect.
7. Назначение метода NormalizeRect класса CRect.
8. Назначение функции GetCapture.
Лабораторная работа № 7. Изучение механизма сериализации
Цель: получить навыки работы с механизмом сериализации
Теоретическая часть
Документ программы на базе MFC представляет собой сложный объект, который может содержать большое многообразие объектов, каждый из которых в свою очередь другие. Задача сохранения объекта в файл на внешнем носителе является более сложной, чем сохранение обычных типов данных, таких как int.
При сохранении объекта в файл записываемая информация должна содержать полную спецификацию класса. Процесс чтения должен синтезировать объект на основе данной спецификации.
Библиотека MFC предоставляет удобный механизм ввода-вывода на внешний носитель объектов, называемый сериализацией. Данный механизм предполагает, что каждый класс сам отвечает за сохранение и восстановление.
|
|
Каждый сериализуемый класс должен содержать виртуальную функцию Serialize():
void Cmfc2Doc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
//добавить сюда код сохранения
}
else
{
//добавить сюда код загрузки
}
}
Метод IsStoring определяет, выполняется сохранение объекта или его восстановление.
Единственным параметром данной функции является указатель на объект класса CArchive. Данный класс предоставляет аналог библиотеки MFC потоковых операций С++. Объект данного класса позволяет направлять объекты документа в файл, либо их восстанавливать.
Объект класса CArchive включает объект типа CFile, который осуществляет работу непосредственно с физическим файлом. В большинстве случаев программисту нет необходимости работать с объектом CFile. Класс CArchive определяет логику структурирования объектов документа при их записи и восстановлении.
Процесс сериализации упрощенно представлен на рисунке 7.1[5]
Риусунок 7.1 – Обобщенная схема процесса сериализации объекта документа
В ответ на сообщение о сериализации объект класса документа инициирует процесс сериализации для базовых типов и своих внутренних объектов. При этом как будет производиться сохранение/восстановление внутренних объектов класс документа не знает. Внутренние объекты в свою очередь сериализуют свои базовые типы и инициируют процесс сериализации для своих объектов.
|
|
Постановка задачи
Добавьте в программу, из предыдущей работы, возможность хранения графических элементов в динамическом массиве на случай восстановления изображения при перерисовке экрана. Также программ должна уметь сохранять рисунок в файл и восстанавливать его из файла на основе механизма сериализции.
Порядок выполнения работы
1.Откройте в среде Visual C++ проект, реализованный в 6 работе.
2. Добавьте в класс документа переменную типа контейнера list для хранения списка графических элементов в разделе protected:
std::list<CElement*> m_ElementList;
3. Подключите библиотеку list в файл mfc2 Doc.h:
#include <list>
4. Добавьте в класс документа метод AddElement, который включает в список новый элемент:
void AddElement(CElement* pElement)
{
m_ElementList.push_back(pElement);
SetModifiedFlag();
};
1. Измените деструктор класса документа таким образом, чтобы пробежаться по списку элементов и удалить каждый из них:
Cmfc2Doc::~Cmfc2Doc()
{
for (auto iter=m_ElementList.begin();iter!=m_ElementList.end();++iter)
delete *iter;
m_ElementList.clear();
}
2. Прорисовка элементов производится в классе представления, а список элементов хранится в классе документа в разделе protected. Поэтому в классе документа требуются методы, которые позволят получить доступ к списку из других классов:
|
|
std::list<CElement*>::const_iterator begin()const
{
return m_ElementList.begin();
}
std::list<CElement*>::const_iterator end()const
{
return m_ElementList.end();
}
Данные методы возвращают указатели на начало и конец списка.
3. В метод OnDraw класса представления добавьте следующий код:
void Cmfc2View::OnDraw(CDC* pDC)
{
Cmfc2Doc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
CElement* pElement(nullptr);
for (auto iter=pDoc->begin();iter!=pDoc->end();++iter)
{
pElement=*iter;
if (pDC->RectVisible(pElement->GetBoundRect()))
pElement->Draw(pDC);
}
}
4. В обработчике события OnLButtonUp класса представления реализуйте код, который добавляет новый элемент в список:
void Cmfc2View::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_pTempElement)
{
GetDocument()->AddElement(m_pTempElement);
InvalidateRect(nullptr);
m_pTempElement=nullptr;
}
}
5. Откомпилируйте проект и убедитесь в работоспособности программы.
6. Добавим в проект механизм сериализации для ввода-вывода рисунка. Для этого добавьте в определение класса CElement макрос DECLARE_SERIAL:
class CElement : public CObject
{
DECLARE_SERIAL(CElement)
protected:
|
|
int m_PenWidth;
…………………………..
7. Добавьте в файл реализации класса CElement макрос IMPLEMENT_SERIAL сразу после директивы #include:
// Element.cpp: файл реализации
#include "stdafx.h"
#include <cmath>
#include "mfc2.h"
#include "Element.h"
IMPLEMENT_SERIAL(CElement,CObject,VERSION_NUMBER)
8. Добавьте код для сериализации объекта класса документа:
void Cmfc2Doc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar<<m_Color//сохранить текущий цвет
<<static_cast<int>(m_Element) //сохранить текущий элемент
<<m_PenWidth//сохранить ширину пера
ar<<m_ElementList.size();
for (auto iter=m_ElementList.begin();iter!=m_ElementList.end();++iter)
ar<<*iter;
}
else
{
int elementtype(0);
ar>>m_Color>>elementtype>>m_PenWidth;
m_Element=static_cast<ElementType>(elementtype);
size_t elementcount(0);
CElement* pElement(nullptr);
ar>>elementcount;
for (size_t i=0;i<elementcount;i++)
{
ar>>pElement;
m_ElementList.push_back(pElement);
}
}
}
9. Добавьте в описание класса CElement макрос DECLARE_SERIAL:
class CElement : public CObject
{
DECLARE_SERIAL(CElement)
protected:
10. Добавьте в CElement метод Serialize:
void CElement::Serialize(CArchive& ar)
{
CObject::Serialize(ar);
if (ar.IsStoring())
{
ar<<m_PenWidth<<m_Color<<m_EnclosingRect;
}
else
{
ar>>m_PenWidth>>m_Color>>m_EnclosingRect;
}
}
11. Добавьте в начало файла Element. cpp макрос:
// CElement
IMPLEMENT_SERIAL(CElement,CObject,VERSION_NUMBER)
12. Определите константу VERSION_NUMBER в файле mfc2Constants.h:
const UINT VERSION_NUMBER=1;
13. Добавьте в начало файла Element. cpp макрос IMPLEMENT_ SERIAL для каждого класса фигуры:
IMPLEMENT_SERIAL(CElement,CObject,VERSION_NUMBER)
IMPLEMENT_SERIAL(CLine,CElement,VERSION_NUMBER)
IMPLEMENT_SERIAL(CRectangle,CElement,VERSION_NUMBER)
IMPLEMENT_SERIAL(CCircle,CElement,VERSION_NUMBER)
IMPLEMENT_SERIAL(CCurve,CElement,VERSION_NUMBER)
14. Добавьте метод Serialize для класса CLine:
void CLine::Serialize(CArchive& ar)
{
CElement::Serialize(ar);
if (ar.IsStoring())
{
ar<<m_StartPoint<<m_EndPoint;
}
else
{
ar>>m_StartPoint>>m_EndPoint;
}
}
15. Добавьте метод Serialize для класса CRectangle:
void CRectangle::Serialize(CArchive& ar)
{
CElement::Serialize(ar);
}
16. Метод Serialize для класса CCircle аналогичен методу класса CRectangle
17. Добавьте метод Serialize для класса CCurve:
void CCurve::Serialize(CArchive& ar)
{
CElement::Serialize(ar);
if (ar.IsStoring())
{
ar<<m_Points.size();
for (size_t i=0;i<m_Points.size();++i)
ar<<m_Points[i];
}
else
{
size_t nPoints(0);
ar>>nPoints;
CPoint point;
for (size_t i=0;i<nPoints;++i)
{
ar>>point;
m_Points.push_back(point);
}
}
}
18. Добавьте вызов функции SetModifiedFlag в следующие методы класса документа: AddElement, DeleteElement.
19. Добавьте вызов функции SetModifiedFlag в обработчик события отпускания левой кнопки мыши класса представления:
void Cmfc2View::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: добавьте свой код обработчика сообщений или вызов стандартного
CClientDC aDC(this);
OnPrepareDC(&aDC);
aDC.DPtoLP(&point);
if (m_MoveMode)
{
m_MoveMode=false;
m_pSelected=nullptr;
GetDocument()->UpdateAllViews(0);
GetDocument()->SetModifiedFlag();
return;
}
20. Подготовьте отчет по работе и ответьте на контрольные вопросы.
Контрольные вопросы
1. Объясните механизм сериализации.
2. Роль объекта класса CArchive при сериализации.
3. Назначение метода SetModifiedFlag.
Дата добавления: 2019-09-13; просмотров: 293; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!