19.01.2021, 18:05 | #1 |
Участник
|
Копирование листов при формировании отчета
Добрый день!
Подскажите в чем может быть проблема. Написан отчет XMLExcelReport, DAX2012. В шаблоне находится 1 лист, созданы именованные диапазоны, настроены группировки ячеек. На вход идет номер партии. Соответственно сколько номеров передано, столько листов должно сформироваться. Если партия 1, то отчет формируется корректно. Если более - Система начинает при добавлении новой строки (диапазон Body) ее формировать на месте отформатированных строк нижестоящего именованного диапазона (Footer). При этом последний лист всегда формируется корректно. В чем может быть причина? |
|
20.01.2021, 10:31 | #2 |
Участник
|
Ни шаблон ваш не понятен, ни кода формирования новых листов нет - поэтому можно только гадать.
Попробую погадать так: может быть, не переключаете номер текущего/активного листа при создании нового? |
|
20.01.2021, 10:54 | #3 |
Участник
|
Вот шаблон https://yadi.sk/i/crRporC89Cxc0A
Диапазон Body клонируется в зависимости от количества параметров партии. Когда происходит копирование листов (не последнего), то отчет формируется таким образом: https://yadi.sk/i/J5h_fQOQOh45xg Т.е. при создании второй строки Body остается форматирование строк Footer. В последнем листе все строки Body такие же как и первая. Новые листы формирую следующим образом: X++: document.workbook().insertSheet(1, i, sheetName); document.copyDefineNames(1, i); this.setCurrentWorksheetNum(i); this.initSectionMap(); |
|
20.01.2021, 11:42 | #4 |
Участник
|
.copyDefineNames() - что-то не стандартное, как я понимаю? а там что?
|
|
20.01.2021, 11:45 | #5 |
Участник
|
Да. Метод копирует метки для нового листа.
X++: public void copyDefineNames(int _copyFromSheet = 0, int _after = 1, str _suffix = '') { Map buffDefinedNamesMap = Map::create(this.definedNamesMap().pack()); MapEnumerator mapEnumerator = buffDefinedNamesMap.getEnumerator(); container mapKey, mapValue; Bookmark bookmarkOrig; if(_suffix == '') _suffix = strFmt('_%1', _after); while(mapEnumerator.moveNext()) { mapKey = mapEnumerator.currentKey(); bookmarkOrig = conPeek(mapKey, 1); mapKey = conPoke(mapKey, 1, strFmt('%1%2', conPeek(mapKey, 1), _suffix)); mapValue = mapEnumerator.currentValue(); mapValue = conPoke(mapValue, 1, workbook.worksheets().lookup(_after).name()); this.definedNamesMap().insert(mapKey, mapValue); } } |
|
20.01.2021, 14:26 | #6 |
Участник
|
Насколько я помню, в стандарте все definedNames были глобальные. То есть нельзя было задать ячейки с одинаковыми именами на разных листах. Была сделана заготовка для глобальных, связанная в первую очередь с системными именами диапазонов, но в полной мере не была сделана. Может быть когда вы размножаете диапазоны давать им префикс или постфикс с именем(или номером) листа? Может быть можно не размножать листы, а если вам надо именно для печати генерить на одном листе и вставлять pageBreak?
|
|
20.01.2021, 15:02 | #7 |
Участник
|
|
|
20.01.2021, 15:04 | #8 |
Участник
|
Так они копируются с постфиксом. С точки зрения определения метки и записи в нее проблем нет. Данные выводятся как надо. Проблема только в форматировании.
|
|
20.01.2021, 15:10 | #9 |
Участник
|
Затрудняюсь ответить на этот вопрос - настолько глубоко не копал принцип работы класса, но то что по метке Header_2 Система однозначно понимает, что нужно вывести значение на второй лист - это да.
|
|
20.01.2021, 19:57 | #10 |
Участник
|
Если я правильно понимаю, то у Вас идея заключается в том, чтобы создать первый лист "как положено": HEADER+BODY+FOOTER. Затем Вы создаете новый лист как копию этого созданного листа и хотите только заменить BODY, оставив без изменения HEADER и FOOTER
Сомневаюсь я, что это возможно... Создание полосы - это метод execute(), а собственно вставка в отчет - document.insertRowsByBookmark() и там дело кончается командой OXML_RU::appendChild(sheetData, row.row()); Т.е. явно вставка в конец, а не в указанное место По-моему, Вам придется на каждом листе повторять формирование HEADER и FOOTER. Соответственно, новые листы создавать не как копии первого, а делать их чистыми Т.е. в команде document.workbook().insertSheet(1, i, sheetName); Первый параметр - указать 0 и формировать эти листы с нуля
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
20.01.2021, 22:07 | #11 |
Участник
|
Я пробовал, но тогда вылезает ошибка в initSectionMap.
В общем по ходу придется все выводить на 1 лист, ибо сложно выявить проблему в недоступных для дебага объектах. |
|
20.01.2021, 23:13 | #12 |
Участник
|
А при чем здесь initSectionMap()? Это же просто список констант, которые записываются в MAP. Идентификаторы полос отчета. Там просто инициализация и наполнение MAP
Я не очень понимаю, зачем Вам вообще вот эти 2 команды document.copyDefineNames(1, i); this.initSectionMap(); Физически же работа происходит так 1. По именам ячеек заполняются ячейки в ШАБЛОНЕ 2. По именам полосы (вот то, что в initSectionMap задается) выделяется секция из шаблона и копируется в итоговый отчет в конце Т.е. я вообще не понимаю какой смысл в этих играх с переименованием. В этом просто нет смысла. По логике, у Вас в методе CreateReport должно быть что-то вроде такого X++: // Инициализация MAP с именами секций отчета // Один раз в самом начале this.initSectionMap(); // Выбор первой записи таблиц-источников // Заполнение первого листа execute(#header); execute(#body); execute(#footer); // Выбор следующей записи таблиц-источников // Создаем новый лист document.insertSheet(0, i, sheetName); // Метод есть и на самом документе // Выбор листа - не уверен, что это нужно this.setCurrentWorksheetNum(i); execute(#header); execute(#body); execute(#footer); // Ну и далее цикл продолжаем // Выбор следующей записи таблиц-источников (...)
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
21.01.2021, 02:21 | #13 |
Участник
|
Можно и не копировать. Просто тогда изначально создавать новый лист с именем шаблонного, а в конце переименовывать. Иначе Система не сможет сопоставить лист и метку.
Если создавать новый лист, то форматы меток не переносятся. Как их перенести отдельно я не в курсе. |
|
21.01.2021, 14:46 | #14 |
Участник
|
Оно когда начинает работу, в initSectionsMap() вычитывает все диапазоны в память. Затем прям в шаблонный диапазон вставляет данные, то есть положение диапазона в который идёт вставка не меняется в процессе работы, зато его не надо пересчитывать. Правда надо всегда заполнять все ячейки, иначе может остаться "старое" значение. Раз положение не меняется, действительно не совсем понятно зачем копировать ячейки, единственно зачем это может быть нужно для "размножения" ячеек по горизонтали, как например, сделано в отчётах по налоговым регистрам, кажется метод называется multiplyCell.
Дальше заполненный шаблон целиком добавляется в target sheetData, который в начале пустой. Если бы он был не пустой то приходилось бы в процессе пересчитывать номера ячеек расположенных ниже, что сильно медленно. То есть чтобы заполнялся второй лист надо только его наличие и как то указать его, может быть что-то с шириной колонок нового листа проблема(может быть его надо не просто добавлять а копировать с исходного как-то?). Вроде бы подход Владимира должен быть правильный. |
|
21.01.2021, 15:08 | #15 |
Участник
|
Цитата:
Далее тупо выделяется полоса шаблона и вот "как есть", со всем форматированием, копируется в конец текущего листа итогового отчета Т.е. у Вас стоит задача не просто создать новый лист отчета, но и как-то "убедить" объект document считать этот созданный лист текущим. Как это сделать я не в курсе. Теоретически, новый лист и так должен стать текущим. Но, мало ли... Цитата:
Так нет в отчете никаких форматов меток. Совсем нет. Все эти метки и форматы - это только в шаблоне. В итоговом отчете они появляются как результат копирования. Просто копирование идет со всеми форматами
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|