События KeyDown и KeyUp. Класс KeyEventArgs
KeyDownи KeyUp. Создайте проект из одной формы, без элементов управления. Введите такой код:
Private Sub Form1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles MyBase.KeyPress
Debug.WriteLine("Сработал KeyPress")
End Sub
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyDown
Debug.WriteLine("Сработал KeyDown")
End Sub
Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyUp
Debug.WriteLine("Сработал KeyUp")
End Sub
Запустите проект, пощелкайте по клавишам клавиатуры и понаблюдайте за результатами в окне Output. Удерживайте нажатыми разные клавиши и тоже наблюдайте.
Выводы: При нажатии почти любой клавиши клавиатуры срабатывает событие KeyDown. Если при этом нажатие приводит к вводу символа, то сразу за ним срабатывает событие KeyPress. Если вы удерживаете клавишу нажатой, эта парочка срабатывает многократно и часто. При отпускании клавиши однократно срабатывает событие KeyUp. Я не рассматриваю ситуацию, когда одновременно удерживаются нажатыми две и более клавиш.
KeyCode. Какие именно клавиши клавиатуры были нажаты или отпущены, вам подскажет свойство KeyCodeобъекта e, принадлежащего классу KeyEventArgs. Введите такой код:
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e KeyEventArgs) Handles MyBase.KeyDown
Debug.WriteLine(e.KeyCode.ToString)
End Sub
Пояснения: Здесь я использовал свойственный объектам метод ToString, который возвращает в виде вразумительной строки имя или значение объекта.
Запустите проект, пройдитесь по всем клавишам клавиатуры (кроме тех, конечно, что выключают компьютер). Вот что вы увидите:
Печать в окне Output | Какая клавиша была нажата |
D L F1 Tab Enter Left Space D1 D2 Escape ControlKey ShiftKey Menu | D L F1 Tab Enter Стрелка влево Пробел Цифра 1 Цифра 2 Esc Ctrl Shift Alt |
И так далее. Пройдитесь по клавишам дополнительной цифровой клавиатурыв правой части клавиатуры при включенном и выключенном индикаторе NumLock.
Свойства Control, Alt, Shift. VB позволяет определить, какие из трех клавиш Ctrl, Alt, Shift удерживались нажатыми в момент срабатывания события KeyDown или KeyUp. Дополните процедуру:
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles MyBase.KeyDown
Debug.WriteLine(e.KeyCode.ToString & " " & e.Control & " " & e.Alt & " " & e.Shift)
End Sub
Здесь я использовал свойства Control, Alt, Shiftобъекта e. Их смысл будет ясен из распечатки в окне Output. Запустите проект, нажмите и удерживайте нажатыми клавиши Alt и Shift (но не Ctrl), после чего щелкните по клавише W. Вот что вы увидите последней напечатанной строкой в окне Output:
W False True True
Все сказанное относится и к событию KeyUp.
Анализировать нажатия клавиш для управления компьютером можно, например, такими операторами:
If e.KeyCode = Keys.F2 Then Debug.WriteLine("Нажата клавиша F2")
If e.Shift Then Debug.WriteLine("Нажата клавиша Shift")
If e.Control And e.KeyCode = Keys.Right Then Debug.WriteLine("Нажата стрелка направо при нажатой кл Ctrl")
Перечисление Keysвключает в себя коды клавиш клавиатуры.
События клавиатуры у элементов управления. События, связанные с клавиатурой, имеются у многих элементов управления. Поместим на форму, к примеру, пару кнопок и текстовое поле. Вдобавок к процедуре Form1_KeyDown напишем три процедуры:
Private Sub Button1_KeyDown …
Private Sub Button2_KeyDown …
Private Sub TextBox1_KeyDown …
Запустим программу и щелкнем по какой-нибудь клавише. Какая из четырех процедур сработает? Та, чей элемент управления находится в фокусе. А поскольку один какой-нибудь элемент на форме всегда находится в фокусе, до процедуры Form1_KeyDown дело никак не доходит. Это не всегда бывает удобно. И против этого в VB есть специальный прием: свойство формы KeyPreviewустанавливается в True. Это означает приказ компьютеру при нажатии на клавишу сначала вызывать событие формы, а уж потом другого объекта. Так, если в фокусе находится кнопка 2, то при нажатии на клавишу клавиатуры сначала выполняется процедура Form1_KeyDown, а сразу за ней – Button2_KeyDown. Сказанное касается большинства клавиш и элементов управления, но не всех.
«Телефонный номер». Разберем пример использования событий клавиатуры. Пусть на форме имеется текстовое поле, которое мы предназначили для ввода телефонных номеров. Сделаем текстовое поле умным – запретим ему воспринимать символы за исключением цифр, пробелов, черточек и точек. Если пользователь попытается ввести неподходящий символ, должно появляться сообщение об ошибке, а сам символ в поле появляться не должен. После окончания ввода можно нажать клавишу Enter, пусть при этом выводится сообщение «Ввод закончен».
Вот код:
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) _
Handles TextBox1.KeyPress
Dim С As Char = e.KeyChar 'Вводимый символ
If Char.IsDigit(С) Or Char.IsSeparator(С) Or С = "-" Or С = "." Then Exit Sub
Beep()
MsgBox("В телефонном номере можно употреблять только цифры, пробелы, черточки и точки!")
e.Handled = True
End Sub
Private Sub TextBox1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles TextBox1.KeyDown
If e.KeyCode = Keys.Enter Then MsgBox("Ввод закончен")
End Sub
Пояснения: Используются события KeyPress и KeyDown текстового поля. Событие KeyDown используется для обработки нажатия на клавишу Enter. Оператор If в первой процедуре предназначен для того, чтобы не создавать проблем цифрам, пробелам, черточкам и точкам. Ведь выход из процедуры (Exit Sub) и есть выход без проблем. Если символ не принадлежит к упомянутым, то выхода из процедуры не происходит и выполняются последние три строки процедуры: раздается сигнал, затем появляется сообщение, а напоследок оператор e.Handled= True заставляет компьютер считать, что неосуществленная стандартная обработка события (в частности – появление символа в текстовом поле) якобы уже произошла, а значит и символу незачем появляться в текстовом поле.
Задание 97.
«Управляемый объект». На клавиатуре имеются четыре клавиши со стрелками для управления курсором. Поместите на форму какой-нибудь элемент управления. При щелчке по любой клавише управления курсором элемент управления должен двигаться с постоянной скоростью в указанном на клавише направлении.
Задание 98.
«Светофор». Нарисуйте светофор: прямоугольник и три круга. При наборе на клавиатуре символа R светофор должен загораться красным светом, G – зеленым, Y - желтым.
Задание 99.
«Зенитка». Вверху справа налево медленно движется вражеский самолет. В подходящий момент вы нажатием любой клавиши запускаете снизу вверх зенитный снаряд. При попадании компьютер выдает соответствующее сообщение.
Не шали! Поставьте при помощи событий клавиатуры преграду тем шалунам, кто в нашем калькуляторе хочет ввести с клавиатуры в текстовое поле для результата любые символы. А потом вспомните, что это можно было сделать, просто превратив текстовое поле в метку или придав текстовому полю свойство ReadOnly.
Проект – Гонки (игра)
Мы с вами создали уже два правильно написанных больших проекта: «Парк под луной» и «Будильник». И этого, конечно, мало. У нас нет опыта создания проектов с движением объектов по форме, да к тому же под управлением мыши и клавиатуры. Поэтому я решил создать с вами такой проект (строк на 150). На этот раз это будет игра.
Постановка задачи
Поставим задачу сделать игру, где наш миниатюрный гоночный автомобиль будет под управлением мыши или клавиатуры нестись от старта до финиша.
На Рис. 14.1 вы видите внешний вид игры (о красоте я не заботился, красоту вы всегда сможете добавить по вкусу):
Рис. 14.1
Процесс игры таков. После загрузки проекта вы нажимаете на кнопку Начинаем сначала. На форме появляется белое квадратное поле для гонки со случайно расположенными газонами. Машина стоит на старте. Нажатием на клавишу пробела вы даете газ и машина со старта набирает скорость. Ваша цель – любым путем побыстрее добраться до финиша. На белом асфальте вы можете газовать до предельной скорости (я выбрал ее значение равным 15). Если же ненароком попадете на газон, то на газоне ваша скорость будет очень мала (я выбрал 1). Поэтому имеет смысл по газонам ездить пореже. Направление движения может быть только горизонтальное и вертикальное, наискосок машина не движется. Выбор направления (руль) – это клавиши со стрелками. Тормоз – клавиша Ctrl. В ограждение въезжать нельзя – катастрофа. Когда приедете на финиш, посмотрите на счетчик времени и увидите ваш результат. Снова нажимайте на кнопку Начинаем сначала. Теперь расположение газонов будет другим. Сажайте за клавиатуру приятеля и смотрите, не покажет ли он время лучше, чем у вас. Можете посмотреть, кто из вас покажет лучшее время из 10 заездов.
Не удивляйтесь, что скорость на спидометре не равна пути, деленному на время. Ведь это мгновенная скорость (то есть настоящая скорость в данное мгновение), а не средняя скорость автомобиля (см. Физика, 9 класс).
Все эти правила я старался сделать как можно проще, чтобы не усложнять проект. Разобравшись в проекте, вы всегда сможете дописать процедуры, делающие процесс гонки более для вас привлекательным.
Для проекта я выбрал вариант игры с одним автомобилем. Я вам намекну, как модифицировать проект, чтобы получилась игра с двумя автомобилями. Однако помните, что для грамотного создания игры с несколькими автомобилями вам нужно будет подняться на новый уровень программирования – научиться создавать собственные классы объектов.
Делим проект на части
Создадим новый проект. Прежде чем что-либо с ним делать, мысленно разделим задачу, как положено, на части (по возможности, конечно). Мы раньше уже делили задачу на части, когда создавали будильник. Сейчас вам очень полезно перечитать тот материал. И проглядеть ту программу.
Можно заметить, что в нашем проекте нет таких независимых частей, как в будильнике. Тем не менее, удобно разделить создание проекта на 3 последовательные части:
1.Рисование всех элементов поля в результате нажатия на кнопку Начинаем сначала. Этим будет заниматься одна группа процедур.
2.Затем управление машиной во время гонки. Этим будет заниматься другая группа процедур. Мы полностью задействуем идею использования таймера так, как я ее изложил в 13.5.11. На каждом импульсе таймера автомобиль должен будет проделывать весь цикл своего функционирования.
3.И наконец – определение поведения машины на газоне, на финише и при столкновении с препятствием. Сюда же я отношу организацию счетчиков на пульте управления (время, скорость, путь) и выдачу сообщений.