Приложение. Создание и модификация шаблонов
SDI- и MDI-приложенийСоздание шаблона приложений
Сначала при помощи средства
AppWizard создается шаблон однооконного или многооконного приложения. При этом генерируются следующие основные классы :- главный класс приложения (производный от базового класса CWinApp );
- класс главного окна приложения (производный от базового класса CFrameWnd или CMDIFrameWnd в зависимости от типа приложения) ;
- класс документа приложения (производный от базового CDocument );
- класс окна просмотра документа (производный от базового CView );
- класс дочернего MDI-окна (производный от базового класса CMDIChildWnd ) – только для mdi-приложения.
Редактирование документов (и обликов)
В классе документа следует определить элементы (простые переменные, переменные структурного типа, объекты различных классов и др.), отвечающие за хранение данных документа, считываемых и записываемых в файл.
Если в процессе работы с документом выделяется дополнительная память для хранения информации, то в деструкторе класса документа
необходимо освободить всю дополнительную память, полученную в процессе работы.В тех методах класса окна просмотра документа, где содержимое документа изменяется, следует выполнить определенные действия
:- объявить указатель pDoc на текущий документ и получить его при помощи метода GetDocument класса окна просмотра ;
- изменить графическое изображение документа;
- изменить содержимое документа, на который указывает pDoc;
- установить флаг изменения документа, вызвав метод pDoc.SetModifiedFlag(TRUE);
- для mdi-приложения вызвать метод pDoc.UpdateAllViews(this) для перерисовки всех обликов документа (кроме текущего ), на который указывает pDoc.
Для класса окна просмотра переопределить метод
OnUpdate для того, чтобы выводить в этом методе только последние изменения, т.к. метод CView::OnUpdate базового класса просто вызывает метод OnDraw для перерисовки всего изображения.Для восстановления всего изображения в окне просмотра после перекрытия окна необходимо изменить метод
OnDraw класса окна просмотра документа, добавив вывод всего изображения .Инициал изация нового документа
Для инициализации нового документа в методе
OnNewDocument класса документа произвести- вызов метод CDocument::OnNewDocument базового класса для полной подготовки к работе с новым документом ;
- инициализацию необходимых данных нового документа ;
- выделение необходимой памяти для работы над документом .
Для очистки содержимого документа при инициализации нового документа в классе документа
необходимо переопределить метод DeleteContents базового класса CDocument (этот метод вызывается методом CDocument::OnNewDocument - обработчиком открытия нового документа). Для этого в определении класса документа необходимо объявить виртуальный метод DeleteContents, а в реализации класса его определить. Работа метода DeleteContents должна заключаться в следующем :- необходимо освободить всю память, выделяемую в процессе работы над предыдущим документом ;
- вызвать метод CDocument::DeleteContents базового класса для полной очистки документа
Сохранение и восстановл ение документов
Чтобы приложение имело возможность сохранения документов в файле, нужно изменить метод Serialize класса документа. Метод Serialize вызывается всякий раз, когда надо сохранить документ в файле на диске или загрузить его из существующего файла. В методе Serialize необходимо определить, как он должен сохранять и восстанавливать документы приложения.
Использование стандартных диалогов выбора файлов
Для того, чтобы иметь возможность при открытии и сохранения документа на диске использовать стандартные диалоговые панели выбора файла с определенными программистом настройками, необходимо в приложении обработать командные сообщения с идентификаторами ID_FILE_OPEN, ID_FILE_SAVE, ID_FILE_SAVE_AS (следует отметить, что обработка этих сообщений должна происходить в разных классах приложения – см. ниже).
В класс документа необходимо добавить элемент BOOL status_new, принимающий значение
TRUE, если пользователь работает с новым документом, и значение FALSE, если пользователь открыл документ, содержащийся в файле на диске. В методе OnNewDocument класса документа необходимо присвоить элементу status_new значение TRUE.При помощи средства
ClassWizard добавить в главный класс приложения (наследованный от класса CWinApp) обработчик командного сообщения с идентификатором ID_FILE_OPEN. Используемый ранее по умолчанию обработчик CWinApp::OnFileOpen этого сообщения убрать из списка обрабатываемых сообщений :BEGIN_MESSAGE_MAP(CApp, CWinApp) …… ON_COMMAND(ID_FILE_OPEN, OnFileOpen) …… END_MESSAGE_MAP()
Изменить заготовку метода OnFileOpen главного класса приложения следующим образом:
void CApp::OnFileOpen() { // Создание стандартной панели выбора файла "Open" CFileDialog DlgOpen(TRUE,(LPCTSTR)"txt",NULL, OFN_HIDEREADONLY,(LPCSTR)" Text Files (*.txt) |*.txt||"); // Отображение стандартной панели выбора файла "Open" if(DlgOpen.DoModal()==IDOK) { // Создание объекта класса документа, связанного с // файлом, и его окна просмотра. // OpenDocumentFile - метод класса CWinApp CDocument *pDoc =OpenDocumentFile(DlgOpen.GetPathName()); // Чтение данных из файла и запись их // в элементы класса документа. pDoc->OnOpenDocument(DlgOpen.GetPathName()); } }
В классе документа переопределить метод OnOpenDocument базового класса CDocument. Для этого в определении класса документа необходимо объявить виртуальный метод OnOpenDocument, а в реализации класса документа необходимо его определить:
BOOL CDoc::OnOpenDocument( const char* pszPathName) { // Вызов метода базового класса. // Он сначала вызывает метод DeleteContents для очистки документа, // а затем метод Serialize для чтения данных из файла if(!CDocument:: OnOpenDocument(pszPathName)) return FALSE; // Инициализация необходимых данных класса, выделение // памяти аналогично методу OnNewDocument . . . . . . . status_new=FALSE; // документ не новый return TRUE; }
При помощи средства
ClassWizard добавить в класс документа обработчики командных сообщений с идентификаторами ID_FILE_SAVE и ID_FILE_SAVE_AS . Изменить заготовки методов-обработчиков следующим образом :void CDoc::OnFileSave() { if(status_new==TRUE) // если документ новый, то выбор имени файла { // Создание стандартной панели выбора файла "SaveAs" CFileDialog DlgSave(FALSE,(LPCSTR)"txt",GetTitle(), OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, (LPCSTR)" Text Files (*.txt) |*.txt||"); // Отображение стандартной панели выбора файла "SaveAs" if(DlgSave.DoModal()==IDOK) { SetPathName(DlgSave.GetPathName()); // Вызов метода базового класса. // Он вызывает метод Serialize для записи данных CDocument:: OnSaveDocument(DlgSave.GetPathName()); status_new=FALSE; // документ уже не новый } } else // Вызов метода базового класса. CDocument:: OnSaveDocument(GetPathName()); } void CDoc::OnFileSaveAs() { // Создание стандартной панели выбора файла "SaveAs" CFileDialog DlgSaveAs(FALSE,(LPCSTR)"txt",GetTitle(), OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, (LPCSTR)" Text Files (*.txt) |*.txt||"); // Отображение стандартной панели выбора файла "SaveAs" if(DlgSaveAs.DoModal()==IDOK) { SetPathName(DlgSaveAs.GetPathName()); // Вызов метода базового класса. // Он вызывает метод Serialize для записи данных CDocument:: OnSaveDocument(DlgSaveAs.GetPathName()); status_new=FALSE; // документ уже не новый } }
Запись и восстановление данных без помощи фрхивных файлов
Если программист не желает производить запись и восстановление документов при помощи архивных файлов и с использованием метода Serialize, то вместо использования в приложении методов CDocument::OnSaveDocument и CDocument::On OpenDocument базового класса документов он может использовать переопределения этих методов OnSaveDocument и On OpenDocument в своем классе документа .
В переопределенном уже ранее методе On
OpenDocument класса документа (см. выше) вместо вызова по умолчанию метода базового класса CDocument::OnOpenDocument(pszPathName)) следует:- вызвать метод
Изменить в методах OnFileSaveAs и OnFileSaveAs (см. выше) вызовы метода
CDocument:: OnSaveDocument на вызовы OnSaveDocument. Затем переопределить метод On SaveDocument в классе документа приложения, для чего в определении класса документа необходимо объявить виртуальный метод On SaveDocument, а в реализации класса документа необходимо его определить. Причем в переопределенном методе On SaveDocument выполнить следующие действия :- объявить объект file класса CFile или производного от него ;
- открыть для объекта file файл с именем pszPathName в режиме для "записи" ;
- записать данные из элементов класса документа в файл file.