Многоколоночные отчеты.
Теги отчеты, программирование
Предисловие.
Чуть больше года назад написал простенький сабж движок. Признаться, сделано это было с одной стороны ради фана, а с другой стороны на случай если когда либо придется еще раз решать подобную задачу, то воспользоваться им, как отправной точкой. В этом уютном, новом бложике попробую презентовать его менее сумбурно, чем это было сделано тогда.
Для начала, нам нужно будет скачать приатаченный к посту файл. Писался он для чистой DAX 3 SP3, впрочем он не затрагивает никаких существующих объектов, так что можно смело грузить его как на трешку, так и на четверку. В последней вроде тоже проверял и даже, кажется, работало
Если у вас все импортировалось нормально, то можно продолжать.
Немного о структуре.
Не вдаваясь в подробности как оно все устроено изнутри, т.к. мне самому страшно влезать туда, спустя более года
, расскажу о базовых моментах, которых достаточно что бы начать использовать проект. Для создания нового отчета нам нужно будет наследоваться от класса SimpleSheetEngineData. В этом классе объявлены всего пять полей. Основными полями являются: reportDataMap, keyHeader, valueHeader. Первое поле представляет собой коллекцию(map) самих данных отчета, и ключ, и значение данной карты должны быть типа контейнер. Оставшиеся два поля, так же являются контейнерами и содержат информацию о заголовках полей ключа и значения, соответственно.
Создим простой пример.
Перекроем у данного класса метод fillReportDataMap следующим образом:
Создадим метод main для запуска нашего отчета:
Запустим наш отчет и получим форму предварительного просмотра данных.
![](http://img-fotki.yandex.ru/get/3905/kir-ozer.11/0_33630_ead06454_XL.jpg)
Нажмем Функции/Печать и увидим сам отчет.
![](http://img-fotki.yandex.ru/get/4104/kir-ozer.11/0_33631_b6fade07_XL.jpg)
Обратите внимание, что я изменил ширину колонок в форме просмотра и ширина колонок в отчете изменилась соответственно (по аналогии с великими и ужасными отчетами ГК).
Реальное предназначение.
Приведенный выше пример иллюстрирует общий принцип работы данного движка, но создавался он все таки для многоколоночных отчетов "растущих в ширину", что и предлагаю реализовать, воспользовавшись примером ниже.
Оставим наших CEO и попробуем вывести в отчет поля и записи таблицы "План счетов". Новая реализация метода fillReportDataMap выглядит следующим образом:
Запустим наш отчет и получим примерно следующую картину.
![](http://img-fotki.yandex.ru/get/3901/kir-ozer.11/0_33632_28cbb384_XL.jpg)
Цветами отмечена группа переключателей, которая отвечает за режим вывода.Увы, в процессе написания текста, обнаружился баг для режима (вроде пофиксил)."Автомасштабирование" - не самый интересный режим, так как он предполагает вывод всех колонок на один лист и их дальнейший просмотр, вероятно, через увеличительное стекло
Более интересным является "Многостраничный вывод". Он последовательно отобразит колонки, расположив не поместившиеся из них, на следующих страницах - "в право". На скриншоте ниже я скрыл некоторые нулевые и пустые столбцы, и можно видеть, что оставшиеся поместились на два альбомных листа.
![](http://img-fotki.yandex.ru/get/4001/kir-ozer.11/0_33633_3df65901_XL.jpg)
Режим "С повтором ключей" работает аналогично предыдущему, но так же отображает на дополнительных страницах значения ключевых полей, что можно попытаться разглядеть на завершающем скриншоте.
![](http://img-fotki.yandex.ru/get/4106/kir-ozer.11/0_33634_fbbdaae0_XL.jpg)
Заключение.
Данный проект ни в коем случае не претендует на законченное решение. Во первых, все это было написано за "один заход", то есть никакого рефакторинга и прочей "доводки до ума" не проводилось. Во вторых, в процессе написания поста нашелся баг, описанный выше. Так же, я совершенно не учитывал работу в 3-х звенной архитектуре, да и печатная форма, на данный момент, не имеет никаких заголовков, итогов и других атрибутов типичного документа. Так уж вышло, что в свое время, мне довелось создать не мало подобных отчетов, причем делалось это, как правило, в дедлайн и в разные промежутки времени. Каждый раз сталкиваясь с таким отчетом, хотелось иметь в запасе отправную точку, от которой можно было бы реализовывать конкретную задачу. Собственно так и появился сей скромный проектик.
p.s. Спасибо всем тем, кто дочитал до этого предложения![Smile](/forums/images/smilies/smile.gif)
Чуть больше года назад написал простенький сабж движок. Признаться, сделано это было с одной стороны ради фана, а с другой стороны на случай если когда либо придется еще раз решать подобную задачу, то воспользоваться им, как отправной точкой. В этом уютном, новом бложике попробую презентовать его менее сумбурно, чем это было сделано тогда.
Для начала, нам нужно будет скачать приатаченный к посту файл. Писался он для чистой DAX 3 SP3, впрочем он не затрагивает никаких существующих объектов, так что можно смело грузить его как на трешку, так и на четверку. В последней вроде тоже проверял и даже, кажется, работало
![Wink](/forums/images/smilies/wink.gif)
Немного о структуре.
Не вдаваясь в подробности как оно все устроено изнутри, т.к. мне самому страшно влезать туда, спустя более года
![Smile](/forums/images/smilies/smile.gif)
Создим простой пример.
X++:
class VerySimpleReport extends SimpleSheetEngineData { }
X++:
void fillReportDataMap() { ; this.description("Hello CEO's report"); this.keyHeader(["Company", "CEO"]); this.valueHeader(["Salary", "Fortune"]); reportDataMap.insert(["Microsoft", "Стив Балмер"], [100000.0, 10000000.0]); reportDataMap.insert(["Apple", "Стив Джобс"], [50000.0, 30000000.0]); reportDataMap.insert(["Google", "Сергей Брин"], [30000.0, 14000000.0]); reportDataMap.insert(["Oracle", "Джозеф Эллисон"], [250000.0, 120000000.0]); }
X++:
static void main(Args _args) { VerySimpleReport verySimpleReport = new VerySimpleReport(); SimpleSheetEngine simpleSheetEngine; ; verySimpleReport.fillReportDataMap(); if (verySimpleReport.breakReport()) return; simpleSheetEngine = SimpleSheetEngine::construct(verySimpleReport); simpleSheetEngine.run(); }
![](http://img-fotki.yandex.ru/get/3905/kir-ozer.11/0_33630_ead06454_XL.jpg)
Нажмем Функции/Печать и увидим сам отчет.
![](http://img-fotki.yandex.ru/get/4104/kir-ozer.11/0_33631_b6fade07_XL.jpg)
Обратите внимание, что я изменил ширину колонок в форме просмотра и ширина колонок в отчете изменилась соответственно (по аналогии с великими и ужасными отчетами ГК).
Реальное предназначение.
Приведенный выше пример иллюстрирует общий принцип работы данного движка, но создавался он все таки для многоколоночных отчетов "растущих в ширину", что и предлагаю реализовать, воспользовавшись примером ниже.
Оставим наших CEO и попробуем вывести в отчет поля и записи таблицы "План счетов". Новая реализация метода fillReportDataMap выглядит следующим образом:
X++:
#define.HeaderFieldCnt(3) #define.SkipedDimField1(9) #define.SkipedDimField2(22) #define.DemoRecCnt(30) void fillReportDataMap() { LedgerTable ledgerTable; DictTable dictTable; int intFieldNum; container key, val; int recNum; ; this.description("План счетов"); dictTable = new DictTable(tableNum(LedgerTable)); for(intFieldNum = 1; intFieldNum < dictTable.fieldCnt(); intFieldNum++) { if (intFieldNum == #SkipedDimField1 || intFieldNum == #SkipedDimField2) continue; if (intFieldNum < #HeaderFieldCnt) key += dictTable.fieldObject(dictTable.fieldCnt2Id(intFieldNum)).label(); else val += dictTable.fieldObject(dictTable.fieldCnt2Id(intFieldNum)).label(); } this.keyHeader(key); this.valueHeader(val); key = conNull(); val = conNull(); while select ledgerTable { for(intFieldNum = 1; intFieldNum < dictTable.fieldCnt(); intFieldNum++) { if (intFieldNum == #SkipedDimField1 || intFieldNum == #SkipedDimField2) continue; if (intFieldNum < #HeaderFieldCnt) key += ledgerTable.(dictTable.fieldCnt2Id(intFieldNum)); else val += ledgerTable.(dictTable.fieldCnt2Id(intFieldNum)); } reportDataMap.insert(key, val); key = conNull(); val = conNull(); recNum++; if (#demoRecCnt == recNum) break; } }
![](http://img-fotki.yandex.ru/get/3901/kir-ozer.11/0_33632_28cbb384_XL.jpg)
Цветами отмечена группа переключателей, которая отвечает за режим вывода.
![Smile](/forums/images/smilies/smile.gif)
Более интересным является "Многостраничный вывод". Он последовательно отобразит колонки, расположив не поместившиеся из них, на следующих страницах - "в право". На скриншоте ниже я скрыл некоторые нулевые и пустые столбцы, и можно видеть, что оставшиеся поместились на два альбомных листа.
![](http://img-fotki.yandex.ru/get/4001/kir-ozer.11/0_33633_3df65901_XL.jpg)
Режим "С повтором ключей" работает аналогично предыдущему, но так же отображает на дополнительных страницах значения ключевых полей, что можно попытаться разглядеть на завершающем скриншоте.
![](http://img-fotki.yandex.ru/get/4106/kir-ozer.11/0_33634_fbbdaae0_XL.jpg)
Заключение.
Данный проект ни в коем случае не претендует на законченное решение. Во первых, все это было написано за "один заход", то есть никакого рефакторинга и прочей "доводки до ума" не проводилось. Во вторых, в процессе написания поста нашелся баг, описанный выше. Так же, я совершенно не учитывал работу в 3-х звенной архитектуре, да и печатная форма, на данный момент, не имеет никаких заголовков, итогов и других атрибутов типичного документа. Так уж вышло, что в свое время, мне довелось создать не мало подобных отчетов, причем делалось это, как правило, в дедлайн и в разные промежутки времени. Каждый раз сталкиваясь с таким отчетом, хотелось иметь в запасе отправную точку, от которой можно было бы реализовывать конкретную задачу. Собственно так и появился сей скромный проектик.
p.s. Спасибо всем тем, кто дочитал до этого предложения
![Smile](/forums/images/smilies/smile.gif)
Всего комментариев 0