Механизм многоколоночной печати (1Cv8)

Материал из КинтВики
Перейти к: навигация, поиск


Задача

Иногда возникает задача печати "в несколько колонок", то есть подобно тому как верстаются газеты/журналы.

При этом на одной странице может быть 2-3-.. колонок данных, причем группировки/детальные данные сначала идут сверху вниз по первой колонке, потом продолжаются на второй колонке и так далее.

Вроде бы простая с точки зрения клиента вещь, но встроенными средствами 1С это сделать нельзя. СКД тоже не умеет так делать. Клиенту это нужно для экономии бумаги и создания очень "плотных" документов типа графиков, прайсов и так далее.

Такую печать можно сделать "руками", но код получается очень запутанный и каждый раз новый.

См. также

Механизм

Все кардинально упрощается, если разделить задачу на две части - группировку данных и собственно печать.

Функция группировки получает на вход таблицу данных и создает таблицу значений, подготовленную для печати - для каждой строки уже задан номер колонки, номер страницы, имя группировки.

Процедура печати просто читает построчно подготовленную таблицу и формирует колонки. При смене страницы выводятся все сформированные колонки.

Механизм универсальный, работает с любыми группировками данных и любым количеством колонок.

Код механизма:

<source lang=1C> // Функция выполняет группировку таблицы данных для многоколоночной печати // // Параметры // тзДанные - // тзГруппировки - // СтрокНаСтранице - // КолонокНаСтранице - // // Возвращаемое значение: // - сгруппированная таблица данных // Функция МногоколоночнаяГруппировкаТаблиц(тзДанные, тзГруппировки, СтрокНаСтранице, КолонокНаСтранице) Экспорт тзРезультат = тзДанные.СкопироватьКолонки(); тзРезультат.Колонки.Добавить("НомерСтраницы"); тзРезультат.Колонки.Добавить("НомерКолонки"); тзРезультат.Колонки.Добавить("НомерСтроки"); тзРезультат.Колонки.Добавить("НомерСтрокиВКолонке"); тзРезультат.Колонки.Добавить("ИмяГруппировки");

стПараметры = Новый Структура("СтрокНаСтранице,КолонокНаСтранице,НомерСтроки,НомерКолонки,НомерСтраницы,НомерСтрокиВКолонке", СтрокНаСтранице, КолонокНаСтранице, 0, 0, 0, 0);

ВывестиГруппировку(тзГруппировки, 0, тзДанные, тзРезультат, стПараметры);

Возврат тзРезультат; КонецФункции

Процедура ВывестиГруппировку(тзГруппировки, УровеньГруппировки, тзДанные, тзРезультат, стПараметры) Если УровеньГруппировки >= тзГруппировки.Количество() Тогда Возврат; КонецЕсли; ИмяГруппировки = тзГруппировки[УровеньГруппировки].ИмяГруппировки;

Если ИмяГруппировки = "Заголовок" Тогда ВывестиСтрокуГруппировки(тзГруппировки, УровеньГруппировки, Новый Структура, тзРезультат, стПараметры); ВывестиГруппировку(тзГруппировки, УровеньГруппировки + 1, тзДанные, тзРезультат, стПараметры); Возврат; КонецЕсли;

тзЗначенияГруппировки = тзДанные.Скопировать(); Если УровеньГруппировки < тзГруппировки.Количество() - 1 Тогда тзЗначенияГруппировки.Свернуть(ИмяГруппировки); Иначе тзЗначенияГруппировки.Сортировать(ИмяГруппировки); КонецЕсли;

Для каждого строкаГруппировка из тзЗначенияГруппировки Цикл тзСтроки = тзДанные.СкопироватьКолонки(); мзСтроки = тзДанные.НайтиСтроки(Новый Структура(ИмяГруппировки, строкаГруппировка[ИмяГруппировки])); Для каждого строка из мзСтроки Цикл новаяСтрока = тзСтроки.Добавить(); ЗаполнитьЗначенияСвойств(новаяСтрока, строка); КонецЦикла; ВывестиСтрокуГруппировки(тзГруппировки, УровеньГруппировки, строкаГруппировка, тзРезультат, стПараметры); ВывестиГруппировку(тзГруппировки, УровеньГруппировки + 1, тзСтроки, тзРезультат, стПараметры); КонецЦикла;

КонецПроцедуры

Процедура ВывестиСтрокуГруппировки(тзГруппировки, УровеньГруппировки, строкаГруппировка, тзРезультат, стПараметры) новаяСтрока = тзРезультат.Добавить(); ЗаполнитьЗначенияСвойств(новаяСтрока, строкаГруппировка); строкВМакетеГруппировки = тзГруппировки[УровеньГруппировки].КоличествоСтрок;

