04.05.2010, 17:23 | #1 |
Участник
|
Вывод в Excel через Array
Доброго времени суток.
Задача: Создать отчет в Excel с табличной частью из шаблона Решение: Есть в отчете табличная область, например, A19:CG35 (N столбцов и M строк). Я заполняю массив Array N x M раз. X++: protected boolean fillData() { . . . ; reportRows = 0; . . . while select returnLine where returnLine.JournalId == returnTable.JournalId { inventTable = InventTable::find(returnLine.ItemId); custInvoiceJour = CustInvoiceJour::findFrominvoiceId(returnLine.InvoiceId); custInvoiceTrans = CustInvoiceTrans::findRecId(returnLine.CustInvoiceTransRecId); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", returnLine.ItemId)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", inventTable.ItemName)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", inventTable.ItemArticle)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", custInvoiceJour.InvoiceExternalId)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", custInvoiceJour.InvoiceDate)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", custInvoiceTrans.Qty)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", custInvoiceTrans.SalesPrice)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", custInvoiceTrans.amountDiscAmountInclTax())); tableRows.value(tableRows.lastIndex() + 1, ""); tableRows.value(tableRows.lastIndex() + 1, ""); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", returnLine.QtyDocument)); tableRows.value(tableRows.lastIndex() + 1, strfmt("%1", returnLine.SummDoc)); tableRows.value(tableRows.lastIndex() + 1, ""); tableRows.value(tableRows.lastIndex() + 1, ""); tableRows.value(tableRows.lastIndex() + 1, ""); reportRows++; } return (reportRows > 0) ? true : false; } return false; } X++: protected void fillTable() { Bookmark bookmark; ; bookmark = strfmt("%1%2:%3%4", #FirstTableCol, this.firstTableRow(), #LastTableCol, this.firstTableRow() + this.numOfRows() - 1); this.insertValue(bookmark, ExcelReportFromTemplate::array2variant(tableRows), 1); } Microsoft Business Solution Axapta 3.0 Build #1951.3730/514-193 SP3/OP023071 |
|
04.05.2010, 18:14 | #2 |
Moderator
|
Код статики ExcelReportFromTemplate::array2variant - в студию!
Хотя я более, чем уверен, что это из-за того, что нельзя передавать двумерные вариантные массивы. Это ограничение Аксапты. Вероятно, придётся в методе fillTable вводить цикл и вставлять букмарками, адреса которых лежат в пределах одной строки Excel, а не сразу всем прямоугольным диапазоном как сейчас. |
|
04.05.2010, 23:26 | #3 |
Участник
|
Помнится, вот здесь был пример импорта из двумерного массива (SafeArray), возможно, по аналогии можно реализовать и экспорт, хотя мне лично больше нравится экспорт в Excel табличных частей отчетов через ADO
|
|
05.05.2010, 08:43 | #4 |
Участник
|
Ты вчерась просил ковер? Ну так я его припер!
ExcelReportFromTemplate::array2variant
X++: static ComVariant array2variant(Array _array) { Integer idx; array arr = new array (types::class); ; if (_array) { for (idx=1; idx <= _array.lastIndex(); idx++) { arr.value(idx, ExcelReportFromTemplate::createVariantFromValue(_array.value(idx))); } return ComVariant::createFromArray(arr); } return ComVariant::createNoValue(); } X++: private static ComVariant createVariantFromValue(anytype _value) { str value; ; switch (typeof(_value)) { case Types::String : case Types::RString : case Types::VarString : return ComVariant::createFromStr(_value); case Types::Enum : return ComVariant::createFromStr(enum2Value(_value)); case Types::Integer : return ComVariant::createFromInt(_value); case Types::Real : return ComVariant::createFromReal(_value); case Types::Date : case Types::DateTime : return ComVariant::createFromDate(_value); case Types::Real : return ComVariant::createFromReal(_value); } return ComVariant::createNoValue(); } Последний раз редактировалось Roman N. Krivov; 05.05.2010 в 08:46. |
|
05.05.2010, 08:45 | #5 |
Участник
|
Цитата:
Сообщение от gl00mie
Помнится, вот здесь был пример импорта из двумерного массива (SafeArray), возможно, по аналогии можно реализовать и экспорт, хотя мне лично больше нравится экспорт в Excel табличных частей отчетов через ADO
|
|
05.05.2010, 08:49 | #6 |
Участник
|
Есть еще вариант сохранить Excel'евский шаблон как XML файл, его редактировать и открывать как уже готовый. Вот только как выделить оттуда табличную часть и добавить нужное количество строк с разбивкой по страницам - данная задача без конкретного решения.
|
|
05.05.2010, 10:36 | #7 |
Участник
|
Цитата:
Вариант с ADO - это, по сути, тот же массив, но выполненный другими средствами. Просто вместо массива заполняется RecordSet. Разный объект-получатель. Поэтому совершенно без разницы, что заполнять Если Вы не в курсе, как это делается, то в среде Axapta создается объект RecordSet и наполняется, а потом заполненный RecordSet просто передается в Excel. Технология совершенно такая же, как и при использовании массивов, но нет проблем с неадекватностью форматов хранения. Цитата:
Если уж Вы перебираете варианты, то есть еще вариант вставки через буфер обмена. Его основной недостаток - слабая управляемость этого самого буфера обмена и возможность его разрушения/изменения в процессе вставки. |
|
|
За это сообщение автора поблагодарили: Gustav (2). |
05.05.2010, 10:39 | #8 |
Moderator
|
Roman N. Krivov, спасибо за демонстрацию кода. Примерно это я и ожидал увидеть.
Цитата:
Цитата:
Цитата:
Заготовьте в шаблоне табличную часть с 2-мя строками в диапазоне A19:CG20. Поименуйте этот диапазон в шаблоне, например, как "TablePart" и далее в своем коде обращайтесь к нему через этот "букмарк", т.е. Range("TablePart") вместо Range("A19:CG20"). Далее вставляйте перед второй строкой нужное кол-во строк. Допустим, надо вам всего 17 строк. 2 уже есть, значит надо вставить еще 15 перед исходной 2-й. После их вставки ваш Range("TablePart") автоматически будет ссылаться уже на Range("A19:CG35"). |
|
05.05.2010, 11:13 | #9 |
Участник
|
Цитата:
Уверен. Там одномерный массив вставлялся целиком. Нет, именно XML (Таблица XML) Вот как раз с данной проблемой и столкнулся. У меня число преобразуется в дату. В качестве типа поля в ADORecordSet использую #adDouble X++: #define.adDouble ( 5) Последний раз редактировалось Roman N. Krivov; 05.05.2010 в 11:15. |
|
05.05.2010, 12:30 | #10 |
Участник
|
Цитата:
Сообщение от gl00mie
Помнится, вот здесь был пример импорта из двумерного массива (SafeArray), возможно, по аналогии можно реализовать и экспорт, хотя мне лично больше нравится экспорт в Excel табличных частей отчетов через ADO
__________________
Axapta v.3.0 sp5 kr2 |
|
05.05.2010, 15:00 | #11 |
Участник
|
Цитата:
|
|
05.05.2010, 15:50 | #12 |
Moderator
|
небольшой оффтопик
Цитата:
Я как раз тут намедни демонстрировал одномерную индексацию ячеек внутри диапазона: Excel диапазон ячеек |
|
06.05.2010, 08:52 | #13 |
Участник
|
Цитата:
Сообщение от Gustav
Excel в душЕ "по строкам" любит больше
Я как раз тут намедни демонстрировал одномерную индексацию ячеек внутри диапазона: Excel диапазон ячеек Код: (1) (2) (3) (4) (5) (6) (7) (8) (9) Код: for (idx = 1; idx <= 9; idx++) { Range("B2:D4").Cells.Item(idx) = ItemsArray[idx]; } Код: Range("B2:D4").Cells.Item(1) = ItemsArray[1]; Range("B2:D4").Cells.Item(2) = ItemsArray[2]; Range("B2:D4").Cells.Item(3) = ItemsArray[3]; Range("B2:D4").Cells.Item(4) = ItemsArray[1]; Range("B2:D4").Cells.Item(5) = ItemsArray[2]; Range("B2:D4").Cells.Item(6) = ItemsArray[3]; Range("B2:D4").Cells.Item(7) = ItemsArray[1]; Range("B2:D4").Cells.Item(8) = ItemsArray[2]; Range("B2:D4").Cells.Item(9) = ItemsArray[3]; Последний раз редактировалось Roman N. Krivov; 06.05.2010 в 08:56. |
|
06.05.2010, 11:09 | #14 |
Участник
|
Цитата:
X++: static void ADORecordSet2Excel(Args _args) { Com comRecordSet; Com comFields; Com comField; ComExcelDocument_RU excel; Com comRange; ; comRecordSet = new COM('ADODB.Recordset'); // формируем структуру Recordset comFields = comRecordSet.Fields(); comFields.Append("FieldStr", COMVariantType::VT_BSTR); comFields.Append("FieldReal", COMVariantType::VT_R8); comFields.Append("FieldDate" , COMVariantType::VT_DATE); // Открываем RecordSet для заполнения comRecordSet.open(); // Формируем первую строку comRecordSet.AddNew(); comField = comFields.Item("FieldStr"); comField.value(comVariant::createFromStr("Первая строка")); comField = comFields.Item("FieldReal"); comField.value(comVariant::createFromReal(123.456)); comField = comFields.Item("FieldDate"); comField.value(comVariant::createFromDate(systemDateGet())); // Формируем вторую строку comRecordSet.AddNew(); comField = comFields.Item("FieldStr"); comField.value(comVariant::createFromStr("Вторая строка")); comField = comFields.Item("FieldReal"); comField.value(comVariant::createFromReal(789.01)); comField = comFields.Item("FieldDate"); comField.value(comVariant::createFromDate(systemDateGet()+10)); // Открываем Excel с пустым листом и сразу делаем его видимым excel = new ComExcelDocument_RU(); excel.newFile("",true); // Определяем ячейку, откуда будет осуществляться вывод comRange = excel.findRange("A1"); // Выводим данные comRange.CopyFromRecordset(comRecordSet); } |
|
06.05.2010, 11:19 | #15 |
Moderator
|
Цитата:
Вот маленький джобик, по-моему, достаточно наглядный: X++: COM rng = sysExcelApplication::construct().workbooks().add().worksheets().itemFromNum(1).cells().range('A1:C3').comObject(); Array arr = new Array(Types::String); ; arr.value(1, '1'); arr.value(2, '2'); arr.value(3, '3'); arr.value(4, '4'); arr.value(5, '5'); arr.value(6, '6'); arr.value(7, '7'); arr.value(8, '8'); arr.value(9, '9'); rng.value2(arr); // вставка в диапазон A1:C3 - размер 3 х 3 rng = rng.Offset(4,0); rng = rng.Resize(1,9); rng.value2(arr); // вставка в диапазон A5:I5 - размер 1 х 9 (одна строка) rng = rng.Offset(3,0); rng = rng.Resize(1,12); rng.value2(arr); // вставка в диапазон A9:L9 - размер 1 х 12 (одна строка) COM::createFromObject(rng.Application()).Visible(true); |
|
06.05.2010, 12:02 | #16 |
Участник
|
Цитата:
А вот результат его работы: (см. аттач) Решил заполнять отчёт через AdoRecordSet. Последний раз редактировалось Roman N. Krivov; 06.05.2010 в 13:07. |
|
Теги |
ado, array, excel, recordset |
|
|