AXForum  
Вернуться   AXForum > Блоги > OZKA's DAX Journal
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

Оценить эту запись

Многоколоночные отчеты.

Запись от Lemming размещена 18.11.2009 в 22:51
Обновил(-а) Lemming 19.11.2009 в 08:32

Предисловие.

Чуть больше года назад написал простенький сабж движок. Признаться, сделано это было с одной стороны ради фана, а с другой стороны на случай если когда либо придется еще раз решать подобную задачу, то воспользоваться им, как отправной точкой. В этом уютном, новом бложике попробую презентовать его менее сумбурно, чем это было сделано тогда.

Для начала, нам нужно будет скачать приатаченный к посту файл. Писался он для чистой DAX 3 SP3, впрочем он не затрагивает никаких существующих объектов, так что можно смело грузить его как на трешку, так и на четверку. В последней вроде тоже проверял и даже, кажется, работало Если у вас все импортировалось нормально, то можно продолжать.

Немного о структуре.

Не вдаваясь в подробности как оно все устроено изнутри, т.к. мне самому страшно влезать туда, спустя более года , расскажу о базовых моментах, которых достаточно что бы начать использовать проект. Для создания нового отчета нам нужно будет наследоваться от класса SimpleSheetEngineData. В этом классе объявлены всего пять полей. Основными полями являются: reportDataMap, keyHeader, valueHeader. Первое поле представляет собой коллекцию(map) самих данных отчета, и ключ, и значение данной карты должны быть типа контейнер. Оставшиеся два поля, так же являются контейнерами и содержат информацию о заголовках полей ключа и значения, соответственно.

Создим простой пример.

X++:
class VerySimpleReport extends SimpleSheetEngineData
{
}
Перекроем у данного класса метод fillReportDataMap следующим образом:

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]);

}
Создадим метод main для запуска нашего отчета:

X++:
static void main(Args   _args)
{
    VerySimpleReport        verySimpleReport = new VerySimpleReport();
    SimpleSheetEngine       simpleSheetEngine;
    ;

    verySimpleReport.fillReportDataMap();

    if (verySimpleReport.breakReport()) return;

    simpleSheetEngine = SimpleSheetEngine::construct(verySimpleReport);
    simpleSheetEngine.run();
}
Запустим наш отчет и получим форму предварительного просмотра данных.


Нажмем Функции/Печать и увидим сам отчет.


Обратите внимание, что я изменил ширину колонок в форме просмотра и ширина колонок в отчете изменилась соответственно (по аналогии с великими и ужасными отчетами ГК).

Реальное предназначение.

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

Оставим наших 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;
    }

}
Запустим наш отчет и получим примерно следующую картину.


Цветами отмечена группа переключателей, которая отвечает за режим вывода. Увы, в процессе написания текста, обнаружился баг для режима (вроде пофиксил)."Автомасштабирование" - не самый интересный режим, так как он предполагает вывод всех колонок на один лист и их дальнейший просмотр, вероятно, через увеличительное стекло

Более интересным является "Многостраничный вывод". Он последовательно отобразит колонки, расположив не поместившиеся из них, на следующих страницах - "в право". На скриншоте ниже я скрыл некоторые нулевые и пустые столбцы, и можно видеть, что оставшиеся поместились на два альбомных листа.


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



Заключение.

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

p.s. Спасибо всем тем, кто дочитал до этого предложения
Вложения
Тип файла: xpo SimpleSheetEngine_Fixed191109_OZKA.xpo (66.0 Кб, 838 просмотров)
Размещено в Без категории
Просмотров 40624 Комментарии 0
Всего комментариев 0

Комментарии

 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:25.