Развитие класса документа
Деструктор класса должен освобождать память, занимаемую динамическими структурами, входящими в состав класса. Метод FreeDocs мы создадим позже, поэтому при проверочных компиляциях проекта либо создайте заглушку – пустое тело функции FreeDocs, либо временно вставляйте символы комментария в строке с вызовом отсутствующей функции:
CTreeDoc::~CTreeDoc() { FreeDocs (); m_Poly.m_Points .clear (); }
Устойчивость данных документа обеспечивается функцией Serialize, и в стартовой заготовке класса уже есть этот метод. Его тело содержит схему сериализации, но не имеет конкретных кодов записи или чтения данных из архива. Мы должны наполнить заготовку кодами так, чтобы документ мог полностью сохранить или восстановить свое состояние. Нет необходимости сохранять абсолютно все данные документа, так как некоторые из них носят тактический (временный) характер. Они заданы по умолчанию и не будут изменяться, например m_szDoc или m_nLogZoom.
С долговременными данными документа мы отождествляем текущий или дежурный полигон m_Poly, который по легенде отражает выбранную и редактируемую в данный момент конструкцию. Он должен полностью изменить свои данные при выборе пользователем одной из картинок в окне правого представления. С этим окном мы связываем контейнер полигонов m_Shapes, который тоже носит временный характер, так как уничтожается и вновь создается при переходе из одной папки в другую и лишь помогает пользователю осуществить выбор. Таким образом, сериализацию документа мы отождествляем с сериализацией дежурного полигона. Поэтому тело функции Serialize выглядит весьма просто:
void CTreeDoc:: Serialize (CArchivei ar) { // Просим объект выполнить сериализацию самостоятельно m_Poly. Serialize (ar); if (ar.IsStoringO) { // Здесь помещается код записи "обычных" данных } else { // Здесь помещается код чтения "обычных" данных
Мы могли бы поместить в ветви условного оператора такой код: ar << m_szDoc << m_nLogZoom; ar >> m_szDoc >> m_nLogZoom; но тогда для обработки документов, расположенных в текущей папке, было бы необходимо поддерживать динамический контейнер объектов CTreeDoc. Чтение документов сводилось бы к вызову Serialize для каждого из них. Такое решение будет более громоздким, чем поддержка контейнера полигонов. Поэтому мы оставляем ветви условного оператора пустыми.
Продолжая развитие темы преобразования координат, создадим тело функции MapToLogPt, которая, получив на входе точку с вещественными World-координатами, возвращает точку с целыми координатами в пространстве Page. В коде этой функции мы помещаем центр симметрии фигуры (точку с координатами CDPoint(0.0)) в центр логической области, отведенной для документа, увеличиваем координаты и преобразуем их к целому типу:
CPoint CTreeDoc::MapToLogPt(CDPointS pt) { { //====== Растяжение и сдвиг int x = m_szDoc.cx/2 + int (m_nLogZoom * pt.x), у = m_szDoc.cy/2 + int (m_nLogZoom * pt.y); return CPoint(x,y); +}
Введите также функцию обратного преобразования координат, которая, получив на входе точку с целыми координатами в пространстве Page, вычисляет соответствующую ей точку с вещественными координатами в пространстве World:
CDPoint CTreeDoc::MapToWorldPt(CPointS pt) { //====== Обратные операции double x = double (pt.x – m_szDoc.cx/2) / m_nLogZoom, у = double (pt.y – m_szDoc.cy/2) / m_nLogZoom; return CDPoint(x, y); }
В настоящий момент, если закомментировать вызовы FreeDocs и ProcessDocs в теле деструктора и функции OnSelchanged класса CLeftview, то вы можете запустить приложение, с тем чтобы устранить возможные ошибки. Но пока никакой новой функциональности оно не обнаружит, так как мы еще не занимались созданием и управлением других представлений его документа. Нам вновь придется вернуться к классу документ, но только после того, как будут разработаны классы связанных с ним представлений.