Диалог ввода числа во встроенном языке 1С 8.3: от ВвестиЧисло до своей формы

· 9 мин

Содержание

Чтобы ввести число от пользователя в 1С 8.3, на клиенте вызывают ПоказатьВводЧисла() с описанием оповещения или Ждать ВвестиЧислоАсинх() в асинхронной процедуре. Старый ВвестиЧисло() работает только там, где разрешены модальные окна.

Частое заблуждение — искать для этого объект Запрос. Запрос во встроенном языке 1С — это обращение к базе данных на языке запросов, к диалогам он отношения не имеет. Функции с названием вроде «ПолучениеЧисла» в платформе тоже нет: ввод числа идёт через диалоги ввода, через ввод значения с описанием типов или через свою форму.

С чего начать: какой метод ввода числа подходит вашей конфигурации

Выбор метода зависит от одного свойства конфигурации — режима использования модальности. Откройте конфигуратор, встаньте на корень дерева конфигурации и откройте свойства. Свойство называется Режим использования модальности и принимает три значения:

  • 🟢 Использовать — модальные окна разрешены, ВвестиЧисло() работает.
  • 🟡 Использовать с предупреждением — работает, но при проверке модулей платформа предупредит.
  • 🔴 Не использовать — модальный вызов падает с ошибкой Использование модальных окон в данном режиме запрещено!.

Типовые конфигурации на 8.3 (БП 3.0, ЗУП 3.1, УТ 11) работают в режиме «Не использовать». Значит, в доработке типовой базы ВвестиЧисло() не годится.

МетодМодальностьВерсия платформыКогда применять
ВвестиЧисло()нужналюбая 8.xстарые самописные конфигурации, обычные формы
ПоказатьВводЧисла()не нужна8.3.3 и новеетиповые конфигурации, веб-клиент
ВвестиЧислоАсинх()не нужнаномер не ниже 8.3.18новый код, линейная логика без оповещений
ВвестиЗначение() / ПоказатьВводЗначения()зависит от варианта8.3.xнужен запрет отрицательных или особый тип
Своя формане нужна8.3.xнесколько полей, диапазон, подсказки

Все диалоги ввода — клиентские методы. Их вызывают только в процедурах с директивой &НаКлиенте. На сервере окна показать нельзя.

Ввод числа через встроенные диалоги: три варианта кода

У всех трёх методов одинаковые параметры по смыслу:

  1. Число — начальное значение в поле.
  2. Подсказка — заголовок окна.
  3. Длина — общее количество разрядов.
  4. Точность — количество знаков после запятой.

Длина и точность работают как квалификаторы реквизита. Если задать длину 5 и точность 2, пользователь введёт максимум 999.99. Точность 0 — только целые.

Модальный ВвестиЧисло()

Метод возвращает Истина, если пользователь нажал ОК, и Ложь при отмене. Само значение пишется в переменную, переданную первым параметром.

&НаКлиенте
Процедура ЗапроситьКоличество(Команда)

    Количество = 1;
    Если ВвестиЧисло(Количество, "Количество, шт.", 10, 0) Тогда
        Объект.Количество = Количество;
    КонецЕсли;

КонецПроцедуры

Переменную объявите до вызова и задайте ей начальное значение. Пользователь увидит его в поле.

Немодальный ПоказатьВводЧисла()

Код разделяется на две процедуры. Первая показывает окно и сразу завершается. Вторая вызывается платформой, когда пользователь закроет диалог.

&НаКлиенте
Процедура ЗапроситьКоличество(Команда)

    Оповещение = Новый ОписаниеОповещения("ПослеВводаКоличества", ЭтотОбъект);
    ПоказатьВводЧисла(Оповещение, 1, "Количество, шт.", 10, 0);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаКоличества(Число, ДополнительныеПараметры) Экспорт

    Если Число = Неопределено Тогда
        Возврат; // пользователь нажал «Отмена»
    КонецЕсли;

    Объект.Количество = Число;

КонецПроцедуры

