лекция. Зиборов. Справочник для опытных и как пособие для начинающих программистов. Компактдиск содержит исходные коды примеров из книги
Скачать 7.39 Mb.
|
Пример 15. Координаты курсора мыши относительно экрана и элемента управления Напишем программу, которую мы условно называем мониторингом положения мыши. Имеем форму, список элементов ListBox и два текстовых поля. Они расположены в форме так, как показано на рис. 3.1. Рис. 3.1. Фрагмент работы программы определения координат курсора мыши Программа заполняет список ListBox данными о местоположении и изменении положения курсора мыши. Кроме того, в текстовых полях отображаются координаты положения курсора мыши относительно экрана, а также относительно элемента Управления ListBox. Для программирования этой задачи после запуска Visual Studio 2010 и выбора шаблона Windows Forms Application С# из панели элементов управления Toolbox перетащим в форму элемент управления ListBox и два текстовых поля. В данной программе нам понадобится обработать три события, относящиеся к объекту listBox1. Чтобы получить три соответствующих пустых обработчика в программном коде, следует в конструкторе формы в панели свойств (Properties) щелкнуть на пиктограмме молнии и в появившемся списке возможных событий для объекта listBox1 выбрать следующие три события: MouseEnter, MouseLeave и MouseMove. Соответственно получим три пустых обработчика событий (листинг 3.1). Листинг 3.1. Координаты курсора мыши относительно экрана и элемента управления // Программа отображает координаты курсора мыши относительно экрана и элемента // управления. Программа содержит форму, список элементов ListBox и два // текстовых поля. Программа заполняет список ListBox данными о местоположении //и изменении положения курсора мыши. Кроме того, в текстовых полях // отображаются координаты положения курсора мыши относительно экрана //и элемента управления ListBox. using System; using System. Windows. Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace Monitoring { public partial class Form1 : Form { public Form1() { InitializeComponent(); base.Text = "Мониторинг движения мыши"; } // Процедура обработки события, когда указатель мыши оказывается //на элементе управления ListBox private void listBox1_MouseEnter(object sender, EventArgs e) { // Добавляем в список элементов новую запись listBox1.Items.Add("Курсор мыши вошел в область ListBox"); } // Процедура обработки события, когда указатель мыши покидает // элемент управления ListBox private void listBox1_MouseLeave(object sender, EventArgs e) { listBox1.Items.Add("Курсор мыши вышел из области ListBox"); } // Процедура обработки события, происходящего при перемещении // указателя мыши по элементу управления ListBox private void listBox1_MouseMove(object sender, MouseEventArgs e) { // Свойство объекта Control MousePosition возвращает точку, // соответствующую текущему положению мыши относительно // левого верхнего угла монитора textBox1.Text = string.Format("X = {0} или {1}", Form1.MousePosition.X, e.X); textBox2.Text = string.Format("Y = {0} или {1}", Form1.MousePosition.Y, e.Y); } } } Как видно, при обработке события мыши MouseEnter, когда курсор мыши входит в границы элемента управления, в список ListBox1 добавляется (метод Add) запись "Курсор мыши вошел в область ListBox". При обработке события мыши MouseLeave, когда курсор мыши выходит за пределы элемента управления, в список ListBox добавляется запись "Курсор мыши вышел из области ListBox". Таким образом, отслеживая поведение мыши, мы заполняем список ListBox1. При обработке события MouseMove, когда курсор мыши перемещается в пределах элемента управления ListBox1, в текстовые поля записываем координаты X и Yкурсора мыши, пользуясь свойством объекта Control MousePosition. Здесь мы получаем координаты положения курсора мыши в системе координат экрана, когда начало координат расположено в левом верхнем углу экрана, ось х направлена вправо, а ось у — вниз. Заметим, что аргументы события мыши е также содержат в себе текущие координаты курсора мыши, но в системе координат элемента управления, в данном случае listBox1. Начало координат этой системы расположено в левом верхнем углу элемента управления listBox1, ось х также направлена вправо, ось у— вниз. Эти координаты получаем из аргументов события е.X и e.Y и выводим их в текстовое поле, отделяя от предыдущих координат словом "или". Таким образом, добиваемся контроля положения курсора мыши, обрабатывая события мыши. Убедиться в работоспособности программы можно, открыв решение Monitoring.sin папки Monitoring. Пример 16. Создание элемента управления Button"программным" способом и подключение события для него Мы знаем, как, используя панель элементов управления, в форму перенести мышью нужный элемент. Чтобы сделать разработку программы более управляемой, в данной программе научимся создавать элементы управления в форме "программным" способом, т. е. с помощью написания непосредственно программного кода, не используя при этом панель элементов управления Toolbox. Понятно, что название "программным" является более чем условным, поскольку в описываемой нами среде трудно назвать что-либо, что "программным" не является. Итак, данная программа создаст командную кнопку в форме "программным" способом, задаст свойства кнопки: ее видимость, размеры, положение, надпись на кнопке и подключит событие "щелчок на кнопке". Для этого создаем новый проект с формой. При этом, как обычно, запускаем Visual Studio 2010, в окне New Project выбираем шаблон Windows Forms Application С#. Далее вводим программный код, представленный в листинге 3.2. Листинг 3.2. Создание кнопки "программным" способом // Программа создает командную кнопку в форме "программным" способом, // т. е. с помощью написания непосредственно программного кода, не используя // при этом панель элементов управления Toolbox. Программа задает свойства // кнопки: ее видимость, размеры, положение, надпись на кнопке //и подключает событие "щелчок на кнопке" using System; using System.Drawing; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace NewButton { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Создание кнопки без панели элементов управления: Button button1 = new Button(); // Задаем свойства кнопки: button1.Visible = true; // Ширина и высота кнопки: button1.Size = new Size(100, 30); // Расположение кнопки в системе координат формы: button1.Location = new Point(100, 80); button1.Text = "Новая кнопка"; // Добавление кнопки в коллекцию элементов управления this. Controls. Add (button1); // Подписку на событие Click для кнопки можно делать "вручную". // связываем событие Click с процедурой обработки этого сооытия: button1.Click += new EventHandler(buttonl_Click); } // Создаем обработчик события Click для кнопки: private void button1_Click(object sender, EventArgs e) { MessageBox.Show("Нажата новая кнопка"); } } } Как видно, сразу после выполнения процедуры InitializeComponent создаем новый объект button1 стандартного класса кнопок. Задаем свойства кнопки: ее видимость (visible), размеры (size), положение (Location) относительно левого нижнего угла формы, надпись на кнопке — "Новая кнопка". Далее необходимо организовать корректную работу с событием "щелчок на созданной нами командной кнопке". В предыдущих примерах мы для этой цели в конструкторе формы дважды щелкали на проектируемой кнопке, и исполняемая среда автоматически генерировала пустой обработчик этого события в программном коде. Или опять же в конструкторе формы в панели свойств проектируемой кнопки щелкали мышью на значке молнии (Events) и в появившемся списке всех событий выбирали необходимое событие. Однако согласно условию задачи мы должны организовать обработку события "программным" способом без использования конструктора формы. Для этого в программном коде сразу после добавления командной кнопки в коллекцию элементов управления ставим оператор "точка" (.) после имени кнопки button1 и в выпадающем списке выбираем необходимое событие click. Затем, как приведено в листинге 3.2, осуществляем так называемую "подписку" на данное событие, т. е. с помощью ключевого слова EventHandler связываем событие click с процедурой обработки события button1_click. Такое название процедуры обработки события принято в среде Visual Studio, но не является обязательным, мы могли бы назвать эту процедуру, например, русскими буквами: "КЛИК". Теперь создадим обработчик события button1_click, как показано в листинге 3.2. В этой процедуре предусматриваем вывод сообщения "Нажата новая кнопка". На рис. 3.2 приведен фрагмент работы программы. Рис. 3.2. Создание кнопки программным способом В заключение отметим, что в случае создания пустого обработчика события в конструкторе формы строка подписки на событие формируется автоматически в методе InitializeComponent в файле Form1.Designer.cs проекта. Убедиться в работоспособности программы можно, открыв решение NewButton.sln папки NewButton. Пример 17. Обработка нескольких событий одной процедурой Для того чтобы события от нескольких элементов управления обрабатывались одной процедурой обработки события, в некоторых языках, например в VB6, было предусмотрено создание массива элементов управления. Однако в современных языках Visual Studio элементы не могут быть сгруппированы в массивы. Но можно организовать обработку нескольких событий одной процедурой путем подписки этих событий на одну и ту же процедуру их обработки. Как это сделать, покажем на примере, когда в форме присутствуют две командные кнопки, и щелчок на любой из них обрабатывается одной процедурой. При этом, используя параметр процедуры sender, будем определять, на какой из двух кнопок щелкнули мышью. Итак, запустим Visual Studio 2010, закажем новый проект шаблона Windows Forms Application С#. Затем из панели элементов перенесем в форму две командных кнопки и текстовую метку. Далее через щелчок правой кнопкой мыши перейдем к вкладке программного кода (листинг 3.3). Листинг 3.3. Связывание двух событий с одной процедурой обработки //В форме имеем две командные кнопки, и при нажатии указателем мыши // любой из них получаем номер нажатой кнопки. При этом в программе // предусмотрена только одна процедура обработки событий using System; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются //в данной программе namespace ДваСобытияОднаПроц { public partial class Form1 : Form { public Form1() { InitializeComponent(); base.Text = "Щелкните на кнопке"; // Подписку на событие можно делать "вручную", но при этом в // Form1.Designer.cs следует удалить (или закомментировать) // соответствующие EventHandler. // Связываем события Click от обеих кнопок с одной процедурой КЛИК: button1.Click += new EventHandler(this.КЛИК); button2.Click += new EventHandler(this.КЛИК); label1.Text = null; // Подпиской на событие называют связывание названия события //с названием процедуры обработки события посредством EventHandler } private void KЛИK(object sender, EventArgs e) { // String S = Convert.ToString(sender); // получить текст, отображаемый на кнопке, можно таким образом: Button Кнопка = (Button)sender; // или string НадписьНаКнопке = ((Button)sender).Text; label1.Text = "Нажата кнопка " + Кнопка.Text; // или Кнопка.Name } } } Как видно из текста программы, сразу после выполнения процедуры ItializeComponent осуществляем так называемую подписку на событие, т. е. вязываем название события с названием процедуры обработки события клик посредством делегата EventHandler. Заметим, что оба события click мы связали с одной и той же процедурой клик. Далее создаем процедуру обработки события клик, ее параметр sender содержит ссылку на объект-источник события, т. е. кнопку, нажатую пользователем. С помощью неявного преобразования можно конвертировать параметр sender в экземпляр класса Button и, таким образом, выяснить все свойства кнопки, которая инициировала событие. На рис. 3.3 приведен пример работы написанной программы. Мы убедились в этом разделе, что сведения об объекте, который создал событие, находятся в объектной переменной sender. Работу этой программы можно исследовать, открыв соответствующее решение в папке ДваСобытияОднаПроц. Рис. 3.3. Фрагмент работы программы, определяющей нажатую кнопку Пример 18. Калькулятор Обработка нескольких событий от разных объектов одной процедурой оказывается весьма полезной при программировании данного приложения. Напишем программу Калькулятор с кнопками-цифрами, выполняющую только арифметические операции, причем управление Калькулятором возможно только мышью. Запустив Visual Studio 2010 и выбрав шаблон Windows Forms Application С# перетащим из панели Toolbox в форму 16 командных кнопок для ввода цифр, арифметических операций, знака "равно" (=) и операции Очистить, а также текстовое поле. Вкладка Form1.cs [Design] будет иметь примерно такой вид, как показано на рис. 3.4. Рис. 3.4. Вкладка конструктора формы В листинге 3.4 приведен программный код данного приложения. Листинг 3.4. Калькулятор // Программа Калькулятор с кнопками цифр. Управление калькулятором возможно // только мышью. Данный калькулятор выполняет лишь арифметические операции using System; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace Calc { public partial class Form1 : Form { string Znak = null; // знак арифметической операции bool Начало_Ввода = true; // ожидание ввода нового числа Double Число1, Число2; // Первое и второе числа, вводимые пользователем public Form1() { InitializeComponent(); this.Text = "Калькулятор"; button1.Text = "1"; button2.Text = "2"; button3.Text = "3"; button4.Text = " 4"; button5.Text = "5"; button6.Text = "6"; button7.Text = "7"; button8.Text = "8"; button9.Text = "9"; button10.Text = "0"; button11.Text = " = "; button12.Text = "+"; button13.Text = "-"; button14.Text = "*"; button15.Text = "/"; button16.Text = "Очистить"; textBox1.Text = "0"; textBox1.TextAlign = HorizontalAlignment.Right; // Связываем все события "щелчок на кнопках-цифрах" //с обработчиком ЦИФРА: this.button1.Click += new System.EventHandler(this.ЦИФРА); this.button2.Click += new System.EventHandler(this.ЦИФРА); this.button3.Click += new System.EventHandler(this.ЦИФРА); this.button4.Click += new System.EventHandler(this.ЦИФРА); this.button5.Click += new System.EventHandler(this.ЦИФРА); this.button6.Click += new System.EventHandler(this.ЦИФРА); this.button7.Click += new System.EventHandler(this.ЦИФРА); this.button8.Click += new System.EventHandler(this.ЦИФРА); this.button9.Click += new System.EventHandler(this.ЦИФРА); this.button10.Click += new System.EventHandler(this.ЦИФРА); this.button12.Click += new System.EventHandler(this.ОПЕРАЦИЯ); this.button13.Click += new System.EventHandler(this.ОПЕРАЦИЯ); this.button14.Click += new System.EventHandler(this.ОПЕРАЦИЯ); this.button15.Click += new System.EventHandler(this.ОПЕРАЦИЯ); this.button11.Click += new System.EventHandler(this.РАВНО); this.button16.Click += new System.EventHandler(this.ОЧИСТИТЬ); } private void ЦИФРА(object sender, EventArgs e) { // Обработка события нажатия кнопки-цифры. // Получить текст, отображаемый на кнопке, можно таким образом: Button Кнопка = (Button)sender; String Digit = Кнопка.Text; if (Начало_Ввода == true) { // Ввод первой цифры числа: textBoxl.Text = Digit; Начало_Ввода = false; return; } // "Сцепливаем" полученные цифры в новое число: if (Начало_Ввода == false) textBoxl.Text = textBox1.Text + Digit; } private void ОПЕРАЦИЯ(object sender, EventArgs e) { // Обработка события нажатия кнопки арифметической операции: Число1 = Double.Parse(textBoxl.Text); // Получить текст, отображаемый на кнопке, можно таким образом: Button Кнопка = (Button)sender; Znak = Кнопка.Text; Начало_Ввода = true; // ожидаем ввод нового числа } private void РАВНО(object sender, EventArgs e) { // Обработка нажатия клавиши "равно" double Результат = 0; Число2 = Double.Parse(textBox1.Text); if (Znak == "+") Результат = Число1 + Число2; if (Znak == "-") Результат = Число1 - Число2; if (Znak == "*") Результат = Число1 * Число2; if (Znak == "/") Результат = Число1 / Число2; Znak = null; // Отображаем результат в текстовом поле: textBox1. Text = Результат.ToString(); Число1 = Результат; Начало_Ввода = true; } private void ОЧИСТИТЬ(object sender, EventArgs e) { // Обработка нажатия клавиши "Очистить" textBox1.Text = "0"; Znak = null; Начало_Ввода = true; } } } В этой книге мы принципиально отказались от задания свойств элементов управления и формы в окне Properties, чтобы не потеряться в огромном количестве этих свойств и не забывать, какое свойство мы изменили, а какое нет. Исходя из этих соображений, автор задал все свойства объектов сразу после выполнения процедуры InitializeComponent. Именно здесь заданы надписи на кнопках, ноль в текстовом поле, причем этот ноль прижат к правому краю поля: textBox1.TextAlign = HorizontalAlignment.Right. Далее связываем все события Click от кнопок-цифр с одной процедурой обработки этих событий цифра. Аналогично все события Click от кнопок арифметических операций связываем с одной процедурой операция. В процедуре обработки события щелчок на любой из кнопок-цифр цифра в строковую переменную Digit копируем цифру, изображенную на кнопке из свойства Text так, как мы это делали в предыдущем примере, когда отлавливали нажатие пользователем одной из двух кнопок. Далее необходимо значение Digit присвоить свойству textBox1.Text, но здесь изначально записан ноль. Если пользователь вводит первую цифру, то вместо нуля нужно записать эту цифру, а если пользователь вводит последующие цифры, то их надо "сцепить" вместе. Для управления такой ситуацией мы ввели булеву (логическую) переменную Начало_Ввода. Мы сознательно назвали эту переменную по-русски, чтобы она выделялась среди прочих переменных, ведь она играет ключевую роль в программе и участвует в обработке практически всех событии. Поскольку мы ввели ее в начале программы, область действия этой переменной — весь класс Form1, т. е. эта переменная "видна" в процедурах обработки всех событий. То есть различаем начало ввода числа Начало_ввода = true, когда ноль следует менять на вводимую цифру, и последующий ввод Начало_Ввода = false, когда очередную цифру следует добавлять справа. Таким образом, если это уже не первая нажатая пользователем кнопка-цифра (Начало_Ввода = false), то "сцепливаем" полученную цифру с предыдущими введенными цифрами, иначе— просто запоминаем первую цифру в текстовом поле textBox1. При обработке событий "щелчок указателем мыши по кнопкам" арифметических операций +, -, *, / в процедуре операция преобразуем первое введенное пользователем число из текстового поля в переменную value1 типа Double. Строковой переменной Znak присваивается символьное представление арифметической операции. Поскольку пользователь нажал кнопку арифметической операции, ожидаем, что следующим действием пользователя будет ввод очередного числа, поэтому присваиваем булевой переменной Начало_ввода значение true. Заметьте, что обрабатывая два других события: нажатие кнопки "равно" и нажатие кнопки Очистить, мы также устанавливаем логическую переменную Hачало_Ввода в состояние true (т. е. начинаем ввод числа). В процедуре обработки события нажатия кнопки "равно" преобразуем второе введенное пользователем число в переменную типа Double. Теперь, поскольку знак apифметической операции нам известен, известны также оба числа, мы можем выполнить непосредственно арифметическую операцию. После того как пользователь получит результат, например result = value1 + value2, возможно, он захочет с зтим результатом выполнить еще какое-либо действие, поэтому этот результат записываем в первую переменную value1. Заметьте, что в этой программе мы сознательно не предусмотрели обработку исключительной ситуации деления на ноль, поскольку среда Visual Studio 2010 (впрочем, как и ее предыдущие версии) взяла на себя обработку этой ситуации. Когда в строковую переменную попадает очень большое число, в эту переменную система пишет слово "бесконечность" (рис. 3.5). Убедиться в работоспособности программы можно, открыв решение Calc.sln в папке Calc. Рис. 3.5. Фрагмент работы калькулятора Пример 19. Ссылка на другие ресурсы LinkLabel Элемент управления LinkLabel позволяет создавать в форме ссылки на Web-страницы, подобно гиперссылкам в HTML-документах, ссылки на открытие файлов какими-либо программами, ссылки на просмотр содержания логических дисков, папок и проч. Напишем программу, которая с помощью элемента управления LinkLabel обеспечит ссылку для посещения почтового сервера www.mail.ru, ссылку для просмотра папки C:\Windows\ и ссылку для запуска текстового редактора Блокнот. Для программирования этой задачи после запуска Visual Studio 2010 выберем шаблон Windows Forms Application С#, затем из панели Toolbox перетащим в форму три элемента управления LinkLabel. Равномерно разместим их в форме. Далее, следуя нашим традициям, не будем задавать никаких свойств этим элементам в окне Properties. Все начальные значения свойств укажем в программном коде сразу после вызова процедуры InitializeComponent (ЛИСТИНГ 3.5). Листинг 3.5. Ссыпки на ресурсы // Программа обеспечивает ссылку для посещения почтового сервера www.mail.ru, // ссылку для просмотра папки C:\Windows\ и ссылку для запуска текстового. // редактора Блокнот с помощью элемента управления LinkLabel using System; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace СсылкиLinkLabel { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Text = "Щелкните по ссылке:"; linkLabel1.Text = "www.mail.ru"; linkLabel2.Text = @"Папка С:\Windows\"; linkLabel3.Text = "Вызвать \"Блокнот\""; this.Font = new System.Drawing.Font("Consoles", 12.0F); linkLabel1.LinkVisited = true; linkLabel2.LinkVisited = true; linkLabel3.LinkVisited = true; // Подписка на события: все три события обрабатываются одной процедурой: linkLabel1.LinkClicked += new System.Windows.Forms. LinkLabelLinkClickedEventHandler(this.ССЫЛКА); linkLabel2.LinkClicked += new Systern.Windows.Forms. LinkLabelLinkClickedEventHandler(this.ССЫЛКА); linkLabel3.LinkClicked += new System.Windows.Forms. LinkLabelLinkClickedEventHandler(this.ССЫЛКА); } private void ССЫЛКА(object sender, LinkLabelLinkClickedEventArgs e) { LinkLabel ссылка = (LinkLabel)sender; switch (ссылка.Name) // Выбор ссылки: { case "linkLabel1": System.Diagnostics.Process.Start( "IExplore.exe", "http://www.mail.ru"); break; case "1inkLabel2": System.Diagnostics.Process.Start("C:WWindowsW"); break; case "linkLabel3": System.Diagnostics.Process.Start("Notepad", "text.txt"); break; } } } } Как видно из программного кода, в свойстве Text каждой из ссылок LinkLabel задаем текст, из которого пользователь поймет назначение каждой ссылки. В задании свойства Text ссылки LinkLabel3 для того, чтобы слово "Блокнот" было в двойных кавычках, используем escape-последовательность (\") . Для большей выразительности задаем шрифт Consolas, 12 пунктов. Это шрифт моноширинный, кстати, по умолчанию редактор в Visual Studio 2010 имеет также шрифт Consolas. Поскольку свойство LinkVisited = true, то соответствующая ссылка отображается как уже посещавшаяся (изменяется цвет). Так же как и в предыдущих разделах, организуем обработку всех трех событий Сlick по каждой из ссылок одной процедурой обработки ссылка. В этой процедуре так же как и в программе о трех кнопках и калькуляторе, в зависимости от имени объекта (ССЫЛКИ), создающего события (linkLabel1, linkLabel2, linkLabel3), Мы вызываем одну из трех программ: либо Internet Explorer, либо Windows Explorer, либо Блокнот. Информация об объекте, создающем событие Сlick, записана в объектную переменную sender. Она позволяет распознавать объекты (ссылки), создающие события. Чтобы "вытащить" эту информацию из sender, объявим переменную ссылка типа LinkLabel и с помощью неявного преобразования выполним конвертирование параметра sender в экземпляр класса LinkLabel. В этом случае переменная ссылка будет содержать все свойства объекта-источника события, в том числе свойство name, с помощью которого мы сможем распознавать выбранную ссылку. Идентифицируя по свойству name каждую из ссылок, с помощью метода start вызываем либо Internet Explorer, либо Windows Explorer, либо Блокнот. Вторым параметром метода start является имя ресурса, подлежащее открытию. Именем ресурса может быть или название Web-страницы, или имя текстового файла. Фрагмент работы обсуждаемой программы приведен на рис. 3.6. Убедиться в ее работоспособности можно, открыв соответствующее решение в папке CcылкиLinkLabel. Рис. 3.6. Ссылки на ресурсы Пример 20. Обработка событий клавиатуры События клавиатуры (клавишные события) создаются в момент нажатия или отпуская ее клавиш. Различают событие Keypress, которое генерируется в момент нажатия клавиши. При удержании клавиши в нажатом состоянии оно генерируется непрерывно с некоторой частотой. С помощью этого события можно распознать нажатую клавишу, если только она не является так называемой модифицирующей,т. е. <Alt>, <Shift> и <Ctrl>. А вот для того чтобы распознать, нажата ли модифицирующая клавиша <Alt>, <Shift> или <Ctrl>, следует обработать либо событие KeyDown, либо событие KeyUp. Событие KeyDown генерируется в первоначальный момент нажатия клавиши, а событие KeyUp — в момент отпускания клавиши. Напишем программу, информирующую пользователя о тех клавишах и комбинациях клавиш, которые тот нажал. Запустим Visual Studio 2010, выберем проект шаблона Windows Forms Application С#, затем из панели Toolbox перетащим в форму две текстовых метки Label. Далее, поскольку нам потребуются клавишные события формы: KeyPress, KeyDown, KeyUp, получим пустые обработчики этих событий традиционным образом. То есть в панели Properties щелкнем на пиктограмме молнии (Events), а затем в списке всех возможных событий выберем каждое из названных событий клавиатуры. Программный код приведен в листинге 3.6. Листинг 3.6. Обработка событий клавиатуры // Программа, информирующая пользователя о тех клавишах и // комбинациях клавиш, которые тот нажал using System; using System.Drawing; using System.Windows. Forms ; // Другие директивы using удалены, поскольку они не используются в данной программе namespace Key { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Устанавливаем шрифт с фиксированной шириной (моноширинный): base.Font = new Font(FontFamily.GenericMonospace, 14.0F); base.Text = "Какие клавиши нажаты сейчас:"; label1.Text = string.Empty; label2.Text = string.Empty; } private void Form1_KeyPress(object sender, KeyPressEventArgs e) { // Здесь событие нажатия клавиши: при удержании // клавиши генерируется непрерывно Label1.Text = "Нажатая клавиша: " + e.KeyChar; } private void Form1_KeyDown(object sender, KeyEventArgs e) { // здесь обрабатываем мгновенное событие первоначального // нажатия клавиши label2.Text = string.Empty; // Если нажата клавиша if (е.Alt == true) label2.Text += "Alt: Yes\n"; else label2.Text += "Alt: No\n"; // Если нажата клавиша if (e.Shift == true) label2.Text += "Shift: Yes\n"; else label2.Text += "Shift: No\n"; // Если нажата клавиша if (e.Control == true) label2.Text += "Ctrl: Yes\n"; else label2.Text += "Ctrl: No\n"; label2.Text += "Код клавиши: " + e.KeyCode + "\nKeyData: " + e.KeyData + "\nKeyValue: " + e.KeyValue; } private void Form1_KeyUp(object sender, KeyEventArgs e) { // Очистка меток при освобождении клавиши Label1.Text = string.Empty; label2.Text = string.Empty; } } } } В первую метку label1 записываем сведения о нажатой обычной (т. е. не модифицирующей и не функциональной) клавише при обработке события Keypress. Во вторую метку из аргумента события е (е.Alt, е.shift и е.control) получаем сведения, была ли нажата какая-либо модифицирующая клавиша (либо их комбинация). Обработчик события KeyUp очищает обе метки при освобождении клавиш. Рис. 3.7. Фрагмент работы программы, определяющей нажатую клавишу Убедиться в работоспособности программы можно, открыв решение Key.sln в папке Key. Пример 21. Разрешаем вводить в текстовое поле только цифры Обычно для диагностики вводимых числовых данных мы пользовались функцией TryParse. Эта функция возвращает true, если на ее вход подаются числовые данные, и false в противном случае. Покажем, как можно совершенно по-другому решить задачу контроля вводимых пользователем данных. Можно вообще не давать возможность пользователю вводить нечисловые данные. Обратите внимание, как происходит ввод числовых данных в программе Калькулятор системы Windows, здесь программа просто не даст возможности пользователю ввести нечисловой символ. Продемонстрируем и мы такое решение на следующем примере. Данная программа анализирует каждый символ, вводимый пользователем в текстовое поле формы. Если символ не является числовым, то текстовое поле получает запрет на ввод такого символа. Таким образом, программа не дает возможность пользователю ввода нечисловых данных. Запустим систему Visual Studio 2010, в окне New Project выберем шаблон Windows Forms Application С#. На панели элементов Toolbox найдем текстовое поле TextBox и перетащим его в форму. Текст программы показан в листинге 3.7. Листинг 3.7. Контроль вводимых пользователем числовых данных (вариант 1) // Программа анализирует каждый символ, вводимый пользователем в текстовое // поле формы. Если символ не является цифрой или Backspace, то текстовое поле // получает запрет на ввод такого символа. using System; * using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace Numbers { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Text = "Введите число"; textBoxl.Clear(); } private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { // Разрешаем ввод только десятичных цифр и Backspace: if (char.IsDigit(e.KeyChar) == true) return; if (e.KeyChar == (char)Keys.Back) return; e.Handled = true; // - запрет на ввод других вводимых символов } } } Как видно из программного кода, сразу после выполнения процедуры InitializeComponent задаем текст строки заголовка "Введите число" и очищаем текстовое поле TextBox1.clear(). Самое интересное начинается при обработке события нажатия клавиши в текстовом поле textBox1_KeyPress. Пустой обработчик этого события мы получаем, как и предыдущих программах, т. е. на вкладке конструктора формы в панели свойств Properties, щелкнув на символе молнии (Events), выбираем в списке всех возможных событий событие Keypress для текстового поля. Управляющая среда Visual Studio 2010 генерирует при этом пустую процедуру обработки данного события. В этой процедуре можно легко определить, какую клавишу нажал пользователь, из аргумента события е. Символ, соответствующий нажатой клавише, cодержится в свойстве аргумента e.KeyChar. На вход функции IsDigital подаем это свойство (т. е. исследуемый символ), а на выходе получаем заключение, является ли исследуемый символ цифрой (true или false). Аргумент события е имеет замечательное свойство Handled, которое либо запрещает получение данного события текстовым полем (true), либо разрешает (false). Всякий раз при очередной работе процедуры textBox1_KeyPress изначально свойство е.Handled = false, т. е. получение данного события текстовым полем разрешено. Последней строкой в процедуре запрещаем ввод символов в текстовое поле, но если пользователь вводит цифру или нажал клавишу <Backspace>, то этот запрет мы обходим с помощью оператора return. Таким образом, мы добиваемся игнорирования текстовым полем нецифровых символов. Рис. 3.8. Контроль введенных данных Интерфейс рассматриваемого приложения показан на рис. 3.8. Убедиться в работоспособности программы можно, открыв соответствующее решение в папке NumbersOnly. Пример 22. Разрешаем вводить в текстовое поле цифры, а также разделитель целой и дробной части числа Мы совсем забыли, уважаемые читатели, что число, вводимое пользователем, может иметь дробную часть после точки или запятой. Причем выяснить, что именно установлено в вашей системе — точка или запятая в качестве разделителя целой и дробной частей числа, можно, например, запустив Калькулятор Windows. Здесь среди экранных кнопок увидим кнопку либо с десятичной точкой, либо с десятичной запятой. Очень легко поменять данную установку системы (обычно по умолчанию в русифицированной версии Windows — запятая). Для этого следует в Панели управления выбрать значок Язык и региональные стандарты, затем на вкладке Региональные параметры щелкнуть на кнопке Настройка и на появившейся новой вкладке указать в качестве разделителя целой и дробной частей либо точку, либо запятую. Нам нужно добиться того, чтобы текстовое поле разрешало ввод только того разделителя, которое указано на вкладке Региональные параметры. Для решения данной задачи запустим Visual Studio 2010, выберем проект шаблона Windows Forms Application С#. На панели элементов Toolbox найдем текстовое поле TextBox и перетащим его в форму. Текст программы представлен в листинге 3.8. Листинг 3.8. Контроль вводимых пользователем числовых данных (вариант 2) // Программа разрешает ввод в текстовое поле только цифровых символов, // а также разделитель целой и дробной частей числа (т. е. точки или запятой) using System; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются вданной программе namespace ТолькоЧисло_ТчкОrЗпт { public partial class Form1 : Form { // Разделитель целой и дробной частей числа может быть // точкой "." или запятой "," в зависимости от // установок в пункте Язык и региональные стандарты // Панели управления ОС Windows: System.Globalization.Culturelnfо Культ = System.Globalization.Culturelnfо.CurrentCulture; string ТчкИлиЗпт; public Form1() { InitializeComponent(); this.Text = "Введите число"; // Выясняем, что установлено на данном ПК в качестве // разделителя целой и дробной частей: точка или запятая ТчкИлиЗпт = Культ.NumberForirat.NumberDecimalSeparator; } private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { bool ТчкИлиЗптНАЙДЕНА = false; // Разрешаю ввод десятичных цифр: if (char.IsDigit(e.KeyChar) == true) return; // Разрешаю ввод if (e.KeyChar == (char)Keys.Back) return; // Поиск ТчкИлиЗпт в textBox, если IndexOf() == -1, то не найдена: if (textBox1.Text.IndexOf(ТчкИлиЗпт) != -1) ТчкИлиЗптНАЙДЕНА = true; // Если ТчкИлиЗпт уже есть в textBox, то запрещаем вводить и ее, // и любые другие символы: if (ТчкИлиЗптНАЙДЕНА == true) { е.Handled = true; return; } // Если ТчкИлиЗпт еще нет в textBox, то разрешаем ее ввод: if (e.KeyChar.ToString() == ТчкИлиЗпт) return; //В других случаях - запрет на ввод: е.Handled = true; } } } Как видно из текста программы, вначале выясняем, что установлено в данной системе в качестве разделителя целой дробной части: точка или запятая. Этот разделитель записываем в строковую переменную ТчкИлиЗпт, которая видна из всех процедур данной программы, поскольку объявлена вне всех процедур. Далее, как и в предыдущем примере, в процедуре обработки события Keypress разрешаем ввод десятичных цифр и нажатие клавиши <Backspace> путем обхода с помощью return последнего оператора процедуры е.Handled = true, запрещающего ввод символа в текстовое поле. В данной задаче мы имеем некоторую сложность с разрешением ввода разделителя целой и дробной частей, поскольку разрешить его ввод мы можем только один раз, но при этом надо помнить, что пользователь может его удалить и ввести в другом месте числовой строки. Эту проблему мы решили следующим образом, каждый раз при очередном нажатии клавиши, разрешив ввод десятичных цифр, в текстовом поле ищем искомый разделитель. Если он найден, то запрещаем ввод любых нецифровых символов, включая злосчастный разделитель. А если не найден, торазрешаем его ввод. На рис. 3.8 показан фрагмент работы программы. Рис. 3.9. Кроме цифр программа разрешает ввод десятичной запятой Убедиться в работоспособности программы можно, открыв соответствующее решение в папке ТолькоЧисло+ТчкОгЗпт. |