Если стПараметры.НомерСтрокиВКолонке + строкВМакетеГруппировки > стПараметры.СтрокНаСтранице Тогда стПараметры.НомерСтрокиВКолонке = 0; стПараметры.НомерКолонки = стПараметры.НомерКолонки + 1; Если стПараметры.НомерКолонки = стПараметры.КолонокНаСтранице Тогда стПараметры.НомерКолонки = 0; стПараметры.НомерСтраницы = стПараметры.НомерСтраницы + 1; КонецЕсли; КонецЕсли;

новаяСтрока.ИмяГруппировки = тзГруппировки[УровеньГруппировки].ИмяГруппировки; новаяСтрока.НомерСтраницы = стПараметры.НомерСтраницы; новаяСтрока.НомерКолонки = стПараметры.НомерКолонки; новаяСтрока.НомерСтрокиВКолонке = стПараметры.НомерСтрокиВКолонке; новаяСтрока.НомерСтроки = стПараметры.НомерСтроки;

стПараметры.НомерСтроки = стПараметры.НомерСтроки + 1; стПараметры.НомерСтрокиВКолонке = стПараметры.НомерСтрокиВКолонке + строкВМакетеГруппировки; КонецПроцедуры

// Процедура многоколоночной печати // // Параметры // табДок - // тзГруппировки - // тзДанные - // Макет - // СтрокНаСтранице - // КолонокНаСтранице - // стЗаголовок - // Процедура МногоколоночнаяПечать(табДок, тзГруппировки, тзДанные, Макет, СтрокНаСтранице, КолонокНаСтранице, стЗаголовок) Экспорт тзМногоколоночная = МедСервис.МногоколоночнаяГруппировкаТаблиц(тзДанные, тзГруппировки, СтрокНаСтранице, КолонокНаСтранице); строкаБарьер = тзМногоколоночная.Добавить(); строкаБарьер.НомерСтраницы = -1;

стОбласти = Новый Структура; Для каждого строка из тзГруппировки Цикл стОбласти.Вставить(строка.ИмяГруппировки, Макет.ПолучитьОбласть(строка.ИмяГруппировки)); КонецЦикла;

ОбластьОтступ = Макет.ПолучитьОбласть("Отступ"); ОбластьШапка = Макет.ПолучитьОбласть("Шапка");

мзТабКолонки = Новый Массив(КолонокНаСтранице);

Для номер = 0 По КолонокНаСтранице - 1 Цикл табКолонка = Новый ТабличныйДокумент; мзТабКолонки[номер] = табКолонка; Если номер = 0 И тзГруппировки.Найти("Заголовок", "ИмяГруппировки") <> Неопределено Тогда Продолжить; КонецЕсли; табКолонка.Вывести(ОбластьШапка); КонецЦикла;

табДок.Вывести(ОбластьОтступ); НомерСтраницы = 0;

Для каждого строкаДанные из тзМногоколоночная Цикл

Если строкаДанные.НомерСтраницы <> НомерСтраницы Тогда Для каждого табКолонка из мзТабКолонки Цикл табДок.Присоединить(табКолонка); КонецЦикла;

НомерСтраницы = строкаДанные.НомерСтраницы; Если НомерСтраницы = -1 Тогда Прервать; КонецЕсли;

табДок.ВывестиГоризонтальныйРазделительСтраниц(); табДок.Вывести(ОбластьОтступ);

Для номер = 0 По КолонокНаСтранице - 1 Цикл табКолонка = Новый ТабличныйДокумент; табКолонка.Вывести(ОбластьШапка); мзТабКолонки[номер] = табКолонка; КонецЦикла;

КонецЕсли;

ИмяГруппировки = строкаДанные.ИмяГруппировки; область = стОбласти[ИмяГруппировки];

Если ИмяГруппировки = "Заголовок" Тогда Для каждого элемент из стЗаголовок Цикл область.Параметры[элемент.Ключ] = элемент.Значение; КонецЦикла; Иначе ЗаполнитьЗначенияСвойств(область.Параметры, строкаДанные); КонецЕсли;

табКолонка = мзТабКолонки[строкаДанные.НомерКолонки]; табКолонка.Вывести(область);

Если ИмяГруппировки = "Заголовок" И строкаДанные.НомерКолонки = 0 Тогда табКолонка.Вывести(ОбластьШапка); КонецЕсли;

КонецЦикла;

КонецПроцедуры


</source>

Тесты механизма:

