Взаимодействие с пользователем в 1С 8.3: предупреждения, вопросы и собственные формы

· 9 мин

Содержание

Диалог с пользователем в 1С 8.3 собирают из четырёх групп методов встроенного языка: вывод сообщений (Сообщить, ПоказатьПредупреждение), вопросы с выбором (ПоказатьВопрос), запрос значений (ПоказатьВводЧисла, ПоказатьВводСтроки и другие) и открытие собственной формы через ОткрытьФорму. Всё это работает на клиенте.

Главная особенность платформы 8.3 — диалоги по умолчанию асинхронные. Метод не останавливает код и не возвращает ответ прямо в точке вызова: результат приходит в отдельный обработчик оповещения. Если держать это в голове, остальное складывается быстро.

Ниже — каждый способ с рабочим примером: от всплывающего уведомления до формы с возвратом выбранного значения и передачей параметров.

Все вызовы ниже выполняются на клиенте, поэтому процедуры помечены директивой &НаКлиенте. Данные для диалога (список значений, параметры структуры) можно подготовить на сервере и передать на клиент, но само окно всегда поднимает клиентский код.

Что нужно показать пользователю?

Сообщения и всплывающие уведомления

Самый частый случай — сообщить пользователю факт: документ проведён, проверка не прошла, настройка сохранена. Для этого есть несколько инструментов разного «веса».

Сообщение в нижней части формы. Текст появляется под формой, может быть привязан к конкретному полю реквизита — удобно для валидации.

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Заполните контрагента";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();

Короткая форма Сообщить("Текст") тоже работает и осталась для совместимости, но без привязки к полю — просто строка в общей ленте сообщений.

Всплывающее предупреждение. Отдельное окно с кнопкой «ОК». В 8.3 используйте асинхронный ПоказатьПредупреждение — он не блокирует интерфейс и работает в веб-клиенте:

ПоказатьПредупреждение(, "Операция завершена", 5, "Готово");

Первый параметр — описание оповещения о завершении (чаще не нужен), затем текст, таймаут в секундах и заголовок окна.

Ненавязчивое оповещение. Всплывает в правом нижнем углу и само исчезает — не требует реакции:

ПоказатьОповещениеПользователя("Записано", , "Документ сохранён");

Для обычного информирования берите оповещение или сообщение под формой — они не прерывают работу. Модальное окно Предупреждение() оставьте для случаев, когда пользователь обязан увидеть текст.

Вопрос с выбором: подтверждение действий

Перед необратимой операцией (удаление, перепроведение, очистка) спрашивают подтверждение. За это отвечает ПоказатьВопрос. Набор кнопок задаёт тип РежимДиалогаВопрос, а нажатую кнопку вы разбираете по значению КодВозвратаДиалога.

