06.05.2010, 14:54 | #41 |
Участник
|
Цитата:
Сообщение от Gustav
Роман, у меня два вопроса:
Последний раз редактировалось Roman N. Krivov; 06.05.2010 в 15:34. |
|
06.05.2010, 16:17 | #42 |
Moderator
|
Цитата:
И как боретесь? В коде что-то отрабатывает или вручную? На картинке-то у вас вроде нормальный вид объединенных ячеек... |
|
06.05.2010, 16:39 | #43 |
Участник
|
Цитата:
X++: . . .
wkss = comDocument.Worksheets();
wks = wkss.Item(cvActiveWks);
rng = wks.Range(_bookmark); // _bookmark = "19:19"
this.insertRows(rng.row(), rng.row() + 1, rstAxa.RecordCount() - 1);
cell = rng.Offset(0,0);
cell.CopyFromRecordset(rstAxa);
. . . X++: protected void insertRows(int _fromRow, int _toRow, int _numOfCopies) { COM comRows, comWorkSheet, comRow, comRowTarget, selection; COMVariant comRowVariant, selVariant; ; if (! _numOfCopies) return; if (! comDocument) throw error(strFmt("@DIS6401", "Excel.Application")); comRow = this.findRange(strFmt("%1:%2", _fromRow, _fromRow)); comRow.copy(); comRowTarget = this.findRange(strFmt("%1:%2", _toRow, _toRow + _numOfCopies - 1)); comRowTarget.select(); comRowTarget.insert(/*#xlShiftDown*/); comWorkSheet = this.getWorkSheet(cvActiveWks); comRows = comWorkSheet.cells(); comRows = COM::createFromVariant(comRows.item(1)); comRows.select(); comExcelApplication.cutCopyMode(false); } |
|
06.05.2010, 16:47 | #44 |
Участник
|
Сейчас немного поэкспериментировал
Первый эксперимент
Суть эксперимента Взял шаблон, добавил в него 32 строки, установил форматы ячеек и убрал из года добавление новый строк. Запустил формирование отчёта для 7строк. Результат В ячейках вместо чисел стоит дата, например: 03.09.1903, вместо 1342,56 Второй эксперимент Суть эксперимента Запустил формирование отчета без шаблона. Результат В ячейках вместо чисел стоит дата, например: 03.09.1903, вместо 1342,56 Последний раз редактировалось Roman N. Krivov; 06.05.2010 в 16:55. |
|
06.05.2010, 16:51 | #45 |
Moderator
|
Цитата:
X++: cell = rng.Offset(0,0); // сейчас это целая строка 19 cell = rng.Resize(1,1); // а станет одиночная ячейка A19 |
|
06.05.2010, 17:01 | #46 |
Участник
|
|
|
06.05.2010, 17:15 | #47 |
Moderator
|
Ох, ну, славно! Хотя по идее должно было работать и с полной строкой 19 (это я так... чисто эвристически делал предположение).
Всё-таки не совсем понятно, почему даже на пустом Excel происходило... Как-то у вас дата, похоже, крепко хваталась со второй колонки и не "отпускалась" до конца строки. Напоминает поведение типа anytype, когда он принимает тип первого присваивания... А покажите цикл заполнения рекордсета? (на радостях) |
|
07.05.2010, 09:34 | #48 |
Участник
|
Цитата:
Цитата:
Сообщение от Gustav
Всё-таки не совсем понятно, почему даже на пустом Excel происходило... Как-то у вас дата, похоже, крепко хваталась со второй колонки и не "отпускалась" до конца строки. Напоминает поведение типа anytype, когда он принимает тип первого присваивания...
А покажите цикл заполнения рекордсета? (на радостях) X++: . . .
rstAxa.AddNew();
for(i=1; i<=arrFields.lastIndex(); i++)
{
cv = this.getValueVariant(conpeek(con, i));
fld = flds.Item(i-1);
fld.Value(cv);
}
rstAxa.Update();
. . . X++: protected COMVariant getValueVariant(anytype _value) { COMVariant ret; ; switch(typeof(_value)) { case Types::Date : ret = COMVariant::createFromDateAndTime(_value, 0); break; case Types::Real : ret = COMVariant::createFromReal(_value); break; case Types::Integer : ret = COMVariant::createFromInt( _value); break; case Types::String : case Types::RString : case Types::VarString : ret = COMVariant::createFromStr( _value); break; default : callStack2infolog(); throw error(strfmt(@"%1(): Не знаю, как преобразовать значение из типа %2 в %3", funcname(), typeof(_value), classstr(COMVariant))); } return ret; } |
|
17.09.2010, 21:22 | #49 |
Участник
|
Извиняюсь, что поднял старую тему, просто что-то поиском не нашел ответа на вроде бы очевидный вопрос, как при экспорте в Excel через RecordSet оставить ячейки не заполненными? Ну, например, если не указана дата, то в ячейке Excel должно быть пусто, а не 00.01.1900.
Разумеется, покопавшись в справке довольно быстро нашел ответ. Но, может, еще кому пригодится. Суть сводится к тому, что соответствующее поле RecordSet должно содержать значение NULL на момент создания новой строки. Вообще-то, по умолчанию, при создании новой строки в RecordSet, если явно не указано значение, то и предпринимается попытка присвоить значение NULL. Однако, опять же по умолчанию, поле RecordSet создается с невозможностью принимать значение NULL и, как следствие, присваивает "пустое" значение Допустимость использования значения NULL задается 4 параметром в методе Fields.Append(). 3 параметр - это размерность поля в байтах. Есть еще 5 параметр - значение по умолчанию, но практического смысла в данном случае 5 параметр не имеет. Тогда код будет выглядеть примерно так X++: static void Job_ADORecordSet2Excel_EmptyCells(Args _args) { Com comRecordSet; Com comFields; Com comField; ComExcelDocument_RU excel; Com comRange; ; #define.adFldIsNullable(32) // Поле может принимать значение NULL #define.adFldMayBeNull(64) // Из поля можно прочитать значение NULL comRecordSet = new COM('ADODB.Recordset'); // формируем структуру Recordset // где каждое поле может принимать значение NULL comFields = comRecordSet.Fields(); comFields.Append("FieldStr", COMVariantType::VT_BSTR, 50, #adFldIsNullable + #adFldMayBeNull); comFields.Append("FieldReal", COMVariantType::VT_R8, 8, #adFldIsNullable + #adFldMayBeNull); // Если нужна только даты без части со временем, то следует указать значение 133 // Такого значения нет в Base Enum с именем COMVariantType comFields.Append("FieldDate", COMVariantType::VT_DATE, 8, #adFldIsNullable + #adFldMayBeNull); // Открываем 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(); // Формируем третью строку comRecordSet.AddNew(); // Наполняем ее данными для сравнения comField = comFields.Item("FieldStr"); comField.value(comVariant::createFromStr("Третья строка")); comField = comFields.Item("FieldReal"); comField.value(comVariant::createFromReal(789.012)); comField = comFields.Item("FieldDate"); comField.value(comVariant::createFromDate(systemDateGet()+2)); // Открываем Excel с пустым листом и сразу делаем его видимым excel = new ComExcelDocument_RU(); excel.newFile("",true); // Определяем ячейку, откуда будет осуществляться вывод comRange = excel.findRange("A1"); // Выводим данные comRange.CopyFromRecordset(comRecordSet); } Собственно, это все работает, если ничего не вводить в поле RecordSet. Но, к сожалению не нашел, а как записать в поле RecordSet значение null ? Единственный, не очень хороший вариант - это присвоение исходного (оригинального) значения, исходя из предположения, что это значение NULL X++: comField = comFields.Item("FieldDate");
comField.value(comField.OriginalValue()); |
|
|
За это сообщение автора поблагодарили: S.Kuskov (5). |
18.09.2010, 10:59 | #50 |
Участник
|
Например, так
X++: ComVariant var;
...
var = new ComVariant(COMVariantInOut::In_out, ComVariantType::VT_BOOL);
var.variantType(ComVariantType::VT_NULL);
comField.value(var);
...
__________________
Axapta v.3.0 sp5 kr2 |
|
|
За это сообщение автора поблагодарили: Владимир Максимов (2), Logger (5), Ace of Database (5), gl00mie (3). |
02.03.2011, 11:44 | #51 |
Участник
|
У меня такой вопрос возник. Вроде по теме.
После сбора данных из нескольких таблиц в ADODB.Recordset мне нужно вывести их форму на grid, чтобы потом можно было их просмотреть/редактировать в самой DAX. Как это можно сделать? Ну естественно напрашивается вариант со временной таблицей, ну а будет ли это быстро? И как вообще ее заполнять? |
|
02.03.2011, 13:49 | #52 |
Moderator
|
Если не зацикливаться на grid'е, то можно посадить на форму ActiveX OWC Spreadsheet и в нем смотреть/редактировать. Spreadsheet поддерживает метод CopyFromRecordset.
|
|
02.03.2011, 14:54 | #53 |
Участник
|
Я об этом как раз подумал. Но я к сожалению недавно с Axapta знаком. Как вывести значение на форму? Скажем rstAxa (это сам рекордсет).
Уточню вопрос, допустим я делаю X++: ExcelSheet = tabExcelSheet.addControl(formControlType::ActiveX, "ExcelSheet"); |
|
02.03.2011, 15:20 | #54 |
Moderator
|
Цитата:
Но лучше помещать на нормальную форму, сохраненную в AOT (не диалог) - тогда можно будет воспользоваться его событиями. В диалоге же это не получается: События FormActiveXControl не получается использовать в диалоге |
|
|
За это сообщение автора поблагодарили: refined (1). |
02.03.2011, 15:31 | #55 |
Участник
|
Да, я как раз пытаюсь через нормальную форму. Я делаю следующим образом:
X++: reportEngine = element.args().caller(); super(); ExcelSheet = tabExcelSheet.addControl(formControlType::ActiveX, "ExcelSheet"); ExcelSheet.widthMode(formwidth::ColumnWidth); ExcelSheet.heightMode(formHeight::ColumnHeight); ExcelSheet.CopyFromRecordset(reportEngine.recordset()); X++: COM recordset()
{
;
return rstAxa;
} Всё, я уже разобрался. Добавил еще строчек кода из http://axforum.info/forums/blog.php?b=26 Просто забыл код закомментировать. Последний раз редактировалось refined; 02.03.2011 в 16:22. Причина: выполнил |
|
02.03.2011, 16:25 | #56 |
Moderator
|
ExcelSheet это FormActiveXControl? Конечно, у него такого метода нет. Метод есть у Range. Надо перейти к нему как-то так:
X++: COM range;
range = ExcelSheet.Range("A1");
range.CopyFromRecordset(...); X++: ExcelSheet = tabExcelSheet.addControl(formControlType::ActiveX, "ExcelSheet"); ExcelSheet.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 P.S. ОК! Хорошо, что разобрались. |
|
03.03.2011, 13:48 | #57 |
Участник
|
В итоге оказалось, что намного проще сделать вывод не сразу в эксель а просто в форму. И в ней сразу делать сводную таблицу.
Так вот у меня с ней как раз и проблема. Она не отрабатывает как Сводная. Как сделать так чтобы при перетаскивании столбцов, они *схлопывались* автоматически? т.е. осуществлялась группировка по полю (одному, двум). Ну и соответсвенно если это число то выводилась сумма? И так, вот сам метод выполняемый на форме: PivotTable = grpPivotTableHolder.addControl(formControlType::ActiveX, "PivotTable"); X++: className = CCUtil::getOfficePivotTableVersion(true); PivotTable.className(className); PivotTable.WidthMode(formwidth::ColumnWidth); PivotTable.HeightMode(formHeight::ColumnHeight); PivotTable.allowFiltering(true); PivotTable.AllowGrouping(true); PivotTable.DataSource(reportEngine.ADORecordset()); Смысл в том чтобы не использовать временную таблицу. Последний раз редактировалось refined; 03.03.2011 в 13:57. |
|
12.09.2014, 17:24 | #58 |
Участник
|
Господа. Прошу помочь разобраться с этим ADO.
Делаю джоб (самый первый пример из этой темы). Все отрабатывает. Пытаюсь воспользоваться этим же кодом в Классе, отчете.... во время запуска выдает ошибку на строке rstAxa = new COM('ADODB.Recordset'); пишет "Объект "COM" не может быть создан" Почему один и тот же код не работает в отчете, классе? Цитата:
static void Job_TestADO_2(Args _args)
{ // ---------------------------------------------------------------------------- // ADODB.Recordset в оперативной памяти без привязки к источнику данных // ---------------------------------------------------------------------------- EmplTable emplTable; COM rstAxa; // ADO: Recordset COM flds, fld; // ADO: Fields, Field COM xlApp; // Excel.Application COM wbks, wbk; // Workbooks, Workbook COM wkss, wks; // Worksheets, Worksheet COM rng, cell, rngCR; // все Range COM font; // Range.Font COM entCol; // Range.EntireColumn COM actWin; // Excel.Application.ActiveWindow int i, iMax; // ============================================================================ // СНАЧАЛА ВЛОЖЕННАЯ ФУНКЦИЯ // ---------------------------------------------------------------------------- // функция для задания типа поля нашего Recordset-а в оперативной памяти // в данном демо-джобе используется для наглядности // для простоты используем всего 3 типа данных: число, строка и дата int adoTypeToExcel(str _type) { switch (_type) { // используются значения констант перечисления DateTypeEnum из топика TypeProperty (ADO) // (см. справку по ADO в файле ADO210.CHM - можно поискать на своем компе) case 'num' : return 5; // adDouble case 'str' : return 8; // adBSTR case 'date': return 133; // adDBDate } return 8; } // ============================================================================ // ТЕПЕРЬ ОСНОВНОЙ ПРОЦЕСС // Recordset создается в оперативной памяти - без Connection! rstAxa = new COM('ADODB.Recordset');
__________________
Dynamics AX 2009 SP1, Rollup 5, SQL Server 2008 Хороший ученик во всем найдет себе учителя... |
|
12.09.2014, 19:39 | #59 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: Отшельник (1). |
19.09.2014, 09:46 | #60 |
Участник
|
S.Kuskov - Сори за молчание.
Спасибо за помощь. К вечеру уже не соображал . Лишний раз убедился, что труд из человека делает обезьяну
__________________
Dynamics AX 2009 SP1, Rollup 5, SQL Server 2008 Хороший ученик во всем найдет себе учителя... |
|
Теги |
ado, comvariant, excel, faq, odbc, sql, интеграция, прямой доступ, формат дат, экспорт, экспорт в excel |
|
|