При разработке печатных форм в 1С часто возникает задача визуального объединения данных. Типичный пример: одно изделие может иметь несколько упаковок, и в печатной таблице название изделия должно занимать одну большую объединенную ячейку слева, а список упаковок — располагаться в строках справа. В этой статье мы подробно разберем, как реализовать такой механизм программно, используя возможности встроенного языка 1С.
Рассмотрим ситуацию: у нас есть запрос, который возвращает список изделий и связанных с ними упаковок. Если мы будем выводить их простым циклом, название изделия будет дублироваться в каждой строке или выводиться только один раз в верхней строке, оставляя под собой пустые ячейки. Наша цель — получить эстетичную форму, где ячейки с названием изделия и его статусом будут объединены вертикально на всю высоту строк, занимаемых его упаковками.
Для решения нам потребуется выполнить три основных условия:
ИТОГИ).Объединить().Чтобы платформа сама сгруппировала данные по изделиям, в тексте запроса необходимо использовать конструкцию ИТОГИ ... ПО (проверить корректность написания поможет консоль запросов). Это позволит нам обходить результат не просто линейно, а по уровням. Проанализируем пример кода запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВременныйИтог.Изделие КАК Изделие,
| ВременныйИтог.СтатусИзделия КАК СтатусИзделия,
| ВременныйИтог.Упаковка КАК Упаковка,
| ВременныйИтог.КоличествоТО КАК КоличествоТО
|ИЗ
| ВременныйИтог КАК ВременныйИтог
|ИТОГИ
| МАКСИМУМ(СтатусИзделия)
|ПО
| Изделие";
Здесь важно, что итоговое поле Изделие станет верхним уровнем выборки, а остальные поля (упаковка, количество) будут доступны на уровне детальных записей (подробнее см. в шпаргалке по языку запросов).
Теперь рассмотрим алгоритм вывода. Основная хитрость заключается в том, чтобы запомнить высоту таблицы до начала вывода строк группы и после. Разница между этими значениями даст нам диапазон строк для объединения.
Разберем программный код реализации:
// Выполняем запрос и получаем выборку по группировкам
Результат = Запрос.Выполнить();
ВыборкаИзделие = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаИзделие.Следующий() Цикл
// 1. Запоминаем номер строки, с которой начинается группа изделия
НачалоГруппы = ТаблицаДокумента.ВысотаТаблицы + 1;
// Выбираем детальные записи (упаковки) для текущего изделия
ВыборкаДетали = ВыборкаИзделие.Выбрать();
ПерваяСтрока = Истина;
Пока ВыборкаДетали.Следующий() Цикл
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
// Заполняем данные упаковки (выводятся всегда)
ОбластьСтрока.Параметры.Упаковка = ВыборкаДетали.Упаковка;
ОбластьСтрока.Параметры.Количество = ВыборкаДетали.КоличествоТО;
// Данные изделия выводим только в первую строку группы (необязательно, но полезно для чистоты)
Если ПерваяСтрока Тогда
ОбластьСтрока.Параметры.Номенклатура = ВыборкаИзделие.Изделие;
ОбластьСтрока.Параметры.Статус = ВыборкаИзделие.СтатусИзделия;
ПерваяСтрока = Ложь;
КонецЕсли;
ТаблицаДокумента.Вывести(ОбластьСтрока);
КонецЦикла;
// 2. Запоминаем номер последней выведенной строки
КонецГруппы = ТаблицаДокумента.ВысотаТаблицы;
// 3. Выполняем объединение ячеек, если в группе больше одной строки
Если КонецГруппы > НачалоГруппы Тогда
// Допустим, Номенклатура в колонке 1, а Статус в колонке 2
Для НомерКолонки = 1 По 2 Цикл
ОбластьДляОбъединения = ТаблицаДокумента.Область(НачалоГруппы, НомерКолонки, КонецГруппы, НомерКолонки);
ОбластьДляОбъединения.Объединить();
// Установим красивое выравнивание по центру
ОбластьДляОбъединения.ВертикальноеПоложение = ВертикальноеПоложение.Центр;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Проанализируем дополнительные аспекты, которые сделают вашу печатную форму профессиональной:
1. Расчет координат через ВысотаТаблицы. Это самый надежный метод. Свойство ВысотаТаблицы объекта ТабличныйДокумент всегда возвращает текущее количество строк. Используя формулу ВысотаТаблицы + 1 перед выводом, мы точно фиксируем начало блока.
2. Вертикальное выравнивание. После вызова метода Объединить() текст по умолчанию может "прилипнуть" к верхнему краю. Чтобы название изделия было посередине огромной ячейки, обязательно устанавливайте свойство ВертикальноеПоложение.Центр для полученной области.
3. Оформление границ. При динамическом объединении ячеек иногда могут "пропадать" линии сетки. Если это произошло, можно принудительно установить границы для объединенной области:
ОбластьДляОбъединения.ГраницаСверху = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
ОбластьДляОбъединения.ГраницаСнизу = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
ОбластьДляОбъединения.ГраницаСлева = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
ОбластьДляОбъединения.ГраницаСправа = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
4. Контроль разрыва страниц. Если одно изделие имеет сотни упаковок, объединенная ячейка может не поместиться на один лист. В этом случае 1С попытается перенести весь блок на следующую страницу. Выясним причину возможного "пустого места": это происходит, если вы не используете метод ПроверитьВывод(). Рекомендуется перед выводом всей группы проверять, поместится ли она, и если нет — выводить ВывестиГоризонтальныйРазделительСтраниц().
Если по каким-то причинам вы не можете изменить запрос, можно использовать линейный обход с контролем смены значения (переменная ТекущееИзделие). Однако этот путь сложнее, так как вам придется сначала выводить все строки, запоминать их номера в массив, и только потом, когда цикл встретит новое изделие, возвращаться к предыдущему диапазону строк для объединения. Использование ИТОГИ и вложенного цикла — гораздо более чистый и надежный способ разработки в среде 1С.
Таким образом, мы рассмотрели основной механизм создания сложных печатных форм. Использование свойств ВысотаТаблицы и метода Объединить() позволяет гибко управлять внешним видом документов, делая их удобными для восприятия пользователем.