Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

Иногда, в результате обработки сообщения функцией DefWindowProc, генерируются другие сообщения. Например, запускается HELLOWIN и выбирается Close из системного меню программы, используя клавиатуру или мышь. DefWindowProc обрабатывает эту информацию. Когда она определяет, что выбрана опция Close, то отправляет сообщение WM_SYSCOMMAND оконной процедуре. WndProc передает это сообщение DefWindowProc. DefWindowProc реагирует на него, отправляя сообщение WM_CLOSE оконной процедуре. WndProc снова передает это сообщение DefWindowProc. DefWindowProc реагирует на сообщение WM_CLOSE, вызывая функцию DestroyWindow. DestroyWindow заставляет Windows отправить сообщение WM_DESTROY оконной процедуре. И наконец, WndProc реагирует на это сообщение, вызывая функцию PostQuitMessage путем постановки сообщения WM_QUIT в очередь сообщений. Это сообщение прерывает цикл обработки сообщений в WinMain и программа заканчивается.

Синхронные и асинхронные сообщения

Ранее было рассказано о передаче окну сообщений, что означает вызов операционной системой Windows оконной процедуры. Но в программах для Windows имеется цикл обработки сообщений, который берет сообщения из очереди сообщений, вызывая функцию GetMessage, и отправляет их оконной процедуре, вызывая функцию DispatchMessage.

Одни и те же сообщения могут быть и "синхронные" (queued), и "асинхронные" (nonqueued)[1]. Cинхронными сообщениями называются сообщения, которые Windows помещает в очередь сообщений программы, и которые извлекаются и диспетчеризуются в цикле обработки сообщений. Асинхронные сообщения передаются непосредственно окну, когда Windows вызывает оконную процедуру. В результате оконная процедура получает все предназначенные для окна сообщения, как синхронные, так и асинхронные. Структура программ для Windows очень проста, поскольку у них имеется только одно центральное место обработки сообщений. Говорят, что синхронные сообщения помещаются в очередь сообщений (post), а асинхронные посылаются прямо в оконную процедуру (send).

НЕ нашли? Не то? Что вы ищете?

Синхронными становятся сообщения, в основном, тогда, когда они являются результатом пользовательского ввода путем нажатия клавиш (например, WM_KEYDOWN и WM_KEYUP), это символы, введенные с клавиатуры (WM_CHAR), результат движения мыши (WM_MOUSEMOVE) и щелчков кнопки мыши (WM_LBOTTONDOWN). Кроме этого синхронные сообщения включают в себя сообщение от таймера (WM_TIMER), сообщение о необходимости плановой перерисовки (WM_PAINT) и сообщение о выходе из программы (WM_QUIT). Сообщения становятся асинхронными во всех остальных случаях. Часто асинхронные сообщения являются результатом синхронных. При передаче асинхронного сообщения в DefWindowProc из оконной процедуры, Windows часто обрабатывает сообщение, отправляя оконной процедуре другие асинхронные сообщения.

Очевидно, что процесс этот сложен, но к счастью большая часть сложностей ложится на Windows. С позиции оконной процедуры, эти сообщения проходят через нее упорядочено или синхронно. Оконная процедура может что-то сделать с этими сообщениями, а может и проигнорировать их. По этой причине оконную процедуру назвали "конечным пунктом обработки" (ultimate hook). Сообщения извещают оконную процедуру почти обо всем, что влияет на окно.

Часто асинхронные сообщения являются результатом вызова определенных функций Windows или непосредственным результатом вызова функции SendMessage. (Кроме этого, сообщения могут помещаться в очередь сообщений посредством вызова функции PostMessage.)

Например, когда WinMain вызывает функцию CreateWindow, Windows создает окно и для этого отправляет оконной процедуре асинхронное сообщение WM_CREATE. Когда WinMain вызывает ShowWindow, Windows отправляет оконной процедуре асинхронные сообщения WM_SIZE и WM_SHOWWINDOW. Когда WinMain вызывает UpdateWindow, Windows отправляет оконной процедуре асинхронное сообщение WM_PAINT.

