<<
>>

Перерисовка изображения

Рассмотрим следующую абстракцию, цель которой — показать, что за содержимое окон на экране отвечают оконные процедуры тех приложений, которым эти окна принадлежат. Роль Windows в этом процессе минимальна и состоит в том, что при определенных действиях с окном оконной процедуре, отвечающей за связь с этим окном, посылается сообщение WM_PAINT.
Получив это сообщение, оконная проце- дура должна уметь заново перерисовать содержимое всего окна или его части. Для общего случая это, если задуматься, не такая уж простая задача. Если у вас возникают трудности с пониманием этого момента работы приложе- ний в Windows, попробуйте развить абстракцию со школьной доской. Представь- те себе школьный класс, в котором процесс обучения выглядит очень необычно. Вместо обычной школьной доски на стене есть некоторая ограниченная область (экран монитора). У каждого ученика (исполняемого файла) есть в портфеле своя доска (окно приложения), которая может (или не может, в зависимости от кон- струкции) менять свой размер.
На всех учеников один комплект цветных мелков (контекст устройства), обладание которым разрешает ученику что-то рисовать на своей доске. Ученик объясняется с присутствующими графическими образами, выводя их на свою доску. Но прежде доску нужно повесить на стену в пределах ограниченной области. Для этого ученик, как ему и положено, подымает руку. Учи- тель (Windows) обязательно помогает ученику выйти к ограничен ной области на стене (запускает на выполнение задачу) и повесить свою доску. Действия учителя и ученика в ходе этого процесса соответствуют определенному алгоритму и дей- ствиям каркасного приложения. В результате могут быть закрыты частично или полностью доски учеников, вышедших к доске ранее и не ушедших пока на свои места в классе. При этом информация в скрытых частях расположенных ниже до- сок других учеников уничтожается в пределах ограниченной области.
Итак, доска ученика с помощью учителя повешена в пределах области на стене, и для того чтобы рисовать на ней, ученик должен попросить у учителя комплект мелков (см. функцию API GetDC или BeginPaint в листинге 16.4). Если ученик его получает, то он может начинать процесс рисования на своей доске. Как только уче- ник заканчивает этот процесс, он должен вернуть учителю комплект мелков (функ- ция ЕпdРаiпt). Далее ученик может закончить ответ и, забрав свою доску, занять свое место в классе (приложение завершило работу и «ушло» на диск). Если уче- ник делает это, то, забирая свою доску, он открывает доски других учеников, и... на этих досках обнаруживаются черные дыры, причем местоположение этих дыр со- ответствует местам, которые были скрыты доской их ушедшего товарища. Чтобы сгладить этот конфуз, учитель срочно оповещает об этом (Windows посылает со- общение WM_PAINT) учеников, у которых было испорчено содержимое досок. Каж- дый из этих учеников должен, попросив у учителя комплект мелков, перерисовать содержимое своей доски. Данная абстракция довольно точно отражает логику работы Windows, причем не только в обозначенном нами контексте. Вы можете дополнить и развить ее в нужную вам сторону. Как решается проблема перерисовки изображения практически? Для этого су- ществует несколько способов, самый общий из которых заключается в использо- вании виртуалъного окна. Суть перерисовки изображения на основе виртуального окна заключается в использовании приложением некоторой области памяти для направления в него всего вывода программы. Реальный вывод в окно приложения осуществляется только как реакция на получение сообщения WM_PAINT. He забы- вайте, что программа с помощью функции IпvаlidаtеRесt() может сама себе послать сообщение WM_PAINT, когда ей потребуется вывести новый фрагмент изображения в окно приложения. Понятие виртуального окна настолько важно для организа- ции работы Windows, что Win32 API содержит ряд функций, поддерживающих работу с этим окном: СrеаtеСоmраtiЫеDС(), SеlесtОbjесt(), GеtStосkОbjесt(), ВitВlt(), СrеаtеСоmраtiblеВitmар() и РаtВ⅛().
Рассмотрим порядок их использования в реаль- ном приложении. Работа с виртуальным окном в программе организуется в два этапа: создание виртуального окна и организация непосредственной работы с ним. Создать вирту- альное окно целесообразно при обработке сообщения WМ_СRЕАТЕ, то есть в момент создания окна приложения. Работать с этим окном можно в любое время, когда требуется вывод в окно. Для наглядности обсуждения приведем фрагмент программы на языке C/C++: //фрагмент оконной процедуры из программы на языке C/C++ case WМ_СRЕАТЕ: //определить размеры экрана mахХ = GеtSуstеmМеtriсs (SМ_СХSСRЕЕN) ; mахY = GеtSуstеmМеtriсs (SМ_СХSСRЕЕN); //строим растровое изображение, совместимое с окном hdс = GеtDС (hwпd) ; mеmdс = СrеаtеСоmраtiblеDС (hdс) ; hbit = СrеаtеСоmраtiblеВitmар (hdс, mахХ, mахY); SеlесtОbjесt (mеmdс, hbit); //закрашиваем окно серым цветом hbrush = GеtStосkОbj есt (GRАY_ВRUSН); SеlесtОbjесt (mеmdс, hbrush); РаtВlt (mеmdс, 0, 0, mахХ, mахY, РАТСОРY); RеlеаsеDС (hwпd, hdс) ; case WМ_РАINТ: //перерисовываем окно ■ hdс = Веg1пРаiпt (hwпd, &paintstruct); //получаем дескриптор реального окна //копируем растровое изображение из памяти на экран ВitВlt (hdс, 0, 0, mахХ, mахY, mеmdс, О, О, SRССОРY) ; ЕпdРаiпt (hwпd, &paiпtstruсt); //освобождаем дескриптор . * //выводим в окно где-то в программе ТехtОut(mеmdс, X, Y, str, strtел(str)); //выводим строку //для немедленного вывода в окно вызываем функцию IпvаlidаtеRесt: IпvаlidаtеRесt (hwпd, NULL, 1); Физически виртуальное окно представляет собой растровое изображение, хра- нящееся в памяти. Работа с этой областью памяти организуется так же, как и с ок- ном приложения на экране монитора. Это означает, что для работы с ним необхо- димо создать контекст устройства памяти, совместимый с контекстом окна. Это действие реализуется двумя функциями: с помощью функции GеtDС() приложе- ние получает контекст окна; функция СrеаtеСоmраtiЫеDС() создает совместимый с контекстом окна контекст памяти memdc. После этого функцией СrеаtеСоmраti- ЫеВitmар() создается совместимое с реальным окном на экране растровое изобра- жение.
Его размеры должны соответствовать размеру окна, для работы с которым оно строится. Поэтому предварительно с помощью функции GеtSуstеmМеtriсs() должны быть получены размеры окна и переданы как параметры в функцию СrеаtеСоmраtiЫеВitmар(), которая возвращает дескриптор на созданное растровое изображение. После этого функция SеlесtОbjесt() выбирает созданное растровое изображение в контекст памяти, который, в свою очередь, является совместимым с контекстом окна. Благодаря такой цепочке связей обращение к растровому изоб- ражению в памяти производится аналогично обращению к реальному окну. На практике это означает, что во всех функциях, выводящих изображение в окно, на месте параметра, соответствующего контексту устройства, необходимо указывать контекст устройства памяти. Например, функция ТехtОut() будет вызываться сле- дующим образом: push lе∩ТХТ_ТЕХТОUТ push offset @@ТХТ_ТЕХТОUТ push 150 push 10 push @@mеmdс calf TextOutA В пятой строке этого фрагмента функции TextOutQ передается не контекст окна, а контекст виртуального окна, что и приводит к выводу не в реальное окно, а в вир- туальное, являющееся растровым изображением. Как мы уже отметили, в програм- ма есть только одно место, где производится вывод в реальное окно, — это фраг- мент программы, обрабатывающий сообщение WM_PAINT. В случае виртуального окна здесь располагается функция ВitВLt(), которая копирует содержимое растрового изображения из контекста памяти в контекст реального окна. Таким образом постоянно обеспечивается актуальное содержимое окна приложения. В листинге 16.8 приведены фрагменты текста программы на языке ассембле- ра, демонстрирующей практическую реализацию способа перерисовки окна при- ложения с использованием виртуального окна. Полный текст программы находится среди файлов, прилагаемых к книге, в каталоге ..\рrglб_З данной главы. Листинг 16.8. Фрагменты приложения рrg16_З.аsm ;Фрагменты приложения (рrgl6_З.asm) для Win32 с использованием меню ;и виртуального окна для перерисовки содержимого окна; .386 locals;разрешает применение локальных меток .model flat, SТDСАLL;модель памяти flat, ; SТDСАLL - передача параметров в стиле С (справа ;вызываемая процедура чистит за собой стек include windowA.inc ; включаемый файл с описаниями базовых структур ;и констант Win32 include menu.inc ;включаемый файл с определением имен пунктов ;меню ;Объявпение внешними используемых в данной программе ;функций Win32 (ASCII); ехtrп GеtМоdulеНапdlеА:РRОС ехtrп GеtDС:РRОС ехtrп ВеgiпРаiпt ;РRОС ехtrп ЕпdРаiпt;РRОС ехtrп МеssаgеВохА:РRОС ехtrп DrаwТехtА:РRОС ехtrп GеtСliепtRесt:РRОС ехtrп GеtSуstеmМеtriсs:РRОС ехtrп СrеаtеСоmраtiЫеDС:РRОС ехtrп СrеаtеСоmраti ЫеВi tmар: РRОС ехtrп SеlесtОbjесt:РRОС ехtrп GеtStосkОbjесt:РRОС ехtrп РаtВlt:РRОС ехtrп ВitВlt:РRОС ехtrп IпvаlidаtеRесt:РRОС ехtrп DеlеtеDС:РRОС .
data mеmdс dd 0 ; ! ! ! это глобальная переменная mахХ dd 0 ; ! ! ! это глобальная переменная maxY dd 0 ;!!!это глобальная переменная 1рRесt RECT . code start proc near ; точка входа в программу: Wi nMai n start endp ;........................... ,Wi лdоwРгос---------------------------------------------------------- Wi лdоwРгос рrос аrд @@hwпd:DWORD, @@mеs:DWОRD, @@wраrаm:DWОRD, @@lраrаm:DWORD uses еbх, еdi , еsi, еbх ;эти регистры обязательно должны сохраняться local @@hdс:DWОRD, @@hbrush:DWORD, @@hb1t:DWORD сmр @@mеs, WМ_DЕSТRОY jе wmdеstrоу сmр @@mеs, WЙ_СRЕАТЕ jе wmсrеаtе сmр @@mеs, WМ_РАINТ jе wшраiпt сrар @@mеs, WМ_СОММАND jе wmсоmmапd jmр default wmсrеаtе: ;создание растрового изображения, совместимого с окном приложения ;получим размер экрана в пикселах iпt GеtSуstеmМеtriсs(int пlпdех) push SМ_СХSСRЕЕN call GеtSуstеmМеtriсs mоv mахХ, еах push SM_CYSCREEN call GеtSуstеmМеtriсs mоv mахY, еах ;лолучить контекст устройства окна на экране @@hdс=GеtDС(@@hwпd) push @@hwпd call GеtDС mоv @@hdс, еах ;получить совместимый контекст устройства памяти ;mеmdс=СrеаtеСоmраtiЫеDС (@@hdс) push @@hdс call СrеаtеСоmраtiblеDС mоv mеmdс, еах ;!!! mеmdс - глобальная переменная
;получить дескриптор растрового изображения в памяти ; @@hbi t=СrеаtеСоmраti ЫеВi tmар (@@hdс , @@mахХ, @@mахY) PATCOPY maxY maxX NULL NULL memdc PatBlt ;освободим контекст устройства RеlеаsеDС(@@hwпd, @@hdс) push @@hdс push @@hwпd call ReleaseDC ; обозначим создание окна звуковым эффектом ;готовим вызов функции ВООL РlауSоuпd(LРСSТR рszSоuпd, ;НМОDULЕ hmоd, DWORD fdwSоuпd) push SND_SYNС+SND_FILЕNАМЕ 14 Зак. 256

_ окна звуковым эффектом push SND_SYNС+SND_FILЕNАМЕ push NDLh push offset playFilePaint call PlaySoundA ;выведем строку текста в окно ВООLТехtОut(НDСhdс,iпtпХStаrt, ;iпt пYStаrt, LРСТSТR`lрStriпg,iпtсbStriпg); push MesWindowLen push offset MesWindow push 100 push 10 push memdc call TextOutA

push SRCCOPY push NULL push NULL push memdc push maxY push maxX push NULL push NDLh push @@hdс call BitBlt ;освободить контекст BOOL EndPaint(HWND hWnd, ;CONST PAINTSTRUCT *lpPaint); push offset ps push @@hwпd call EndPaint mov eax, 0 ;возвращаемое значение - jmp ехit_wпdрrос wmdestroy:

вывод виртуального окна в реальное окно ВООL ВitВlt(НDС hdсDеst, iпt пХDеst, iпt пYDеst inf nHeight, НDС hdсSrс, iпt пХSrс, iпt пYSrс, 0 wmcommand: ;вызов процедуры обработки сообщений от меню ;МепuРrос (DWORD @@hwпd, DWORD @@wраrаm) push @@wраrаm push @@hwпd call МепuРrос ехi t_wпdрrос exit_wпdрrос: rеt WiпdоwРrос епdр

;обработка сообщений от меню МепuРrосргос аrg @@hwпd:DWORD, @@wраrаm:DWORD uses ebx local mov ebx, @@wраrаm ;в Ьх идентификатор меню jmр @@ехit @@idmdrаwtехt: ;получим размер рабочей области BOOL GetClientRect(НWND hWпd, ;LРRЕСТ IрRесt) ; push offset IpRect push @@hwпd call GetClientRect ;выведем строку текста в окно iпt ;RРСТSТR lрStгiпg, int пСоuпt, ;РРRЕСТ IрRесt, UINТ uFоrmаt) ; push DT_SINGLELINE+DT_BOTTOM push offset IpRect push -1 push offset @@ТХТ_DRАWТЕХТ push memdc call DrawTextA ;генерация сообщения WМ_РАINТ для вывода строки на экран ;ВООL IпvаlidаtеRесt (НWND hWпd, CONST RЕСТ НрRесt, ВООL ЬЕrаsе) push 1 push NULL push @@hwпd call InvalidateRect jmp @@ехit @@idmtехtоut: ;выведем строку текста в окно BOOL TextOut(HDC hdc, int nXStart, ;int nYStart, LPCTSTR IpString, intcbString) push lепТХТ_ТЕХТОUТ push offset @@ТХТ_ТEXTOUT push 150 push 10 push memdc call TextOutA

;генерация сообщения WМ_РАINТ для вывода строки на экран @@idmiепgth: jmp @@ехit @@idmrесtапglе: jmp @@ехit @@idmреасосk: jmp @@ехit @@idmlасеs : jmp @@ехit @@idmаbоut: jmp @@ехit @@ехit: mov eax, 0 rеt @@ТХТ ABOUT db 'IDМ ABOUT', 0 Листинг 16.8 (продолжение) @@ТХТ_LАСЕS db ' IDИ_LАСЕS' , 0 @@ТХТ_РЕACOCK db 'IDМ_РЕАСОСК', Э @@ТХТ_RЕСТАNGLЕ db 'IDМ_RЕСТАNGLЕ', О @@ТХТ LЕNGТНdb 'IDМ_LЕNGТН', О @@ТХ^Г_ТЕХТОUТ db 'Текст выведен функцией TEXTOUT' lепТХТ_ТЕХТОUТ=$-@@ТХТ_ТЕХТОUТ @@ТХТ_DRАWТЕХТ db 'Текст выведен функцией DRАWТЕХТ', О МепuРrосепdр end start Возможно, результаты работы программы из листинга 16.8 вам покажутся не очень красивыми, но такая цель и не ставилась.

Назначение этой программы — исследовательское. Из-за задержек, вызванных воспроизведением звуковых фай- лов, хорошо виден момент перерисовки окна. Такую технологию можно использо- вать для более глубокого исследования механизмов работы Windows.
<< | >>
Источник: В. И. Юров. Assembler. Учебник для вузов. 2-е изд. 2003

Еще по теме Перерисовка изображения:

  1. ИЗОБРАЖЕНИЕ ДВОЙСТВЕННОЕ
  2. Микширование изображения
  3. Совмещение изображений
  4. Название и изображение
  5. 7. Право на неприкосновенность личного изображения
  6. Стирание записи изображения и звука
  7. Соотношение изображения и слова
  8. Качество приема, звучания и изображения.
  9. § 6. Права на индивидуальный облик и собственное изображение (п. 1686-1692)
  10. Видеомагнитофон
  11. ЗРЕНИЕ БИНОКУЛЯРНОЕ
  12. СТЕРЕОСКОП
  13. Телевизор
  14. МЕТОДИКА РИСУНОЧНАЯ
  15. ПИГМАЛИОНОФИЛИЯ
  16. 6.17.3. Сначала картины, а потом слова
  17. Звук в телевидении