Московский государственный университет имени М.В.Ломоносова
Опубликован: 01.11.2004 | Доступ: свободный | Студентов: 11275 / 456 | Оценка: 4.12 / 4.01 | Длительность: 19:20:00
ISBN: 978-5-9556-0077-9
Специальности: Программист
Лекция 20:

Библиотека классов MFC среды проектирования Visual Studio .NET. SDI и MDI приложения

< Лекция 19 || Лекция 20: 123 || Лекция 21 >

Шаблоны документа

Класс CDocTemplate

Класс CDocTemplate является абстрактным классом, предоставляющим основные возможности для работы с шаблонами документов.

Шаблон документа определяет отношение между тремя типами классов.

  • Класс документа, наследуемый от CDocument.
  • Класс отображения, выполняющий показ данных для указанного класса документа. Класс отображения может быть наследован от классов CView, CScrollView, CFormView, CEditView. (Класс CEditView может быть использован и напрямую.)
  • Класс окна-рамки, содержащий отображение. Для SDI-приложений этот класс наследуется от базового класса CFrameWnd, а для MDI-приложений - от базового класса CMDIChildWnd. Однако, если в приложении не требуется переопределять поведение объекта "окно-рамка", то может быть создан объект "окно-рамка" непосредственно базового класса, без объявления производных классов.

Для каждого типа документа в приложении создается отдельный шаблон документа.

Класс CDocTemplate является абстрактным классом и, следовательно, не может использоваться непосредственно для создания объектов. Обычно для создания шаблонов применяются его производные классы CSingleDocTemplate и CMultiDocTemplate. Однако можно создать и свой собственный производный класс шаблона документа.

Например:

BEGIN  
IDR_MYTYPE "\nSheet\nWorksheet\n
        Worksheets (*.myc)\n.myc\ 
     n MyCalcSheet\nMyCalc Worksheet"
END
BOOL CMyApp::InitInstance()
{
   CMultiDocTemplate* pDocTemplate;
   pDocTemplate = new CMultiDocTemplate(
      IDR_MYTYPE,
      RUNTIME_CLASS(CMyDoc),
      RUNTIME_CLASS(CMDIChildWnd),      
      RUNTIME_CLASS(CMyView));
   AddDocTemplate(pDocTemplate);
     // ...
}
Класс CSingleDocTemplate

Класс CSingleDocTemplate определяет шаблон документа для SDI-приложений: одновременно может быть открыт только один документ; документ отображается в главном окне. Как правило, SDI-приложения поддерживают только один тип документа и, соответственно, имеют только один объект CSingleDocTemplate.

Класс CMultiDocTemplate

Класс CMultiDocTemplate определяет шаблон документа для MDI-приложений: одновременно может быть открыто несколько документов; главное окно используется как пространство, в котором можно открывать несколько окон-рамок для отображения документов.

Документы

Класс CDocument

Класс CDocument предоставляет основные возможности управления документами.

Класс CDocument поддерживает набор стандартных операций над документом: создание, загрузка, сохранение.

Каждый документ содержит указатель на сопоставленный ему объект шаблона документа - для каждого типа документа; свой шаблон.

Пользователи взаимодействуют с документом посредством объекта отображение (наследуемого от класса Cview - или его производных классов), ассоциированного с документом.

Для работы с документами в приложении следует:

  1. создать производный класс от класса CDocument для каждого типа документа;
  2. добавить переменные члены класса для хранения данных каждого документа;
  3. реализовать методы - члены класса, выполняющие чтение и изменение данных документа.
Сериализация данных

Библиотека MFC реализует модель обмена данными между документом и файлом через специальный объект, называемый архивом. Обмен данными между приложением и архивом называется сериализацией. Для обмена используется метод Serialize класса документа.

При создании шаблона приложения с помощью мастера AppWizard можно добавить меню File, содержащее пункты Open, Save и Save as. Для обработки каждого из указанных пунктов меню, AppWizard вставляет в программный код класса документа (производного от CDocument) переопределяемый метод Serialize - либо для чтения состояния документа из архива, либо для записи (загрузки) состояния документа в архив. Программисту необходимо только вставить в метод Serialize код, выполняющий запись переменных в архив и чтение переменных из архива.

Для использования средств сериализации следует включить в объявление и реализацию класса макросы DECLARE_SERIAL и IMPLEMENT_SERIAL соответственно.

Создание SDI-приложения

Начинать разработку приложения следует с формирования "макета" приложения, который автоматически формируется мастером приложений AppWizard.

Мастер приложений MFC Application Wizard позволяет создавать следующие шаблоны для приложений с архитектурой "документ-отображение":

  • Single document - приложения с SDI-интерфейсом.
  • Multiple documents - приложения с MDI-интерфейсом, поддерживающие только одно окно верхнего уровня.

Мастер приложений позволяет последовательно формировать шаблон SDI приложения (Single Document Interface), включая или не включая в него поддержку таких элементов, как: доступ к информации из баз данных, реализация возможностей контейнера или сервера, применение OLE, использование элементов ActiveX, а также реализацию встроенной панели инструментов, строки состояния, некоторых пунктов меню.

Так, при формировании SDI приложения будут созданы следующие классы:

  • производный класс от класса приложения CApp ;
  • класс рамки окна;
  • класс документа (производный от CDocument );
  • класс отображения (производный от CView ).

