На этом шаге мы рассмотрим общие положения, связанные в выводом информации на различные устройства.
На этом шаге мы расскажем, какие возможности отображения данных на устройства вывода - экран и принтер -
предоставляет класс CView.
Контекст устройства и GDI
В Windows приложения и устройства вывода взаимодействуют п другом посредством интерфейса
графических устройств (Graphics Device Interface, GDI). Его использование гарантирует правильный вывод
на все GDI-совместимые устройства.
GDI управляет структурой данных, называемой контекстом устройства, которая содержит информацию о текущих
атрибутах данного устройства. В нее можно включить информацию о цветовой палитре, шрифтах, толщине пера, рисующего
линии, типе кисти, закрашивающей области. В Windows API есть GDI-функции для рисования линий и
других геометрических фигур, для закрашивания областей и печати текста. Все эти функции осуществляют вывод на контекст
устройства, описатель которого передается в качестве параметра.
В MFC контекст устройства и многие функции GDI инкапсулирует класс CDC. В нем представлены
функции создания и инициализации контекста устройства, а также функции рисования. Помимо класса CDC существует
масса специализированных классов, производных от него (таблица 1).
Таблица 1. Классы, производные от CDC
Класс | Описание |
---|---|
CPaintDC | Инкапсулирует контекст устройства, подготовленный для перерисовки недействительной области окна при получении сообщения WM_PAINT. Конструктор этого класса вызывает функцию CWnd::BeginPaint(), которая создает контекст устройства и подготавливает клиентскую область к графическому выводу. Для очистки памяти из деструктора вызывается функция CWnd::EndPaint() |
CClientDC | Описывает контекст устройства, представляющего клиентскую область окна |
CWindowDC | Инкапсулирует контекст устройства, представляющего все окно вместе с рамкой |
CMetafileDC | Содержит набор структур, хранящих изображение в аппаратно-независимом формате, который необходим при рисовании в метафайл Windows |
Рисование в представлении
Графический вывод данных приложения осуществляется функцией-членом объекта представления OnDraw(). В производном от CView
классе, котьорый создал мастер АррWizard, имеется функция-заглушка OnDraw(). К ней можно
добавлять свой код для отображения данных. Она выглядит следующим образом:
void CMyAppView::OnDraw(CDC* pDC) { CMyAppDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here }
Обратите внимание на то, что в эту функцию передается указатель на объект CDC. Он необходим для вызова рисующих функций контекста устройства.
Кроме того, функция OnDraw() получает указатель на объект документа, который Вы можете использовать для обращения к данным приложения.
Приведем простую реализацию функции OnDraw().
- Реализация функции OnDraw().
- Перейдите в проект МуАрр.
- В окне ClassView щелкните правой кнопкой значок класса CMyAppDoc.
- В появившемся контекстном меню выберите пункт Add Member Variable.
Рис.1. Выбор пункта Add Member Variable - В диалоговом окне Add Member Variable в поле Variable Type введите CString и в поле Variable Name - m_string.
- Оставьте переключатель Access установленным в Public и, чтобы создать переменную, щелкните кнопку ОК.
Рис.2. Создание переменной - Раскройте ветвь CMyAppDoc и убедитесь, что переменная m_string была добавлена в класс.
- Найдите значок конструктора класса CMyAppDoc (он находится под значком самого класса и называется CMyAppDoc).
Обратите внимание на значок, изображающий ключ, рядом с названием функции. Он показывает, что данная функция является
защищенным членом класса. Для перехода к редактированию конструктора дважды щелкните его значок.
Рис.3. Выбор конструктора - Добавьте в конструктор следующую строку: m_string = "Hello, World!";
Рис.4. Добавление строки - Раскройте узел CMyAppView. Перейдите к редактированию функции OnDraw(), дважды щелкнув ее значок.
- Вместо комментария, начинающегося с //TODO, добавьте в функцию OnDraw() следующий код:
CSize TextSize = pDC->GetTextExtent(pDoc->m_string); CRect rect(10,10, 10+TextSize.cx,10+TextSize.cy); rect.InflateRect(4,4); pDC->Rectangle(&rect); pDC->TextOut(10,10,pDoc->m_string);
Рис.5. Функция OnDraw() - Соберите и запустите программу. Проверьте, отображается ли в левом верхнем углу прямоугольник с надписью "Hello World!".
Текст измененного приложения можно взять здесь (39 Кб).
Выводы:
- для вывода на экран функциям-членам класса СDC необходим указатель на контекст устройства;
- указатель на документ используется для получения данных приложения;
- код рисования создается так, чтобы при изменении данных они во всех случаях отображались корректно - в данном примере прямоугольник
всегда обрамляет текст. Попробуйте изменить строку CMyAppDoc::m_string на более длинную, перекомпилируйте программу и запустите ее -
все элементы отображаются правильно.
Вызов функции OnDraw() каркасом приложения
Если изменение данных документа может повлиять на их отображение, то представление должно быть перерисовано.
Обычно такое происходит при внесении пользователем изменений в представление. При этом код, обновляющий
данные документа, должен вызывать функцию-член класса документа UpdateAllViews(), уведомляющую все
представления о необходимости перерисовки.
Функция UpdateAllViews() вызывает функцию-член каждого представления OnUpdate(). По умолчанию
при этом перерисовывается вся клиентская область представления. Вы можете переопределить эту
функцию так, что перерисовываться будут только те части окна, в которых произошло изменение.
Когда представление становится недействительным, Windоws сылает ему сообщение WM_PAINT. Обработчик
этого cooбщения OnPaint() создает контекст устройства на основе класса CPaintDC и
передает его в функцию OnDraw().
Печать и предварительный просмотр
В программировании для Windows практически не существует разницы между выводом на экран и на принтер, потому что
GDI - аппаратно-независимый интерфейс. Одни и те же функции могут использоваться для отображения на экран и
для печати на принтер в зависимости от контекста устройства. Если объект класса CDC, который получает функция OnDraw(),
представляет принтер, то и вывод выполняется на него.
Библиотека MFC позволяет осуществить печать документа. Каркас приложения сам отображает диалоговое окно Print и создает
контекст устройства для принтера. При выборе пункта Print в меню File представление передает этот контекст устройства
в функцию OnDraw(), которая и осуществляет вывод.
Рис.6. Вызов каркасом приложения функции OnDraw()
Однако между выводом на принтер и на экран есть существенные различия. При печати документ должен быть разделен на страницы,
поэтому Вам необходимо знать размер листа бумаги. Кроме того важна на ориентация листа (книжная или альбомная). Для этого в
классе CView предусмотрены специальные функции.
На следующем шаге мы рассмотрим конкретный пример приложения в архитектуре "документ/вид".