Работа с диалоговыми окнами — одна из ключевых задач при разработке пользовательских интерфейсов в 1С:Предприятие. Без грамотно спроектированных диалогов даже самая функциональная конфигурация будет неудобной для конечных пользователей. В этой статье мы разберём все этапы создания диалогов: от базовых форм с кнопками "Да/Нет" до сложных модальных окон с динамической логикой, привязкой к данным и обработкой событий.
Особое внимание уделим практическим примерам кода на встроенном языке 1С, типичным ошибкам новичков и способам оптимизации производительности. Вы узнаете, как правильно использовать Вопрос(), ПредопределенноеЗначение(), работать с управляемыми формами и настраивать взаимодействие между клиентом и сервером. Материал будет полезен как начинающим разработчикам, так и опытным программистам, которые хотят систематизировать знания о диалогах в 1С 8.3.
Все примеры в статье актуальны для последних версий платформы 1С:Предприятие 8.3 (включая 8.3.23 и новее), но основные принципы применимы и к более ранним релизам. Если вы работаете с 1С 7.7, часть методов будет недоступна — об этом мы отдельно упомянем в соответствующих разделах.
1. Базовые диалоги: Вопрос(), Предупреждение(), Сообщить()
Начнём с самых простых встроенных функций, которые позволяют быстро вывести сообщение пользователю или получить подтверждение действия. Эти методы не требуют создания форм и работают напрямую из кода.
Функция Вопрос() — самый распространённый способ запросить у пользователя подтверждение. Она возвращает Истина (если нажали "Да") или Ложь (если "Нет"). Пример использования:
Если Вопрос("Сохранить изменения перед закрытием?", РежимДиалогаВопрос.ДаНет) Тогда
СохранитьДанные();
КонецЕсли;
Обратите внимание на второй параметр — РежимДиалогаВопрос. Он определяет набор кнопок в диалоге:
- 🔹
.ДаНет— кнопки "Да" и "Нет" - 🔹
.ОкОтмена— кнопки "ОК" и "Отмена" - 🔹
.ДаНетОтмена— три кнопки - 🔹
.Ок— только кнопка "ОК" (аналогСообщить())
Для вывода информационных сообщений без запроса подтверждения используйте Сообщить() или Предупреждение(). Последнее подсвечивает текст жёлтым фоном, что привлекает внимание пользователя:
Предупреждение("Документ содержит ошибки! Проверьте реквизиты контрагента.", 10);
Цифра 10 в примере выше — это время показа сообщения в секундах (актуально для тонкого клиента и веб-клиента).
Если вам нужно вывести длинный текст с переносами строк, используйте символ | внутри функции Вопрос() или Сообщить(). Пример: Сообщить("Строка 1|Строка 2|Строка 3");
2. Создание диалогов через управляемые формы
Когда стандартных функций Вопрос() и Сообщить() недостаточно, приходит очередь управляемых форм. Они позволяют создавать диалоги любой сложности: с полями ввода, выпадающими списками, табличными частями и динамической логикой.
Рассмотрим пошагово, как создать простую модальную форму с двумя полями и кнопкой "Сохранить":
- Создайте новую форму в дереве конфигурации (раздел "Общие → Формы").
- Добавьте реквизиты:
- 📝
ИмяПользователя(тип "Строка", длина 50) - 📅
ДатаРождения(тип "Дата")
- 📝
- Поместите элементы на форму:
- 🖥️ Поле ввода для
ИмяПользователя - 🗓️ Поле календаря для
ДатаРождения - 💾 Кнопка "Сохранить" с обработчиком события
Нажатие
- 🖥️ Поле ввода для
- 🔲 Установите
Модальность = Истина - 🔲 Задайте
Заголовок = "Ввод данных пользователя"
Код обработчика кнопки "Сохранить" может выглядеть так:
Процедура Сохранить(Команда)
Если ИмяПользователя = "" Тогда
Предупреждение("Введите имя пользователя!");
Возврат;
КонецЕсли;
// Сохраняем данные в базу или передаём их дальше
Сообщить("Данные сохранены: " + ИмяПользователя + ", " + Формат(ДатаРождения, "ДФ=dd.MM.yyyy"));
Закрыть();
КонецПроцедуры
☑️ Проверка перед открытием формы
Важный нюанс: если вы открываете форму из серверного кода (например, из модуля документа), используйте метод ОткрытьФормуМодально():
Перем Результат;
ОткрытьФормуМодально("ОбщаяФорма.МояФорма", Результат, ЭтотОбъект);
3. Передача параметров в диалог и возвращение результатов
Часто диалоговое окно нужно не просто показать, а передать в него начальные данные и получить результат после закрытия. Для этого в 1С используется механизм параметров формы.
Допустим, мы хотим передать в форму текущего пользователя и вернуть выбранную им дату. Модифицируем предыдущий пример:
1. Объявляем параметры формы в свойствах формы (закладка "Параметры"):
- 👤
ТекущийПользователь(тип "Строка")
2. Добавляем реквизит для возврата результата:
- 📅
ВыбраннаяДата(тип "Дата")
3. Код открытия формы с параметрами:
Перем РезультатФормы;
ПараметрыФормы = Новый Структура("ТекущийПользователь", ПользователиИнформационнойБазы.ТекущийПользователь());
ОткрытьФормуМодально("ОбщаяФорма.МояФорма", РезультатФормы, ЭтотОбъект, ПараметрыФормы);
Если РезультатФормы.ВыбраннаяДата <> Неопределено Тогда
Сообщить("Пользователь " + РезультатФормы.ТекущийПользователь + " выбрал дату: " + РезультатФормы.ВыбраннаяДата);
КонецЕсли;
4. В модуле формы обрабатываем параметры при создании:
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.ТекущийПользователь <> Неопределено Тогда
ИмяПользователя = Параметры.ТекущийПользователь;
КонецЕсли;
КонецПроцедуры
И возвращаем результат при закрытии:
Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
Результат = Новый Структура("ВыбраннаяДата, ТекущийПользователь", ДатаРождения, ИмяПользователя);
Возврат Результат;
КонецПроцедуры
Что будет если не обработать параметры формы?
Если не проверить передаваемые параметры на Неопределено, при открытии формы без параметров возникнет ошибка "Поле объекта не обнаружено". Всегда используйте конструкцию Если Параметры.ИмяПараметра <> Неопределено Тогда.
4. Динамическое управление элементами диалога
Современные диалоги в 1С редко бывают статичными. Чаще всего элементы формы нужно показывать или скрывать в зависимости от действий пользователя, проверять введённые данные на корректность и динамически заполнять списки.
Рассмотрим пример формы с динамической логикой:
- 🔘 Чекбокс "Я согласен с условиями"
- 🔒 Кнопка "Продолжить", которая активна только при установленном чекбоксе
- 📋 Поле "Комментарий", которое становится обязательным, если выбрана определённая опция
Код для управления видимостью и доступностью элементов:
Процедура ФлагСогласияПриИзменении(Элемент)
КнопкаПродолжить.Доступность = ФлагСогласия;
КонецПроцедуры
Процедура ТипОперацииПриИзменении(Элемент)
Если ТипОперации = Перечисления.ТипыОпераций.Срочная Тогда
Комментарий.Видимость = Истина;
Комментарий.Обязательное = Истина;
Иначе
Комментарий.Видимость = Ложь;
Комментарий.Обязательное = Ложь;
КонецЕсли;
КонецПроцедуры
Для валидации данных используйте обработчик ПередЗаписью:
Процедура ПередЗаписьюНаСервере(Отказ, СтандартнаяОбработка)
Если ТипОперации = Перечисления.ТипыОпераций.Срочная И Комментарий = "" Тогда
Предупреждение("Для срочной операции обязателен комментарий!");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Критическая особенность: в управляемых формах 1С 8.3 все изменения свойств элементов (например, Видимость или Доступность) должны выполняться на клиенте. Если вы попробуете изменить их на сервере, получите ошибку "Операция не разрешена в серверном контексте".
5. Использование внешних обработок для диалогов
Когда диалог нужно использовать в нескольких конфигурациях или передавать его между разными базами, удобно оформить его как внешнюю обработку. Это также полезно для тестирования новых форм без внесения изменений в основную конфигурацию.
Алгоритм создания диалога во внешней обработке:
- Создайте новую внешнюю обработку в Конфигураторе (
Файл → Новый → Внешняя обработка). - Добавьте форму с нужными элементами (аналогично обычной форме).
- В модуле обработки экспортируйте функцию открытия диалога:
Функция ОткрытьДиалогПараметров(Параметры) ЭкспортРезультат = Неопределено;
ОткрытьФормуМодально("Обработка.МояОбработка.Форма.Форма", Результат,, Параметры);
Возврат Результат;
КонецФункции
- Подключите обработку к основной конфигурации через
ВнешниеОбработки.Подключить().
Пример вызова внешней обработки из кода:
ПутьКФайлу = "C:\Dialogs\ParamForm.epf";
Обработка = ВнешниеОбработки.Создать(ПутьКФайлу);
Параметры = Новый Структура("Заголовок, МинимальнаяДата", "Выберите период", ТекущаяДата());
Результат = Обработка.ОткрытьДиалогПараметров(Параметры);
Если Результат <> Неопределено Тогда
Сообщить("Выбрано: " + Результат.НачалоПериода + " - " + Результат.КонецПериода);
КонецЕсли;
Внешние обработки удобны для распределенных систем, но требуют контроля версий. Всегда проверяйте совместимость обработки с версией платформы 1С, особенно при обновлениях.
6. Распространённые ошибки и их решение
Даже опытные разработчики 1С сталкиваются с типичными проблемами при работе с диалогами. Мы собрали самые частые ошибки и способы их устранения:
| Ошибка | Причина | Решение |
|---|---|---|
| Форма открывается, но не закрывается по кнопке "ОК" | Отсутствует обработчик события Нажатие или не вызван метод Закрыть() |
Добавьте в обработчик кнопки вызов Закрыть(Истина); |
| Не передаются параметры в форму | Параметры передаются неверной структурой или не объявлены в свойствах формы | Проверьте имена параметров в ОткрытьФормуМодально() и в свойствах формы |
| Элементы формы не обновляются при изменении данных | Изменения выполняются на сервере, а не на клиенте | Перенесите код в клиентский модуль или используйте ОповеститьОбИзменении() |
| Диалог "подвисает" при открытии | Долгие операции выполняются в обработчике ПриОткрытии |
Вынесите тяжелые операции в фоновые задания или оптимизируйте запросы |
Ещё одна распространённая проблема — утечка памяти при частом открытии модальных форм. Чтобы избежать этого:
- 🗑️ Всегда закрывайте формы явно через
Закрыть(). - 🔄 Не создавайте формы в циклах без контроля.
- 📉 Используйте
ОчиститьЗначение()для больших коллекций данных после работы.
Если диалог должен открываться часто (например, при выборе строк в таблице), рассмотрите вариант с одной формой, которая динамически обновляет данные вместо создания новых экземпляров.
7. Продвинутые техники: асинхронность и интеграция с API
Для сложных сценариев может потребоваться асинхронное взаимодействие с диалогами или интеграция с внешними системами через HTTP-сервисы и REST API.
Пример 1: Асинхронный запрос данных в диалоге
Допустим, при открытии формы нужно загрузить справочник контрагентов из внешней системы. Чтобы не блокировать интерфейс, используем ВыполнитьОбработкуНаСервереБезКонтекста():
Процедура ПриОткрытии(Отказ)
ЗапросДанныхНаСервере();
КонецПроцедуры
Процедура ЗапросДанныхНаСервере()
ВыполнитьОбработкуНаСервереБезКонтекста("ПолучитьКонтрагентовИзAPI", Структура);
КонецПроцедуры
Процедура ПолучитьКонтрагентовИзAPI(Параметры) Экспорт
HTTPСоединение = Новый HTTPСоединение("api.example.com");
Ответ = HTTPСоединение.Получить("/contractors");
// Обработка ответа и обновление формы
ОповеститьОбИзменении("Контрагенты");
КонецПроцедуры
Пример 2: Диалог с ожиданием фонового задания
Если операция занимает много времени (например, формирование большого отчёта), покажите пользователю диалог с прогресс-баром:
Процедура СформироватьОтчетНаСервере()
Прогресс = Новый ПрогрессИндикатор("Формирование отчёта...", 100);
ФоновоеЗадание = ФоновыеЗадания.Выполнить(
"ОбщийМакет.МодульСФормированиемОтчета.СформироватьДанные",
Структура,
Новый ОписаниеОповещения("ПослеФормированияОтчета", ЭтотОбъект)
);
Прогресс.Закрыть();
КонецПроцедуры
Процедура ПослеФормированияОтчета(Результат, ДополнительныеПараметры) Экспорт
Если Результат.Успех Тогда
ОткрытьФормуМодально("ОбщаяФорма.ПросмотрОтчета", Результат.Данные);
Иначе
Предупреждение("Ошибка формирования: " + Результат.ОписаниеОшибки);
КонецЕсли;
КонецПроцедуры
Для интеграции с Telegram-ботами или другими мессенджерами можно создавать диалоги, которые отправляют уведомления во внешние системы. Пример кода для отправки сообщения в Telegram при сохранении данных из формы:
Процедура СохранитьИОтправитьУведомление()
// Сохраняем данные
Объект.Записать();
// Формируем сообщение
ТекстСообщения = "Пользователь " + ПользователиИнформационнойБазы.ТекущийПользователь() + "%0A";
ТекстСообщения = ТекстСообщения + "Сохранён документ №" + Объект.Номер + " от " + Объект.Дата;
// Отправляем в Telegram
HTTPЗапрос = Новый HTTPЗапрос("https://api.telegram.org/bot{TOKEN}/sendMessage");
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json");
HTTPЗапрос.УстановитьТекст(
JSON.Записать(
Новый Структура(
"chat_id", "{CHAT_ID}",
"text", ТекстСообщения
)
)
);
HTTPСоединение = Новый HTTPСоединение();
Ответ = HTTPСоединение.ПослатьДляОбработки(HTTPЗапрос);
КонецПроцедуры
При работе с внешними API всегда обрабатывайте возможные ошибки сети. Используйте конструкцию Попытка...Исключение для защиты от падений.
8. Оптимизация производительности диалогов
Плохо оптимизированные диалоги могут тормозить работу 1С, особенно в режиме тонкого клиента или веб-клиента. Вот ключевые рекомендации по оптимизации:
1. Минимизируйте данные в формах:
- 📉 Не загружайте в форму все поля объекта — только те, что нужны для диалога.
- 🔄 Используйте
ОтбориПорядокпри загрузке справочников в выпадающие списки. - 🗃️ Для больших табличных частей применяйте постраничную загрузку.
2. Оптимизируйте серверные вызовы:
- 🔌 Объединяйте несколько запросов к серверу в один.
- 📡 Используйте
ПоместитьВоВременноеХранилище()для передачи больших данных. - ⚡ Для часто используемых диалогов кэшируйте данные на клиенте.
3. Управляйте обновлениями интерфейса:
- 🔄 Отключайте автоматическое обновление формы (
АвтоОбновление = Ложь) при массовых изменениях. - 🎨 Используйте
ПриостановитьОтрисовку()иВозобновитьОтрисовку()для пакетных операций.
Пример оптимизированного кода для загрузки данных в форму:
Процедура ЗагрузитьДанныеНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 100
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ПометкаУдаления = ЛОЖЬ
|УПОРЯДОЧИТЬ ПО
| Артикул";
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецПроцедуры
Процедура ПриОткрытии(Отказ)
Данные = ВыполнитьНаСервере("ЗагрузитьДанныеНаСервере");
ЭлементыФормы.СписокНоменклатуры.Список = Данные;
КонецПроцедуры
Критический совет: если ваш диалог содержит таблицу с более чем 500 строками, обязательно реализуйте ленту прокрутки или постраничный просмотр. В противном случае пользователи с медленным интернетом будут испытывать задержки при открытии формы.
Оптимизация диалогов — это не только скорость, но и удобство. Всегда тестируйте формы на реальных данных, а не на тестовых выборках из 10 записей.
FAQ: Ответы на частые вопросы
Как сделать диалог с таймером автоматического закрытия?
Используйте функцию ЗапуститьОбработкуОжидания() в модуле формы. Пример кода:
Перем ТаймерЗакрытия;
Процедура ПриОткрытии(Отказ)
ТаймерЗакрытия = ЗапуститьОбработкуОжидания("ЗакрытьПоТаймауту", 10000); // 10 секунд
КонецПроцедуры
Процедура ЗакрытьПоТаймауту()
Закрыть();
КонецПроцедуры
Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
Если ТаймерЗакрытия <> Неопределено Тогда
ПрерватьОбработкуОжидания(ТаймерЗакрытия);
КонецЕсли;
КонецПроцедуры
Можно ли создать диалог без формы, только на встроенном языке?
Да, для простых случаев можно использовать комбинацию Вопрос() и ВводСтроки(). Пример:
Имя = ВводСтроки("Введите ваше имя:", , "Иван Иванов");
Если Имя <> Неопределено Тогда
Возраст = ВводЧисла("Введите ваш возраст:", 18);
Сообщить("Здравствуйте, " + Имя + "! Вам " + Возраст + " лет.");
КонецЕсли;
Однако такой подход не подходит для сложных диалогов с валидацией и динамической логикой.
Как сделать диалог с вкладками?
Добавьте на форму элемент ГруппаПанелей (в палате элементов "Панель"). Затем:
- Настройте количество вкладок в свойстве
Элементы. - Для каждой вкладки добавьте
Группус нужными элементами. - Установите свойство
Заголовокдля каждой группы (это будет название вкладки).
Пример структуры:
Форма
├── ГруппаПанелей (Вкладки)
│ ├── Группа1 (Заголовок = "Основные данные")
│ │ ├── ПолеВвода1
│ │ └── ПолеВвода2
│ └── Группа2 (Заголовок = "Дополнительно")
│ ├── Флажок1
│ └── Таблица1
└── КнопкаСохранить
Почему моя форма открывается не по центру экрана?
Позиция формы определяется свойством ПоложениеОкна. Чтобы форма открывалась по центру, установите:
ЭтотОбъект.ПоложениеОкна = ПоложениеОкна.ЦентрЭкрана;
Также проверьте, не переопределяется ли положение в обработчике ПередОткрытием.
Как запретить изменение размера диалогового окна?
Установите свойства формы:
ЭтотОбъект.ИзменениеРазмера = Ложь;
ЭтотОбъект.Границы = Новый Границы(0, 0, 0, 0);
Если нужно фиксировать только ширину или высоту, используйте:
ЭтотОбъект.МинимальнаяШирина = ЭтотОбъект.Ширина;
ЭтотОбъект.МинимальнаяВысота = ЭтотОбъект.Высота;