Код программы (внизу пояснение кода)
&НаКлиенте
Процедура ПрибавитьЦифру(Команда)
//ПРОВЕРЯЕМ ЧИСЛО ВЫБРАННОЕ ПОЛЬЗОВАТЕЛЕМ (ИМЯ КОМАНДЫ)
Событие = ЭтаФорма.ТекущийЭлемент;
//ДОБАВЛЯЕМ ЗНАЧЕНИЕ ЧИСЛА К ИТОГОВОМУ ПОЛЮ (СТРОКА)
ИтоговоеПоле = ИтоговоеПоле + Событие.Заголовок;
КонецПроцедуры
&НаКлиенте
Процедура Операция(Команда)
//ПОЛУЧАЕМ ИМЯ СОБЫТИЯ (ИМЯ КОМАНДЫ)
Событие = ЭтаФорма.ТекущийЭлемент;
Если Событие.Имя = "Стереть" Тогда
//КОМАНДА "СТЕРЕТЬ" УБИРАЕТ ПОСЛЕДНИЙ СИМВОЛ СПРАВА (БЕРЕМ ВСЕ СИМВОЛЫ - 1 ОТ ЛЕВОГО КРАЯ)
ИтоговоеПоле = Лев(ИтоговоеПоле,СтрДлина(ИтоговоеПоле) - 1);
ИначеЕсли Событие.Имя = "Очистить" Тогда
//КОМАНДА "ОЧИСТИТЬ" СТИРАЕТ ЗНАЧЕНИЕ В "ИТОГОВОЕПОЛЕ"
ИтоговоеПоле = "";
ИначеЕсли Событие.Имя = "Разделить" Или
Событие.Имя = "Умножить" Или
Событие.Имя = "Прибавить" Или
Событие.Имя = "Отнять" Тогда
//ПРОВЕРИМ НЕТ ЛИ ДО ЭТОГО ЗНАКА ОПЕРАЦИИ. ЕСЛИ ЕСТЬ ЗАМЕНИМ НА ТЕКУЩИЙ
ПредыдущийСимвол = Прав(ИтоговоеПоле, 1);
Если ПредыдущийСимвол = "+"
ИЛИ ПредыдущийСимвол = "-"
ИЛИ ПредыдущийСимвол = "*"
ИЛИ ПредыдущийСимвол = "/" Тогда
//ЗАМЕНИМ. ПОЛУЧИМ ИТОГОВУЮ СТРОКУ БЕЗ ПОСЛЕДНЕГО ЗНАКА И ЗАМЕНИМ НА НУЖНЫЙ
ИтоговоеПоле = Лев(ИтоговоеПоле, СтрДлина(ИтоговоеПоле) - 1) + Событие.Заголовок;
Иначе
//НИЧЕГО МЕНЯТЬ НЕ НАДО, ПРОСТО ДОБАВИМ
ИтоговоеПоле = ИтоговоеПоле + Событие.Заголовок;
КонецЕсли;
ИначеЕсли Событие.Имя = "Точка" И СтрДлина(ИтоговоеПоле) Тогда
//КОМАНДА ТОЧКА ДОБАВЛЯЕТ ДРОБНУЮ ЧАСТЬ ЧИСЛА
//МОЖНО ПОСТАВИТЬ, ЕСЛИ ДО ЭТОГО БЫЛО ВВЕДЕНА ПЕРВАЯ (ЦЕЛАЯ) ЧАСТЬ ЧИСЛА
//И В ЭТОМ ЧИСЛЕ НЕТ УЖЕ ТОЧКИ
//ПРИМЕР
//+. НЕЛЬЗЯ
//52. МОЖНО
//52.41. НЕЛЬЗЯ
//АЛГОРИТМ ДЕЙСТВИЙ
//ПРОВЕРИМ ЕСТЬ ЛИ У НАС В СТРОКЕ ЛЮБОЙ СИМВОЛ ОПЕРАЦИИ (+ - * /)
//ЕСЛИ НЕТ, ТО ЗНАЧИТ ЭТО ПЕРВОЕ ЧИСЛО. В НЕМ ДОЛЖНО БЫТЬ НЕ БОЛЬШЕ ОДНОЙ ТОЧКИ
//ЕСЛИ ЕСТЬ, ТО МОЖЕТ БЫТЬ ЭТО ВТОРОЕ, ТРЕТЬЕ И ТД ЧИСЛО. ПОЛУЧИМ ЕГО ДО СИМВОЛА И ПРОВЕРИМ НЕТ ЛИ В НЕМ ТОЧКИ
ПрисутствуютСимволыОперации = СтрНайти(ИтоговоеПоле, "+")
ИЛИ СтрНайти(ИтоговоеПоле, "-")
ИЛИ СтрНайти(ИтоговоеПоле, "*")
ИЛИ СтрНайти(ИтоговоеПоле, "/");
Если ПрисутствуютСимволыОперации Тогда
//СИМВОЛЫ ЕСТЬ, ПОЛУЧАЕМ ЧИСЛО ДО БЛИЖАЙЩЕГО СИМВОЛА (+ - * /)
СписокЦифрСтроки = ПолучитьСписокЦифр(ИтоговоеПоле);
//ПОЛУЧИМ ПОСЛЕДНЕЕ ЧИСЛО ИЗ СПИСКА
ПоследнийЭлемент = СписокЦифрСтроки.Получить(СписокЦифрСтроки.Количество() - 1);
Если Не СтрЧислоВхождений(ПоследнийЭлемент, ".")
И Не СтрЧислоВхождений(ПоследнийЭлемент, ",") Тогда
ИтоговоеПоле = ИтоговоеПоле + ".";
КонецЕсли;
Иначе
//СИМВОЛОВ НЕТ, ЗНАЧИТ ЭТО ПЕРВОЕ ЧИСЛО
//ЕСЛИ НЕ БУДЕТ ВХОЖДЕНИЙ, ЗНАЧИТ ДОБАВЛЯЕМ
Если НЕ СтрЧислоВхождений(ИтоговоеПоле, ".")
И Не СтрЧислоВхождений(ПоследнийЭлемент, ",") Тогда
ИтоговоеПоле = ИтоговоеПоле + ".";
КонецЕсли;
КонецЕсли;
ИначеЕсли Событие.Имя = "Ровно" Тогда
//ЗАПОЛНИМ СПИСОК ДЛЯ СВЕРКИ ЗНАЧЕНИЙ
МассивВозможныхСимволов = Новый Массив;
МассивВозможныхСимволов.Добавить("*");
МассивВозможныхСимволов.Добавить("/");
МассивВозможныхСимволов.Добавить("+");
МассивВозможныхСимволов.Добавить("-");
//ПОЛУЧИМ ТОЛЬКО СПИСОК ЦИФР ИЗ СТРОКИ
СписокЦифр = ПолучитьСписокЦифр(ИтоговоеПоле);
//ПОЛУЧИМ ПОСЛЕДОВАТЕЛЬНОСТЬ ОПЕРАЦИЙ СТРОКИ
МассивОпераций = Новый Массив;
Для Счет = 1 по СтрДлина(ИтоговоеПоле) Цикл
//ПРОЙДЕМСЯ ПО КАЖДОМУ СИМВОЛУ (СЧЕТ = 1, ПОТОМ 2, 3 И ТД)
ОбрабатываемыйСимвол = Сред(ИтоговоеПоле, Счет, 1);
//ЕСЛИ СИМВОЛА НЕТ В НАШЕМ СПИСКЕ "МАССИВ ВОЗМОЖНЫХ СИМВОЛОВ", ЗНАЧИТ ЭТО ЧИСЛО ИЛИ ТОЧКА, ПРОПУСКАМ
Если Не МассивВозможныхСимволов.Найти(ОбрабатываемыйСимвол) = Неопределено Тогда
МассивОпераций.Добавить(ОбрабатываемыйСимвол);
КонецЕсли;
КонецЦикла;
//МОЖЕТ БЫТЬ ПОСТАВИЛИ ЛИШНИЙ ЗНАК И НАЖАЛИ РАВНО, ТОГДА ДОБАВИМ В КОНЕЦ НОЛЬ (ПО ХОРОШЕМУ ПРОСТО УБРАТЬ ЛИШНИЙ ЗНАК, НО ДОЛЬШЕ)
//ПРИМЕР
//14 + 15 +
//+ В КОНЕЦ ЛИШНИЙ, ДОБАВИМ ПРОСТО 0 В КОНЕЦ
Если СписокЦифр.Количество() = МассивОпераций.Количество() Тогда
СписокЦифр.Добавить(0);
КонецЕсли;
//ПОЛУЧИМ ЗНАЧЕНИЕ И ОГРАНИЧИМ ПО ТОЧНОСТИ, ВЫБРАННОЙ ПОЛЬЗОВАТЕЛЕМ
СтрокаФормата = "ЧДЦ=" + Точность;
ИтоговоеПоле = Формат(ВычислитьВыраженияНаСервере(СписокЦифр, МассивОпераций), СтрокаФормата);
КонецЕсли;
КонецПроцедуры
Функция ПолучитьСписокЦифр(СтрокаРазбивки)
//ЗАМЕНЯЕМ В СТРОКЕ СИМВОЛ (+ - * /) НА \ И РАЗДЕЛЯЕМ СТРОКУ НА ЭЛЕМЕНТЫ
//БЫЛО
//23+45*67
//ПОСЛЕ ЗАМЕНЫ СТАЛО
//23\45\67
//ПОСЛЕ РАЗДЕЛЕНИЯ
//1. 23
//2. 45
//3. 67
СтрокаБезСимволов = СтрЗаменить(СтрокаРазбивки, "+", "\");
СтрокаБезСимволов = СтрЗаменить(СтрокаБезСимволов, "*", "\");
СтрокаБезСимволов = СтрЗаменить(СтрокаБезСимволов, "-", "\");
СтрокаБезСимволов = СтрЗаменить(СтрокаБезСимволов, "/", "\");
Список = СтрРазделить(СтрокаБезСимволов, "\");
Возврат Список;
КонецФункции
Функция ВычислитьВыраженияНаСервере(МассивЦифр,МассивОпераций)
//АЛГОРИТМ
//ПРИМЕР
//2+2*2-3*6
//СОЗДАЕМ ДВА ДОПОЛНИТЕЛЬНЫХ СПИСКА, ОДИН БУДЕТ ХРАНИТ ЦИФРЫ ДЛЯ СЛОЖЕНИЯ, ВТОРОЙ ОПЕРАЦИИ
//В ПЕРВЫЙ СПИСОК КЛАДЕМ НАШ ПЕРВЫЙ ЭЛЕМЕНТ - 2, ВО ВТОРОЙ КЛАДЕМ НАШЕ ДЕЙСТВИЕ. + ИМЕЕТ ПРИОРИТЕТ 1
//СМОТРИМ ДАЛЬШЕ, 2 КЛАДЕМ В ПЕРВЫЙ СПИСОК (2 2) И ПРОВЕРЯЕМ, ОПЕРАЦИИ * БОЛЬШЕ ПО ПРИОРИТЕТУ ЧЕМ ПРЕДЫДУЩАЯ
//ЕСЛИ ПРИОРИТЕТ БОЛЬШЕ, ТО КЛАДЕМ ТАКЖЕ В СТЕК И ИДЕМ ДАЛЬШЕ. ЕСЛИ НЕТ, ТО БЕРЕМ ДВА ПОСЛЕДНИХ ЧИСЛА ИЗ ПЕРВОГО СПИСКА И ПОСЛЕДНЮЮ ОПЕРАЦИЮ
//ОПЕРАЦИЮ УБИРАЕМ И ДВА ЧИСЛА УБИРАЕМ, ЗАПЫСЫВАЕМ РЕЗУЛЬТАТ
//ДОБАВИМ ВРЕМЕННЫЕ ПЕРЕМЕННЫЕ ДЛЯ РАСЧЕТА
ВременныйСписокОпераций = Новый Массив;
ВременныйСписокЦифр = Новый Массив;
//ДОБАВИМ СООТ. ОПЕРАЦИИ И ЕЕ ПРИОРИТЕТА
СоотПриоритетов = Новый Соответствие;
СоотПриоритетов.Вставить("+", 1);
СоотПриоритетов.Вставить("-", 1);
СоотПриоритетов.Вставить("*", 2);
СоотПриоритетов.Вставить("/", 2);
Результат = 0;
Для Счет = 0 По МассивЦифр.Количество() - 1 Цикл
Если ВременныйСписокОпераций.Количество() Тогда
//ЕСЛИ ОПЕРАЦИЙ БОЛЬШЕ НЕТ И ЭТО БЫЛА ПОСЛЕДНЯЯ ПОЧИТАЕМ ЗНАЧЕНИЕ
Если МассивОпераций.Количество() = Счет Тогда
//ДОБАВИМ ПОСЛЕДНЕЕ ЧИСЛО В ПОСЛЕДОВАТЕЛЬНОСТЬ
ВременныйСписокЦифр.Добавить(Число(МассивЦифр.Получить(Счет)));
//ВСЕ НАШИ ПЕРЕДАННЫЕ СПИСКИ МЫ ПРОШЛИ, ОСТАЛОСЬ ПРОЙТИСЬ ПО ВРЕМЕННЫМ ТАБЛИЦАМ ОТ БОЛЬШЕГО К МЕНЬШЕМУ
Пока ВременныйСписокОпераций.Количество() Цикл
ПервоеЧисло = ВременныйСписокЦифр.Получить(ВременныйСписокЦифр.Количество() - 2);
ВтороеЧисло = ВременныйСписокЦифр.Получить(ВременныйСписокЦифр.Количество() - 1);
Операция = ВременныйСписокОпераций.Получить(ВременныйСписокОпераций.Количество() - 1);
Если Операция = "+" Тогда
Результат = Результат + ПервоеЧисло + ВтороеЧисло;
ИначеЕсли Операция = "-" Тогда
Результат = Результат + ПервоеЧисло - ВтороеЧисло;
ИначеЕсли Операция = "*" Тогда
Результат = Результат + (ПервоеЧисло * ВтороеЧисло);
ИначеЕсли Операция = "/" Тогда
Результат = Результат + (ПервоеЧисло / ВтороеЧисло);
КонецЕсли;
//УДАЛИМ ПОСЛЕДНЮЮ ЦИФРУ И ОПЕРАЦИЮ И ЗАПИШЕМ НОВУЮ
ВременныйСписокЦифр.Удалить(ВременныйСписокЦифр.Количество() - 1);
ВременныйСписокОпераций.Удалить(ВременныйСписокОпераций.Количество() - 1);
ВременныйСписокЦифр.Добавить(Результат);
КонецЦикла;
Иначе
Если СоотПриоритетов.Получить(МассивОпераций.Получить(Счет)) >
СоотПриоритетов.Получить(ВременныйСписокОпераций.Получить(ВременныйСписокОпераций.Количество() - 1)) Тогда
//ЕСЛИ ТЕКУЩАЯ ОПЕРАЦИЯ БОЛЬШЕ ПО ПРИОРИТЕТУ, ТО ПРОСТО ДОБАВЛЯЕМ В СПИСОК
ВременныйСписокЦифр.Добавить(Число(МассивЦифр.Получить(Счет)));
ВременныйСписокОпераций.Добавить(МассивОпераций.Получить(Счет));
Иначе
//ЕСЛИ ТЕКУЩАЯ ОПЕРАЦИЯ МЕНЬШЕ ИЛИ РАВНА ПО ПРИОРИТЕТУ, ТО СНАЧАЛА ВЫПОЛНЯЕМ СТАРУЮ
ПервоеЧисло = ВременныйСписокЦифр.Получить(ВременныйСписокЦифр.Количество() - 1);
ВтороеЧисло = Число(МассивЦифр.Получить(Счет));
Операция = ВременныйСписокОпераций.Получить(ВременныйСписокОпераций.Количество() - 1);
Если Операция = "+" Тогда
Результат = Результат + ПервоеЧисло + ВтороеЧисло;
ИначеЕсли Операция = "-" Тогда
Результат = Результат + ПервоеЧисло - ВтороеЧисло;
ИначеЕсли Операция = "*" Тогда
Результат = Результат + (ПервоеЧисло * ВтороеЧисло);
ИначеЕсли Операция = "/" Тогда
Результат = Результат + (ПервоеЧисло / ВтороеЧисло);
КонецЕсли;
//УДАЛИМ ПОСЛЕДНЮЮ ЦИФРУ И ОПЕРАЦИЮ И ЗАПИШЕМ НОВУЮ
ВременныйСписокЦифр.Удалить(ВременныйСписокЦифр.Количество() - 1);
ВременныйСписокОпераций.Удалить(ВременныйСписокОпераций.Количество() - 1);
ВременныйСписокЦифр.Добавить(Результат);
КонецЕсли;
КонецЕсли;
Иначе
//ОПЕРАЦИЙ НЕТ, ДОБАВЛЯЕМ ЗНАЧЕНИЕ ЧИСЛА И ОПЕРАЦИИ В СТЕК
ВременныйСписокЦифр.Добавить(Число(МассивЦифр.Получить(Счет)));
ВременныйСписокОпераций.Добавить(МассивОпераций.Получить(Счет));
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Объяснение решений:
1. В обработке за все кнопки калькулятора отвечает всего две команды, одна за цифры, другая за операции.
В подобных обработках на каждую кнопку калькулятора добавляют свою команду.
Плюсы решения:
- Простота кода, нет кучи команд, в которых легко запутаться;
Минусы решения:
- Нет возможности привязать горячие клавиши на каждую цифру;
2. В обработке использовал свой расчет значения.
Плюс решения:
- Легко добавить нужные команды, например ( ) n! nn. Для этого добавляем новые операции и пишем приоритет данной операции;
Минусы решения:
- Большое количество кода;
Альтернатива:
- Простые операции + - * / можно сделать через типовую функцию Вычислить(Выражение);
Описание создания формы:
- Создал новую чистую обработку;
- Добавил реквизиты:
Реквизит "ИтоговоеПоле" хранит в себе значение выражения и результат после расчета.
Реквизит "Точность" является числом с видом "Поле переключателя" и видом "Тумблер".
- Добавил команды:
Команда "Операция" отвечает за:
"Стереть последний символ",
"Очистить значения",
"Точка (точность)",
"Равно",
"Математические операции + - * /"
При необходимости добавления новой операции добавляем новую команду формы с ссылкой на команду и в коде описываем алгоритм работы команды, абсолютно любой (из примеров выше степень, факториал и прочие (не забываем указать приоритет операции)).
Команда "ПрибавитьЦифру" отвечает за добавление цифр от 0 до 9.
Структура формы обработки:
У групп - "Обертка", "Кнопочки", "Цифры" и "ЭлементыУправления" группировка вертикальная, остальные горизонтальные.
Группа "Обертка" имеет ширину - 17.
Описание кода:
- При нажатии на кнопки, связанные с командами "Операция" и "ПрибавитьЦифру", добавляется значение числа или знака операции в реквизит "ИтоговоеПоле", сам реквизит закрыт для редактирования пользователем
Обработка универсальна, работает на любых конфигурациях на управляемых формах, запускается через "Файл" - "Открыть".