Сообщения не похожи на аппаратные прерывания. Во время обработки в оконной процедуре одного сообщения программа не может быть прервана другим сообщением. Только в том случае, если оконная процедура вызвала функцию, которая сама стала источником нового сообщения, то оконная процедура начнет обрабатывать это новое сообщение еще до того, как функция вернет управление программе.

Цикл обработки сообщений и оконная процедура работают не параллельно. Когда оконная процедура обрабатывает сообщение, то это результат вызова функции DispatchMessage в WinMain. DispatchMessage не завершается до тех пор, пока оконная процедура не обработала сообщение.

Оконная процедура должна быть повторно-входимой (reentrant). Это означает, что Windows часто вызывает WndProc с новым сообщением, как результат вызова функции DefWindowProc в WndProc с предыдущим сообщением. В большинстве случаев повторная входимость оконной процедуры не создает проблем, но об этом следует знать.

Часто возникает необходимость того, чтобы оконная процедура сохраняла информацию, полученную в сообщении, и использовала ее при обработке другого сообщения. Тогда эту информацию следует описывать в оконной процедуре в виде статических переменных, либо хранить в глобальных переменных.

В Windows можно выводить информацию только в рабочую область окна, и нельзя быть уверенным в том, что там что-нибудь будет оставаться, до тех пор пока программа специально не выведет что-нибудь поверх. Например, окно диалога другого приложения может перекрыть часть рабочей области. Хотя Windows будет пытаться сохранить и восстановить область экрана под окном диалога, это не всегда получается. После того как окно диалога удаляется с экрана, Windows выдаст запрос, требующий, чтобы программа перерисовала эту часть рабочей области.

Windows — это операционная система, управляемая сообщениями. Windows уведомляет приложения о различных событиях путем постановки синхронных сообщений в очередь сообщений приложения или путем отправки асинхронных сообщений соответствующей процедуре окна. Посылая синхронное сообщение WM_PAINT, Windows уведомляет оконную процедуру о том, что часть рабочей области окна необходимо обновить.

Сообщение WM_PAINT

Большинство программ для Windows вызывают функцию UpdateWindow при инициализации в WinMain, сразу перед входом в цикл обработки сообщений. Windows использует эту возможность для асинхронной отправки в оконную процедуру первого сообщения WM_PAINT. Это сообщение информирует оконную процедуру о том, что рабочая область готова к рисованию. После этого оконная процедура должна быть готова в любое время обработать дополнительные сообщения WM_PAINT и даже перерисовать, при необходимости, всю рабочую область окна. Оконная процедура получает сообщение WM_PAINT при возникновении одной из следующих ситуаций:

q Предварительно скрытая область окна открылась, когда пользователь передвинул окно или выполнил какие-то действия, в результате которых окно вновь стало видимым.

q Пользователь изменил размера окна (если в стиле класса окна установлены биты CS_HREDRAW и CS_HVREDRAW).

q В программе для прокрутки части рабочей области используются функции ScrollWindow или ScrollDC.

q Для генерации сообщения WM_PAINT в программе используются функции InvalidateRect или InvalidateRgn.

В некоторых случаях, когда часть рабочей области временно закрывается, Windows пытается сначала ее сохранить, а затем восстановить. Это не всегда возможно. В некоторых случаях Windows может послать синхронное сообщение WM_PAINT. Обычно это происходит, когда:

· Windows удаляет диалоговое окно или окно сообщения, которое перекрывало часть окна программы.

· Раскрывается пункт горизонтального меню и затем удаляется с экрана.

В некоторых случаях Windows всегда сохраняет перекрываемую область, а потом восстанавливает ее. Происходит это всегда, когда:

· Курсор мыши перемещается по рабочей области.

· Иконку перемещают по рабочей области.

Программа должна быть структурирована таким образом, чтобы в ней была собрана вся информация, необходимая для рисования в рабочей области, но рисование осуществлялось бы только "по запросу" — когда Windows отправит оконной процедуре синхронное сообщение WM_PAINT. Если программе необходимо перерисовать свою рабочую область, она может заставить Windows сгенерировать сообщение WM_PAINT. Это может показаться не самым простым способом вывода информации на экран, но структура программы от этого только улучшится.

Действительные и недействительные прямоугольники

Хотя оконная процедура должна быть готова в любой момент, при получении сообщения WM_PAINT, перерисовать всю рабочую область, часто бывает необходимо перерисовать только небольшую ее часть (обычно прямоугольную область внутри рабочей зоны окна). Это наиболее очевидно, когда часть рабочей области закрыта диалоговым окном. Перерисовка требуется только для прямоугольной области, вновь открывающейся при удалении окна диалога.

Эту область называют "недействительном регионом" (invalid region) или "регионом обновления" (update region). Появление недействительного региона в рабочей области вынуждает Windows поместить синхронное сообщение WM_PAINT в очередь сообщений приложения. Оконная процедура получает сообщение WM_PAINT только тогда, когда часть рабочей области недействительна, т. е. требует обновления.

В Windows для каждого окна поддерживается "структура информации о рисовании" (paint information structure). В этой структуре содержатся (помимо другой информации) координаты минимально возможного прямоугольника, содержащего недействительную область. Эта информация носит название "недействительного прямоугольника" (invalid rectangle); иногда — "недействительного региона" (invalid region). Если еще один регион рабочей области становится недействительным перед обработкой сообщения WM_PAINT, Windows рассчитывает новый недействительный регион, который содержит оба эти региона и запоминает эту новую информацию в структуре информации о рисовании. Windows не помещает в очередь сообщений сразу несколько сообщений WM_PAINT.

Оконная процедура, вызывая функцию InvalidateRect, может задать недействительный прямоугольник в своей рабочей области. Если в очереди сообщений уже содержится сообщение WM_PAINT, Windows рассчитывает новый недействительный прямоугольник. В противном случае Windows помещает новое сообщение WM_PAINT в очередь сообщений. При принятии сообщения WM_PAINT (как мы позже увидим в этой главе), оконная процедура может получить координаты недействительного прямоугольника. Она также может получить эти координаты в любое другое время, вызвав функцию GetUpdateRect.

После того как оконная процедура вызывает функцию BeginPaint при обработке сообщения WM_PAINT, вся рабочая область становится действительной. Программа, вызвав функцию ValidateRect, также может сделать действительной любую прямоугольную зону в рабочей области. Если этот вызов делает действительной всю рабочую область, тогда любое сообщение WM_PAINT, имеющееся в это время в очереди сообщений, удаляется из нее и не обрабатывается.

Для рисования в рабочей области окна, используются функции графического интерфейса устройства. В Windows имеется несколько функций GDI для вывода строк текста в рабочей области окна. Популярная функция TextOut. Формат этой функции следующий:

TextOut(hdc, x, y, psString, iLength);

Функция TextOut выводит на экран строку символов. Параметр psString — это указатель на строку символов, а iLength — длина строки символов. Параметры x и y определяют начальную позицию строки символов в рамках рабочей области. (Более подробно об этом будет рассказано в дальнейшем.) Параметр hdc — это "описатель контекста устройства" (handle to a device context), являющийся важной частью GDI. Практически каждой функции GDI в качестве первого параметра необходим этот описатель.

Контекст устройства

Описатель — это просто число, которое Windows использует для внутренней ссылки на объект. Описатель контекста устройства — это паспорт окна для функций GDI. Этот описатель дает полную свободу при рисовании в рабочей области окна.

Контекст устройства фактически является структурой данных, которая внутренне поддерживается GDI. Контекст устройства связан с конкретным устройством вывода информации, таким как принтер, плоттер или дисплей. Что касается дисплея, то в данном случае контекст устройства обычно связан с конкретным окном на экране.

Некоторые значения в контексте устройства являются графическими "атрибутами" (attributes). Эти атрибуты определяют некоторые особенности работы функций рисования GDI. Например, для функции TextOut эти атрибуты контекста устройства задают цвет текста, цвет фона для текста, процедуру преобразования координат x и y, передаваемых функции TextOut в координаты рабочей области, а также шрифт, используемый для вывода текста.

Когда программе необходимо начать рисование, она должна получить описатель контекста устройства. После окончания рисования программа должна освободить описатель. Когда программа освободит описатель, он становится недействительным и не должен далее использоваться. Во время обработки каждого отдельного сообщения программа должна получить и освободить описатель. За исключением описателя контекста устройства, созданного функцией CreateDC, не следует хранить описатель контекста устройства в промежутке между обработкой различных сообщений.

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

Получение описателя контекста устройства. Первый метод

Этот метод используется при обработке сообщений WM_PAINT. Применяются две функции: BeginPaint и EndPaint. Для этих двух функций требуется описатель окна (передаваемый в оконную процедуру в качестве параметра) и адрес переменной типа структуры PAINTSTRUCT. Программисты, пишущие программы для Windows, обычно называют эту структурную переменную ps и определяют ее внутри оконной процедуры следующим образом:

PAINTSTRUCT ps;

Во время обработки сообщения WM_PAINT оконная процедура сначала вызывает BeginPaint для заполнения полей структуры ps. Возвращаемым значением функции BeginPaint является описатель контекста устройства. Обычно он передается переменной с именем hdc. Эта переменная определяется в оконной процедуре следующим образом:

HDC hdc;

Тип данных HDC определяется как 32-разрядное беззнаковое целое. Затем программа может использовать функции GDI, например TextOut. Вызов функции EndPaint освобождает описатель контекста устройства.

Типовой процесс обработки сообщения WM_PAINT выглядит следующим образом:

case WM_PAINT:

hdc=BeginPaint(hwnd, &ps);

[использование функций GDI]

EndPaint(hwnd, &ps);

return 0;

При обработке сообщения WM_PAINT в оконной процедуре функции BeginPaint и EndPaint должны обязательно вызываться парой. Если в оконной процедуре сообщения WM_PAINT не обрабатываются, то они должны передаваться в DefWindowProc (процедура обработки сообщений по умолчанию), реализованной в Windows.

DefWindowProc обрабатывает сообщения WM_PAINT следующим образом:

case WM_PAINT:

BeginPaint(hwnd, &ps);

EndPaint(hwnd, &ps);

return 0;

Следующие одна за другой функции BeginPaint и EndPaint просто превращают ранее недействительный регион в действительный. Но нельзя делать следующее:

case WM_PAINT:

return 0; // ОШИБКА!!!

Windows помещает сообщение WM_PAINT в очередь сообщений, поскольку часть рабочей области окна недействительна (требует перерисовки). До тех пор пока не вызовутся функции BeginPaint и EndPaint (или ValidateRect), Windows не сделает эту область действительной. Вместо этого Windows снова отправит сообщение WM_PAINT. И снова, и снова, и снова...

Структура информации о рисовании

Структура определяется так:

typedef struct tagPAINTSTRUCT

{

HDC hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

}

PAINTSTRUCT;

Windows заполняет поля этой структуры, когда программа вызывает BeginPaint. В программе можно использовать только первые три поля структуры. Остальные используются Windows.

Поле hdc — это описатель контекста устройства. Возвращаемым значением функции BeginPaint также является описатель контекста устройства, и такая избыточность характерна для Windows.

В подавляющем большинстве случаев, в поле fErase установлен флаг TRUE (т. е., ненулевое значение), означающий, что Windows обновит фон недействительного прямоугольника. Windows перерисует фон, используя кисть, заданную в поле hbrBackground структуры WNDCLASSEX, которую использовали при регистрации класса окна во время инициализации WinMain. Многие программы для Windows используют белую кисть:

wndclass. hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);

Однако, если, вызывая функцию InvalidateRect, делаете недействительным прямоугольник рабочей зоны программы, то последний параметр этой функции определяет, нужно ли стирать фон. Если этот параметр равен FALSE (т. е. 0), Windows не будет стирать фон и поле fErase также будет равно FALSE.

Поле rcPaint структуры PAINTSTRUCT — это структура типа RECT. В ней имеется четыре поля: left, top, right и bottom. Поле rcPaint структуры PAINTSTRUCT определяет границы недействительного прямоугольника, как показано на рис. Значения заданы в пикселях относительно левого верхнего угла рабочей области. Недействительный прямоугольник — это та область, которую необходимо перерисовать. Хотя программа для Windows может просто перерисовать всю рабочую область окна при получении сообщения WM_PAINT, перерисовка только той области окна, которая задана этим прямоугольником, экономит время.

right

 

left

 

0

 

bottom

 

top

 

0

 

Границы недействительного прямоугольника

Прямоугольник rcPaint в PAINTSTRUCT — это не только недействительный прямоугольник, это также и "отсекающий" (clipping) прямоугольник. Это означает, что Windows рисует только внутри отсекающего прямоугольника. (Или точнее, если недействительная зона не является прямоугольником, Windows рисует только внутри этой зоны.) Когда используется описатель контекста устройства из структуры PAINTSTRUCT, Windows не будет рисовать вне прямоугольника rcPaint.

Чтобы при обработке сообщения WM_PAINT рисовать вне прямоугольника rcPaint, можно сделать вызов:

InvalidateRect (hWnd, NULL, TRUE);

перед вызовом BeginPaint. Это сделает недействительной всю рабочую область и обновит ее фон. Если же значение последнего параметра будет равно FALSE, то фон обновляться не будет. Все что там было, останется неизменным.

Если оказывалось, что область вывода текста на экран находится внутри недействительного прямоугольника, то функция DrawText перерисовывала ее. Если при обработке вызова DrawText Windows не находит такие области, на экран ничего не выводится. Но такой поиск требует времени. Программист, заботящийся об эффективности и быстродействии, захочет при обработке сообщений WM_PAINT использовать размеры недействительного прямоугольника, чтобы не обращаться лишний раз к вызо GDI.

Получение описателя контекста устройства. Второй метод

Также можно получить описатель контекста устройства, если необходимо рисовать в рабочей области при обработке отличных от WM_PAINT сообщений, или если необходим описатель контекста устройства для других целей, например, для получения информации о самом контексте устройства. Вызывается GetDC для получения описателя контекста устройства и ReleaseDC, если он больше не нужен:

hdc=GetDC(hwnd);

[использование функций GDI]

ReleaseDC(hwnd, hdc);

Также как BeginPaint и EndPaint, функции GetDC и ReleaseDC следует вызывать парой. Если при обработке сообщения вызывается GetDC, то перед выходом из оконной процедуры необходимо вызвать ReleaseDC. Не вызываутся GetDC при обработке одного сообщения, а ReleaseDC при обработке другого.

В отличие от описателя контекста устройства, полученного из структуры PAINTSTRUCT, в описателе контекста устройства, возвращаемом функцией GetDC, определен отсекающий прямоугольник, равный всей рабочей области. Можно рисовать в любом месте рабочей области, а не только в недействительном прямоугольнике (если недействительный прямоугольник вообще определен). В отличии от BeginPaint, GetDC не делает действительными какие-либо недействительные зоны.

Как правило, используются вызовы функций GetDC и ReleaseDC в ответ на сообщения от клавиатуры (например, в программах текстовых редакторов) или на сообщения от манипулятора мышь (например, в программах рисования). Они позволяют обновлять рабочую область непосредственно в ответ на пользовательский ввод информации с клавиатуры или с помощью мыши, при этом специально делать недействительной часть окна для выдачи сообщений WM_PAINT. Однако, в программах должно содержаться достаточно информации для обновления экрана в любой момент, когда получается сообщение WM_PAINT.

Полосы прокрутки являются одними из самых лучших возможностей, который дает графический интерфейс и манипулятор мышь. Они просты в использовании и обеспечивают удобный просмотр информации. Можно пользоваться полосами прокрутки для вывода на экран текста, графики, электронных таблиц, записей баз данных, картинок — всего, что требует больше пространства, чем доступно в рабочей области окна.

Полосы прокрутки предназначены для просмотра информации как в вертикальном (движение вверх и вниз), так и в горизонтальном (движение вправо и влево) направлениях. Можно щелкнуть мышью на стрелке в любом конце полосы прокрутки или между стрелками. Бегунок ("scroll box" или "thumb") перемещается по длине полосы прокрутки, индицируя положение информации на экране относительно документа в целом. Можно с помощью мыши переместить бегунок в конкретное положение. На рис. показано рекомендуемое использование вертикальной полосы прокрутки для просмотра текста.

