В процессе разработки на платформе 1С:Предприятие часто возникает задача по формированию печатных форм, где требуется разместить несколько независимых информационных блоков или "областей" на одном листе. Например, это может быть печать 12 промокодов, ценников или этикеток на стандартном листе формата А4 в альбомной ориентации. В рамках данной темы мы рассмотрим, как эффективно решить эту задачу, используя стандартные механизмы работы с макетами и табличными документами в 1С, а также как избежать распространенных ошибок. В качестве готового альтернативного решения можно использовать программу для печати этикеток и ценников по шаблонам.
Прежде чем мы перейдем к решению задачи по размещению множества областей, важно вспомнить базовые принципы работы с макетами в 1С. Макет в 1С — это по сути шаблон, который содержит оформление (границы, шрифты, цвета) и placeholders для данных, которые будут выведены в будущую печатную форму. Он состоит из ячеек и именованных областей.
Для взаимодействия с макетами и их частями мы используем следующие методы:
ПолучитьМакет(): Этот метод вызываем у объекта конфигурации (например, у документа, отчета, обработки) для получения объекта типа МакетТабличногоДокумента. Этот объект представляет собой загруженный шаблон макета.ПолучитьОбласть(): После того как мы получили объект макета, мы вызываем этот метод у него, чтобы получить конкретную именованную область. Имя области должно точно соответствовать тому, что вы указали в свойствах области в конфигураторе.Рассмотрим базовый пример вывода одной области в табличный документ:
Процедура Печать(ТабДок) Экспорт
// Создаем новый экземпляр табличного документа, в который будем выводить информацию
ТабДок = Новый ТабличныйДокумент;
// Получаем макет по его имени (например, "Основной") у объекта документа "РасходнаяНакладная"
Макет = Документы.РасходнаяНакладная.ПолучитьМакет("Основной");
// Получаем конкретную область из макета по ее имени (например, "Заголовок")
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
// Заполняем параметры области данными. Параметры должны быть определены в макете.
ОбластьЗаголовок.Параметры.НомерДокумента = Номер;
ОбластьЗаголовок.Параметры.От = Дата;
ОбластьЗаголовок.Параметры.Кому = Контрагент;
// Выводим заполненную область "Заголовок" в табличный документ.
// Метод Вывести() по умолчанию размещает область, начиная новую строку.
ТабДок.Вывести(ОбластьЗаголовок);
// Выводим следующую область "Шапка". В данном случае, без предварительного заполнения параметров,
// если таковые не требуются или уже заданы в макете по умолчанию.
ТабДок.Вывести(Макет.ПолучитьОбласть("Шапка"));
// Если у нас есть табличная часть или таблица значений "Состав",
// мы можем итерировать по ней и выводить строки.
ОбластьСтрока = Макет.ПолучитьОбласть("Строка"); // Получаем область строки до цикла
Для Каждого СтрСостава Из Состав Ци // "Состав" - это, например, табличная часть документа
ОбластьСтрока.Параметры.Заполнить(СтрСостава); // Заполняем параметры области из текущей строки
ТабДок.Вывести(ОбластьСтрока); // Выводим заполненную строку
КонецЦикла;
// Выводим "Подвал" отчета, заполняя итоговые параметры
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
ОбластьПодвал.Параметры.ИтогоКоличество = Состав.Итог("Количество");
ОбластьПодвал.Параметры.ИтогоСумма = Состав.Итог("Сумма");
ТабДок.Вывести(ОбластьПодвал);
// Устанавливаем параметры отображения табличного документа для пользователя
ТабДок.ТолькоПросмотр = Истина;
ТабДок.ОтображатьЗаголовки = Истина;
ТабДок.ОтображатьСетку = Ложь;
// Показываем сформированный табличный документ на экране
ТабДок.Показать();
КонецПроцедуры
Этот код демонстрирует последовательный вывод областей друг под другом, что является поведением по умолчанию для метода Вывести(). Однако наша задача — разместить области не только по вертикали, но и по горизонтали.
Вывести и ПрисоединитьДля размещения нескольких областей на одном листе, особенно когда нам нужно организовать их в несколько рядов и колонок (например, 3 ряда по 4 колонки), нам потребуется комбинировать два ключевых метода объекта ТабличныйДокумент:
Вывести(Область): Этот метод, как мы уже знаем, добавляет указанную область в табличный документ, начиная новую строку. Если документ пуст, он добавляет область в самом начале. Если документ уже содержит данные, новая область будет размещена под последней выведенной областью, смещаясь вниз.Присоединить(Область): В отличие от Вывести(), этот метод добавляет указанную область горизонтально. Он располагает новую область справа от последней выведенной или присоединенной области в текущей строке. Ключевое отличие: он не начинает новую строку, а продолжает текущую, что позволяет нам строить ряды из нескольких областей.Рассмотрим подробнее, как мы можем использовать эти методы для размещения, например, 12 областей на листе А4 в альбомной ориентации, организуя их в 3 ряда по 4 колонки.
Для построения сложного макета, где элементы располагаются как по горизонтали, так и по вертикали, нам необходимо грамотно задавать имена областей. Если у нас есть шаблон одной ячейки или блока, который нужно многократно повторять и располагать как угодно, мы можем назвать его, например, Строка|Столбец. Такое именование (с использованием разделителя |) часто используется для обозначения пересекающихся областей или логических блоков, которые могут быть выведены как часть строки и как часть столбца. В нашем случае, это будет единый блок, который мы будем выводить последовательно.
Мы будем использовать циклы для итерации по количеству необходимых элементов. Внутри цикла нам потребуется логика для отслеживания текущего положения — является ли текущий элемент первым в новом ряду или он должен быть присоединен к текущему ряду. Если элемент первый в новом ряду, используем Вывести(). В противном случае, используем Присоединить().
Посмотрим на пример кода, который демонстрирует этот подход для печати промокодов:
Функция СформироватьОтчетСПромокодами(НачНомер, КонНомер, Префикс) Экспорт
// Получаем текущий объект отчета или обработки, из которого вызывается функция.
// РеквизитФормыВЗначение используется в управляемых формах для доступа к данным формы.
ОтчетОбъект = РеквизитФормыВЗначение("Объект");
// Получаем макет, который мы подготовили в конфигураторе.
// Предполагается, что макет называется "Промокод".
Макет = ОтчетОбъект.ПолучитьМакет("Промокод");
// Создаем новый табличный документ, который будет нашей печатной формой.
ТабличныйДокумент = Новый ТабличныйДокумент;
// Получаем область из макета, которую мы будем многократно выводить/присоединять.
// Предполагается, что в макете есть область с именем "Строка|Столбец".
ОбластьДляВывода = Макет.ПолучитьОбласть("Строка|Столбец");
// Инициализируем счетчик столбцов. Он будет отслеживать, сколько элементов
// уже выведено в текущем ряду по горизонтали.
Столбик = 0;
// Определяем, сколько областей должно быть в одном ряду по горизонтали.
// В нашем случае, для 12 областей и 3 рядов, это 4 колонки.
КолвоПоГоризонтали = 4;
// Константа для пересчета размеров из пикселей в миллиметры и обратно.
// Это может быть полезно для точной настройки размеров рисунков.
КоличествоМиллиметровВПикселе = 0.264583; // Примерное значение для 96 DPI
// Итерируем по диапазону номеров, например, для генерации промокодов.
Для Сч = НачНомер по КонНомер Цикл
// Формируем номер промокода, добавляя префикс и дополняя нулями до 6 символов.
Номер = Префикс + Прав("000000" + Формат(Сч,"ЧГ="), 6);
// Устанавливаем параметр "Номер" в текущей области.
// В макете должна быть ячейка с параметром "Номер".
ОбластьДляВывода.Параметры.Номер = Номер;
// Проверяем, есть ли в области рисунок с именем "Штрихкод".
Если ОбластьДляВывода.Рисунки.Найти("Штрихкод") Тогда
Рисунок = ОбластьДляВывода.Рисунки.Штрихкод; // Получаем объект рисунка
// Подготавливаем параметры для генерации картинки штрихкода.
ПараметрыШтрихкода = Новый Структура;
// Корректируем ширину и высоту рисунка, если это необходимо,
// с учетом пересчета из пикселей в миллиметры и небольшого запаса.
ПараметрыШтрихкода.Вставить("Ширина", Окр(Рисунок.Ширина / КоличествоМиллиметровВПикселе * 1.1));
ПараметрыШтрихкода.Вставить("Высота", Окр(Рисунок.Высота / КоличествоМиллиметровВПикселе * 1.1));
ПараметрыШтрихкода.Вставить("Штрихкод", СокрЛП(Номер)); // Сам текст штрихкода
ПараметрыШтрихкода.Вставить("ТипКода", 2); // Тип штрихкода (например, EAN13)
ПараметрыШтрихкода.Вставить("ОтображатьТекст", Ложь); // Не показывать текст под штрихкодом
// Получаем сгенерированную картинку штрихкода и присваиваем ее рисунку в области.
Рисунок.Картинка = МенеджерОборудованияВызовСервера.ПолучитьКартинкуШтрихкода(ПараметрыШтрихкода);
КонецЕсли;
// Обновляем счетчик столбцов. Если Столбик достиг КолвоПоГоризонтали,
// это означает, что текущий элемент должен быть первым в новом ряду (счетчик = 1).
// Иначе, просто увеличиваем счетчик для текущего ряда.
Столбик = ?(Столбик >= КолвоПоГоризонтали, 1, Столбик + 1);
Если Столбик = 1 Тогда // Если это первый элемент в новом ряду
ТабличныйДокумент.Вывести(ОбластьДляВывода); // Начинаем новый ряд, выводя область
Иначе // Если это не первый элемент в текущем ряду
ТабличныйДокумент.Присоединить(ОбластьДляВывода); // Присоединяем область по горизонтали к текущему ряду
КонецЕсли;
КонецЦикла;
// В данном примере функция возвращает сформированный табличный документ.
// Если требуется сразу показать его, можно добавить ТабличныйДокумент.Показать();
Возврат ТабличныйДокумент;
КонецФункции
В этом примере мы видим, как переменная Столбик используется для отслеживания текущей позиции в ряду. Когда Столбик становится 1 (то есть мы начинаем новый ряд или это первый элемент вообще), вызывается метод Вывести(). Для всех последующих областей в том же ряду используется метод Присоединить(). Этот механизм позволяет нам равномерно распределить, например, 12 областей (4 колонки * 3 ряда) на одном листе. Для практического примера реализации такого алгоритма подойдёт обработка для печати ценников и этикеток в несколько колонок.
Обратите внимание на использование РеквизитФормыВЗначение("Объект"), что характерно для управляемых форм и позволяет получить текущий объект формы (например, отчет, из которого вызывается печать) для дальнейшей работы с его макетами.
Переменная Состав, которая может встречаться в других примерах кода, обычно представляет собой табличную часть документа или просто таблицу значений, которая содержит набор данных для заполнения однотипных областей (например, строки товаров в накладной). В нашем примере с промокодами мы итерируем по диапазону номеров, но принцип заполнения области параметрами остается тем же.
Чтобы гарантировать, что все 12 областей корректно уместятся на листе А4, особенно в альбомном формате, нам необходимо правильно настроить параметры страницы табличного документа. Эти настройки можно выполнить программно:
// Устанавливаем альбомную ориентацию страницы для табличного документа
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
// Включаем автоматическое масштабирование. Это очень полезно,
// так как позволяет содержимому табличного документа автоматически подстраиваться
// под ширину страницы, предотвращая обрезку.
ТабДок.АвтоМасштаб = Истина;
// Или, если требуется более точный контроль, можно установить конкретный масштаб в процентах.
// Например, если АвтоМасштаб не дает желаемого результата.
// ТабДок.Масштаб = 75; // Устанавливаем масштаб 75%
Помимо программной настройки, пользователи также имеют возможность самостоятельно настроить эти параметры (ориентацию, масштаб, поля страницы) через меню "Параметры страницы" в режиме предварительного просмотра печатной формы. Это дает дополнительную гибкость, но программные настройки являются основой для получения стабильного результата.
В процессе разработки и отладки могут возникнуть различные сложности. Рассмотрим наиболее частые проблемы и способы их решения при работе с макетами.
Эта ошибка является одной из самых распространенных и указывает на то, что объект, у которого вы пытаетесь вызвать метод ПолучитьОбласть(), не является объектом типа МакетТабличногоДокумента, или же сам метод ПолучитьОбласть написан с ошибкой (опечаткой в имени).
Возможные причины и способы исправления:
ПолучитьОбласть. Затем убедитесь, что имя области, которую вы пытаетесь получить (например, "Заголовок", "Строка|Столбец"), точно соответствует имени, заданному в конфигураторе в свойствах этой области макета. Имена областей чувствительны к регистру, поэтому "Заголовок" и "заголовок" — это разные имена.ПолучитьОбласть(), действительно содержит объект, полученный методом ПолучитьМакет(). Например:
// Правильно:
Макет = ОтчетОбъект.ПолучитьМакет("ИмяВашегоМакета"); // Макет - это объект типа МакетТабличногоДокумента
Область = Макет.ПолучитьОбласть("ИмяОбласти"); // У Макет есть метод ПолучитьОбласть()
// Неправильно (если ОтчетОбъект - это, например, ссылка на документ, а не объект-макет):
// Область = ОтчетОбъект.ПолучитьОбласть("ИмяОбласти"); // У ссылки на документ нет такого метода
Метод ПолучитьМакет() всегда вызывается у объектов конфигурации (например, Документы.РасходнаяНакладная.ПолучитьМакет("Основной")), у экземпляров отчетов или обработок. Результатом вызова ПолучитьМакет() будет объект МакетТабличногоДокумента, и уже у этого объекта можно вызывать ПолучитьОбласть().
Экспорт, если вызываются извне текущего модуля.Иногда разработчики сталкиваются с проблемой, когда изменения, внесенные в макет (например, размеры ячеек, границы, расположение областей), не сохраняются после закрытия конфигуратора, либо после сохранения и печати макет выглядит искаженно.
Возможные причины и способы исправления:
F7 или через меню "Конфигурация" -> "Обновить конфигурацию базы данных". Если этого не сделать, изменения останутся только в конфигурации, открытой в конфигураторе, но не будут применены к рабочей базе.Решение: Старайтесь унифицировать структуру макетов, если они используются совместно. Или, если это невозможно, тщательно контролируйте размеры выводимых областей. Вы можете использовать свойства ТабличныйДокумент, такие как ШиринаКолонок, чтобы программно выравнивать колонки, но это сложнее, чем создание единообразной структуры в макете.
ТабличныйДокумент.Масштаб, ТабличныйДокумент.Поля), так и в пользовательских настройках печати.В заключение, работа с макетами в 1С:Предприятие предоставляет мощные и гибкие инструменты для создания разнообразных печатных форм. Понимание принципов работы методов Вывести() и Присоединить(), а также внимательное отношение к именованию областей, настройкам печати и обработке возможных ошибок, позволит вам эффективно решать даже самые сложные задачи по формированию отчетности и печатных документов в вашей системе.