&НаКлиенте
Процедура УдалитьСтроку(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеВопросаОбУдалении", ЭтотОбъект);
    ПоказатьВопрос(Оповещение, "Удалить выделенную строку?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВопросаОбУдалении(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        // здесь удаляем строку
    КонецЕсли;
КонецПроцедуры

Код после вызова ПоказатьВопрос выполняется сразу, не дожидаясь ответа. Всю реакцию на выбор пишите только в процедуре-обработчике, имя которой передали в ОписаниеОповещения.

Доступные наборы кнопок:

РежимКнопкиКогда применять
ДаНетДа · Нетпростое подтверждение
ДаНетОтменаДа · Нет · Отменаесть третий вариант — отказаться вовсе
ОКОтменаОК · Отменасогласие с возможностью передумать
ПовторитьОтменаПовторить · Отменапосле сбоя предложить повтор

Если нужны нестандартные надписи на кнопках, вместо РежимДиалогаВопрос передайте СписокЗначений: значение станет кодом возврата, а представление — текстом кнопки.

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

В обработчике тогда сравнивайте результат не с КодВозвратаДиалога, а со значениями, которые вы положили в список: Если Результат = "Провести" Тогда. Так из одного вопроса получается три осмысленных варианта вместо сухого «Да/Нет».

Запрос данных: число, строка, дата

Когда от пользователя нужно получить одно значение, не поднимая отдельную форму, подойдут методы ввода. Все они асинхронные и возвращают результат в обработчик оповещения.

&НаКлиенте
Процедура ВвестиКоличество(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеВводаКоличества", ЭтотОбъект);
    ПоказатьВводЧисла(Оповещение, 0, "Укажите количество", 10, 0);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВводаКоличества(Число, ДополнительныеПараметры) Экспорт
    Если Число <> Неопределено Тогда
        // пользователь ввёл значение и нажал ОК
    КонецЕсли;
КонецПроцедуры

Параметры ПоказатьВводЧисла — описание оповещения, начальное значение, подсказка, длина и точность. Аналогично устроены соседи:

  • 🔢 ПоказатьВводЧисла — число с заданной точностью;
  • 🔤 ПоказатьВводСтроки — строка, можно включить многострочный режим;
  • 📅 ПоказатьВводДаты — дата или дата со временем;
  • 📋 ПоказатьВводЗначения — значение заданного типа или выбор из СписокЗначений.

Если пользователь закрыл окно крестиком или нажал «Отмена», в обработчик придёт Неопределено. Проверяйте это перед тем, как использовать значение, иначе получите ошибку на пустом результате.

ПоказатьВводЗначения удобен, когда выбор ограничен справочником или заранее известным перечнем — пользователь не вводит текст руками, а выбирает из предложенного, и опечатки исключены. Тип значения задают описанием типов:

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

Пользователь получит поле с кнопкой выбора, за которой откроется форма списка справочника — отдельную форму выбора писать не придётся.

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

Стандартных окон хватает для одного-двух значений. Как только нужно несколько полей, проверки при вводе или выбор из таблицы — делайте собственную форму. Обычно это общая форма конфигурации, которую открывают как модальное окно поверх владельца.

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

&НаКлиенте
Процедура ПослеВыбораПериода(Результат, ДополнительныеПараметры) Экспорт
    Если Результат <> Неопределено Тогда
        НачалоПериода = Результат.Начало;
    КонецЕсли;
КонецПроцедуры

Чтобы форма вернула значение, в ней при нажатии «ОК» вызывают Закрыть с нужным результатом — он и придёт в обработчик закрытия владельца:

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

Режим БлокироватьОкноВладельца не даёт работать с исходной формой, пока диалог открыт, но при этом не блокирует всё приложение — это современная замена устаревшему модальному открытию.

Есть и второй способ вернуть значение — через механизм выбора. В форме диалога вызывают ОповеститьОВыборе(Значение), а у владельца срабатывает стандартный обработчик ОбработкаВыбора:

// у формы-владельца
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора) Экспорт
    ВыбраннаяСтавка = ВыбранноеЗначение;
КонецПроцедуры

Этот вариант уместен, когда одна форма служит источником выбора для нескольких владельцев. Для разового диалога «открыл — получил ответ» проще описание оповещения о закрытии: вся логика остаётся в одной процедуре, и не нужно заводить общий обработчик ОбработкаВыбора.

Параметры диалога и передача данных в форму

Диалог редко открывают «пустым»: в него передают исходные значения, а поведение настраивают параметрами.

Передача данных в форму. Второй аргумент ОткрытьФорму — структура параметров. Форма читает их при создании:

// при открытии
Параметры = Новый Структура("Организация, Дата", ВыбраннаяОрганизация, ТекущаяДата());
ОткрытьФорму("ОбщаяФорма.Настройки", Параметры, ЭтотОбъект);
// в открываемой форме
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("Организация") Тогда
        Организация = Параметры.Организация;
    КонецЕсли;
КонецПроцедуры

Проверка через Свойство страхует от ситуации, когда форму открыли без параметра.

Настройка стандартных диалогов. У ПоказатьВопрос и ПоказатьПредупреждение есть полезные параметры:

  • ⏱ Таймаут — через сколько секунд окно закроется само. Удобно, когда ответ не критичен;
  • ✅ КнопкаПоУмолчанию — какая кнопка активна при нажатии Enter;
  • 🏷 Заголовок — текст в шапке окна вместо стандартного.
ПоказатьВопрос(Оповещение, "Продолжить?", РежимДиалогаВопрос.ДаНет,
    15, КодВозвратаДиалога.Нет, "Подтверждение");

Здесь окно закроется через 15 секунд, по умолчанию выделена «Нет» — безопасный вариант, если пользователь просто нажмёт Enter не читая.

Модальность, асинхронность и прерывание ввода

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

Режим задаётся свойством конфигурации Режим использования модальности в Конфигураторе. Для новых решений ставьте значение Не использовать — платформа при сборке подскажет все места, где остались модальные вызовы.

Синтаксис Асинх/Ждать. Начиная с версии платформы не ниже 8.3.18, асинхронный код можно писать линейно, без отдельных обработчиков:

&НаКлиенте
Асинх Процедура УдалитьСтрокуАсинх(Команда)
    Ответ = Ждать ВопросАсинх("Удалить строку?", РежимДиалогаВопрос.ДаНет);
    Если Ответ = КодВозвратаДиалога.Да Тогда
        // удаляем
    КонецЕсли;
КонецПроцедуры

Оператор Ждать приостанавливает только эту процедуру, не замораживая интерфейс. Читается как обычный последовательный код — это удобнее цепочек из описаний оповещений.

Прерывание пользователем. Любой диалог можно закрыть, не выбрав ответ. Для вопросов это КодВозвратаДиалога.Отмена, для методов ввода — Неопределено. Отдельную ветку «пользователь отказался» в обработчике стоит предусматривать всегда, иначе цепочка диалогов оборвётся с ошибкой.

Если речь о долгой операции в цикле, а не о диалоге, прерывание обрабатывают иначе — методом ОбработкаПрерыванияПользователя(). Вызов внутри цикла даёт платформе шанс отреагировать на команду остановки, которую пользователь подал с клавиатуры.

Когда диалог лучше не показывать

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

  • Валидация заполнения. Вместо вопроса «Вы не указали контрагента, продолжить?» привяжите сообщение к полю через СообщениеПользователю и установите Отказ = Истина в проверке. Пользователь увидит подсветку поля прямо на форме.
  • Подтверждение каждого шага. Если спрашивать согласие на каждое действие, пользователь привыкает жать «Да» не читая. Подтверждение нужно только перед необратимыми операциями.
  • Информирование об успехе. «Документ записан» уместнее показать ненавязчивым оповещением в углу, а не окном с «ОК», которое приходится закрывать руками.

Хорошее правило: модальное окно оправдано там, где цена ошибки высока — удаление, перепроведение, выгрузка. В остальных случаях выбирайте сообщение под формой или всплывающее оповещение.

Типичные ошибки при работе с диалогами

Разбор частых граблей — отдельно от шагов выше, чтобы не искать их по тексту.

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