| Китай |
Пользовательский интерфейс Windows Forms для C#
Упражнение 2. Простой калькулятор
Разработаем калькулятор, выполняющий простые действия над целыми и вещественными числами в десятичной форме.
-
Поместите
на форму элементы из вкладки Common Controls панели Toolbox в
соответствии с таблицей, чтобы пользовательский интерфейс
формы был таким
Здесь мы использовали некоторые префиксы при назначении имен элементам управления. Для лучшей узнаваемости в коде программы элементов управления и их типа рекомендуется использовать общеупотребительные префиксы, которые приведены в таблице
static void Main()
{
Application.Run(new Calculate());
}
Листинг
25.10.
Добавление к форме Calculate точки входа
-
Выполните
команду меню WinFormsApp Properties и
для вкладки Application установите в свойстве Startup
Object форму Calculate стартовой -
Защитите
интерфейс формы Calculate от случайных
изменений, выполнив команду Format/Lock
Controls меню оболочки
Теперь нужно реализовать функциональность интерфейса. Прежде всего нужно защитить поля ввода от всех символов, кроме цифр, одного знака минус и одной точки. Стрелки и клавиша Del в текстовых полях функционируют, но работу клавиши Backspace нужно учесть явно.
-
Объявите
в конце класса Calculate логическое
поле isNumeric для
отфильтровывания нецифровых символов, которые пользователь
может попытаться ввести в текстовые поля
private bool isNumber = false;Листинг 25.11. Добавим логическую переменную isNumeric
-
Выделите
текстовое поле txtFirst и через панель Properties в
режиме Events создайте обработчик для события KeyDown.
Заполните обработчик так
private bool isNumber = false;
private void txtFirst_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
isNumber =
e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
|| e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
|| e.KeyCode == Keys.Back;
}
Листинг
25.12.
Обработчик события KeyDown для текстовых полей txtFirst и txtSecond
-
Выделите
текстовое поле txtFirst и через панель Properties в
режиме Events создайте обработчик для
события KeyPress. Заполните обработчик
так
private void txtFirst_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
TextBox box = (TextBox) sender;// Явное преобразование типов
switch(e.KeyChar) // Переключатель
{
case '-': // Разрешаем минус, если он первый
if(box.Text.Length == 0)
isNumber = true;
break;
case '.':
// Точка не должна быть первой
if(box.Text.Length == 0)
break;
// Точка не должна следовать сразу за минусом
if(box.Text[0] == '-' && box.Text.Length == 1)
break;
// Точка должна быть одна
if(box.Text.IndexOf('.') == -1)
isNumber = true; // Еще не было точек
break;
}
// Запрещаем в текстовом поле лишние символы
if(!isNumber)
e.Handled = true;
}
Листинг
25.13.
Обработчик события KeyPress для полей txtFirst и txtSecond
-
Выделите
текстовое поле txtSecond и через панель Properties в
режиме Events подключите к событиям KeyDown и KeyPress соответствующие
обработчики, только что созданные для поля txtFirst.
Обработчики подключите через раскрывающиеся списки
полей значений
Здесь мы одни и те же обработчики используем для разных полей, поскольку необходимо выполнять одинаковые действия. Задача одна - не допускать для ввода в поля никакие другие символы, кроме цифр, одного минуса и одной точки. Возможность ввода цифр реализована для основной ( keyboard ) и дополнительной ( keypad ) частей клавиатуры. Параметр sender передает в обработчик ссылку на активное текстовое поле, вызвавшее событие редактирования.
Конечно, программа будет более понятна, если для каждого элемента создавать свой обработчик. Но очень часто, как в нашем случае, преобладающая часть кода может быть совершенно одинакова в каждом обработчике. Тогда имеет смысл объединять несколько индивидуальных обработчиков в один. Какой подход выбрать - зависит от конкретной задачи и предпочтений программиста.
-
Добавьте
в конец класса Calculate объявления числовых
переменных, с которыми мы будем производить простые арифметические
операции
// Объявляем числовые переменные как поля-члены класса
// Их можно объявить как локальные и внутри обработчика btn_Click()
// Но оставляем область видимости класс, вдруг где-нибудь еще пригодятся!
private double numFirst, numSecond, numResult;
Листинг
25.14.
Добавление числовых переменных-членов класса Calculate
-
Установите
в панели Properties режим Events,
найдите событие Click и введите вручную в
поле значений этого события имя обработчика btn_Click
-
В
созданный оболочкой общий обработчик для всех выделенных
кнопок введите следующий код
// Один обработчик для всех кнопок-операций
private void btn_Click(object sender, System.EventArgs e)
{
// Копируем текстовые поля в локальные переменные
string strFirst = string.Copy(txtFirst.Text);
string strSecond = string.Copy(txtSecond.Text);
// Замена в строке точки символом запятой
// для корректного преобразования в число
int pos = strFirst.IndexOf('.');
if(pos != -1)
{
strFirst = strFirst.Substring(0, pos)
+ ','
+ strFirst.Substring(pos + 1);
}
pos = strSecond.IndexOf('.');
if(pos != -1)
{
strSecond = strSecond.Substring(0, pos)
+ ','
+ strSecond.Substring(pos + 1);
}
// Преобразуем текст в число для выполнения операций
if(txtFirst.Text.Length > 0)
numFirst = Convert.ToDouble(strFirst);
else
numFirst = 0.0D;
if(txtSecond.Text.Length > 0)
numSecond = Convert.ToDouble(strSecond);
else
numSecond = 0.0D;
// Выполняем нужную операцию
string btnText = "";// Создали строковую переменную
bool divideFlag = false;// Флаг деления на ноль
Button btn = (Button) sender;// Явное приведение типов для распознавания кнопок
switch(btn.Name)// Переключатель
{
case "btnIncrement":// Операция сложения
btnText = "\"+\"";// Экраны кавычек
numResult = numFirst + numSecond;
break;
case "btnDecrement":// Операция вычитания
btnText = "\"-\"";// Экраны кавычек
numResult = numFirst - numSecond;
break;
case "btnIncrease":// Операция умножения
btnText = "\"*\"";// Экраны кавычек
numResult = numFirst * numSecond;
break;
case "btnDivide":// Операция деления
btnText = "\":\"";// Экраны кавычек
// Проверяем корректность деления
if (Math.Abs(numSecond) < 1.0E-30)
{
MessageBox.Show(
"Делить на ноль нельзя!", // Сообщение
"Ошибка", // Заголовок окна
MessageBoxButtons.OK, // Кнопка OK
MessageBoxIcon.Stop);// Критическая иконка
divideFlag = true;
}
else
numResult = numFirst / numSecond;
break;
}
// Для отображения в панели Output режима Debug
System.Diagnostics.Debug.WriteLine("Нажата кнопка " + btnText);// Конкатенация
// Отображение результата
if(!divideFlag)
{
txtResult.Text = Convert.ToString(numResult);
this.Validate(); // Обновить экран (можно убрать-излишне)
}
}
Листинг
25.15.
Обработчик нажатия кнопок-операций btn_Click()
Здесь мы прежде всего скопировали значения полей ввода в промежуточные текстовые переменные, используя статический метод System.String. Copy() класса String (псевдоним string ). Затем мы проверяем наличие символа "точки" в этих переменных и при обнаружении производим замену на символ "запятая" с полным формированием новой строки. Мы не можем заменить символ "на месте" в существующей строке, обратившись к нему как элементу массива, поскольку индексная форма адресации в строках существует только для чтения.
Но мы можем, сформировав новую строку справа от знака присваивания, присвоить результат вновь той же самой ссылке, которая фактически будет адресоваться к новой области памяти, а старая строка, как брошенный фрагмент памяти, будет оставлена для сборщика мусора. Операция замены точки на запятую выполняется для того, чтобы корректно преобразовать текстовое значение поля ввода в числовое, иначе генерируется исключение.
Далее мы явно приводим переданную в обработчик ссылку типа object на нажатую кнопку к типу Button. В заголовке переключателя выделяем имя нажатой кнопки и выполняем соответствующую арифметическую операцию. Перед выполнением последней операции мы проверяем возможность возникновения случая " деления на ноль " и при его обнаружении предупреждаем пользователя выводом простого диалогового окна сообщений, отменяя саму операцию деления.
После переключателя мы располагаем оператор вывода строки System.Diagnostics.Debug.WriteLine() с выполненной операцией в панель оболочки Output. Этот класс предназначен для работы с программой в отладочном режиме Debug и автоматически изымается из кода при компиляции окончательного варианта приложения в режиме Release.
На последнем этапе, в коде обработчика, мы выводим результат в соответствующее текстовое поле с предварительным преобразованием типов. Затем мы даем команду системе обновить окно приложения, хотя в данном случае эта мера является излишней - система и так обновляет результат в текстовом поле.
Теперь создадим обработчик нажатия на кнопку закрытия формы.
-
В
режиме Design двойным щелчком на кнопке btnExit создайте
обработчик, который заполните так
private void btnExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
Листинг
25.16.
Код закрытия формы калькулятора
-
Запустите
проект и проверьте функциональность простого калькулятора
Теперь мы должны подключить разработанную форму калькулятора к основному окну приложения.
-
Установите
в качестве стартовой форму Start. Для
этого выполните команду меню оболочки Project/WinFormsApp
Properties и в появившемся диалоговом окне установите
для вкладки Application свойство Startup
Object в
значение WinFormsApp.Program
-
Откройте
файл Start.cs в режиме View Code.
Через раскрывающийся список Members в
верхней части окна редактора кода найдите обработчик события generalList_SelectedIndexChanged(),
который мы создали ранее, и дополните его вызовом окна
калькулятора
private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
{
switch(generalList.SelectedIndex + 1)
{
case 1:
Smiles frm1 = new Smiles();
frm1.ShowDialog();
break;
case 2:
Calculate frm2 = new Calculate();
frm2.ShowDialog();
break;
}
}
Листинг
25.17.
Код вызова окна калькулятора в модальном режиме
-
В
панели Solution Explorer оболочки щелкните
дважды на пиктограмме файла Start.cs,
чтобы открыть его в режиме View
Designer,
выделите элемент списка в клиентской области формы и через
панель Properties добавьте в свойство Items строку
" 2)
Простой калькулятор " -
Запустите
приложение и проверьте его работоспособность




