|  12.01.2012, 13:03 | #1 | 
| Участник |  Excel. пустые ячейки 
			
			Доброго дня. Сторонняя программа дает Excel-файл. Я его порезал убрав лишнее. Файл в аттаче. Суть в том, что есть данные в первом столбце и нет во втором. И вот такой код есть: X++: static void checkExcell(Args _args) { FilePath path=''; container conFilter = ["Файл (*.xls)", "*.xls"]; SysExcelApplication exappl; SysExcelCells excells; SysExcelWorksheets exsheets; SysExcelWorksheet exsheet; int row; real a,b; ; path = WinAPI::getOpenFileName(0,conFilter,"", "Укажите файл ",'',""); if (!path) return; exappl = SysExcelApplication::construct(); exappl.workbooks().open(path); exsheets = exappl.workbooks().item(1).worksheets(); exsheet = exsheets.itemFromNum(1); excells = exsheet.cells(); for(row = 1;row<3;row++) { a = excells.item(row,1).value().double(); //info(strfmt('%1',a)); // строка 1 b = excells.item(row,2).value().double(); info(strfmt('%1',a)); // строка 2 info(strfmt('%1',b)); } exappl.quit(); } Во втором случае выводится ожидаемое. В первом же случае, вместо 0 (в ячейке 2-го столбца пусто) получаем данные из первого столбца. Если в файле во второй колонке проставить значения, а потом удалить - все опять корректно работает. Axapta 2009. В 3-й такой проблемы не наблюдаю. | 
|  | |
| За это сообщение автора поблагодарили: S.Kuskov (2). | |
|  12.01.2012, 13:47 | #2 | 
| Участник | 
			
			Интересно. Видимо второй (и последующие) вызов метода item() натыкается на какой-то мусор, оставшийся после первого вызова. А вызов info() каким-то образом подчищает этот мусор. В качестве workaround могу предложить позиционироваться на ячейке при помощи метода offset: X++: static void checkExcell(Args _args) { FilePath path=''; container conFilter = ["Файл (*.xls)", "*.xls"]; SysExcelApplication exappl; SysExcelCells excells; SysExcelWorksheets exsheets; SysExcelWorksheet exsheet; SysExcelCell excell; // fix int row; real a,b; ; path = WinAPI::getOpenFileName(0,conFilter,"", "Укажите файл ",'',""); if (!path) return; exappl = SysExcelApplication::construct(); exappl.workbooks().open(path); exsheets = exappl.workbooks().item(1).worksheets(); exsheet = exsheets.itemFromNum(1); excells = exsheet.cells(); excell = excells.item(1,1); // fix for(row = 1;row<3;row++) { //a = excells.item(row,1).value().double(); a = excell.offset(row - 1, 0).value().double(); // fix //info(strfmt('%1',a)); // строка 1 //b = excells.item(row,2).value().double(); b = excell.offset(row - 1, 1).value().double(); // fix info(strfmt('%1',a)); // строка 2 info(strfmt('%1',b)); } exappl.quit(); } | 
|  | |
| За это сообщение автора поблагодарили: Logger (3), Димитрий (1). | |
|  12.01.2012, 13:54 | #3 | 
| Участник | 
			
			Да, действительно. Так заработало корректно. Но, код подобного типа расскидан по системе, т.к. даже не думал, что можно в такое вляпаться. Честно скажу, что в большей степени бы порадовала заплатка на класс работы с Экселем.   | 
|  | 
|  12.01.2012, 14:03 | #4 | 
| Участник | 
			
			Да, так и получилось. На SysExcelCells X++: public SysExcelCell item(int _row, int _column, boolean first = false) { if (first) return SysExcelCell::construct(version,COM::createFromVariant(cells.item(_row,_column))); else { if (!excell) excell = this.item(1,1,true); return excell.offset(_row - 1, _column-1); } } SysExcelCell excell; Работает. | 
|  | 
|  12.01.2012, 14:31 | #5 | 
| Участник | 
			
			Но проблем при такой заплатке есть. Если первая ячейка объединена с рядом стоящими, то работает неверно. | 
|  | 
|  12.01.2012, 19:04 | #6 | 
| Участник | 
			
			Общее правило при работе с любыми внешними (по отношению к Axapta) объектами: Следует избегать многосоставных конструкций. Со многими точками. А в данном случае, нужно просто явно указать класс объекта, который будет выполнять обработку. В данном случае - чтение значение ячейки X++: static void checkExcell(Args _args) { FilePath path=''; container conFilter = ["Файл (*.xls)", "*.xls"]; SysExcelApplication exappl; SysExcelCells excells; SysExcelWorksheets exsheets; SysExcelWorksheet exsheet; int row; real a,b; // Добавчик SysExcelCell excellOne; SysExcelCell excellTwo; ; path = WinAPI::getOpenFileName(0,conFilter,"", "Укажите файл ",'',""); if (!path) return; exappl = SysExcelApplication::construct(); exappl.workbooks().open(path); exsheets = exappl.workbooks().item(1).worksheets(); exsheet = exsheets.itemFromNum(1); excells = exsheet.cells(); for(row = 1;row<3;row++) { // Вот это надо сделать excellOne = excells.item(row,1); excellTwo = excells.item(row,2); a = excellOne.value().double(); //info(strfmt('%1',a)); // строка 1 b = excellTwo.value().double(); info(strfmt('%1',a)); // строка 2 info(strfmt('%1',b)); } exappl.quit(); } 
				__________________ - Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... | 
|  | 
|  12.01.2012, 20:51 | #7 | 
| Участник | Цитата: 
		
			Сообщение от Владимир Максимов
			   Общее правило при работе с любыми внешними (по отношению к Axapta) объектами: Следует избегать многосоставных конструкций. Со многими точками. А в данном случае, нужно просто явно указать класс объекта, который будет выполнять обработку. В данном случае - чтение значение ячейки | 
|  | 
|  12.01.2012, 20:58 | #8 | 
| Участник | 
			
			Думаю, что "обертка" не особо помогает при не явной инициализации промежуточных COM-объектов. Все "скрытые" COM-объекты - потенциальный источник проблем. Кто его знает как там с распределением памяти дела обстоят? Лучше уж потратить лишние переменные и иницилизировать все промежуточные COM-объекты явным образом.
		 
				__________________ - Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... | 
|  | 
| Теги | 
| excel | 
|  | 
| 
 |