|
09.10.2008, 19:48 | #1 |
Модератор
|
Спасибо, вопрос закрыт.
по имени ячейки берем номер строки X++: public int getCellName_RowNum(MSOfficeBookMark_RU bookMark, int _workSheet = 1) { COM comRange, comWorkSheet; COM comApplication; if (m_comDocument) { comWorkSheet = this.getWorkSheet(_workSheet); comApplication = m_comDocument.application(); comWorkSheet.activate(); if (comWorkSheet && comApplication) { comRange = comApplication.range(bookMark); } } return comRange.Row(); } X++: public int getCellName_ColumnNum(MSOfficeBookMark_RU bookMark, int _workSheet = 1) { COM comRange, comWorkSheet; COM comApplication; if (m_comDocument) { comWorkSheet = this.getWorkSheet(_workSheet); comApplication = m_comDocument.application(); comWorkSheet.activate(); if (comWorkSheet && comApplication) { comRange = comApplication.range(bookMark); } } return comRange.Column(); } X++: static void Job104(Args _args) { ComExcelDocument_RU doc = new ComExcelDocument_RU(); ; doc.open("C:\\test.xls"); doc.insertValue("test", 100); info('Row='+int2str(doc.getCellName_RowNum('test')) + ' Col='+ int2str(doc.getCellName_ColumnNum('test')) ); doc.insertClearRow(2); doc.insertValue("test", 200); doc.visible(true); } |
|
09.10.2008, 22:01 | #2 |
Участник
|
Если даже в самом коде явно присутствуют как минимум два ветвления, ведущие к тому, что comRange может оказаться неинициализированным, не говоря уже о том, что на листе книги Excel может отсутствовать указанная "закладка", то имеет смысл проверять перед возвратом строки/столбца, что comRange на что-то ссылается, иначе придется то и дело ловить ошибки времени выполнения "объект такой-то неинициализирован".
Последний раз редактировалось gl00mie; 09.10.2008 в 22:05. |
|
09.10.2008, 22:43 | #3 |
Moderator
|
О, больная тема! О, любимая мозоль!
Poleax, бросайте изучать ComExcelDocument_RU, начинайте изучать Excel! Тогда вы будете знать, что для вставки пустой строки перед ячейкой не надо узнавать ее номер, чтобы потом скормить его методу-обертке, вставляющему i-ю строку в таблицу. Если танцевать от comRange, а не от вездесущего текстового букмарка ("test"), который на каждом шаге переводится всё в тот же comRange (который почему-то приговорен быть локальным в методах этого класса), то пустая строка перед comRange вставляется так: Код: comRange.EntireRow().Insert() P.S. При желании можно сократить кол-во строк до одной, если воcпользоваться последними достижениями в этой области X++: comEarlyBindingImitation( comRange,'EntireRow()','Insert()'); |
|
10.10.2008, 12:43 | #4 |
Moderator
|
офф-топ
Ну, вот как раз еще один поучительный пример под горячую руку.
Это код фирменного (со слоя dis) метода из класса ComExcelDocument_RU (DAX 3.0, SP4). Я добавил несколько своих комментариев (в исходном фирменном виде метод не содержит комментариев, а также самой последней строки кода): X++: void copyAndInsertRange(str _bookMark, int _workSheet = 1) { COM comRange, comRange1, comWorkSheet; int colNumber, colsNumber; int rowNumber, rowsNumber; ; if (! m_comDocument) throw error(strFmt("@DIS6401", this.getApplicationName())); comRange = this.findRange(_bookMark, _workSheet); if (! comRange) { return; } rowNumber = comRange.row(); comRange1 = comRange.rows(); rowsNumber = comRange1.count(); // вычитаем единицу... (продолжение см. ниже) rowNumber = rowNumber - 1; colNumber = comRange.column(); comRange1 = comRange.columns(); colsNumber = comRange1.count(); /* // этот фрагмент кода не нужен, // он даже вредит, если выбрать диапазон, начинающийся со строки A comRange.copy(); comRange1 = this.findRange(ComExcelDocument_RU::numToNameCell(colNumber, rowNumber), _workSheet); if (! comRange1) { return; } comRange1.select(); m_comApplication.cutCopyMode(false); */ comRange = comRange.entireRow(); comRange.insert(); // следующие арифметические упражнения - без комментариев... ррррр! // P.S. А впрочем все-таки скажу. // Если бы в начале метода исходный comRange = this.findRange(_bookMark, _workSheet) // был сохранен в отдельную переменную, например, comRange0, // то вместо следующего ужасающего comRange = this.findRange(... достаточно было бы простого // comRange = comRange0 - поскольку при вставке строк перед Range его адрес автоматически переопределяется! comRange = this.findRange(ComExcelDocument_RU::numToNameCell(colNumber, rowNumber + rowsNumber + 1) + ":" + ComExcelDocument_RU::numToNameCell(colNumber + colsNumber - 1, rowNumber + 2*rowsNumber), _workSheet); if (! comRange) { return; } comRange.copy(); // ...чтобы потом вернуть эту вычтенную ранее единицу обратно (rowNumber + 1) :) comRange1 = this.findRange(ComExcelDocument_RU::numToNameCell(colNumber, rowNumber + 1), _workSheet); comRange1.select(); comWorkSheet = this.getWorkSheet(_workSheet); if (comWorkSheet) { comWorkSheet.paste(); } // а вот здесь этот оператор не помешает (при данном подходе) m_comApplication.cutCopyMode(false); } X++: void copyAndInsertRangeNew(str _bookMark, int _workSheet = 1) { COM comRange, comRange1; int rowsNumber; ; if (! m_comDocument) throw error(strFmt("@DIS6401", this.getApplicationName())); comRange = this.findRange(_bookMark, _workSheet); if (! comRange) { return; } rowsNumber = any2int(COM::createFromObject( comRange.Rows() ).Count()); COM::createFromObject(comRange.EntireRow()).Insert(); comRange1 = comRange.Offset(-rowsNumber); comRange.Copy(comRange1); } X++: void copyAndInsertRangeNew2(COM _comRange) { COM comRange1; int rowsNumber; ; rowsNumber = any2int(COM::createFromObject( _comRange.Rows() ).Count()); COM::createFromObject(_comRange.EntireRow()).Insert(); comRange1 = _comRange.Offset(-rowsNumber); _comRange.Copy(comRange1); } И в качестве постскриптума и для большей ясности - код VBA, который делает ту же работу, что и вышеприведенные методы X++: Код: Sub Macro1() Dim rng As Range Set rng = Worksheets(1).Range("B2:C4") rng.EntireRow.Insert rng.Copy rng.Offset(-rng.Rows.Count) End Sub |
|
|
За это сообщение автора поблагодарили: blokva (3), Poleax (2). |
Теги |
excel, документация, как правильно, ax3.0 |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|