Алекс Jenter - Программирование на Visual C++. Архив рассылки
- Название:Программирование на Visual C++. Архив рассылки
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Алекс Jenter - Программирование на Visual C++. Архив рассылки краткое содержание
РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.
Программирование на Visual C++. Архив рассылки - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
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 занимается сопровождением этого кода вместо меня!
Так что это был за флаг 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;
}
}
Когда мы наконец получаем сообщение WM_TIMER, функция OnTimer устанавливает значение m_fDraw в TRUE, уничтожает таймер и перерисовывает клиентскую область окна представления.
void CMetavw1View::OnTimer(UINT nIDEvent) {
m_fDraw = TRUE;
m_uiTimer = 0;
KillTimer(1);
InvalidateRect(NULL);
}
Переменная m_fFullDragOn, встречавшаяся в OnSize, устанавливается вызовом функции FullDragOn в конструкторе класса представления. Эта функция смотрит в ключе HKEY_CURRENT_USER\Control Panel\Desktop реестра, включена ли опция показа содержимого окна. Если значение подключа DragFullWindows равно 1, функция возвращает TRUE, иначе она возвращает FALSE. [Расположение ключей в реестре сильно зависит от типа и версии системы. Используйте эту возможность с осторожностью. – прим. перев.]
BOOL CMetavw1View::FullDragOn() {
HKEY hkey = NULL;
DWORD dwType;
long lResult;
LPSTR lpszDataBuf;
DWORD cbData = 0;
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ, &hkey);
if (hkey) {
// Получить размер ключа.
lResult = RegQueryValueEx(hkey, "DragFullWindows", NULL, &dwType, NULL, &cbData);
// Зарезервировать память под значение ключа.
lpszDataBuf = (LPSTR)malloc(cbData * sizeof(char));
// Получить значение ключа.
lResult = RegQueryValueEx(hkey, "DragFullWindows", NULL, &dwType, (LPBYTE)lpszDataBuf, &cbData);
return (*lpszDataBuf == '1');
}
return FALSE;
}
Общий результат таков: когда окно изменяет размер, ничего не перерисовывается до тех пор, пока изменение размера не прекратится.
Вы наверное помните, что в задаче Найджела было требование, что программа должна выводить документ на экран в различных представлениях: либо в виде изображения, либо в виде заголовка метафайла отображаемого как текст. Никаких проблем; наверняка для этого есть свой мастер наподобие AppWizard. К моему сильнейшему изумлению, никакого мастера не было! Так что я посмотрел статью Дейла Роджерсона (Dale Rogerson) "Multiple Views for a Single Document" ("Несколько представлений для одного документа") в MSDN. Она была очень полезной. Тем не менее, пока вы не проделаете это три или четыре раза, вы очень просто можете запутаться! Поверьте мне, я потерял несколько часов, когда брался то за добавление второго представления, то за написание класса CEMF. Я советую полностью сфокусироваться на втором представлении, пока оно не заработает как надо. Найджел добавил второе представление в одну из своих программ-примеров ("VIEWDIB: Views Multiple DIBs Simultaneously" Прим. редактора: к сожалению, это приложение больше не входит в состав библиотеки MSDN), основанную на статье Дейла. Он вывел следующий список, основанный на своем опыте. Имея статью Дейла и список Найджела, я смог добавить второе представление без особых хлопот. А если я могу это сделать, то вы тоже можете!
1. Воспользуйтесь ClassWizard чтобы создать новый класс представления; например, CAppSecondView.
2. Добавьте включение заголовочного класса нового представления в нужный cpp-файл (см. пункт 12).
3. Добавьте функцию GetDocument к коду класса представления и заголовку. (Скопируйте ее из другого класса представления.)
Читать дальшеИнтервал:
Закладка: