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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!