|
06.05.2012, 17:53 | #1 |
Участник
|
выбивает Excel при использовании merge()
Всем здравствуйте! Вопрос.
Есть класс, реализующий сбор данных, которые после выводятся в эксель. При выводе данных производится форматирование ячеек, в частности объединение. При определённых параметрах отчёта, доходя до определённой строки, говорит о невозможности объединения ячеек, говорит что выделенная область уже имеет ячейки, которые объединены с другими, хотя предыдущие 11960 таких же строк вывел нормально. Дал отчёту построиться без объединений, range формируется верно и не затрагивает уже объединённых ячеек, то есть ошибки быть не должно. Уже всё проверил, не знаю что искать и где... Может кто сталкивался? Спасибо. DAX 2009 Последний раз редактировалось Cardagant; 06.05.2012 в 18:32. |
|
07.05.2012, 11:57 | #2 |
MCITP
|
Может есть смысл в эту сторону покопать?
__________________
Zhirenkov Vitaly |
|
07.05.2012, 22:13 | #3 |
Участник
|
Давно не общался с АХ.
Возможно в записи 11960 есть какие СПЕЦСИМВОЛЫ. (Как бы логично, если 12к записей отработали, а одна нет, то она и виновата.) А, не создаёт ли класс лишних строк в экселе? Видел как то такое, затраивались строки. Был не верно написан цикл.
__________________
Бывает, что человек молчит, когда ничего не знает о данном предмете, но чаще – когда знает о нем все. (Джордж Бернард Шоу) Последний раз редактировалось Silence; 07.05.2012 в 22:18. Причина: Дополнил |
|
08.05.2012, 09:45 | #4 |
Участник
|
Цитата:
Может ли это быть какой-либо баг Экселя, какое-то ограничение на количество объединений в сессии и т д? Уже не знаю что предполагать. |
|
08.05.2012, 11:49 | #5 |
MCITP
|
Цитата:
Сообщение от Cardagant
Всё верно, что предыдущие 11960, что строки последующие. Строки не задваиваются, затраиваются и т д. Диапазон формируется верно, никаких наложений на существующие области нет.
Может ли это быть какой-либо баг Экселя, какое-то ограничение на количество объединений в сессии и т д? Уже не знаю что предполагать. Если проблема в ней, то цикл пойдёт дальше и наверное придётся таки проверить данные в этой строке....
__________________
Zhirenkov Vitaly |
|
08.05.2012, 14:12 | #6 |
Участник
|
Идея прекрасная, попробовал. Пропустил строку 11960, он выбился с той же ошибкой, но со сдвигом на одну строку, на ту, которую пропустил)
|
|
10.05.2012, 10:44 | #7 |
Участник
|
Приведите уже код выгрузки в Excel. Интересуют следующие вопросы
1. Для экспорта используется ранее созданный шаблон или создается новый (чистый) лист Excel? Если шаблон, то не остался ли в нем какой-либо мусор в строке 11960? 2. Какой механизм экспорта в Excel используется (поячеечная вставка, буфер обмена, RecordSet, ...)? 3. Как формируется Range для метода Merge? Проверить для строки 11960 какие ячейки попали в Range и какие значения есть в этих ячейках
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
10.05.2012, 23:20 | #8 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
Приведите уже код выгрузки в Excel. Интересуют следующие вопросы
1. Для экспорта используется ранее созданный шаблон или создается новый (чистый) лист Excel? Если шаблон, то не остался ли в нем какой-либо мусор в строке 11960? 2. Какой механизм экспорта в Excel используется (поячеечная вставка, буфер обмена, RecordSet, ...)? 3. Как формируется Range для метода Merge? Проверить для строки 11960 какие ячейки попали в Range и какие значения есть в этих ячейках 2. Механизм экспорта - поячеечная вставка, также COM использует OWC10.SpreadSheet.10, возможно, он задаёт ограничение на количество объединений? Опытным путём установил, что в некоторых разных конфигурациях начальных параметров данного отчёта, производится одинаковое количество объединений, после вылетает с вышеописанной ошибкой о невозможности объединения. Написал джоб, который последовательно объединяет 40000 раз по 2 строки в первой колонке, действие очевидно, но и здесь вылетел, хотя всё прозрачно и диапазоны 100% верны, файл изначально чист. 3. В Range попадает верный диапазон, ячейки перед объединением пусты. Последний раз редактировалось Cardagant; 10.05.2012 в 23:34. |
|
10.05.2012, 11:40 | #9 |
Moderator
|
сделайте excel.visible(true) и посмотрите на проблемной строке пошагово какие ячейки выбираются перед обьединением.
__________________
С уважением, kvan. |
|
10.05.2012, 23:38 | #10 |
Участник
|
Спасибо за совет. Уже пробовал, всё подбирается верно. Если программно закрыть документ Эксель, а после снова открыть и продолжить выгрузку данных, то ошибки нет, всё выгружается верно.
|
|
11.05.2012, 14:28 | #11 |
Участник
|
И все-таки код приведите. Тот фрагмент где формируется Range и вызывается merge(). Такое впечатление, что у Вас где-то накапливаются и не очищаются ссылки. Соответственно, происходит переполнение некоего внутреннего стека объекта OWC.
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
11.05.2012, 15:23 | #12 |
Moderator
|
Господа, мне наконец удалось получить это сообщение об ошибке: 0xE004002C The selected cells cannot be merged. The range partially intersects a merged cell. Воспроизвелось на OWC.Spreadsheet (и на 10, и на 11) и на Axapta 3.0. В Excel не воспроизвелось (интересно, о каком же "Excel" мы все-таки тут рассуждаем? )
Суть проблемы не в номере строки, а в количестве выполненных операций Merge на одном листе - 32766. Это максимум. Далее вылетает вышеупомянутое сообщение. Но обо всём по порядку. Вот джоб, реабилитирующий Excel (на каждом шаге по два Merge, и общее их кол-во значительно превышает 32766 - проблем нет): X++: { COM rng = SysExcelApplication::construct().workbooks().add().worksheets().itemFromNum(1).range('A1').comObject(); COM wks = rng.Parent(); COM cells = wks.Cells(); int i; ; COM::createFromObject(rng.Application()).Visible(true); for (i=1; i<=65536-1; i+=2) // только Excel 2003 был в распоряжении { rng = wks.Range(cells.Item(i,1),cells.Item(i+1,1)); rng.Merge(); rng.Value2(i); rng = wks.Range(cells.Item(i,2),cells.Item(i+1,2)); rng.Merge(); rng.Value2(i); } } X++: { Form form = new Form(); Args args = new Args(); FormRun formRun; FormActiveXControl ss; COM worksheet; COM range; COM cells; int i; COM rng = SysExcelApplication::construct().workbooks().add().worksheets().itemFromNum(1).range('A1').comObject(); COM wks = rng.Parent(); COM clls = wks.Cells(); int j; ; COM::createFromObject(rng.Application()).Visible(true); form.addDesign('Design'); args.object(form); formRun = classFactory.formRunClass(args); formRun.init(); formRun.design().caption('Табличный процессор'); ss = formRun.design().addControl(FormControlType::ActiveX, 'Spreadsheet'); //ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.heightMode(FormHeight::ColumnHeight); ss.widthMode(FormWidth::ColumnWidth); range = ss.Range('A1'); worksheet = range.Parent(); cells = worksheet.Cells(); j=0; //for (i=1; i<=80000-1; i+=2) //for (i=1; i<=32766; i++) for (i=1; i<=20; i++) { j++; // вывод в Excel для визуализации счетчика rng = COM::createFromVariant(clls.Item(j)); rng.Value2(j); // вывод в Speadsheet //range = ss.Range(cells.Item(i,1),cells.Item(i+1,1)); range = ss.Range(cells.Item(i,1),cells.Item(i,2)); range.Merge(); range.Value2(i); //range = ss.Range(cells.Item(i,2),cells.Item(i+1,2)); //range = ss.Range(cells.Item(i,3),cells.Item(i,6)); //range.Merge(); //range.Value2(i); } formRun.run(); formRun.wait(); } Ограничение 32766 действует в пределах текущего рабочего листа, которых в Spreadsheet'е по умолчанию три: Sheet1, Sheet2, Sheet3. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (2), Cardagant (1). |
12.05.2012, 00:02 | #13 |
Участник
|
Да, именно так! Именно эта ошибка вылетает у меня, именно об этой ошибке я говорю! Писал аналогичный джоб, чтоб выявить это, получил тот же результат, о котором писал в своих сообщениях выше и о котором пишете Вы. Подскажите есть ли способ избежать или исправить эту ошибку? Помогает сохранение и переоткрытие файла. Возможно сможете подсказать способы лучше? Спасибо!
Последний раз редактировалось Gustav; 12.05.2012 в 00:51. Причина: удалил цитату на свое полное сообщение - излишне! |
|
12.05.2012, 13:57 | #14 |
Moderator
|
Чуть отвлекусь на другое. На Сапфоруме участвовал в дискуссии по поводу ошибки Excel при многократном копировании листа внутри рабочей книги. Обнаружил рекомендацию Microsoft - как раз сохранять и переоткрывать файл ( http://support.microsoft.com/kb/210684/ru ).
Полагаю, что такой способ неплох для многих болезней. Тем более, Вы как раз это и обнаружили в своем случае. Ну дык, так и делайте тогда. Добавьте в класс счетчик merge и, не дожидаясь критического числа, сохраняйтесь и переоткрывайтесь. И осторожный совет - при таких заморочках переходите на нормальный Excel... |
|
12.05.2012, 14:11 | #15 |
Участник
|
Цитата:
Тогда, судя по всему, придётся сравнить производительность обоих способов и выбрать наиболее подходящий в данном случае. Спасибо Вам, Gustav, за совет. |
|
12.05.2012, 16:11 | #16 |
Участник
|
Сделал программное копирование через copy()/paste(). Действительно, после 32766 объединений paste() уже не может скопировать объединенные ячейки. Хотя и ошибок не выдает.
X++: static void Job_Test(Args _args) { Form form = new Form(); Args args = new Args(); FormRun formRun; FormActiveXControl ss; COM worksheet; COM range; COM rangeSource; COM rangeTarget; COM cells; int i; int maxI; int timeNowBegin = timeNow(); SysOperationProgress progress; ; form.addDesign('Design'); args.object(form); formRun = classFactory.formRunClass(args); formRun.init(); formRun.design().caption('Табличный процессор'); ss = formRun.design().addControl(FormControlType::ActiveX, 'Spreadsheet'); //ss.className('{0002E541-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 10.0 ss.className('{0002E559-0000-0000-C000-000000000046}'); // Microsoft Office Spreadsheet 11.0 ss.heightMode(FormHeight::ColumnHeight); ss.widthMode(FormWidth::ColumnWidth); range = ss.Range('A1'); worksheet = range.Parent(); cells = worksheet.Cells(); // Объединение ячеек в первой строке range = ss.Range(cells.Item(1,1),cells.Item(1,2)); range.Merge(); // Первую строку указываю как источник для последующего копирования rangeSource = ss.Range('1:1'); rangeSource.copy(); #AviFiles //maxI = 20; //maxI = 32767; maxI = 33000; //maxI = 36409; //maxI = 37000; progress = new SysOperationProgress(); progress.setAnimation(#aviStopwatch); progress.setTotal(maxI); progress.setCaption("Проверка объединения"); progress.setText("Подготовка..."); progress.update(true); for (i=2; i<=maxI; i++) { progress.setText(strFmt("Осталось %1 из %2", maxI - i + 1, maxI)); progress.incCount(); // Копирую в текущую строку "образцовую" строку rangeTarget = ss.Range(strFmt('%1:%1',i)); rangeTarget.paste(); // Запись значения // range = ss.Range(cells.Item(i,1),cells.Item(i,2)); range = ss.Range('A'+ int2str(i)); range.Value2(i); } info("Время выполнения " + time2str(timeNow()-timenowBegin,1,1)); formRun.run(); formRun.wait(); } PS: Где-то в районе 36400 строк OWC съедает всю доступную (ему) память и начинаются дикие торомоза. Так что, думаю, при работе с OWC вообще не стоит использовать такое количество строк. Даже если бы и не было никаких ошибок
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
Теги |
excel, merge, owc, spreadsheet |
|
|