При разработке отчетов и обработок на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с задачей вывода множества однотипных документов или отчетов. Типичная ситуация: в коде организован цикл, внутри которого заполняется макет, и в конце каждой итерации вызывается метод Показать(). Однако вместо ожидаемой стопки окон на экране пользователь видит только одну таблицу — результат последней итерации. Разберем подробно, почему так происходит и как заставить систему открывать каждое сформированное окно.
Проанализируем ситуацию. В 1С 7.7 объект типа Таблица является ссылочным. Если мы создаем объект один раз до начала цикла и затем просто вызываем Показать() внутри итераций, система воспринимает это как команду обновить содержимое уже существующего (или последнего открытого) окна, связанного с этой переменной. Программа добросовестно выполняет весь код в отладчике, но графический интерфейс просто перерисовывает данные в одном и том же контейнере.
Выясним причину глубже: для того чтобы операционная система создала новое независимое окно, ей нужен новый дескриптор. В контексте встроенного языка 1С это означает, что нам необходимо на каждой итерации создавать абсолютно новый экземпляр объекта.
Рассмотрим основной и самый правильный способ решения данной задачи. Чтобы каждое окно открывалось отдельно, мы должны перенести инициализацию переменной Таблица внутрь тела цикла. Таким образом, на каждом шаге будет порождаться новый программный объект, никак не связанный с предыдущим.
Посмотрим на пример реализации:
// В обработке или отчете
Для Ном = 1 По КоличествоИтераций Цикл
// Создаем НОВЫЙ объект на каждой итерации
Таб = СоздатьОбъект("Таблица");
// Выбираем макет (из ресурсов ert-файла)
Таб.ИсходнаяТаблица("ИмяМакета");
// Заполняем секции данными
// Например: Таб.ВывестиСекцию("Шапка");
// Выводим на экран
Таб.Показать("Отчет № " + Ном);
КонецЦикла;
В данном примере крайне важно использовать метод СоздатьОбъект("Таблица") именно внутри конструкции Для ... Цикл. Обратите внимание, что в метод Показать() мы добавили строковый параметр. Это позволяет задать уникальный заголовок окна, что критически важно для удобства пользователя, когда открывается более 3–5 окон одновременно.
Проанализируем ситуацию, когда нам не нужно плодить множество окон, а требуется получить один большой документ, разделенный на листы. Это актуально, если отчет в дальнейшем будет отправлен на печать или сохранен как единый файл. Для этого в платформе предусмотрен метод НоваяСтраница().
Разберем этот подход подробнее:
Таблица один раз до начала цикла.Таб.НоваяСтраница().Таб.Показать().
Таб = СоздатьОбъект("Таблица");
Для Ном = 1 По 10 Цикл
Таб.ВывестиСекцию("Данные");
Если Ном < 10 Тогда
Таб.НоваяСтраница();
КонецЕсли;
КонецЦикла;
Таб.Показать("Общий отчет");
Этот метод позволяет избежать перегрузки оперативной памяти и интерфейса при очень большом количестве итераций (например, более 100), так как отрисовка 100 окон может привести к нестабильной работе системы («Недостаточно ресурсов»).
Часто вывод в таблицу в цикле используется для последующего сохранения данных в формате XLS. Существует известная проблема: при сохранении больших таблиц (более 2500–3000 строк) 1С 7.7 может «зависнуть» на длительное время. Рассмотрим, как это победить.
Основная причина «подвисания» — параметр автовысота строки. По умолчанию 1С пытается рассчитать высоту каждой ячейки для идеального соответствия печатному листу, что крайне ресурсоемко. Чтобы ускорить процесс, выполните следующие действия в макете:
Опции(0,0,0,0), чтобы отключить отрисовку сетки и заголовков, что также немного ускоряет работу.Если же данных действительно много (десятки тысяч строк), рекомендуется рассмотреть возможность прямой записи в файл без использования визуального объекта Таблица. Например, через объект Текст в формате CSV или через использование внешней компоненты Йоксель (Yoksel), которая работает с форматом Excel гораздо быстрее штатных средств.
Если ваша задача — не показать макеты пользователю, а сформировать файлы на диске, то метод Показать() использовать не нужно. Проанализируем схему автоматического сохранения:
ПутьКПапке = "C:\Reports\";
Для Ном = 1 По СписокКонтрагентов.РазмерСписка() Цикл
Контрагент = СписокКонтрагентов.ПолучитьЗначение(Ном);
Таб = СоздатьОбъект("Таблица");
Таб.ИсходнаяТаблица("Макет");
// ... заполнение ...
ИмяФайла = ПутьКПапке + "Отчет_" + Контрагент.Код + ".xls";
Таб.Записать(ИмяФайла, "XLS");
КонецЦикла;
Важный нюанс: при генерации имен файлов в цикле обязательно добавляйте уникальный идентификатор (код, текущее время или номер итерации), иначе каждый последующий файл будет перезаписывать предыдущий.
В случае если пользователю требуется распечатать все эти макеты «пачкой», мы можем использовать метод Напечатать(0). Параметр 0 означает печать без вывода диалога выбора принтера. Это значительно экономит время: система просто отправляет сформированный макет в очередь печати и переходит к следующей итерации цикла.
Подведем итог: для вывода множества окон используем СоздатьОбъект внутри цикла. Для формирования единого документа на разные листы — НоваяСтраница(). А при работе с большими объемами данных для Excel — обязательно отключаем автовысоту строк в макете.