Все действия пользователя при взаимодействии с приложением сводятся к перемещению мыши, нажатию кнопок мыши и нажатию клавиш клавиатуры. Рассмотрим обработку в приложении событий, связанных с этими манипуляциями пользователя.
1 События мыши
В компонентах C++Builder определен ряд событий, связанных с мышью. Это события:
Событие Описание
OnClick Щелчок мыши на компоненте и некоторые другие действия
пользователя.
OnDblClick Двойной щелчок мыши на компоненте.
OnMouseDown Нажатие клавиши мыши над компонентом. Возможно распознавание нажатой кнопки и координат курсора мыши.
OnMouseMove Перемещении курсора мыши над компонентом. Возможно распознавание нажатой кнопки и координат курсора мыши.
OnMouseUp Отпускание ранее нажатой кнопки мыши над компонентом.
Возможно распознавание нажатой кнопки и координат курсора мыши.
OnStartDrag Начало процесса «перетаскивания» объекта. Возможно распознавание перетаскиваемого объекта.
OnDragOver Перемещение «перетаскиваемого» объекта над компонентом.
Возможно распознавание перетаскиваемого объекта и коорди
нат курсора мыши.
OnDragDrop Отпускание ранее нажатой кнопки мыши после «перетаскива
ния» объекта. Возможно распознавание перетаскиваемого
объекта и координат курсора мыши.
OnEndDrag Еще одно событие при отпускании ранее нажатой кнопки
мыши после «перетаскивания» объекта. Возможно распознавание перетаскиваемого объекта и координат курсора мыши.
OnEnter Событие в момент получения элементом фокуса в результате
манипуляции мышью, нажатия клавиши табуляции или про
граммной передачи фокуса.
OnExit Событие в момент потери элементом фокуса в результате ма
нипуляции мышью, нажатия клавиши табуляции или про
граммной передачи фокуса.
Как видно из приведенной таблицы, эти события охватывают все мыслимые манипуляции с мышью и даже дублируют многие из них. Наиболее широко используется событие OnClick. Обычно оно наступает, если пользователь щелкнул на компоненте, т.е. нажал и отпустил кнопку мыши, когда указатель мыши находился на компоненте. Но это событие происходит также и при некоторых других действиях пользователя. Оно наступает, если:
• Пользователь выбрал элемент в сетке, дереве, списке, выпадающем списке, нажав клавишу со стрелкой.
• Пользователь нажал клавишу пробела, когда кнопка или индикатор были в фокусе.
• Пользователь нажал клавишу Enter, а активная форма имеет кнопку по умолчанию, указанную свойством Default.
• Пользователь нажал клавишу Esc, а активная форма имеет кнопку прерывания, указанную свойством Cancel.
• Пользователь нажал клавиши быстрого доступа к кнопке или индикатору. Например, если свойство Caption индикатора записано как «&Полужирный» и символ ‘П’ подчеркнут, то нажатие пользователем комбинации клавиш Alt+П вызовет событие OnClick в этом индикаторе.
• Приложение установило в true свойство Checked радиокнопки RadioButton.
• Приложение изменило свойство Checked индикатора CheckBox.
• Вызван метод Click элемента меню.
Для формы событие OnClick наступает, если пользователь щелкнул на пустом месте формы или на недоступном компоненте.
Обилие событий, связанных с мышью, а также фактическое дублирование некоторых из них требуют четкого представления о последовательности отдельных событий, наступающих при том или ином действии пользователя. Рассмотрим эти последовательности.
В момент запуска приложения из рассматриваемых нами событий наступает только событие OnEnter в компоненте, на который передается фокус. Это событие не связано с какими-то действиями пользователя, так что не будем на нем останавливаться.
Теперь рассмотрим простейшее действие пользователя: переключение с помощью мыши фокуса с одного элемента на другой. Последовательность событий в этом случае приведена в таблице 1.
Таблица 1. Последовательность событий мыши при переключении фокуса
Действие пользователя Событие
Перемещение курсора мыши в пределах первого компонента Множество событий OnMouseMove в первом компоненте
Перемещение курсора мыши в пределах формы Множество событий OnMouseMove в форме
Перемещение курсора мыши в пределах второго компонента Множество событий OnMouseMove во втором компоненте
Нажатие кнопки мыши OnExit в первом компоненте
OnEnter во втором компоненте
OnMouseDown во втором компоненте
Отпускание кнопки мыши OnClick во втором компоненте
OnMouseUp во втором комноненте
События OnMouseMove происходят постоянно в процессе перемещения курсора мыши и даже просто при его дрожании, неизбежном, если пользователь не снимает руки с мыши. Это надо учитывать и пользоваться этим событием очень осторожно, поскольку оно, в отличие от других, происходит многократно.
Как видно из приведенной таблицы, каждое действие пользователя, связанное с нажатием или отпусканием кнопки мыши приводит к серии последовательно наступающих событий. В обработчиках событий OnMouseDown и OnMouseUp можно распознать, какая кнопка мыши нажата и в какой точке компонента находится в данный момент курсор мыши.
Рассмотренная в таблице 1 последовательность событий имеет место, если во втором компоненте свойство DragMode равно dmManual (ручное начало процесса перетаскивания), как это установлено по умолчанию. Если же это свойство равно dmAutomatic (автоматическое начало процесса перетаскивания), то все рассмотренные события, связанные с манипуляцией мышью, заменяются следующими:
OnMouseDown Заменяется на OnStartDrag
OnMouseMove Заменяется на событие OnDragOver того компонента, над которым перемещается курсор мыши
OnMouseUp Заменяется на событие OnDragDrop компонента, над которым завешается перетаскивание (если компонент может воспринять информацию от перетаскиваемого объекта), и последующее событие OnEndDrag компонента, который перетаскивался
События OnExit и OnEnter вообще не возникают, поскольку переключения фокуса не происходит. Не наступает также событие OnClick.
Если в примере, приведенном в таблице 1, щелчок делается на объекте, который уже находится в этот момент в фокусе, то не происходят события OnExit и OnEnter. В этом случае при нажатии кнопки наступает только событие OnMouseDown, а при отпускании кнопки — события OnClick и OnMouseUp.
6.2 Распознавание источника события, нажатых кнопок и клавиш, координат курсора
Во все обработчики событий, связанных с манипуляциями мыши (как и во все другие обработчики) передается параметр Sender типа указателя на TObject. Этот параметр содержит указатель на компонент, в котором произошло событие. Он не требуется, если пишется обработчик события для одного конкретного компонента. Однако часто один обработчик применяется для нескольких компонентов. При этом какие-то операции могут быть общими для любых источников события, а какие-то требовать специфических действий. Тогда Sender можно использовать для распознания источника события. Правда, поскольку тип TObject не имеет никаких полезных для пользователя свойств и методов, то объект Sender следует рассматривать как объект одного из производных от TObject типов.
Помимо параметра Sender в обработчики событий OnMouseDown и OnMouseUp передаются параметры, позволяющие распознать нажатую кнопку, нажатые при этом вспомогательные клавиши, а также определить координаты курсора мыши. Заголовок обработчика события OnMouseDown или OnMouseUp может иметь, например, следующий вид:
void _fastcall TForml::EditlMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
Помимо уже рассмотренного нами параметра Sender в обработчик передаются параметры Button, Shift, X и Y.
Параметр Button типа TMouseButton определяет нажатую в этот момент кнопку мыши. Тип TMouseButton — перечислимый тип, определяемый следующим образом:
enum TMouseButton { mbLeft, mbRight, mbMiddle };
Значение mbLeft соответствует нажатию левой кнопки мыши, значение mbRight — правой, а значение mbMiddle — средней. Например, если вы хотите, чтобы обработчик реагировал на нажатие только левой кнопки, вы можете его первым оператором написать:
if (Button != mbLeft) return;
Тогда, если значение Button не равно mbLeft, т.е. нажата не левая кнопка, выполнение обработчика прервется.
Параметр Shift типа TShiftState определяет, какие вспомогательные клавиши на клавиатуре нажаты в момент нажатия кнопки мыши. Тип TShiftState — множество, определенное следующим образом:
enum Classes_1 { ssShift, ssAlt, ssCtrl, ssLeft, ssRight,
ssMiddle, ssDouble };
typedef Set<Classes_1, ssShift, ssDouble>TshiftState (см. п. 7. );
Элементы этого множества соответствуют нажатию клавиш Shift (ssShift), Alt (ssAlt), Ctrl (ssCtrl), а также кнопок: левой (ssLeft), правой (ssRight), средней (ssMiddle). Информация о нажатых кнопках в параметрах Button и Shift имеет различный смысл. Параметр Button соответствует кнопке, нажимаемой в данный момент, а параметр Shift содержит информацию о том, какие кнопки были нажаты, включая и те, которые были нажаты ранее. Например, если пользователь нажмет левую кнопку мыши, а затем, не отпуская ее, нажмет правую, то после первого нажатия множество Shift будет равно [ssLeft], а после второго — [ssLeft, ssRight]. Если до этого пользователь нажал и не отпустил какие-то вспомогательные клавиши, то информация о них также будет присутствовать в множестве Shift.
Поскольку Shift является множеством, проверять наличие в нем тех или иных элементов надо методом Contains. Например, если вы хотите прореагировать на событие, заключающееся в нажатии левой кнопки мыши при нажатой клавише Alt, можно использовать оператор:
if ((Button == mbLeft) && (Shift.Contains(ssAlt)))
В приведенной структуре if первое условие (Button == mbLeft) можно заменить эквивалентным ему условием, проверяющим параметр Shift:
if (Shift.Contains (ssLeft) && (Shift.Contains(ssAlt)))
Аналогичные параметры Button и Shift передаются и в обработчик события OnMouseUp. Отличие только в том, что параметр Button соответствует не нажимаемой в данный момент, а отпускаемой кнопке. Параметр Shift передается также в обработчик события OnMouseMove, так что и в этом обработчике можно определить, какие клавиши и кнопки нажаты.
Во все события, связанные с мышью, передаются также координаты курсора X и Y. Эти параметры определяют координаты курсора в клиентской области компонента. Благодаря этому можно обеспечить различную реакцию в зависимости от того, в какой части клиентской области расположен курсор.