Далее приводится код основных фрагментов SDI-приложения, автоматически создаваемого мастером MFC Application Wizard.

// App1.cpp : Файл реализации класса приложения
// (включает также код класса CAboutDlg для диалога About)
// Таблица сообщений класса CApp1App
BEGIN_MESSAGE_MAP(CApp1App, CWinApp)
  ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
  ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
  ON_COMMAND(ID_FILE_PRINT_SETUP, 
                            CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
CApp1App::CApp1App()    {  }      // Конструктор
CApp1App theApp;               // Объект приложение
BOOL CApp1App::InitInstance()  // Первый выполняемый метод //приложения
{  CWinApp::InitInstance();  
    // Регистрация шаблонов документа 
  CSingleDocTemplate* pDocTemplate;
  pDocTemplate = new CSingleDocTemplate( // Строка 
                                     //описания шаблона
    IDR_MAINFRAME,
    RUNTIME_CLASS(CApp1Doc),
    RUNTIME_CLASS(CMainFrame), // Главное окно 
                              // SDI приложения
    RUNTIME_CLASS(CApp1View));
  AddDocTemplate(pDocTemplate);

  m_pMainWnd->ShowWindow(SW_SHOW); // Отображение 
                        // главного окна приложения
  m_pMainWnd->UpdateWindow();
  return TRUE;
}
// Класс CAboutDlg, реализующий диалог About
class CAboutDlg : public CDialog
{public:
  CAboutDlg();
  enum { IDD = IDD_ABOUTBOX };  // Идентификатор ресурса диалога
protected:
  virtual void DoDataExchange(CDataExchange* pDX); 
protected:
  DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)  { }
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{  CDialog::DoDataExchange(pDX);}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) // Таблица сообщений
END_MESSAGE_MAP()
void CApp1App::OnAppAbout() // Обработчик команды меню About
{  CAboutDlg aboutDlg;
  aboutDlg.DoModal(); // Отображение модального диалога 
}
// App1Doc.cpp : файл реализации класса документа CApp1Doc 
IMPLEMENT_DYNCREATE(CApp1Doc, CDocument)
BEGIN_MESSAGE_MAP(CApp1Doc, CDocument) // Таблица сообщений
END_MESSAGE_MAP()
CApp1Doc::CApp1Doc()    {}
CApp1Doc::~CApp1Doc()  { }
BOOL CApp1Doc::OnNewDocument()  // Переопределение метода,
{            // вызываемого при открытии документа
  if (!CDocument::OnNewDocument())
    return FALSE;
  // Место для добавления кода инициализации документа
  return TRUE;
}
void CApp1Doc::Serialize(CArchive& ar)     // Сериализация
{  if (ar.IsStoring())
  {    // Место для добавления кода сохранения
  }
  else
  {    // Место для добавления кода загрузки
  }
}
// App1View.cpp : файл реализации класса CApp1View 
IMPLEMENT_DYNCREATE(CApp1View, CView)
BEGIN_MESSAGE_MAP(CApp1View, CView)    // Таблица сообщений
  ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
CApp1View::CApp1View() { }
CApp1View::~CApp1View() { }
BOOL CApp1View::PreCreateWindow(CREATESTRUCT& cs)
{ return CView::PreCreateWindow(cs); }
void CApp1View::OnDraw(CDC* /*pDC*/)
{  CApp1Doc* pDoc = GetDocument(); // Указатель на документ
  ASSERT_VALID(pDoc);
}
BOOL CApp1View::OnPreparePrinting(CPrintInfo* pInfo)
{ return DoPreparePrinting(pInfo);   // Действие по умолчанию
}
void CApp1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { }
void CApp1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { }
// MainFrm.cpp : файл реализации класса CMainFrame 
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //Таблица сообщений
  ON_WM_CREATE()
END_MESSAGE_MAP()
static UINT indicators[] =
{  ID_SEPARATOR,         // Идентификаторы ресурсов
  ID_INDICATOR_CAPS,   // для строки состояния
  ID_INDICATOR_NUM,
  ID_INDICATOR_SCRL,
};
CMainFrame::CMainFrame()  {   }
CMainFrame::~CMainFrame() {   }
// Обработчик сообщения, получаемого при создания окна
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{  if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    return -1;
  return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{  if( !CFrameWnd::PreCreateWindow(cs) )
    return FALSE;
  return TRUE;
}
Листинг 20.1.
< Лекция 19 || Лекция 20: 123 || Лекция 21 >
Александр Демьяненко
Александр Демьяненко

Можно ли сдавать один и тот же тест несколько раз?
Или же один и тот же тест можно сдать лишь однажды?

Максим Стогний
Максим Стогний

Добрый день!

Скажите, пожалуйста, если в терминологии объектно-ориентированного программирования функции также называются методами или методами - членами класса, в примере объявления указателя на метод использовали в формальном описании оба названия:

тип_метода (имя_класса::*имя_метода_указателя)
    (список параметров);
тип_функции (*имя_ функции_указателя)
    (список параметров);

при этом можно было  тип_функции во втором описании заменить на тип_метода? Т.е.:

тип_метода (*имя_ метода_указателя)
    (список параметров);