В данном уроке мы разработаем с вами калькулятор на C#. Программа будет написана согласно принципам объектно-ориентированного программирования (ООП): будет определен интерфейс для методов, реализующих функционал клавиш математических операций калькулятора, от интерфейса выполним наследование и напишем соответствующий класс и методы. Калькулятор, помимо базовых операций сложения, вычитания, умножения и деления, будет предоставлять возможность выполнять операции: извлечения квадратного корня, извлечения корня произвольной степени, возведения в квадрат, возведения в произвольную степень, вычисления факториала, а также работу с регистром памяти (MRC).
Создание пользовательского интерфейса калькулятора
Создадим в Visual Studio проект на Visual C# Windows Forms. Добавим на форму элемент GroupBox, в который поместим Label. В свойстве Dock, элемента Label, необходимо указать Right, чтобы Label был привязан к правому краю. Связка данных элементов управления будет реализовывать дисплей калькулятора.
Калькулятор также содержит кнопки. Всего их 28 штук. Пользовательский интерфейс представлен на рисунке 1.
Кнопка «+/-» меняет знак операнда на противоположный.
Кнопка MRC, а также кнопки M+, M-, M×, M÷, реализуют отдельный регистр памяти калькулятора и команды для управления им. Что такое MRC можно прочитать — здесь.
Программирование калькулятора на C#
Реализация интерфейса класса
Поскольку наш калькулятор будет написан в рамках парадигмы ООП (объектно-ориентированного программирования), то начнем кодирование с описания структуры интерфейса для класса, реализующего математические операции программы.
Добавим в проект класс InterfaceCalc.cs и определим в созданном файле интерфейс InterfaceCalc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
//интерфейс public interface InterfaceCalc { //а - первый аргумент, b - второй void Put_A(double a); //сохранить а void Clear_A(); double Multiplication(double b); double Division(double b); double Sum(double b); double Subtraction(double b); //вычитание double SqrtX(double b); double DegreeY(double b); double Sqrt(); double Square(); double Factorial(); double MemoryShow(); //показать содержимое регистра памяти void Memory_Clear(); //стереть содержимое регистра памяти //* / + - к регистру памяти void M_Multiplication(double b); void M_Division(double b); void M_Sum(double b); void M_Subtraction(double b); //вычитание } |
Для выполнения математических операций понадобится два операнда: a и b (например, a + b). Операнд a придется хранить в памяти калькулятора, пока пользователь будет вводить второй аргумент операции. Для сохранения числа a объявим прототип метода void Put_A(double a), для очистки — void Clear_A(). Для умножения, деления, сложения и вычитания чисел a и b соответственно понадобятся методы: double Multiplication(double b), double Division(double b), double Sum(double b), double Subtraction(double b). Вычисление корня степени b из a: double SqrtX(double b). Возведение числа a в степень b: double DegreeY(double b). Вычисление квадратного корня: double Sqrt(). Возведение числа a в квадрат: double Square(). Вычисление факториала a!: double Factorial(). Теперь объявления методов для работы с регистром памяти (MRC) калькулятора. Показать содержимое памяти и очистить его: double MemoryShow(), void Memory_Clear(). M×, M÷, M+ и M- к регистру соответственно: void M_Multiplication(double b), void M_Division(double b), void M_Sum(double b), void M_Subtraction(double b).
Создание класса, реализующего интерфейс InterfaceCalc
Теперь добавим в калькулятор класс, который будет реализовывать написанный ранее интерфейс. Для этого в проекте создадим класс Calc : InterfaceCalc. Как вы видите, здесь используется наследование (оператор «двоеточие»). В данном классе напишем реализацию всех методов, требуемых спецификацией нашего интерфейса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
public class Calc : InterfaceCalc { private double a = 0; private double memory = 0; public void Put_A(double a) { this.a = a; } public void Clear_A() { a = 0; } public double Multiplication(double b) { return a * b; } public double Division(double b) { return a / b; } public double Sum(double b) { return a + b; } public double Subtraction(double b) //вычитание { return a - b; } public double SqrtX(double b) { return Math.Pow(a, 1 / b); } public double DegreeY(double b) { return Math.Pow(a, b); } public double Sqrt() { return Math.Sqrt(a); } public double Square() { return Math.Pow(a, 2.0); } public double Factorial() { double f = 1; for (int i = 1; i <= a; i++) f *= (double)i; return f; } //показать содержимое регистра мамяти public double MemoryShow() { return memory; } //стереть содержимое регистра мамяти public void Memory_Clear() { memory = 0.0; } //* / + - к регистру памяти public void M_Multiplication(double b) { memory *= b; } public void M_Division(double b) { memory /= b; } public void M_Sum(double b) { memory += b; } public void M_Subtraction(double b) { memory -= b; } } |
Поле private double memory — будет содержать регистр памяти (MRC).
Реализация работы калькулятора
Перейдем к написанию кода в классе Form1.
Объявим два поля:
1 2 3 |
Calc C; int k; |
Это классовая переменная C для класса Calc и целое число k. С помощью k будем считать количество нажатий кнопки MRC, чтобы при первом нажатии выводить значение регистра памяти на экран, а при последующем повторном — стирать значение регистра.
Далее. Нам понадобится ряд методов, которые будут обеспечивать правильное функционирование калькулятора.
Дисплеем в нашем калькуляторе является Label. Его содержимое — это строка текста. Нажатие на цифровые клавиши — это конкатенация текущего значения строки с символом клавиши. Необходимо исключить дублирование нулей в левой части строки (это делают 2-й и 3-й if в коде ниже), а также не допустить написание цифр, если в Label находится знак «бесконечность» (он появляется, например, при делении на ноль; 1-й if). Для решения данных проблем напишем метод CorrectNumber():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private void CorrectNumber() { //если есть знак "бесконечность" - не даёт писать цифры после него if (labelNumber.Text.IndexOf("∞") != -1) labelNumber.Text = labelNumber.Text.Substring(0, labelNumber.Text.Length - 1); //ситуация: слева ноль, а после него НЕ запятая, тогда ноль можно удалить if (labelNumber.Text[0] == '0' && (labelNumber.Text.IndexOf(",") != 1)) labelNumber.Text = labelNumber.Text.Remove(0, 1); //аналогично предыдущему, только для отрицательного числа if (labelNumber.Text[0] == '-') if (labelNumber.Text[1] == '0' && (labelNumber.Text.IndexOf(",") != 2)) labelNumber.Text = labelNumber.Text.Remove(1, 1); } |
Еще необходим метод, проверяющий: не нажата ли какая-нибудь кнопка калькулятора из математических операций, требующих два операнда. Данная проверка необходима для недопущения нажатия других мат. операций, если какая-либо уже нажата. Код метода CanPress():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private bool CanPress() { if (!buttonMult.Enabled) return false; if (!buttonDiv.Enabled) return false; if (!buttonPlus.Enabled) return false; if (!buttonMinus.Enabled) return false; if (!buttonSqrtX.Enabled) return false; if (!buttonDegreeY.Enabled) return false; return true; } |
Также, напишем вспомогательный метод FreeButtons(), который снимает нажатия со всех кнопок математических операций калькулятора, требующих два операнда (умножение, деление, сложение, вычитание, вычисление корня произвольной степени и возведение числа в произвольную степень):
1 2 3 4 5 6 7 8 9 |
private void FreeButtons() { buttonMult.Enabled = true; buttonDiv.Enabled = true; buttonPlus.Enabled = true; buttonMinus.Enabled = true; buttonSqrtX.Enabled = true; buttonDegreeY.Enabled = true; } |
Со вспомогательными методами закончили. Идем дальше.
В конструкторе Form1 создадим экземпляр класса Calc, а также в «дисплей» калькулятора занесем значение ноль.
1 2 3 4 5 6 7 8 |
public Form1() { InitializeComponent(); C = new Calc(); labelNumber.Text = "0"; } |
Теперь перейдем к кодированию обработчиков нажатий кнопок калькулятора. Кнопка «Очистка» (CE):
1 2 3 4 5 6 7 8 9 |
private void buttonClear_Click(object sender, EventArgs e) { labelNumber.Text = "0"; C.Clear_A(); FreeButtons(); k = 0; } |
В «дисплей» записывается ноль, переменная a стирается, нажатия с кнопок математических операций снимаются и k обнуляется.
Кнопка изменения знака у числа «+/-«:
1 2 3 4 5 6 7 |
private void buttonChangeSign_Click(object sender, EventArgs e) { if (labelNumber.Text[0] == '-') labelNumber.Text = labelNumber.Text.Remove(0, 1); else labelNumber.Text = "-" + labelNumber.Text; } |
Кнопка «запятая» (будет добавлена, если ее еще нет и на «дисплее» нет знака бесконечность):
1 2 3 4 5 |
private void buttonPoint_Click(object sender, EventArgs e) { if ((labelNumber.Text.IndexOf(",") == -1) && (labelNumber.Text.IndexOf("∞") == -1)) labelNumber.Text += ","; } |
Теперь цифровые клавиши 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
private void button0_Click(object sender, EventArgs e) { labelNumber.Text += "0"; CorrectNumber(); } private void button1_Click(object sender, EventArgs e) { labelNumber.Text += "1"; CorrectNumber(); } private void button2_Click(object sender, EventArgs e) { labelNumber.Text += "2"; CorrectNumber(); } private void button3_Click(object sender, EventArgs e) { labelNumber.Text += "3"; CorrectNumber(); } private void button4_Click(object sender, EventArgs e) { labelNumber.Text += "4"; CorrectNumber(); } private void button5_Click(object sender, EventArgs e) { labelNumber.Text += "5"; CorrectNumber(); } private void button6_Click(object sender, EventArgs e) { labelNumber.Text += "6"; CorrectNumber(); } private void button7_Click(object sender, EventArgs e) { labelNumber.Text += "7"; CorrectNumber(); } private void button8_Click(object sender, EventArgs e) { labelNumber.Text += "8"; CorrectNumber(); } private void button9_Click(object sender, EventArgs e) { labelNumber.Text += "9"; CorrectNumber(); } |
Кнопка «Равно»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private void buttonCalc_Click(object sender, EventArgs e) { if (!buttonMult.Enabled) labelNumber.Text = C.Multiplication(Convert.ToDouble(labelNumber.Text)).ToString(); if (!buttonDiv.Enabled) labelNumber.Text = C.Division(Convert.ToDouble(labelNumber.Text)).ToString(); if (!buttonPlus.Enabled) labelNumber.Text = C.Sum(Convert.ToDouble(labelNumber.Text)).ToString(); if (!buttonMinus.Enabled) labelNumber.Text = C.Subtraction(Convert.ToDouble(labelNumber.Text)).ToString(); if (!buttonSqrtX.Enabled) labelNumber.Text = C.SqrtX(Convert.ToDouble(labelNumber.Text)).ToString(); if (!buttonDegreeY.Enabled) labelNumber.Text = C.DegreeY(Convert.ToDouble(labelNumber.Text)).ToString(); C.Clear_A(); FreeButtons(); k = 0; } |
В зависимости от того, какая из кнопок математических операций нажата, будет вызван соответствующий метод из класса Calc, вычисляющий данную функцию, и результат выведется в Label.
Далее кнопки математических операций. Сработают только в том случае, если другие в данный момент не нажаты (CanPress() вернет true):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
//кнопка Умножение private void buttonMult_Click(object sender, EventArgs e) { if(CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonMult.Enabled = false; labelNumber.Text = "0"; } } //кнопка Деление private void buttonDiv_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonDiv.Enabled = false; labelNumber.Text = "0"; } } //кнопка Сложение private void buttonPlus_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonPlus.Enabled = false; labelNumber.Text = "0"; } } //кнопка Вычитание private void buttonMinus_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonMinus.Enabled = false; labelNumber.Text = "0"; } } //кнопка Корень произвольной степени private void buttonSqrtX_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonSqrtX.Enabled = false; labelNumber.Text = "0"; } } //кнопка Возведение в произвольную степень private void buttonDegreeY_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); buttonDegreeY.Enabled = false; labelNumber.Text = "0"; } } //кнопка Корень квадратный private void buttonSqrt_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); labelNumber.Text = C.Sqrt().ToString(); C.Clear_A(); FreeButtons(); } } //кнопка Квадрат числа private void buttonSquare_Click(object sender, EventArgs e) { if (CanPress()) { C.Put_A(Convert.ToDouble(labelNumber.Text)); labelNumber.Text = C.Square().ToString(); C.Clear_A(); FreeButtons(); } } //кнопка Факториал private void buttonFactorial_Click(object sender, EventArgs e) { if (CanPress()) { if ((Convert.ToDouble(labelNumber.Text) == (int)(Convert.ToDouble(labelNumber.Text))) && ((Convert.ToDouble(labelNumber.Text) >= 0.0))) { C.Put_A(Convert.ToDouble(labelNumber.Text)); labelNumber.Text = C.Factorial().ToString(); C.Clear_A(); FreeButtons(); } else MessageBox.Show("Число должно быть >= 0 и целым!"); } } |
Калькулятор вычислит факториал только в том случае, если текущее введенное число целое и больше, либо равно нулю.
Кнопки математических операций над регистром памяти (MRC):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//кнопка М+ private void buttonMPlus_Click(object sender, EventArgs e) { C.M_Sum(Convert.ToDouble(labelNumber.Text)); } //кнопка М- private void buttonMMinus_Click(object sender, EventArgs e) { C.M_Subtraction(Convert.ToDouble(labelNumber.Text)); } //кнопка М* private void buttonMMult_Click(object sender, EventArgs e) { C.M_Multiplication(Convert.ToDouble(labelNumber.Text)); } //кнопка М/ private void buttonMDiv_Click(object sender, EventArgs e) { C.M_Division(Convert.ToDouble(labelNumber.Text)); } |
И последняя кнопка — «MRC». Она показывает содержимое регистра памяти на экран, а при повторном нажатии стирает его:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private void buttonMRC_Click(object sender, EventArgs e) { if (CanPress()) { k++; if (k == 1) labelNumber.Text = C.MemoryShow().ToString(); if (k == 2) { C.Memory_Clear(); labelNumber.Text = "0"; k = 0; } } } |
На этом написание калькулятора на C# закончено. Спасибо за прочтение статьи! Если есть какие-либо вопросы, задавайте их в комментариях. Исходник программы доступен по ссылке ниже.
Скачать исходник
Ссылки по теме
Калькулятор Windows Forms на языке C#
Калькулятор процентных ставок на C#
Простенький калькулятор Windows Forms на C#
Обратная польская запись. Калькулятор на C#
Поделиться в соц. сетях:
Не понятно для чего нужно было писать интерфейс InterfaceCalc, если в дальнейшем создается объект класса Calc. Объясните пожалуйста, в каком месте идет обращение к объекту класса через интерфейс?
Интерфейс в ООП — это ни что иное, как спецификация для класса: он описывает тот набор методов, который класс, использующий интерфейс, должен реализовывать.
В данной программе InterfaceCalc как раз описывает все методы, реализованные в Calc.