- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
LPPALETTEENTRY m_pPal;
UINT m_palNumEntries;
LPLOGPALETTE m_pLogPal;
LOGPALETTE m_LogPal;
HPALETTE m_hPal;
};
Функция Load подозрительно смотрит на начало файла, как и мой предыдущий код в функции Serialize. Но теперь нет объекта типа CArchive со всеми его преимуществами. Нет проблем. Использование объекта типа CFile позволяет прочитать сигнатуру. Функции GetEMFCoolStuff и LoadPalette взяты из моей программы-примера EMFDCODE в MSDN. Они получают копии заголовка метафайла, строки описания, и палитры внедренной в метафайл. Конечно, они теперь находятся в классе CEMF.
BOOL CEMF::Load(const char *szFileName) {
UINT uiSig;
// Сохранить имя файла.
m_szPathName = szFileName;
// Проверить сигнатуру
CFile cfEMF;
cfEMF.Open(m_szPathName, CFile::modeRead | CFile::shareDenyWrite);
cfEMF.Read(&uiSig, sizeof(UINT));
cfEMF.Close();
// Если это EMF, получить его дескриптор.
if (uiSig == EMR_HEADER) {
m_hemf = GetEnhMetaFile(m_szPathName);
GetEMFCoolStuff();
LoadPalette();
} else m_hemf = NULL;
// Возвращаем результат.
return ((m_hemf) ? TRUE : FALSE);
}
Функция Draw вызывается из функции OnDraw класса представления. Особо интересного там ничего не происходит. Если есть палитра, на что указывает не равное NULL значение переменной-члена m_hPal, палитра выбирается в контекст устройства (DC). Я был сильно озадачен, когда узнал что CDC::SelectPalette требует указатель на объект типа CPalette. Но я был так же заинтригован, когда вдруг обнаружил функцию CPalette::FromHandle. Я мог легко преобразовать дескриптор палитры в объект типа CPalette. Далее это было уже просто делом воспроизведения метафайла с помощью CDC::PlayMetaFile.
BOOL CEMF::Draw(CDC *pdc, RECT *pRect) {
ASSERT(m_hemf);
BOOL fRet = FALSE;
CRect crect;
CPalette cpalOld = NULL;
if (m_hemf) {
if (m_hPal) {
CPalette cpal;
if ((cpalOld = pdc->SelectPalette(cpal.FromHandle(m_hPal), FALSE))) pdc->RealizePalette();
}
fRet = pdc->PlayMetaFile(m_hemf, pRect);
if (cpalOld) pdc->SelectPalette(cpalOld, FALSE);
}
return (fRet);
}
Что же еще находится в классе CEMF? Как я упоминал выше, есть две закрытых (private) функции, которые управляются с палитрой и заголовком. Я их не буду обсуждать в этой статье, кому интересно см. статьи "Enhanced Metafiles in Win32" и "EMFDCODE.EXE: An Enhanced Metafile Decoding Utility", обе доступны в MSDN. Конечно, вы вероятно захотите также взглянуть на файлы CEMF.CPP и CEMF.H программы METAVIEW, приложенной к статье! Если вы захотите сделать из этого класса что-либо серьезное, предлагаю добавить следующую дополнительную функциональность: возможность делать нумерованые последовательности метафайлов и работать с метафайлами, содержащимися в буфере обмена. Опять же, эти темы описываются в вышеупомянутых статьях.
Отображение документаЕсли я понял Найджела правильно, задача состояла в том, чтобы отображать документ тремя различными способами. Во-первых, как картинку в дочернем окне; потом, в виде текста описывающего заголовок метафайла (тоже в дочернем окне), и, наконец, как картинку в окне предварительного просмотра. К тому же, два представления в дочерних окнах нужно было реализовать через архитектуру многодокументного интерфейса (MDI) предоставленную MFC. Рассмотрим каждую из этих задач по отдельности.
Вывод изображения в дочернем окнеЗдесь никаких проблем. Надо просто вызвать функцию-член Draw из класса CEMF. Посмотрите поближе на функцию OnDraw в файле METAVVW.CPP.
void CMetavw1View::OnDraw(CDC* pDC) {
CMetavw1Doc* pDoc = GetDocument();
// Флаг для предотвращения рисования во время
// изменения размера окна, см. OnSize() и FullDragOn() в этом модуле.
if (m_fDraw) {
// Если мы печатаем или находимся в режиме предварительного
// просмотра, рабочий прямоугольник узнается из CPrintInfo в OnPreparePrinting
if (pDC->IsPrinting()) {
pDoc->m_cemf.Draw(pDC, &m_rectDraw);
} else {
GetClientRect(&m_rectDraw);
pDoc->m_cemf.Draw(pDC, &m_rectDraw);
}
}
}
Этот код организован вокруг двух условных операторов о которых стоит сказать отдельно. Первое условие является тестом типа "все-или-ничего". Если m_fDraw равно FALSE, не делается никакой попытки что-то нарисовать. Так что же означает m_fDraw? Ну, это мой хитрый прием №2, и я скоро к нему вернусь. Второе условие проверяет ведется ли отрисовка на принтер (или предварительный просмотр) или в дочернее окно. Член-функция IsPrinting класса CDC – это встроенная (inline) функция, которая возвращает public-переменную CDC::m_bPrinting. Раньше, прежде чем воспользоваться этой функцией, я проверял m_bPrinting напрямую. Когда я обнаружил функцию IsPrinting, это меня озадачило. Ведь эта функция просто возвращала значение m_bPrinting и все. Но похоже это больше в духе C++. Если название переменной m_bPrinting в будущем изменилось бы, мой код перестал бы работать. Но это все еще меня немного беспокоит. Как-никак, а я бывал достаточно сообразителен, чтобы при необходимости залезать в отладчик, прослеживать за несколькими переменными и затем придумывать способ получения желаемого результата. И это приводит меня к моей первой (и возможно последней) гипотезе: инкапсуляция и сокрытие данных могут мстить за чрезмерный энтузиазм.
Ладно, хватит о гипотезах. Вернемся к программе. Мы обсуждаем отрисовку документа в дочернем окне. Клиентскую область окна мы получили с помощью 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) панели управления), которая разрешает показывать содержимое окна при его перетаскивании и изменении размера. И я хочу вам сказать, что если вы воспроизводите огромный метафайл, который делает много сложных вещей, вы эту опцию просто возненавидите. Так как ее отключить? Нет, этого делать нельзя! Помните, эту опцию включил пользователь. Вам не стоит самостоятельно отключать ее. Вы можете сказать, "раньше это меня никогда не останавливало!". Ну, все равно удобного способа отключить ее нет. Чтобы справиться с ней, я решил воспользоваться "одноразовым" таймером.