09.10.2008, 18:08 | #1 |
Модератор
|
ComExcelDocument_RU по именнованной ячейки вывести номер ее строки.
Вопрос: В Excel файле есть куча именованных ячеек.
Может кто нибудь знает как написать метод для класса ComExcelDocument_RU, чтоб по названию ячейки выдавал номер строки? к примеру назвать такой метод- CellName2RowNum необходимо использовать для этого кода X++: static void Job104(Args _args) { ComExcelDocument_RU doc = new ComExcelDocument_RU(); int i; ; doc.open("C:\\test.xls"); doc.insertValue("test", 100); i=ComExcelDocument_RU::CellName2RowNum("test"); // info(int2str(i)); doc.insertClearRow(i); doc.insertValue("test", 200); i=ComExcelDocument_RU::CellName2RowNum("test"); // info(int2str(i)); doc.visible(true); } |
|
09.10.2008, 18:39 | #2 |
Участник
|
Смотрите в сторону коллекции Names у объектов Application, Workbook, Worksheet
Только, в общем случае, имя может ссылаться на несколько ячеек, так что однозначно назвать колонку или столбец не получится
__________________
Axapta v.3.0 sp5 kr2 |
|
09.10.2008, 19:08 | #3 |
Модератор
|
вот к примеру метод возращающий область, его как то можно допилить чтоб возвращал именно номер строки?
X++: public COM getFindRange(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; } |
|
09.10.2008, 19:19 | #4 |
Участник
|
|
|
09.10.2008, 19:39 | #5 |
Модератор
|
спасибо, я как раз уже насчупал его.. comRange.Row();
все оказывается просто |
|
09.10.2008, 19:48 | #6 |
Модератор
|
Спасибо, вопрос закрыт.
по имени ячейки берем номер строки 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 | #7 |
Участник
|
Если даже в самом коде явно присутствуют как минимум два ветвления, ведущие к тому, что comRange может оказаться неинициализированным, не говоря уже о том, что на листе книги Excel может отсутствовать указанная "закладка", то имеет смысл проверять перед возвратом строки/столбца, что comRange на что-то ссылается, иначе придется то и дело ловить ошибки времени выполнения "объект такой-то неинициализирован".
Последний раз редактировалось gl00mie; 09.10.2008 в 22:05. |
|
09.10.2008, 22:43 | #8 |
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 | #9 |
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). |
10.10.2008, 21:17 | #10 |
Модератор
|
Хорошо Gustav интересный код. Обязательно пригодится и использую.
Только у меня, еще немного другой вопрос. Как сделать чтоб передали методу параметры (str _bookMark, int _workSheet = 1) и для _BookMark скопировать всю эту область и вставить ниже, под копируемой областью. (с полным форматированием, и если ячейка именованная пользователем, то именованную ячейку перенести вниз.) ? А содержимое _bookMark оставить как есть.. но уже без имени ячейки. Т.е. копируем вставляем не всю строку, а только ту область которую указали. |
|
11.10.2008, 23:56 | #11 |
Moderator
|
Т.е., как я понял, всё происходит так же, как и в методе copyAndInsertRange, только перед "букмарком" вставляются не полные строки, а диапазон с таким же размером, как у исходного "букмарка".
На VBA это выглядит так (отличие в одной строке): Код: Sub Macro2() Dim rng As Range Set rng = Range("B2:C4") rng.Insert xlShiftDown 'где константа xlShiftDown = -4121 rng.Copy rng.Offset(-rng.Rows.Count) End Sub X++: // с COM::createFromObject(_comRange.EntireRow()).Insert(); // на _comRange.Insert( #xlShiftDown ); // и выше добавить: #define.xlShiftDown(-4121) |
|
13.10.2008, 19:46 | #12 |
Модератор
|
Gustav Спасибо, а что за значение такое #define.xlShiftDown(-4121)?
|
|
13.10.2008, 21:21 | #13 |
Модератор
|
Вопрос немного усложнился.
Объединены ячейки 3 шт. Общей ячейке задано имя 'test'. при использовании X++: void copyAndInsertBlock(str _bookMark, int _workSheet = 1) { #define.xlShiftDown(-4121) 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()); comRange.Insert( #xlShiftDown ); // и выше добавить: #define.xlShiftDown(-4121) comRange1 = comRange.Offset(-rowsNumber); comRange.Copy(comRange1); } Как сделать так чтоб можно было копировать и дублировать именованную ячейку без потери объединения? |
|
14.10.2008, 09:03 | #14 |
Moderator
|
ну, если хелп по Excel на своем компе совсем лениво открывать, то хотя бы здесь посмотрите: http://msdn.microsoft.com/en-us/library/bb178850.aspx
Цитата:
Сообщение от Poleax
при вставки объединенной ячейки появляется сообщение "Данная операция приведет к отмене объединения ячеек" т.е. ниже в файле Excel есть объединенные ячейки. Объединение с них снимается и в итоге данные передаваемые в именованную ячейку вставляются не в 3-ную объединенную, а самую первую. А две остальных даже не копируются вниз.
Как сделать так чтоб можно было копировать и дублировать именованную ячейку без потери объединения? Если всё-таки хочется решать задачу именно в вашей постановке, то видится такой извратный вариант - сдвигать все оставшиеся ячейки шаблона ниже места вставки вправо (как дверь шкафа-купе), потом делать копирование, потом возвращать "дверь" обратно. Стоит ли игра таких свеч? |
|
14.10.2008, 11:03 | #15 |
Модератор
|
Цитата:
Сообщение от Gustav
ну, если хелп по Excel на своем компе совсем лениво открывать, то хотя бы здесь посмотрите: http://msdn.microsoft.com/en-us/library/bb178850.aspx
Цитата:
Сообщение от Gustav
Самый простой вариант решения проблемы - вернуться к вставке полных строк. Еще вариант - отказаться от объединенных ячеек. В подавляющем большинстве практических случаев они могут быть безболезненно для отображения заменены центрированием по выделению (Формат \ Ячейки \ Выравнивание \ По горизонтали \ По центру выделения).
Если всё-таки хочется решать задачу именно в вашей постановке, то видится такой извратный вариант - сдвигать все оставшиеся ячейки шаблона ниже места вставки вправо (как дверь шкафа-купе), потом делать копирование, потом возвращать "дверь" обратно. Стоит ли игра таких свеч? В отчете ячейки слишком мелкие и они объединены в "по больше". Как у именованной ячейки узнать с кем она объединена? (сколько ячеек в право и сколько вниз.) А потом после вставке основной первой именованной все остальные продублировать также и после всего их объединить? |
|
14.10.2008, 12:10 | #16 |
Moderator
|
Ну-ну! Идём в Excel в редактор кода VBA по Alt+F11, пишем в окне отладки: Range("A1").Insert
Щелкаем мышкой в середине слова Insert и жмем F1 - появляется топик хелпа Читая топик, видим интересующую нас константу xlShiftDown. Копируем эту строку в окно отладки и ставим перед ней восклицательный знак (сократитель команды Print), после чего нажимаем Enter Ну это-то конечно. Типа "пусть работает железная пила" См. MergeArea - cвойство объекта Range. Возвращает тоже Range. Например, если объединены ячейки A1:C2, то Range("A1").MergeArea.Address вернет $A$1:$C$2. Еще есть булевское свойство MergeCells объекта Range - возвращает True, если ячейка входит в объединение. |
|
14.10.2008, 12:26 | #17 |
Участник
|
Еще можно воспользоваться Object Browser'ом (кнопка F2 в VBA). В разделе Globals перечислены все константы и их значения
__________________
Axapta v.3.0 sp5 kr2 |
|
14.10.2008, 12:42 | #18 |
Пенсионер
|
Цитата:
Сообщение от Poleax
Вопрос немного усложнился.
Объединены ячейки 3 шт. Общей ячейке задано имя 'test'. при использовании ..... при вставки объединенной ячейки появляется сообщение "Данная операция приведет к отмене объединения ячеек" т.е. ниже в файле Excel есть объединенные ячейки. Объединение с них снимается и в итоге данные передаваемые в именованную ячейку вставляются не в 3-ную объединенную, а самую первую. А две остальных даже не копируются вниз. Как сделать так чтоб можно было копировать и дублировать именованную ячейку без потери объединения? Это что же вы в файле перекрываете именованные объединенные диапазоны? Очень странно это, зачем тогда объединять и именовать? Если Вы хотите то что написали в первом посту, то Gustav Вам подсказал как это делать, если Вам требуется перекрывать объединенные дипазоны, то это совсем другая задача, А может Вы просто опишите Вашу задачу не кусками, а целиком и Вам возможно подскажут правильное решение.
__________________
Законы природы еще никто не отменял! А еще у меня растет 2 внучки!!! Кому интересно подробности тут: http://www.baby-shine.com/ |
|
|
За это сообщение автора поблагодарили: aidsua (1). |
14.10.2008, 13:06 | #19 |
Moderator
|
Цитата:
Код: Sub Macro1() Range("A6:C12").Insert xlShiftToRight 'xlShiftToRight = -4161 End Sub Sub Macro2() Dim rng As Range Set rng = Range("B3") rng.Insert xlShiftDown 'xlShiftDown = -4121 rng.Copy rng.Offset(-rng.Rows.Count) End Sub Sub Macro3() Range("A6:C12").Delete xlShiftToLeft 'xlShiftToLeft = -4159 End Sub После отработки Macro1 - сдвинули "дверь" вправо: После отработки Macro2 - выполнили размножение (объединенная голубая ячейка не мешает): После отработки Macro3 - вернули "дверь" назад: |
|
|
За это сообщение автора поблагодарили: aidsua (1). |
14.10.2008, 13:11 | #20 |
Модератор
|
blokva
Задача: в Excel файле есть ячейка с именем. ("TEST") оказывается она ре одинарная а состоит из нескольких, объединенных. Надо продублировать ячейку вниз целиком и полностью, с сохранением форматирования и объединений. Каждый раз при дублировании ячейки вниз в нее вставляю через цикл значение. На данный момент вставка происходит, все хорошо, кроме одного. Если ячейка состояла из нескольких то при вставке объединение теряется. Gustav Спасибо за мастер-класс по Help(у). Как мне в аксапте вытянуть этот диапазон Range("A1").MergeArea.Address чтоб потом по нему megre сделать. X++: COM comRange, comRange1, comR;
comR=comRange.MergeArea();
comR.merge(); //че то не то.. |
|