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