Три вещи, на которых спотыкаются чаще всего:

  • 📌 процедура-обработчик обязательно Экспорт, иначе платформа её не найдёт;
  • 📌 у обработчика два параметра: результат и дополнительные параметры;
  • 📌 код после ПоказатьВводЧисла() в первой процедуре выполнится сразу, не дожидаясь ввода. Всё, что зависит от числа, переносите в обработчик.

Через ДополнительныеПараметры передают контекст — например, номер строки табличной части:

Оповещение = Новый ОписаниеОповещения("ПослеВводаКоличества", ЭтотОбъект,
    Новый Структура("ИдентификаторСтроки", Элементы.Товары.ТекущаяСтрока));

Асинхронный ВвестиЧислоАсинх()

С платформы 8.3.18 появились асинхронные методы. Код снова выглядит линейно, но окно немодальное.

&НаКлиенте
Асинх Процедура ЗапроситьКоличество(Команда)

    Число = Ждать ВвестиЧислоАсинх(1, "Количество, шт.", 10, 0);
    Если Число = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Объект.Количество = Число;

КонецПроцедуры

Процедура помечается словом Асинх, вызов — оператором Ждать. При отмене возвращается Неопределено. Режим совместимости конфигурации должен быть не ниже 8.3.18, иначе ключевые слова не распознаются.

Ограничение знака и типа: ввод числа через ВвестиЗначение

ВвестиЧисло() не умеет запрещать минус. Для количества, цены или процента это неудобно. Задачу решает ввод значения с описанием типов:

&НаКлиенте
Процедура ЗапроситьЦену(Команда)

    ТипЦены = Новый ОписаниеТипов("Число",
        Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный));

    Оповещение = Новый ОписаниеОповещения("ПослеВводаЦены", ЭтотОбъект);
    ПоказатьВводЗначения(Оповещение, 0, "Цена, руб.", ТипЦены);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаЦены(Значение, ДополнительныеПараметры) Экспорт

    Если Значение = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Объект.Цена = Значение;

КонецПроцедуры

Квалификатор ДопустимыйЗнак.Неотрицательный не даст ввести отрицательное значение прямо в поле. Длина 15 и точность 2 совпадают с типичным реквизитом суммы.

Асинхронная пара для этого метода — ВвестиЗначениеАсинх(), модальная — ВвестиЗначение().

Проверка введённого числа и повторный запрос

Длина, точность и знак — это ограничения формата. Бизнес-правила («скидка от 0 до 30 %», «количество кратно 10») проверяете сами. Лучший момент — в обработчике сразу после ввода.

Пример: скидка не больше 30 %. Если введено больше, сообщаем и снова открываем диалог с введённым значением.

&НаКлиенте
Процедура ЗапроситьСкидку(Команда)
    ПоказатьВводСкидки(0);
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьВводСкидки(НачальноеЗначение)

    Оповещение = Новый ОписаниеОповещения("ПослеВводаСкидки", ЭтотОбъект);
    ПоказатьВводЧисла(Оповещение, НачальноеЗначение, "Скидка, % (0–30)", 5, 2);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаСкидки(Число, ДополнительныеПараметры) Экспорт

    Если Число = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Если Число < 0 Или Число > 30 Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Скидка должна быть от 0 до 30 %.";
        Сообщение.Сообщить();
        ПоказатьВводСкидки(Число);
        Возврат;
    КонецЕсли;

    Объект.ПроцентСкидки = Число;

КонецПроцедуры

Не крутите повторный запрос без выхода. Отмена всегда должна завершать цикл — проверка Число = Неопределено стоит первой.

Проверка прямо в поле формы

Часто диалог вообще не нужен: число вводят в поле реквизита на форме документа. Тогда проверку ставят в обработчик события поля ПриИзменении. Он срабатывает, когда пользователь ушёл из поля с новым значением.

&НаКлиенте
Процедура ПроцентСкидкиПриИзменении(Элемент)

    Если Объект.ПроцентСкидки > 30 Тогда
        Объект.ПроцентСкидки = 30;
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Скидка ограничена 30 %, значение исправлено.";
        Сообщение.Поле = "Объект.ПроцентСкидки";
        Сообщение.Сообщить();
    КонецЕсли;

КонецПроцедуры

