Вход/Регистрация
Программирование на Visual C++. Архив рассылки
вернуться

Jenter Алекс

Шрифт:

Ладно, хватит о гипотезах. Вернемся к программе. Мы обсуждаем отрисовку документа в дочернем окне. Клиентскую область окна мы получили с помощью GetClientRect и поместили в m_rectDraw.

if (pDC->IsPrinting) {

 pDoc->m_cemf.Draw(pDC, &m_rectDraw);

} else {

 GetClientRect(&m_rectDraw);

 pDoc->m_cemf.Draw(pDC, &m_rectDraw);

}

Затем вызывается функция Draw и пуф! Появляется картинка.

Вывод изображения в окно предварительного просмотра и на принтер

Да, я схитрил. Я здесь сразу буду заниматься двумя представлениями, в окне предварительного просмотра и на принтере. Но я это делаю исключетельно потому, что для MFC между ними очень мало разницы.

Если IsPrinting возвращает TRUE, вызывается функция Draw с тем, что поначалу кажется неинициализированным m_rectDraw.

if (pDC->IsPrinting) {

 pDoc->m_cemf.Draw(pDC, &m_rectDraw);

} else {

 GetClientRect(&m_rectDraw);

 pDoc->m_cemf.Draw(pDC, &m_rectDraw);

}

К счастью, это все-таки не так. Библиотека опять приходит на помощь. Когда мы печатаем или находимся в режиме предварительного просмотра, несколько функций вызываются до OnDraw. Эти функции можно перекрыть своими. В данном случае я перекрыл функцию OnPrint (которая в конце концов вызывает OnDraw). В эту функцию передается указатель на объект типа CPrintInfo. Один из переменных-членов этого класса – объект типа CRect, определяющий доступную для печати область. Этот прямоугольник просто копируется в m_rectDraw до вызова OnDraw.

void CMetavw1View::OnPrint(CDC* pDC, CPrintInfo* pInfo) {

 m_rectDraw = pInfo->m_rectDraw;

 OnDraw(pDC);

}

Остальное все уже достояние истории. Вызывайте Draw и дело сделано!

Одно замечание касательно предварительного просмотра. Я потратил немного времени, пытаясь выянить размеры "страницы" предварительного просмотра. Почесывал задумчиво голову, пытаясь понять, как мне получить координаты точки отсчета и размеры центрированной в окне "страницы". Я даже дошел до того, что сделал копию объекта CPreviewDC (закрытого объекта AFX) просто чтобы узнать координаты точки отсчета. Но мне все равно никак не удавалось получить размеры. Слава богу, я вспомнил свою гипотезу-теперь-ставшую-аксиомой: инкапсуляция и сокрытие данных могут мстить за чрезмерный энтузиазм. Так что немного поворчав по поводу MFC, я наконец понял, что все масштабирование в окне предварительного просмотра будет осуществляться автоматически. А наблюдая при изменении размера за CPrintInfo::m_rectDraw, я заметил что он все время остается одинаковым. Точно как я хотел! Еще одно очко в пользу MFC.

Что может быть легче?

Я не знаю насчет вас, но мой код, отвечающий за рисование, обычно достаточно объемен. И я действительно впечатлен предварительным просмотром, обычным рисованием и печатью, умещенными в 19 строк кода (включая комментарии). Правда, мне пришлось написать класс CEMF. Но послушайте, я ведь могу теперь использовать его в своих будущих программах! И да, библиотека MFC взяла на себя предварительный просмотр и печать. Но знаете что? Пусть Microsoft занимается сопровождением этого кода вместо меня!

ПРИЕМ №2: РАЗБИРАЕМСЯ С ПОКАЗОМ СОДЕРЖИМОГО ОКНА ПРИ ПЕРЕТАСКИВАНИИ

Так что это был за флаг m_fDraw в функции OnDraw? Вспомните, что он связан в тестом типа "все-или-ничего". Если m_fDraw равняется FALSE, не делается никакой попытки что-либо нарисовать. Я придумал этот прием когда начал отображать большие метафайлы в клиентской области в ответ на изменение размера окна. В системе есть опция (которая устанавлявается в окне Экран (Desktop) панели управления), которая разрешает показывать содержимое окна при его перетаскивании и изменении размера. И я хочу вам сказать, что если вы воспроизводите огромный метафайл, который делает много сложных вещей, вы эту опцию просто возненавидите. Так как ее отключить? Нет, этого делать нельзя! Помните, эту опцию включил пользователь. Вам не стоит самостоятельно отключать ее. Вы можете сказать, "раньше это меня никогда не останавливало!". Ну, все равно удобного способа отключить ее нет. Чтобы справиться с ней, я решил воспользоваться "одноразовым" таймером.

Что такое одноразовый таймер? Просто говоря, это таймер который используется один раз, а потом уничтожается. Основная реализация, в случае изменения размера окна, – запустить таймер при получении сообщения WM_SIZE. Если таймер уже существует (в случае последовательных сообщений WM_SIZE), уничтожить его и запустить еще один. Когда наконец сообщение WM_TIMER пробивается скозь очередь других сообщений, уничтожаем таймер. Помните, что вы не получите сообщения WM_TIMER, пока не прекратится изменение окна приложения. У сообщений WM_TIMER очень низкий приоритет. Следующие две функции, OnSize и OnTimer, иллюстрируют как я приспособил таймер для этого приложения. В дополнение к созданию и уничтожению таймеров, эти функции устанавливают значение m_fDraw.

void CMetavw1View::OnSize(UINT nType, int cx, int cy) {

 CView::OnSize(nType, cx, cy);

 // Это нужно делать только если опция отображения содержимого

 // окна при перемещении и изменении размера включена

 if (m_fFullDragOn) {

if (!m_uiTimer) KillTimer(1);

m_uiTimer = SetTimer(1, 100, NULL);

m_fDraw = FALSE;

 }

}

  • Читать дальше
  • 1
  • ...
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: