Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A05_API.doc
Скачиваний:
5
Добавлен:
12.11.2019
Размер:
1.3 Mб
Скачать

SetArcDirection (hdc, ad_clockwise);

то функция Arc нарисует дугу, показанную на рис. 5.7.

Функция Arc не использует текущую позицию пера и не обновляет ее.

Функция ArcTo отличается от функции Arc тем, что она проводит линию из текущей позиции пера в заданную начальную точку дуги, и только после этого рисует дугу. После завершения рисования функция ArcTo перемещает текущую позицию пера в конечную точку дуги.

5.5.5. Рисование прямоугольника. Для рисования прямоугольников предусмотрены функции Rectangle, FillRect, FrameRect, InvertRect и DrawFocusRect. Мы рассмотрим только первую.

Функция Rectangle имеет следующий прототип:

Bool Rectangle (hdc hdc, int xLeft, int yTop, int xRight int yBottom);

Она рисует прямоугольник, определяемый четырьмя координатами. Параметры xLeft и yTop задают положение левого верхнего угла, а xRight и yBottom – положение правого нижнего угла. Стороны прямоугольника всегда параллельны горизонтальной и вертикальной сторонам экрана.

5.5.6. Рисование эллипса. Для рисования эллипсов предназначена функция Ellipse, прототип которой приведен ниже:

Bool Ellipse (hdc hdc, int xLeft, int yTop, int xRight, int yBottom);

Функция рисует эллипс в ограничивающем прямоугольнике, заданном координатами xLeft, yTop, xRight, yBottom. Ранее уже рассматривалось рисование дуги эллипса с помощью функции Arc.

5.5.7. Рисование многоугольника. Для рисования произвольного многоугольника предназначенииа функция Polygon:

Bool Polygon (hdc hdc, const point * lpPoints, int nCount);

Работа этой функции напоминает рисование ломаных линий функцией Polyline. Второй параметр функции принимает адрес массива точек, а третий – количество точек. В отличие от Polyline функция Polygon автоматически замыкает фигуру.

Контрольные вопросы

5.6. Средства ввода

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

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

На рис. 5.8 приведена схема обработки сообщения от клавиатуры, используемая в операционной системе.

Модель клавиатурного ввода

Рис. 5.8

Каждой клавише на клавиатуре соответствует два уникальных целых числа, называемых скан-кодом нажатия и скан-кодом отпускания клавиши. Скан-код (scan code) является аппаратно-зависимым, т. е. на клавиатурах разных производителей одна и та же клавиша может иметь разные скан-коды. Когда пользователь нажимает или отпускает клавишу, драйвер клавиатуры получает соответствующие скан-коды. Полученный скан-код преобразуется драйвером в виртуальный код клавиши (virtual key code). Этот код является уже аппаратно-независимым, поэтому в системе Windows он однозначно идентифицирует нажатую или отпущенную клавишу. Завершающим действием драйвера является создание сообщения, содержащего скан-код, виртуальный код клавиши и другую информацию о нажатой / отпущенной клавише. Это сообщение помещается в системную очередь сообщений.

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

5.6.2. Фокус ввода. Все приложения, работающие одновременно под управлением Windows, должны иметь возможность получать данные от клавиатуры. Если какое-то приложение имеет более одного окна, то клавиатура должна разделяться между окнами в рамках одного приложения. Это разделение Windows реализует, используя понятие фокуса ввода. Фокус ввода (keyboard focus) – это всременное свойство окна, которое означает, что все сообщения от клавиатуры направляются именно этому окну. В каждый момент времени из всех окон, имеющихся на экране, только одно окно может иметь фокус ввода.

Понятие фокуса ввода тесно связано с понятием активного окна. Активное окно - это окно верхнего уровня, с которым в данный момент работает пользователь. Система выделяет текст заголовка активного окна, поэтому отыскать его на экране довольно просто. Если активное окно минимизировано, то Windows выделяет текст заголовка на пнели задач.

Фокусом ввода всегда владеет либо активное окно, либо одно из его дочерних окон. Часто дочерними окнами являются элементы управления – кнопки, переключатели, флажки, текстовые поля и списки, которые обычно размещаются в окне диалога. Элементы управления по-разному показывают, что они находятся в фокусе. Так, вокруг текста кнопки выводится точечная линия, а текстовое поле показывает, что оно получило фокус ввода, при помощи мигающего курсора.

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

Обрабатывая сообщения WM_SETFOCUS и WM_KILLFOCUS, оконная процедура может определить текущий статус связанного с ней окна. Первое сообщение показывает, что окно получило фокус ввода, второе – что окно потеряло фокус ввода.

Для работы с фокусом ввода предусмотрены следующие функции:

  • функция HWND SetFocus (HWND hWnd) устанавливает фокус ввода на окно hWnd,

  • функция HWND GetFocus () возвращает дескриптор окна, имеющего фокус ввода в текущий момент.

5.6.3. Клавиши и символы. Клавиатура всегда генерирует некоторые числовые коды, но ее можно рассматривать либо как совокупность отдельных физических клавиш, либо как средство генерации кодов символов.

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

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

Клавиши можно разделить на следующие четыре группы:

  • клавиши-переключатели – Caps Lock, Nem Lock, Scroll Lock и в некоторых случаях клавиша Insert. При нажатии такой клавиши включается ее состояние, а при повторном нажатии – выключается. Как правило, на клавиатуре есть световые индикаторы состояния клавиш-переключателей.

  • клавиши управления регистром – Shift, Ctrl и Alt. В нажатом состоянии такая клавиша меняет интерпретацию других клавиш. Иногда такие клавиши называют клавишами-модификаторами.

  • клавиши, не генерирующие символов, - функциональные клавиши, клавиши управления курсором, Pause, Delete.

  • символьные клавиши – буквы, цифры и другие символы, пробел, Tab, Backspace, Esc и Enter. Клавиши Tab, Backspace, Esc и Enter также можно рассматривать как клавиши без символов.

Сообщения клавиатуры, которые приложение получает от Windows, можно разделить на «аппаратные» и «символьные». Это разделение соответствует указанной выше двойственной интерпретации клавиатуры.

5.6.4. Аппаратные сообщения. Аппаратные сообщения от клавиатуры приведены в таблице 5.1.

Обычно различают системные и несистемные сообщения. Для системных сообщений используется префикс SYS в составе идентификатора кода сообщения.

Аппаратные сообщения от клавиатуры Таблица 5.1

Категория

Клавиша нажата

Клавиша отпущена

Несистемные сообщения

WM_KEYDOWN

WM_KEYUP

Системные сообщения

WM_SYSKEYDOWN

WM_SYSKEYUP

Системные сообщения WM_SYSKEYDOWN и WM_SYSKEYUP, вырабатываемые обычно при нажатии клавиш в сочетании с клавишей Alt, более важны для Windows, чем для приложения. Эти сообщения вызывают команды программного или системного меню. Они также используются для вызова системных функций, таких как смена активного окна (Alt + Tab), или как быстрые клавиши системного меню (Alt в сочетании с функциональной клавишей). Поскольку система Windows самостоятельно отрабатывает всю логику Alt – клавиш, то программистам, фактически, не нужно обрабатывать эти сообщения. Оконная процедура приложения в конце концов получит другие сообщения, являющиеся следствием этих аппаратных сообщений клавиатуры (например, выбор команды меню).

Обычно сообщения о нажатии и отпускании клавиш появляются парами. Однако если пользователь оставит клавишу нажатой так долго, что включится автоповтор, то Windows пошлет оконной процедуре серию сообщений WM_KEYDOWN и одно сообщение WM_KEYUP, когда, в конце концов, клавиша будет отпущена.

Для всех аппаратных сообщений клавиатуры 32-разрядная переменная lParam, передаваемая в оконную процедуру, содержит 6 полей (таблица 5.2).

Интерпретация полей параметра lParam Таблица 5.2

Разряды

Назначение

Описание

15 … 0

Счетчик повторений

Число повторений данного сообщения. Равно либо единице, либо числу нажатий в режиме автоповтора, когда пользователь удерживает клавишу нажатой. Для сообщения WM_KEYUP всегда равен единице

23 … 16

Скан - код

Восьмибитный скан-код ОЕМ

24

Флаг расширенной клавиатуры

Устанавливается в единицу для дополнительных клавиш расширенной клавиатуры IBM (функциональные клавиши в верхней части клавиатуры, клавиши Alt и Ctrl на правой стороне клавиатуры и некоторые другие клавиши)

29

Код контекста

Устанавливается в единицу, если нажата клавиша Alt (для сообщений WM_KEYDOWN и WM_KEYUP всегда равен нулю)

30

Флаг предыдущего состояния клавиши

Единица, если клавиша была нажата, и нуль, если клавиша была отпущена

31

Флаг нового состояния клавиши

Нуль, если клавиша нажата, и единица, если клавиша отпущена

Хотя некоторая информация в lParam при обработке аппаратных сообщений может оказаться полезной, гораздо более важен параметр wParam, содержащий виртуальный код клавиши.

Виртуальный код клавиши (virtual key code) идентифицирует нажатую или от пущенную клавишу и является аппаратно-независимым. Идентификаторы виртуальных клавиш определены в файле winuser.h. В таблице 5.3 приведены наиболее часто используемые коды.

Виртуальные коды клавиш Таблица 5.3

Десятичное значение

Шестнадцатеричное значение

Идентификатор

Клавиатура IBM

3

03

VK_CANCEL

Ctrl+Break

8

08

VK_BACK

Backspace

9

09

VK_TAB

Tab

13

0D

VK_RETURN

Enter

16

10

VK_SHIFT

Shift

17

11

VK_CONTROL

Ctrl

18

12

VK_MENU

Alt

19

13

VK_PAUSE

Pause

20

14

VK_CAPITAL

Caps Lock

27

1B

VK_ESCAPE

Esc

32

20

VK_SPACE

Пробел

33

21

VK_PRIOR

Page Up

34

22

VK_NEXT

Page Down

35

23

VK_END

End

36

24

VK_HOME

Home

37

25

VK_LEFT

Стредка влево

38

26

VK_UP

Стрелка вверх

39

27

VK_RIGHT

Стрелка вправо

40

28

VK_DOWN

Стрелка вниз

44

2C

VK_SNAPSHOT

Print Screen

45

2D

VK_INSERT

Insert

46

2E

VK_DELETE

Delete

48 … 57

30 … 39

0 … 9 (на основной клавиатуре)

65 … 90

41 … 5A

A … Z

112 … 123

70 … 7B

VK_F1 … VK_F12

F1 … F12

144

90

VK_NUMLOCK

Num Lock

145

91

VK_SCROLL

Scroll Lock

Обычно оконная процедура обрабатывает только небольшую часть из всех аппаратных сообщений клавиатуры, игнорируя остальные. Наприме, она может обрабатывать только те сообщения WM_KEYDOWN, которые содержат виртуальные коды для клавиш управления курсором, клавиши Shift и функциональных клавиш. В то же время аппаратные сообщения для символьных клавиш удобнее обрабатывать, используя символьное сообщение WM_CHAR.

5.6.5. Символьные сообщения. Когда нажимается символьная клавиша, генерируемый код зависит от многих факторов. На его формирование влияет положение клавиш-переключателей и клавиш управлениия регистром, а также текущая кодовая страница, установленная в системе. Все эти факторы учитывает функция TranslateMessage, вызываемая в цикле обработки сообщений, который находится в теле функции WinMain и имеет вид:

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg);

DispatchMessage(&msg);

}

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

Между этими двумя функциями располагается вызов функции TranslateMessage, которая преобразует аппаратные сообщения клавиатуры в символьные сообщения. Если аппаратным сообщением является WM_KEYDOWN, а нажатая клавиша в сочетании с положением клавиш-модификаторов соответствует некоторому символу, то TranslateMessage помещает символьное сообщение в очередь сообщений.

В результате системной обработки сообщения WM_KEYDOWN может быть инициировано символьное сообщение WM_CHAR или WM_DEADCHAR.

Рассмотрим кратко назначение сообщения WM_DEADCHAR. На некоторых неамериканских клавиатурах имеются так называемые немые клавиши (dead keys), предназначенные для ввода диакритических знаков, таких как, например, «умляут». Диакритические знаки вводятся в паре с обычными символами, в результате чего формируется составной символ. Например, для ввода на немецкой клавиатуре символа «U» (Uумляут) пользователь сначала нажимает немую клавишу «умляут», а затем – клавишу U. В нашей программе не нужно обрабатывать сообщение WM_DEADCHAR, поскольку Windows берет это на себя, вырабатывая в результате сообщение WM_CHAR, которое содержит ANSI – код буквы с диакритическим знаком.

Таким образом, обработка символьных сообщений обычно сводится к обработке сообщения WM_CHAR. Параметр lParam сообщения WM_CHAR, передаваемый в оконную процедуру, имеет то же значение, что и параметр lParam породившего его аппаратного сообщения. Параметр wParam содержит код символа ANSI.

Символьные сообщения передаются в оконную процедуру в промежутке между аппаратными сообщениями клавиатуры. Например, если переключатель Caps Lock выключен, а пользователь нажимает и отпускает клавишу A, то оконная процедура получит следующие три сообщения:

WM_KEYDOWN, // Виртуальная клавиша А

WM_CHAR, // ANSI – код символа «а»

WM_KEYUP, // Виртуальная клавиша А.

Если пользователь, удерживая клавишу Shift, нажимает клавишу А, отпускает клавишу А и затем отпускает клавишу Shift, то оконная процедура получит пять сообщений:

WM_KEYDOWN, // Виртуальная клавиша VK_SHIFT

WM_KEYDOWN, // Виртуальная клавиша А

WM_CHAR, // ANSI – код символа «а»

WM_KEYUP, // Виртуальная клавиша А

WM_KEYUP, // Виртуальная клавиша VK_SHIFT.

5.6.6. Мышь. Мышь – это устройство ввода информации с одной или более кнопками. Windows поддерживает однокнопочную, двухкнопочную или трехкнопочную мышь, а также мышь с колесиком. Наличие мыши можно определить при помощи функции GetSystemMetrics:

fMouse = GetSystemMetrics (SM_MOUSEPRESENT);

Если мышь установлена, то значение fMouse будет равно TRUE. Количество кнопок у мыши определяется следующим вызовом:

cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS);

Если мышь не установлена, то функция вернет нулевое значение.

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

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

Наличие мыши с колесиком можно определить при помощи вызова все той же функции GetSystemMetrics:

fMouseWheel = GetSystemMetrics (SM_MOUSEWHEELPRESENT);

Функция возвращает значение TRUE, если у мыши есть колесо.

Когда пользователь перемещает мышь, Windows передвигает по экрану небольшую растровую картинку, которая выступает в качестве курсора мыши (mouse cursor).

У курсора мыши есть горячая точка (hot spot) – пиксел, соответствующий положению курсора на экране. Когда говорят о позиции курсора мыши, то имеют в виду именно позицию горячей точки. Например, горячая точка стандартного курсора в виде стрелки (IDC_ARROW) находится на кончике стрелки. Другой курсор, в виде перекрестья (IDC_CROSS), имеет горячую точку в центре крестообразного шаблона.

Следует помнить, что курсор, используемый по умолчанию, для конкретного окна задается при определении структуры класса окна, например, следующим оператором:

wc.hCursor = LoadCursor (NULL, IDC_ARROW);

Действия пользователя с мышью принято описывать следующими терминами:

  • щелчок – нажатие и отпускание кнопки мыши;

  • двойной щелчок – быстрое двойное нажатие и отпускание кнопки мыши;

  • перетаскивание – перемещение мыши при нажатой кнопке.

Кнопки трехкнопочной мыши называются левой, средней и правой кнопками. В связанных с мышью идентификаторах, которые определены в заголовочных файлах Windows, используются краткие обозначения, соответственно, LBUTTON, MBUTTON и RBUTTON. На двухкнопочной мыши имеются только левая и правая кнопки. Единственная кнопка однокнопочной мыши является левой.

5.6.7. Сообщения мыши. Изучая ввод с клавиатуры, мы видели, что Windows посылает сообщения клавиатуры только тому окну, которое имеет фокус ввода. С мышью Windows ведет себя несколько иначе. Оконная процедура получает сообщения мыши, и когда мышь проходит через окно, и при щелчке внутри окна, даже если окно не активно или не имеет фокуса ввода.

Если мышь перемещается по клиентской области окна, то оконная процедура получает сообщение WM_MOUSEMOVE. Если кнопка мыши нажимается или отпускается внутри клиентской области, то оконная процедура получает следующие сообщения:

Кнопка

Нажатие

Отпускание

Нажатие (второй щелчок)

Левая

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLC

Средняя

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MBUTTONDBLCLC

Правая

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_RBUTTONDBLCLC

Для всех этих сообщений значение параметра lParam содержит положение мыши. При этом в младшем слове находится значение координаты х, а в старшем слове – значение координаты y. Отсчет координат ведется от левого угла клиентской области окна. Эти значения можно извлечь из lParam при помощи макросов LOWORD и HIWORD.

Значение параметра wParam показывает состояние кнопок мыши и клавиш Shift и Ctrl. Можно проверить параметр wParam при помощи соответствующих битовых масок:

MK_LBUTTON, // Левая клавиша нажата

MK_MBUTTON, // Средняя клавиша нажата

MK_RBUTTON, // Правая клавиша нажата

MK_SHIFT, // Клавиша Shift нажата

MK_CONTROL. // Клавиша Ctrl нажата

Если пользователь щелкнет левой кнопкой мыши в клиентской области неактивного окна, то Windows сделает это окно активным, а затем передаст оконной процедуре сообщение WM_LBUTTONDOWN.

5.6.8. Обработка двойного щелчка. Два последовательных щелчка воспринимаются системой как двойной щелчок, если они происходят в течение достаточно короткого промежутка времени. Пользователь может самостоятельно задать этот интервал при помощи системного приложения Мышь (Mouse), которое можно найти в группе Панель управления.

Следует особо подчеркнуть, что окно будет получать сообщения о двойном щелчке (DBLCLK) только в том случае, если стиль соответствующего класса окна содержит флаг CS_DBLCLKS. Поэтому перед регистрацией окна класса нужно присвоить полю style структуры WNDCLASS значение, включающее этот флаг. Впрочем, если используется объект класса KWnd, то следует модифицировать стиль класса окна вызовом следующих инструкций:

style = GetClassLong (hWnd, GCL_STYLE);

SetClassLong (hWnd, GCL_STYLE, style | CS_DBLCLKS);

Если класс окна определен без флага CS_DBLCLKS и пользователь делает двойной щелчок левой кнопкой мыши, то оконная процедура последовательно получает сообщения WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDOWN и WM_LBUTTONUP.

Если класс окна определен с флагом CS_DBLCLKS, то после двойного щелчка оконная процедура получит сообщения WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK и WM_LBUTTONUP. Легко заметить, что в этом случае в последовательности сообщений второе сообщение WM_LBUTTONDOWN заменяется сообщением WM_LBUTTONDBLCLK.

Пример обработки сообщения WM_LBUTTONDBLCLK приведен в листинге .

5.6.9. Обработка сообщений от колеса мыши. При нажатии на колесо мыши Windows генерирует такие же сообщения, какие вырабатываются при нажатии средней кнопки трехкнопочной мыши. Прокрутка же колесика вызывает сообщение WM_MOUSEWHEEL.

Если мы хотим обрабатывать это сообщение в коде программы, то в начале программного файла необходимо добавить следующую директиву:

#include <zmouse.h>

В заголовочном файле zmouse.h определены все необходимые константы.

Младшая часть параметра wParam сообщения WM_MOUSEWHEEL интерпретируется точно так же, как для других сообщений мыши, т.е. показывает состояние кнопок мыши и клавиш Shift и Ctrl.

Старшая часть параметра wParam содержит значение, отображающее дистанцию, пройденную колесом. Оно рассчитывается как количество шагов колеса при прокрутке, умноженное на коэффициент WHEEL_DELTA. В заголовочном файле zmouse.h этот коэффициент определен со значением 120.

Обработка сообщения WM_MOUSEWHEEL довольно проста, и ее пример можно найти в следующем разделе.

5.6.10. Пример программы «Просмотрщик текста». Рассмотрим приложение, предназначенное для чтения, вывода на экран и просмотра просмотра текстов. Назовем его «TextViewer». Приложение должно обрабатывать сообщения мыши, а также обеспечивать для пользователя общаться через клавиатурный интерфейс. Второе требование означает, что все операции, выполняемые мышью, должны быть продублированы на клавиатуре.

Есть два пути решения поставленной задачи. Обрабатывая сообщение WM_KEYDOWN, можно просто продублировать код, отвечающий за обработку сообщений WM_VSCROLL и WM_HSCROLL, но это некрасиво и непрактично с точки зрения дальнейшего сопровождения программы. Мы выберем второй путь: при появлении аппаратного сообщения клавиатуры, которое дублирует сообщения мыши, будем вызывать код, который создается для обработки сообщений с префиксом SB_. Фактически это означает, что оконная процедура должна послать сама себе сообщение SB_.

В Windows имеется несколько функций для отправки сообщений. В данногй ситуации лучше использовать функцию SendMessage, имеющую следующий прототип:

LRESULT SendMessage (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

Параметры функции имеют тот же смысл, что и параметры, передаваемые в оконную процедуру. Когда вызывается функция SendMessage, Windows вызывает оконную процедуру с дескриптором окна hWnd, передавая ей эти четыре параметра. После того как оконная процедура закончит обработку сообщения, Windows передает управление следующему за вызовом SendMessage оператору.

Далее следует исходный текст приложения TextViewer. Приложение размещено в трех модулях: главном модуле uTextViewer.cbproj; модуле uTVWindow.h(.cpp) регистрации оконного класса, создания окна и показа окна на экране; модуле uDocument.h(.cpp) обработки текстового файла и вывода документа в клиентскую область окна.

// модуль uTextViewer.cbproj

//---------------------------------------------------------------------------

#include <windows.h>

#include <zmouse.h> // для обработки колесика мыши

#include < uTVWindow.h >

#include < uDocument.h >

#include <vcl.h>

#define FILE_NAME "C:\\УчебникООПС++\\ProgramsAPI\\TextVi\\FILE.txt"

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

KDocument doc;

//---------------------------------------------------------------------------

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

MSG msg;

if (!doc.Open(FILE_NAME)) return 0;

KWnd mainWnd("Text Viewer Advanced", hInstance, nCmdShow, MainWndProc, NULL,

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, CS_HREDRAW | CS_VREDRAW,

WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL);

while (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

HDC hDC;

PAINTSTRUCT ps;

TEXTMETRIC tm;

int cxClient = 0, cyClient = 0;

static int xInc, yInc;

short status;

switch (uMsg)

{

case WM_CREATE:

hDC = GetDC(hWnd);

GetTextMetrics(hDC, &tm);

doc.Initialize(&tm);

ReleaseDC(hWnd, hDC);

break;

case WM_SIZE:

hDC = GetDC(hWnd);

cxClient = LOWORD(lParam);

cyClient = HIWORD(lParam);

if (cxClient > 0) doc.ScrollSettings(hWnd, cxClient, cyClient);

ReleaseDC(hWnd, hDC);

break;

case WM_VSCROLL:

switch (LOWORD(wParam))

{

case SB_LINEUP: yInc = -1; break;

case SB_LINEDOWN: yInc = 1; break;

case SB_PAGEUP: yInc = -(int)doc.vsi.nPage; break;

case SB_PAGEDOWN: yInc = (int)doc.vsi.nPage; break;

case SB_THUMBTRACK: yInc = HIWORD(wParam) - doc.vsi.nPos; break;

case SB_TOP: yInc = -(int)doc.vsi.nPage; break;

case SB_BOTTOM: yInc = doc.vsi.nMax - doc.vsi.nPos; break;

default: yInc = 0;

}

doc.UpdateVscroll(hWnd, yInc);

break;

case WM_HSCROLL:

switch (LOWORD(wParam))

{

case SB_LINELEFT: xInc = -1; break;

case SB_LINERIGHT: xInc = 1; break;

case SB_PAGELEFT: xInc = -0.8 * (int)doc.hsi.nPage; break;

case SB_PAGERIGHT: xInc = 0.8 * (int)doc.hsi.nPage; break;

case SB_THUMBTRACK: xInc = HIWORD(wParam) - doc.hsi.nPos; break;

case SB_TOP: xInc = -doc.hsi.nPos; break;

case SB_BOTTOM: xInc = doc.hsi.nMax - doc.hsi.nPos; break;

default: xInc = 0;

}

doc.UpdateHscroll(hWnd, xInc);

break;

case WM_MOUSEWHEEL:

if (LOWORD(wParam) & MK_SHIFT)

{

xInc = -3 * (short)HIWORD(wParam) / WHEEL_DELTA;

doc.UpdateVscroll (hWnd, yInc);

}

else

{

yInc = -3 * (short)HIWORD(wParam) / WHEEL_DELTA;

doc.UpdateVscroll(hWnd,yInc);

}

break;

case WM_KEYDOWN:

switch (wParam)

{

case VK_UP: SendMessage (hWnd, WM_VSCROLL, SB_LINEUP, 0);

break;

case VK_DOWN: SendMessage (hWnd, WM_VSCROLL, SB_LINEDOWN, 0);

break;

case VK_LEFT: SendMessage (hWnd, WM_HSCROLL, SB_LINELEFT, 0);

break;

case VK_RIGHT: SendMessage (hWnd, WM_HSCROLL, SB_LINERIGHT, 0);

break;

case VK_PRIOR: SendMessage (hWnd, WM_VSCROLL, SB_PAGEUP, 0);

break;

case VK_NEXT: SendMessage (hWnd, WM_VSCROLL, SB_PAGEDOWN, 0);

break;

case VK_HOME:

status = GetKeyState(VK_CONTROL);

if (0x80 & status) SendMessage (hWnd, WM_VSCROLL, SB_TOP, 0);

else SendMessage (hWnd, WM_HSCROLL, SB_TOP, 0);

break;

case VK_END:

status = GetKeyState(VK_CONTROL);

if (0x80 & status) SendMessage (hWnd, WM_VSCROLL, SB_BOTTOM, 0);

else SendMessage (hWnd, WM_HSCROLL, SB_BOTTOM, 0);

break;

}

break;

case WM_PAINT:

hDC = BeginPaint(hWnd, &ps);

doc.PutText(hWnd, hDC);

EndPaint(hWnd, &ps);

break;

case WM_DESTROY: PostQuitMessage(0); break;

default: return (DefWindowProc(hWnd, uMsg, wParam, lParam));

};

return 0;

}

//---------------------------------------------------------------------------

// модуль uTVWindow.h

//---------------------------------------------------------------------------

#ifndef uTVWindowH

#define uTVWindowH

#include <windows.h>

//---------------------------------------------------------------------------

class TTVWindow

{

public:

TTVWindow(LPTSTR windowName, HINSTANCE hInst, int cmdShow,

LRESULT (WINAPI* pWndProc) (HWND,UINT,WPARAM,LPARAM),

LPTSTR menuName = NULL,

int x = CW_USEDEFAULT, int y = 0,

int width = CW_USEDEFAULT, int height = 0,

UINT classStyle = CS_HREDRAW | CS_VREDRAW,

DWORD winStyle = WS_OVERLAPPEDWINDOW,

HWND hParent = NULL);

HWND GetWnd() {return hWnd;}

protected:

HWND hWnd;

WNDCLASSEX wc;

};

#endif

// модуль uTVWindow.cpp

//---------------------------------------------------------------------------

#include "uTVWindow.h"

//---------------------------------------------------------------------------

TTVWindow::TTVWindow(LPTSTR windowName, HINSTANCE hInst, int cmdShow,

LRESULT (WINAPI* pWndProc) (HWND,UINT,WPARAM,LPARAM),

LPTSTR menuName, int x, int y, int width, int height,

UINT classStyle, DWORD windowStyle, HWND hParent)

{

char szClassName[] = "WindowClass"; //"KWndClass";

wc.cbSize = sizeof(wc);

wc.style = classStyle;

wc.lpfnWndProc = pWndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInst;

wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor (NULL, IDC_ARROW);

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

wc.lpszMenuName = menuName;

wc.lpszClassName = szClassName;

wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);

// Регистрируем класс окна

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]