Свойство Поле привязывает сообщение к полю: пользователь увидит, где ошибка, и щелчком по сообщению перейдёт к нему. Для жёсткого запрета при записи добавьте проверку в модуль объекта, в обработчик ОбработкаПроверкиЗаполнения, — тогда документ с неверным числом не запишется ни из формы, ни из обработки.

Если число пришло строкой

Из файла, буфера или поля типа «Строка» число приходит текстом: "1 250,50". Функция Число() на такой строке упадёт с исключением. Очистите строку и оберните преобразование в Попытка:

&НаКлиентеНаСервереБезКонтекста
Функция СтрокаВЧисло(Знач Текст, ЗначениеПоУмолчанию = 0)

    Текст = СтрЗаменить(Текст, " ", "");
    Текст = СтрЗаменить(Текст, Символы.НПП, "");
    Текст = СтрЗаменить(Текст, ",", ".");

    Попытка
        Возврат Число(Текст);
    Исключение
        Возврат ЗначениеПоУмолчанию;
    КонецПопытки;

КонецФункции

Символы.НПП — неразрывный пробел. Его подставляет сама 1С при форматировании разрядов, и именно он чаще всего ломает обратное преобразование.

Клиент-серверный вариант: куда попадает введённое число

Диалог живёт на клиенте, а запись в базу, расчёты и запросы — на сервере. Число нужно явно передать параметром серверной процедуры:

&НаКлиенте
Асинх Процедура ПересчитатьЦены(Команда)

    Процент = Ждать ВвестиЧислоАсинх(0, "Наценка, %", 6, 2);
    Если Процент = Неопределено Тогда
        Возврат;
    КонецЕсли;

    ПересчитатьЦеныНаСервере(Процент);

КонецПроцедуры

&НаСервере
Процедура ПересчитатьЦеныНаСервере(Процент)

    Если Процент < 0 Или Процент > 500 Тогда
        ВызватьИсключение "Недопустимая наценка: " + Формат(Процент, "ЧДЦ=2; ЧН=0");
    КонецЕсли;

    Для Каждого Строка Из Объект.Товары Цикл
        Строка.Цена = Окр(Строка.Цена * (1 + Процент / 100), 2);
    КонецЦикла;

КонецПроцедуры

Что учесть при таком разделении:

  • 🔁 Проверку дублируйте на сервере. Клиентский код можно обойти, серверный — нет. Для записи в базу это обязательно.
  • 📡 Один серверный вызов вместо пяти. Соберите все введённые значения на клиенте и передайте за один раз — каждый вызов сервера идёт по сети.
  • 🚫 Фоновые задания, регламентные задания, HTTP-сервисы, обработчики ПриЗаписи выполняются без пользовательского окна. Спрашивать там нечего — значение берите из параметров или настроек.
  • 🌐 Веб-клиент блокирует модальные окна независимо от вкуса разработчика, поэтому код для него — только ПоказатьВводЧисла() или асинхронный вариант.

Своя форма для ввода чисел: когда стандартного окна мало

Стандартный диалог даёт одно поле и заголовок. Если нужно несколько чисел сразу, пояснение под полем, диапазон или кнопки «+/–», делайте свою форму. Обычно её создают в общей форме или в форме обработки.

Шаги

  1. Создайте форму, на вкладке Реквизиты добавьте реквизит Значение типа Число с нужными длиной и точностью. Для неотрицательных значений в квалификаторе отметьте «Неотрицательное».
  2. Перетащите реквизит на форму. В свойствах поля задайте МинимальноеЗначение и МаксимальноеЗначение — платформа не пропустит значение за границами.
  3. Для мелкого шага включите у поля КнопкаРегулирования — появятся стрелки увеличения и уменьшения.
  4. На вкладке Параметры формы добавьте параметр НачальноеЗначение типа Число.
  5. Добавьте команду «Готово» с обработчиком, который закрывает форму и возвращает число.

Код формы ввода:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Значение = Параметры.НачальноеЗначение;
КонецПроцедуры

&НаКлиенте
Процедура Готово(Команда)
    Если ПроверитьЗаполнение() Тогда
        Закрыть(Значение);
    КонецЕсли;
