При работе в 1С:Предприятии с обычными формами часто возникает задача вывести сообщение пользователю. Однако, если нам необходимо, чтобы это сообщение содержало кнопки для взаимодействия и при этом не блокировало основной интерфейс приложения, задача становится более сложной. Системные функции 1С, предназначенные для вывода сообщений, в обычных формах могут вести себя непредсказуемо, блокируя интерфейс или отображая информацию не так, как мы ожидаем. Давайте подробно разберем эту проблему и найдем наиболее эффективные решения.
Основной вопрос, с которым сталкиваются разработчики: как в обычном приложении, использующем обычные формы, показать пользователю отдельное окно с кнопкой, не блокируя при этом работу с основной формой или всем приложением?
Начнем с анализа системных функций, которые 1С предоставляет для вывода диалоговых окон: ПоказатьВопрос() и ПоказатьПредупреждение(). На первый взгляд, они кажутся подходящими для нашей задачи, но при ближайшем рассмотрении в контексте обычных форм и требования неблокирующего интерфейса выявляются значительные ограничения.
Функция ПоказатьВопрос() предназначена для создания немодального диалога, который позволяет пользователю выбрать один из предложенных вариантов ответа (кнопок). Результат выбора обрабатывается в специальной процедуре-оповещении. Рассмотрим пример ее использования:
Процедура КнопкаВыполнитьНажатие(Кнопка)
// Создаем список кнопок для вопроса
СписокКнопок = Новый СписокЗначений;
СписокКнопок.Добавить(1, "Кнопка 1");
СписокКнопок.Добавить(2, "Кнопка 2");
СписокКнопок.Добавить(3, "Кнопка 3");
// Создаем описание оповещения, которое будет вызвано после ответа пользователя
// "ОбработкаОтветаНаВопрос" - имя процедуры, "ЭтаФорма" - контекст, где ее искать
ОП = Новый ОписаниеОповещения("ОбработкаОтветаНаВопрос", ЭтаФорма);
// Вызываем функцию ПоказатьВопрос
// Первый параметр - описание оповещения, второй - текст вопроса, третий - список кнопок
ПоказатьВопрос(ОП, "Текст вопроса", СписокКнопок);
КонецПроцедуры
Процедура ОбработкаОтветаНаВопрос(РезультатВопроса, ДополнительныеПараметры) Экспорт
// Эта процедура будет вызвана после того, как пользователь нажмет кнопку.
// РезультатВопроса будет содержать значение, связанное с выбранной кнопкой.
Сообщить("Выбрана кнопка: " + РезультатВопроса);
КонецПроцедуры
В теории, этот подход выглядит многообещающим. Однако, как показал опыт автора темы и подтверждается практикой, в обычных формах (особенно на платформе 8.3.18 с режимом совместимости 8.3.14):
ПоказатьВопрос() может привести к полной блокировке интерфейса формы-владельца и даже всего приложения. Пользователь может видеть окно вопроса, но не может взаимодействовать с другими элементами управления, меню или переключаться на другие окна приложения. Несмотря на то, что это окно не является истинно модальным в смысле остановки выполнения кода, для пользователя оно ведет себя как блокирующее.Таким образом, несмотря на наличие механизма ОписаниеОповещения, ПоказатьВопрос() не обеспечивает требуемого неблокирующего поведения в обычных формах 1С. Автор темы подтвердил это, заметив: "Выглядит как будто не блокирует, но ничего не работает", и "выводит в окно сообщений".
Функция ПоказатьПредупреждение() используется для вывода краткого информационного сообщения, которое автоматически закрывается через заданное время или по нажатию кнопки "ОК". Пример использования:
// Пример использования ПоказатьПредупреждение
ПоказатьПредупреждение(,"Это текст сообщения");
Или с задержкой и локализованным текстом:
ПоказатьПредупреждение(,НСтр("ru = 'Выберите документ!'; en = 'Select a document!'"), 10);
Хотя эта функция и доступна начиная с версии 8.3.3 (и, следовательно, должна работать на платформе 8.3.18), она также имеет серьезные недостатки для нашей задачи:
ПоказатьПредупреждение() также является блокирующим окном. Оно останавливает взаимодействие пользователя с основной формой до своего закрытия. Автор темы ясно указал: "ПоказатьПредупреждение также блокирует интерфейс".Итак, обе системные функции, ПоказатьВопрос() и ПоказатьПредупреждение(), не подходят для реализации неблокирующего сообщения с кастомными кнопками в обычных формах 1С из-за их блокирующего поведения и/или ограниченных возможностей по настройке кнопок.
В целом, следует помнить, что процедуры Показать... в 1С изначально разрабатывались с учетом перехода к управляемому интерфейсу и работы в режиме без использования модальности. В обычных формах, особенно в более старых режимах совместимости, их поведение может быть "артефактным" или не соответствовать ожиданиям разработчика, привыкшего к немодальным диалогам управляемых форм.
Поскольку системные функции не справляются с поставленной задачей, наиболее надежным и гибким решением в обычных формах является создание собственной формы. Этот подход дает нам полный контроль над внешним видом, функциональностью и, самое главное, режимом открытия окна. Автор темы пришел к этому же выводу, заявив: "Ничего не поделаешь, придется делать форму (уже сделал)".
Давайте подробно разберем шаги по созданию такой формы и ее открытию в неблокирующем режиме.
На созданной форме нам потребуется разместить следующие элементы:
РезультатВыбора типа "Число" или "Строка".В модуле формы сообщения реализуем процедуры-обработчики для каждой кнопки. В этих процедурах мы будем выполнять следующие действия:
РезультатВыбора в соответствии с нажатой кнопкой.Закрыть().Пример кода для формы сообщения:
// В модуле формы "ФормаСообщения"
// Реквизит формы для хранения результата выбора
// Создайте его на форме (например, РезультатВыбора, тип Число)
Перем мТекстСообщения Экспорт; // Переменная для хранения текста сообщения
// Процедура, вызываемая при создании формы на сервере (если форма обычная)
// В обычных формах часто используется при создании на клиенте, но лучше
// использовать Параметры для инициализации.
Процедура ПриСозданииНаСервере()
// Здесь можем получить параметры, переданные при открытии формы
// ...
КонецПроцедуры
// Процедура, вызываемая при открытии формы
Процедура ПриОткрытии()
// Устанавливаем текст надписи из переданного параметра
ЭлементыФормы.НадписьСообщения.Заголовок = мТекстСообщения;
// Если нужно, можем динамически создавать или скрывать кнопки
// в зависимости от переданных параметров.
КонецПроцедуры
Процедура КнопкаДаНажатие(Элемент)
ЭтотОбъект.РезультатВыбора = 1; // Например, 1 для "Да"
Закрыть();
КонецПроцедуры
Процедура КнопкаНетНажатие(Элемент)
ЭтотОбъект.РезультатВыбора = 0; // Например, 0 для "Нет"
Закрыть();
КонецПроцедуры
Процедура КнопкаОтменаНажатие(Элемент)
ЭтотОбъект.РезультатВыбора = -1; // Например, -1 для "Отмена"
Закрыть();
КонецПроцедуры
Обратите внимание, что реквизит РезультатВыбора должен быть создан в свойствах формы, чтобы он был доступен после закрытия формы. Также можно использовать параметр формы для передачи текста сообщения, чтобы форма была более универсальной.
Самый важный шаг – это открытие формы сообщения таким образом, чтобы она не блокировала интерфейс вызывающей формы. Для этого используем метод ОткрытьФорму().
Ключевым моментом является правильное использование параметров метода ОткрытьФорму(), особенно в части, касающейся модальности.
// В модуле вызывающей формы (где мы хотим показать сообщение)
Процедура ПоказатьНеблокирующееСообщение()
// Определяем имя формы, которую хотим открыть
ИмяФормыСообщения = "Обработка.МояОбработкаСообщений.Форма.ФормаСообщения";
// Создаем структуру параметров для передачи в форму сообщения
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ТекстСообщения", "Внимание! Это важное сообщение, но вы можете продолжить работу.");
// Можем передать список кнопок, чтобы форма сама их отобразила,
// или другие данные, необходимые для ее работы.
// Создаем ОписаниеОповещения для обработки результата после закрытия формы сообщения.
// "ОбработкаЗакрытияФормыСообщения" - имя процедуры в текущей форме,
// которая будет вызвана при закрытии ФормыСообщения.
Оповещение = Новый ОписаниеОповещения("ОбработкаЗакрытияФормыСообщения", ЭтаФорма);
// Открываем форму
// Второй параметр - владелец формы (для обычных форм часто ЭтаФорма)
// Третий параметр - уникальный идентификатор формы (необязательно, но полезно)
// Четвертый параметр - режим открытия (для неблокирующего - РежимОткрытияОкна.Независимый или по умолчанию)
ОткрытьФорму(ИмяФормыСообщения, ПараметрыФормы, ЭтаФорма, , Оповещение);
// ВНИМАНИЕ: Код после ОткрытьФорму() продолжит выполняться сразу же,
// потому что форма открывается НЕМОДАЛЬНО!
// Результат выбора пользователя будет доступен только в процедуре-оповещении.
Сообщить("Код после вызова формы сообщения продолжает выполняться.");
КонецПроцедуры
// Процедура-обработчик для оповещения о закрытии формы сообщения
Процедура ОбработкаЗакрытияФормыСообщения(ЗакрытаяФорма, РезультатЗакрытия) Экспорт
// ЗакрытаяФорма - ссылка на объект формы, которая была закрыта
// РезультатЗакрытия - результат, переданный при закрытии формы (если он был задан)
Если ЗакрытаяФорма.РезультатВыбора = 1 Тогда
Сообщить("Пользователь выбрал 'Да'.");
ИначеЕсли ЗакрытаяФорма.РезультатВыбора = 0 Тогда
Сообщить("Пользователь выбрал 'Нет'.");
ИначеЕсли ЗакрытаяФорма.РезультатВыбора = -1 Тогда
Сообщить("Пользователь выбрал 'Отмена'.");
Иначе
Сообщить("Форма сообщения закрыта без явного выбора.");
КонецЕсли;
// Здесь мы можем продолжить логику, зависящую от выбора пользователя
КонецПроцедуры
Ключевые моменты при вызове ОткрытьФорму() для неблокирующего поведения:
ОписаниеОповещения: Обязательно используйте этот механизм для обработки результата выбора пользователя. Поскольку форма открывается немодально, код после ОткрытьФорму() продолжает выполняться. Результат выбора пользователя будет доступен только в процедуре-оповещении.РежимОткрытияОкна: В обычных формах, если этот параметр не указан явно как блокирующий (например, РежимОткрытияОкна.БлокироватьОкноВладельца или РежимОткрытияОкна.БлокироватьВесьИнтерфейс), форма по умолчанию открывается в неблокирующем режиме относительно вызывающей формы. Это обеспечивает требуемое поведение.Таким образом, создание собственной формы является наиболее гибким и надежным способом для реализации неблокирующих сообщений с кастомными кнопками в обычных формах 1С. Этот подход позволяет полностью контролировать логику, внешний вид и поведение окна, обходя ограничения системных функций.
Если вам нужно просто информировать пользователя без необходимости получать от него ответ через кнопку, существуют более простые неблокирующие методы:
Сообщить():
Этот метод выводит текст в окно сообщений 1С (панель "Сообщения"). Он полностью неблокирующий и никак не прерывает работу пользователя. Однако он не предоставляет никаких кнопок для взаимодействия.
Сообщить("Это просто информационное сообщение.");
Мы можем использовать его для вывода отладочной информации или сообщений, которые не требуют немедленного ответа пользователя.
ПоказатьОповещениеПользователя():
Эта функция выводит всплывающее оповещение в правом нижнем углу экрана, которое автоматически исчезает через некоторое время. Это также неблокирующий способ информирования, аналогичный системным уведомлениям операционной системы. Он не предоставляет кнопок для взаимодействия и предназначен исключительно для кратковременного информирования.
ПоказатьОповещениеПользователя("Документ проведен успешно!", "Документ", "Элемент.Наименование");
Здесь можно указать текст оповещения, заголовок и (опционально) ссылку на объект, чтобы при нажатии на оповещение открывался соответствующий элемент. Этот метод прекрасно подходит для ненавязчивых уведомлений о завершении фоновых операций или других событий, не требующих активного участия пользователя.
Эти методы полезны для информирования, но не решают исходную задачу, поскольку не предоставляют кнопок для взаимодействия с пользователем.
Мы подробно рассмотрели проблему вывода неблокирующего сообщения с кнопкой в обычных формах 1С:Предприятия. Выяснили, что системные функции ПоказатьВопрос() и ПоказатьПредупреждение(), несмотря на их предназначение, в обычных формах версии 8.3.18 (и совместимости 8.3.14) демонстрируют поведение, не соответствующее требованиям: они блокируют интерфейс и/или не позволяют настроить кнопки так, как нам необходимо.
Наиболее надежным и гибким решением является создание собственной, произвольной формы. Этот подход обеспечивает полный контроль над внешним видом, логикой и, что критически важно, режимом открытия окна. Используя ОткрытьФорму() с ОписаниеОповещения, мы можем добиться полностью неблокирующего поведения и асинхронной обработки ответа пользователя.
Если же требуется просто информировать пользователя без взаимодействия через кнопки, то методы Сообщить() и ПоказатьОповещениеПользователя() являются отличными неблокирующими вариантами.
Таким образом, если вы работаете с обычными формами и сталкиваетесь с задачей вывода неблокирующего диалога с настраиваемыми кнопками, создайте свою форму. Это даст вам необходимый контроль и предсказуемый результат.