Программисты иногда сталкиваются с проблемой терминологии, относящейся к полосам прокрутки, поскольку их точка зрения отличается от пользовательской. Пользователь, который передвигает бегунок вниз, хочет увидеть нижнюю часть документа; однако, программа фактически перемещает документ вверх относительно окна. Документация Windows и идентификаторы ее заголовочных файлов основываются на точке зрения пользователя: Прокрутка вверх означает движение к началу документа; прокрутка вниз означает движение к концу.

Переместите бегунок для пере­­хода в нужное место

 

Щелкните здесь для прокрутки на одну строку вниз

 

Щелкните здесь для прокрутки на одну строку вверх

 

Щелкните здесь для прокрутки на одну страницу вниз

 

Щелкните здесь для прокрутки на одну страницу вверх

 

Вертикальная полоса прокрутки

Вставить в окно приложения вертикальную или горизонтальную полосу прокрутки очень просто. Все, что нужно сделать, это включить идентификатор WS_VSCROLL (вертикальная прокрутка) и WS_HSCROLLW (горизонтальная прокрутка) или оба сразу в описание стиля окна в инструкции CreateWindow. Эти полосы прокрутки всегда размещаются у правого края или в нижней части окна и занимают всю высоту или ширину рабочей области. Рабочая область не включает в себя пространство, занятое полосами прокрутки. Ширина вертикальной полосы прокрутки и высота горизонтальной постоянны для конкретного дисплейного драйвера. Если необходимы эти значения, можно получить их, вызвав функцию GetSystemMetrics.

Windows обеспечивает всю логику работы мыши с полосами прокрутки. Однако, у полос прокрутки нет интерфейса клавиатуры. Если необходимо дублировать клавишами управления курсором некоторые функции полос прокрутки, необходимо точно реализовать эту логику.

Диапазон и положение полос прокрутки

Каждая полоса прокрутки имеет соответствующий "диапазон" (range) (два целых, отражающих минимальное и максимальное значение) и "положение" (position) (местоположение бегунка внутри диапазона). Когда бегунок находится в крайней верхней (или крайней левой) части полосы прокрутки, положение бегунка соответствует минимальному значению диапазона. Крайнее правое (или крайнее нижнее) положение бегунка на полосе прокрутки соответствует максимальному значению диапазона.

По умолчанию устанавливается следующий диапазон полосы прокрутки: 0 (сверху или слева) и 100 (снизу или справа), но диапазон легко изменить на какое-нибудь более подходящее для программы значение:

SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw);

Параметр iBar равен либо SB_VERT, либо SB_HORZ, iMin и iMax являются минимальной и максимальной границами диапазона, а bRedraw устанавливается в TRUE, если необходимо, чтобы Windows перерисовала полосы прокрутки на основе вновь заданного диапазона.

Положение бегунка всегда дискретно. Например, полоса прокрутки с диапазоном от 0 до 4 имеет пять положений бегунка, как показано на рис. Для установки нового положения бегунка внутри диапазона полосы прокрутки можно использовать функцию SetScrollPos:

SetScrollPos (hwnd, iBar, iPos, bRedraw);

Параметр iPos — это новое положение бегунка, оно должно быть задано внутри диапазона от iMin до iMax. Для получения текущего диапазона и положения полосы прокрутки в Windows используются похожие функции (GetScrollRange и GetScrollPos).

Далее перечислены сферы ответственности Windows по поддержке полос прокрутки:

· Управляет логикой работы мыши с полосой прокрутки.

· Обеспечивает временную "инверсию цвета" при нажатии на кнопку мыши на полосе прокрутки.

· Перемещает бегунок в соответствие с тем, как внутри полосы прокрутки его перемещает пользователь.

· Отправляет сообщения полосы прокрутки в оконную процедуру для окна, содержащего полосу прокрутки.

Ниже представлены сферы ответственности программы:

· Инициализация диапазона полосы прокрутки.

· Обработка сообщений полосы прокрутки.

· Обновление положения бегунка полосы прокрутки.

Положение 4

 

Положение 3

 

Положение 2

 

Положение 1

 

Положение 0

 

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8