КонецПроцедуры

Вызов из другой формы:

&НаКлиенте
Процедура ОткрытьВводНормы(Команда)

    Параметры = Новый Структура("НачальноеЗначение", Объект.Норма);
    Оповещение = Новый ОписаниеОповещения("ПослеВводаНормы", ЭтотОбъект);

    ОткрытьФорму("ОбщаяФорма.ВводНормы", Параметры, ЭтотОбъект,,,,
        Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаНормы(Результат, ДополнительныеПараметры) Экспорт

    Если Результат = Неопределено Тогда
        Возврат; // форму закрыли крестиком
    КонецЕсли;

    Объект.Норма = Результат;

КонецПроцедуры

Значение, переданное в Закрыть(), приходит в обработчик оповещения первым параметром. Закрытие крестиком даёт Неопределено.

Режим БлокироватьОкноВладельца не делает форму модальной в смысле платформы. Он блокирует только окно-владелец и работает при режиме модальности «Не использовать».

Если реквизиту поставить флажок «Проверка заполнения: Выдавать ошибку», ПроверитьЗаполнение() не пропустит ноль. Учтите это: для числа «пусто» и «0» — одно и то же значение.

Своя форма ввода числа готова, если
Выполнено: 0 / 6

Как показать число пользователю: Формат() и свойства поля

Ввод — половина дела. Число нужно ещё правильно вывести: в сообщении, заголовке, печатной форме.

Функция Формат() принимает форматную строку из пар «ключ=значение» через точку с запятой:

КлючЧто делаетПримерРезультат
ЧДЦзнаков после запятой, с округлениемФормат(1234.567, "ЧДЦ=2")1 234,57
ЧГ=0убирает группировку разрядовФормат(1234567, "ЧГ=0")1234567
ЧРДразделитель дробной частиФормат(12.5, "ЧДЦ=2; ЧРД=.")12.50
ЧНчто выводить вместо нуляФормат(0, "ЧН=—")—
ЧЦобщее число разрядовФормат(42, "ЧЦ=6; ЧВН=")000042
ЧВНвыводить ведущие нулисм. строку выше

Склеивать число со строкой через «+» без Формат() нельзя: при значении 1250 в тексте появится 1 250 с неразрывным пробелом, а в коде документа или имени файла это ломает сравнение. Для идентификаторов всегда пишите Формат(Число, "ЧГ=0").

Ещё два приёма:

  • 🧾 ЧислоПрописью() — сумма словами для печатных форм: ЧислоПрописью(1250.50, "Л=ru_RU", "рубль, рубля, рублей, м, копейка, копейки, копеек, ж, 2").
  • 🖊️ Свойства поля формы Формат и ФорматРедактирования. Первое управляет видом в списке, второе — видом при редактировании. Например, ЧДЦ=2 в формате и ЧГ=0 в формате редактирования: в списке 1 250,00, а при вводе цифры не прыгают из-за пробелов.

Частые вопросы

Можно ли ограничить ввод только целыми числами?
Да. Задайте точность 0 в ПоказатьВводЧисла() или в квалификаторе типа. Дробную часть пользователь ввести не сможет.
Почему ПоказатьВводЧисла() не ждёт ответа и код идёт дальше?
Метод немодальный: он только открывает окно. Всё, что зависит от введённого числа, пишите в процедуре-обработчике оповещения или используйте Ждать ВвестиЧислоАсинх().
Как отличить отмену от ввода нуля?
В немодальном и асинхронном вариантах отмена даёт Неопределено, а ноль — это число 0. В модальном ВвестиЧисло() смотрите на возвращаемое Истина/Ложь.
Работает ли ввод числа в обычных формах толстого клиента?
Работает ВвестиЧисло() при разрешённой модальности. Немодальные методы тоже доступны в обычном приложении на 8.3, но переписывать старый код без необходимости смысла нет.
Как запросить сразу два числа, например количество и цену?
Стандартным диалогом — только двумя вызовами подряд. Удобнее своя форма с двумя полями, которая возвращает в Закрыть() структуру с обоими значениями.