В практике разработчика 1С иногда возникают ситуации, когда необходимо программно открыть множество форм для выполнения определенных расчетов или эмуляции действий пользователя. Однако часто программисты сталкиваются со странным поведением системы: несмотря на вызов метода Закрыть(), окна продолжают висеть на экране "каскадом", пока весь алгоритм не отработает до конца. Проанализируем, почему это происходит, и разберем эффективные способы решения этой задачи.
Для начала разберем внутренние механизмы платформы 1С:Предприятие 8.3. Графический интерфейс управляемого приложения работает в однопоточном режиме. Когда мы запускаем длительный цикл, в котором открываются и закрываются формы, поток интерфейса оказывается полностью занят выполнением программного кода. Рассмотрим ситуацию подробнее:
Форма.Открыть() отправляет запрос системе на создание и отрисовку окна.Форма.Закрыть() помечает форму как закрытую и посылает сообщение в очередь событий графической подсистемы.Пока ваш цикл (например, по 100500 формам) не завершится, у платформы просто нет "времени" и ресурсов потока, чтобы обновить экран и убрать закрытые окна. Именно поэтому пользователь видит нагромождение форм, которые фактически уже имеют статус Открыта() = Ложь, но визуально остаются на месте.
Прежде чем использовать сложные хаки, проанализируем самый простой вариант — ошибки в логике ветвления. Как выяснилось в ходе обсуждения темы, часто причиной является преждевременный выход из процедуры (например, по условию Возврат), из-за чего выполнение просто не доходит до строки с закрытием формы. Рассмотрим правильную конструкцию для гарантированного закрытия:
// Пример безопасного закрытия формы в цикле
Для Каждого Параметр Из МассивПараметров Цикл
ФормаП = ПолучитьФорму("ОбщаяФорма.МояРасчетнаяФорма", Параметры);
ФормаП.Открыть();
// ... выполнение расчетов или эмуляция ввода ...
// Проверяем, открыта ли форма перед попыткой закрытия
Если ФормаП.Открыта() Тогда
ФормаП.Закрыть();
КонецЕсли;
КонецЦикла;
Важный нюанс: если внутри методов формы, которые вы вызываете, есть свои обработчики закрытия или отказы, форма может остаться открытой. Убедитесь, что логика внутри самой формы не блокирует ее программное закрытие.
Если форм действительно много и вам нужно, чтобы они исчезали с экрана в процессе работы, а не в самом конце, необходимо периодически "отдавать" управление системе. Разберем, как это сделать через механизм ПодключитьОбработчикОжидания(). Рассмотрим алгоритм по шагам:
Посмотрим на пример кода:
&НаКлиенте
Процедура ЗапуститьОбработкуФорм()
ПеременныеМодуля.ТекущийИндекс = 0; // Инициализируем счетчик
ВыполнитьСледующийШаг();
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьСледующийШаг()
// Обрабатываем одну форму
Если ПеременныеМодуля.ТекущийИндекс < ПеременныеМодуля.ОбщееКоличество Тогда
ПараметрыФормы = СформироватьПараметры(ПеременныеМодуля.ТекущийИндекс);
Форма = ПолучитьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);
Форма.Открыть();
// Тут ваша логика эмуляции
// ...
Форма.Закрыть();
ПеременныеМодуля.ТекущийИндекс = ПеременныеМодуля.ТекущийИндекс + 1;
// Даем платформе "вдохнуть", чтобы закрыть окно визуально
ПодключитьОбработчикОжидания("ВыполнитьСледующийШаг", 0.1, Истина);
КонецЕсли;
КонецПроцедуры
В современных релизах 1С (начиная с 8.3.18) мы можем использовать асинхронное программирование. Это позволяет писать код более линейно, не разрывая его на несколько процедур с обработчиками ожидания. Выясним, как это помогает в нашей ситуации. Использование операторов Ждать (Await) позволяет временно прервать выполнение процедуры, позволяя интерфейсу обновиться.
Проанализируем ситуацию с точки зрения ресурсов системы. Открытие "100500" форм — это не только визуальная проблема, но и серьезная нагрузка на память. Каждая форма в 1С — это сложный объект. Даже после вызова Закрыть(), объект формы может не сразу удаляться из памяти (работать будет сборщик мусора).
Основные опасности:
1cv8.exe может переполниться, что приведет к аварийному завершению ("Out of memory").Рассмотрим более профессиональные подходы, которые позволяют избежать "слайд-шоу" из окон:
РеквизитФормыВЗначение("Объект"). Это позволит выполнить код модуля без создания визуального окна.ТестируемоеПриложение. Он гораздо стабильнее эмулирует нажатия кнопок, чем методы WScript.Shell или прямое открытие форм.Подведем итог: если вы столкнулись с "незакрывающимися" формами, сначала проверьте, не пропускает ли ваш код команду закрытия из-за условий. Если же логика верна, но окна висят визуально — используйте ПодключитьОбработчикОжидания для принудительной передачи управления графической подсистеме.