Макет, используемый для печати:

Файл:Макет многоколоночной печати 1.png

<source lang=1C> Процедура Тест_МногоколоночнаяПечать() Экспорт тзДанные = Новый ТаблицаЗначений; тзДанные.Колонки.Добавить("Дата"); тзДанные.Колонки.Добавить("Кабинет"); тзДанные.Колонки.Добавить("ЛечебноеМесто"); тзДанные.Колонки.Добавить("Сеанс"); тзДанные.Колонки.Добавить("Пациент");

ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 1"); ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 2");

тзГруппировки = СоздатьТЗГруппировки(); СтрокНаСтранице = 10; КолонокНаСтранице = 3;

макет = ПолучитьМакет("ГрафикСеансов");

стЗаголовок = Новый Структура("ГруппаЛечебныхМест,ДатаС,ДатаПо", ссЛечебноеОтделение, Формат('20100101', "ДФ='dd.MM.yy'") , Формат('20100131', "ДФ='dd.MM.yy'")); табДок = Новый ТабличныйДокумент; МедСервис.МногоколоночнаяПечать(табДок, тзГруппировки, тзДанные, макет, СтрокНаСтранице, КолонокНаСтранице, стЗаголовок);

Если Интерактивно Тогда табДок.Показать(); КонецЕсли;

КонецПроцедуры


Процедура Тест_МногоколоночнаяГруппировкаТаблиц() Экспорт тзДанные = Новый ТаблицаЗначений; тзДанные.Колонки.Добавить("Дата"); тзДанные.Колонки.Добавить("Кабинет"); тзДанные.Колонки.Добавить("ЛечебноеМесто"); тзДанные.Колонки.Добавить("Сеанс"); тзДанные.Колонки.Добавить("Пациент");

ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 1"); ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 2");

тзГруппировки = СоздатьТЗГруппировки(); СтрокЗаголовок = 3; СтрокНаСтранице = 10; КолонокНаСтранице = 2;

тзМногоколоночная = МедСервис.МногоколоночнаяГруппировкаТаблиц(тзДанные, тзГруппировки, СтрокНаСтранице, КолонокНаСтранице);

ПроверитьСтроку(тзМногоколоночная, 0, 0, 0, 0, "Заголовок"); ПроверитьСтроку(тзМногоколоночная, 1, 0, 0, 3, "Дата", '2010.02.10'); ПроверитьСтроку(тзМногоколоночная, 2, 0, 0, 6, "Кабинет", "Грязевые ванны"); ПроверитьСтроку(тзМногоколоночная, 3, 0, 0, 7, "ЛечебноеМесто", "Ванна 1"); ПроверитьСтроку(тзМногоколоночная, 4, 0, 0, 8, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 5, 0, 0, 9, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 6, 0, 1, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 15, 0, 1, 9, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 16, 1, 0, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 23, 1, 0, 7, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 24, 1, 0, 8, "ЛечебноеМесто", "Ванна 2"); ПроверитьСтроку(тзМногоколоночная, 25, 1, 0, 9, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 26, 1, 1, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 35, 1, 1, 9, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 36, 2, 0, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 44, 2, 0, 8, "Сеанс");

КонецПроцедуры

Процедура Тест_МногоколоночнаяГруппировкаТаблиц2() Экспорт тзДанные = Новый ТаблицаЗначений; тзДанные.Колонки.Добавить("Дата"); тзДанные.Колонки.Добавить("Кабинет"); тзДанные.Колонки.Добавить("ЛечебноеМесто"); тзДанные.Колонки.Добавить("Сеанс"); тзДанные.Колонки.Добавить("Пациент");

ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 1"); ДобавитьСеансы(тзДанные, '2010.02.10', "Грязевые ванны", "Ванна 2");

ДобавитьСеансы(тзДанные, '2010.02.11', "Грязевые ванны", "Ванна 1"); ДобавитьСеансы(тзДанные, '2010.02.11', "Грязевые ванны", "Ванна 2");

тзГруппировки = СоздатьТЗГруппировки();

СтрокНаСтранице = 15; КолонокНаСтранице = 2;

тзМногоколоночная = МедСервис.МногоколоночнаяГруппировкаТаблиц(тзДанные, тзГруппировки, СтрокНаСтранице, КолонокНаСтранице);

ПроверитьСтроку(тзМногоколоночная, 0, 0, 0, 0, "Заголовок"); ПроверитьСтроку(тзМногоколоночная, 1, 0, 0, 3, "Дата", '2010.02.10'); ПроверитьСтроку(тзМногоколоночная, 2, 0, 0, 6, "Кабинет", "Грязевые ванны"); ПроверитьСтроку(тзМногоколоночная, 3, 0, 0, 7, "ЛечебноеМесто", "Ванна 1"); ПроверитьСтроку(тзМногоколоночная, 4, 0, 0, 8, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 10, 0, 0, 14, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 11, 0, 1, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 23, 0, 1, 12, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 24, 0, 1, 13, "ЛечебноеМесто", "Ванна 2"); ПроверитьСтроку(тзМногоколоночная, 25, 0, 1, 14, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 26, 1, 0, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 40, 1, 0, 14, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 41, 1, 1, 0, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 44, 1, 1, 3, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 45, 1, 1, 4, "Дата", '2010.02.11'); ПроверитьСтроку(тзМногоколоночная, 46, 1, 1, 7, "Кабинет", "Грязевые ванны"); ПроверитьСтроку(тзМногоколоночная, 47, 1, 1, 8, "ЛечебноеМесто", "Ванна 1"); ПроверитьСтроку(тзМногоколоночная, 48, 1, 1, 9, "Сеанс"); ПроверитьСтроку(тзМногоколоночная, 53, 1, 1, 14, "Сеанс");

ПроверитьСтроку(тзМногоколоночная, 54, 2, 0, 0, "Сеанс");

КонецПроцедуры


Функция СоздатьТЗГруппировки() тзГруппировки = Новый ТаблицаЗначений; тзГруппировки.Колонки.Добавить("ИмяГруппировки"); тзГруппировки.Колонки.Добавить("КоличествоСтрок");

строка = тзГруппировки.Добавить(); строка.ИмяГруппировки = "Заголовок"; строка.КоличествоСтрок = 3;

строка = тзГруппировки.Добавить(); строка.ИмяГруппировки = "Дата"; строка.КоличествоСтрок = 3;

строка = тзГруппировки.Добавить(); строка.ИмяГруппировки = "Кабинет"; строка.КоличествоСтрок = 1;

строка = тзГруппировки.Добавить(); строка.ИмяГруппировки = "ЛечебноеМесто"; строка.КоличествоСтрок = 1;

строка = тзГруппировки.Добавить(); строка.ИмяГруппировки = "Сеанс"; строка.КоличествоСтрок = 1;

Возврат тзГруппировки; КонецФункции

Процедура ПроверитьСтроку(тзМногоколоночная, НомерСтроки, НомерСтраницы, НомерКолонки, НомерСтрокиВКолонке, ИмяГруппировки, ЗначениеГруппировки = Неопределено) строка = тзМногоколоночная[НомерСтроки]; Тестирование.ПроверитьРавенство(НомерСтраницы, строка.НомерСтраницы); Тестирование.ПроверитьРавенство(НомерКолонки, строка.НомерКолонки); Тестирование.ПроверитьРавенство(НомерСтрокиВКолонке, строка.НомерСтрокиВКолонке); Тестирование.ПроверитьРавенство(ИмяГруппировки, строка.ИмяГруппировки); Если ЗначениеГруппировки <> Неопределено Тогда Тестирование.ПроверитьРавенство(ЗначениеГруппировки, строка[ИмяГруппировки]); КонецЕсли; КонецПроцедуры


Процедура ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, Сеанс, Пациент = Неопределено) строка = тзДанные.Добавить(); строка.Дата = Дата; строка.Кабинет = Кабинет; строка.ЛечебноеМесто = ЛечебноеМесто; строка.Сеанс = Сеанс; Если Пациент <> Неопределено Тогда строка.Пациент = Пациент; КонецЕсли; КонецПроцедуры

Процедура ДобавитьСеансы(тзДанные, Дата, Кабинет, ЛечебноеМесто) ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "09:00 - 09-30", ссИванов); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "09:30 - 10-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "10:00 - 10-30", ссПетров); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "10:30 - 11-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "11:00 - 11-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "11:30 - 12-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "12:00 - 12-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "12:30 - 13-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "13:00 - 13-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "13:30 - 14-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "14:00 - 14-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "14:30 - 15-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "15:00 - 15-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "15:30 - 16-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "16:00 - 16-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "16:30 - 17-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "17:00 - 17-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "17:30 - 18-00"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "18:00 - 18-30"); ДобавитьСтроку(тзДанные, Дата, Кабинет, ЛечебноеМесто, "18:30 - 19-00"); КонецПроцедуры

</source>

Развитие

  • Сейчас момент переноса на следующую колонку/страницу произвольный. Может быть, для улучшения внешнего вида новые колонки должны по возможности начинаться с вывода группировки.