|  14.10.2008, 13:13 | #21 | 
| Модератор | 
			
			Gustav  то что на картинках красное, она и есть объединенная ячейка.
		 | 
|  | 
|  14.10.2008, 13:36 | #22 | 
| Moderator | Цитата: Код: Sub VBA_Macro4()
    Dim comRange As Range
    Dim comR As Range
    Dim addr As String
    
    Set comRange = Worksheets(1).Range("B2:D4")
    
    addr = comRange.Range("A1").MergeArea.Address
    'здесь Range("A1") говорит о том, что из объединенной ячейки надо взять
    'левую верхнюю ячейку диапазона - не путать с ячейкой A1 всего листа
    'без этого просто comRange.MergeArea.Address вызовет ошибку
    
    '...........................
    
    Set comR = Worksheets(1).Range(addr)
    comR.Merge
End Sub | 
|  | 
|  14.10.2008, 13:58 | #23 | 
| Moderator | Цитата: Код:  
Sub Macro22()
    Dim rng As Range
    Set rng = Range("B2:C4")
    
    If rng.MergeCells Then
        Set rng = rng.Range("A1").MergeArea
    End If
    
    rng.Insert xlShiftDown 'где константа xlShiftDown = -4121
    rng.Copy rng.Offset(-rng.Rows.Count)
End SubP.S. Соответственно, добавка в метод: X++: if (comRange.MergeCells()) { comRange = comRange.Range('A1'); comRange = comRange.MergeArea(); } | 
|  | 
|  14.10.2008, 14:16 | #24 | 
| Модератор | X++: void copyAndInsertBlock(str _bookMark, int _workSheet = 1) { #define.xlShiftDown(-4121) COM comRange, comRange1, comR; int rowsNumber, colsNumber; str s; ; if (! m_comDocument) throw error(strFmt("@DIS6401", this.getApplicationName())); comRange = this.findRange(_bookMark, _workSheet); if (! comRange) { return; } rowsNumber = any2int(COM::createFromObject( comRange.Rows() ).Count()); // comR=comRange.MergeArea(); //s=comRange.MergeArea.Address; comRange.Insert( #xlShiftDown ); comRange1 = comRange.Offset(-rowsNumber); /* if (comRange.MergeCells()) { comRange1 = comRange.Range(_bookMark); comRange1 = comRange.MergeArea(); } */ comRange.Copy(comRange1); } | 
|  | 
|  14.10.2008, 14:19 | #25 | 
| Moderator | 
			
			Да уже всё распутано, вроде. Глаза постом выше поднимите   if (comRange.MergeCells()) перед Insert надо поставить и не comRangeОдин, а просто comRange там - идёт преобразование comRange по ходу. Вот ваш метод: 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; } if (comRange.MergeCells()) { comRange = comRange.Range('A1'); comRange = comRange.MergeArea(); } rowsNumber = any2int(COM::createFromObject( comRange.Rows() ).Count()); comRange.Insert( #xlShiftDown ); // и выше добавить: #define.xlShiftDown(-4121) comRange1 = comRange.Offset(-rowsNumber); comRange.Copy(comRange1); } | 
|  | |
| За это сообщение автора поблагодарили: gl00mie (5). | |
|  14.10.2008, 16:12 | #26 | 
| Модератор | 
			
			какой интересный код получился Gustav Спасибо. Про 'A1' конечно забавно..
		 | 
|  | 
|  14.10.2008, 17:20 | #27 | 
| Moderator | 
			
			Ага, c Excel вообще весело   Любой прямоугольный диапазон из нескольких ячеек можно рассматривать как виртуальный лист внутри рабочего листа (worksheet) со своим локальным началом "A1" в левом верхнем углу этого диапазона. Причем диапазонам можно произвольно неограниченно "вкладываться" друг в друга (наверное, есть системные ограничения, я не проверял). Поэтому запись Range("B2").Range("B2").Range("B2").Range("B2").Range("B2").Range("B2").Range("B2") - вовсе не бред сумасшедшего, а ссылка на ячейку H8:  ? Range("B2").Range("B2").Range("B2").Range("B2").Range("B2").Range("B2").Range("B2").Address $H$8 | 
|  | 
|  14.10.2008, 18:08 | #28 | 
| Модератор | 
			
			Gustav еще немного вопросов. (конечно понимаю что я тебя замучал, но все таки) 1) comRange.Insert( #xlShiftDown ); работает так же как и comRange.Insert(); Так зачем #xlShiftDown указывать? 2) Если ли какой нибудь метод в котором можно выставить по умолчание согласие на - "Данная операция приведет к отмене объединения ячеек". Чтоб сообщение не появлялось. 3) Как можно написать еще один метод на примере copyAndInsertBlock в котором именованная ячейка переползает в нижнею без вставки новой ячейки? Т.е. есть ячейка "test" в нее вставили значение, и имя ячейки переместилось вниз (хоть скопированием данных ячейки хоть без) | 
|  | 
|  14.10.2008, 18:40 | #29 | 
| Moderator | Цитата: 
		
			Сообщение от Poleax
			   Gustav еще немного вопросов. (конечно понимаю что я тебя замучал, но все таки) 1) comRange.Insert( #xlShiftDown ); работает так же как и comRange.Insert(); Так зачем #xlShiftDown указывать? 2) Если ли какой нибудь метод в котором можно выставить по умолчание согласие на - "Данная операция приведет к отмене объединения ячеек". Чтоб сообщение не появлялось. 3) Как можно написать еще один метод на примере copyAndInsertBlock в котором именованная ячейка переползает в нижнею без вставки новой ячейки? Т.е. есть ячейка "test" в нее вставили значение, и имя ячейки переместилось вниз (хоть скопированием данных ячейки хоть без)  2. Есть. Выражаюсь на VBA. Надо поставить Application.DisplayAlerts = False перед Insert и потом обязательно восстановить после него (ну или после всего цикла в другом методе) Application.DisplayAlerts = True 3. Не очень понял пока. У нас она и так съезжает. Зачем это надо? Чтобы все время в "test" писать? Типа не менять оператор doc.insertValue('test', ...) ? | 
|  | 
|  14.10.2008, 19:19 | #30 | 
| Модератор | Цитата: 
		
			3. Не очень понял пока. У нас она и так съезжает. Зачем это надо? Чтобы все время в "test" писать? Типа не менять оператор doc.insertValue('test', ...) ?
		
	 Победить то объединенную ячейку удалось. Но красота пропала в шаблоне. Фокус и задание в том, что есть одна строка в ней 4 именованных ячейки. Эту строку мы размножаем и по циклу заполняем последовательно столбцы. Если проявляется новое значение в 1 столбце надо вставить строку. ну и соответственно все значения для остальных столбцов. Идея с copyAndInsertBlock отрабатывает прекрасно кроме формата ниже лежащих строк :-( но если вы вставляем строку то и все 4 именованных ячейки переходят на строку ниже... :-) вызов расчета столбцов сделан отдельно. т.е. нельзя за один так цикла расчитать 4 значения для 4 ячеек. А получается что цикл пробегает только по одному столбцу. В итоге.. решение пока где то рядом. | 
|  | 
|  14.10.2008, 19:42 | #31 | 
| Модератор | Мысль в картинках... 
			
			Есть шаблон. В нем есть место где строчка. В данном примере она в Excel № 76 (картинка 1) Работает вставка пока так с использованием copyAndInsertBlock и InsertRow. (картинка 2) Как видно текст сместился по всем столбцам вниз. НО форматирование осталось  (Картинка 3) В конечном варианте должно появится такое. (Картинка 4) если использовать copyAndInsertBlock, то данные там где надо, то высота строк сползает.   Может у кого есть светлая мысль? Последний раз редактировалось Poleax; 14.10.2008 в 19:55. | 
|  | 
|  14.10.2008, 19:48 | #32 | 
| Moderator | 
			
			Размышляя, набросал тут 3 демонстрационных цикла вывода в Excel (чуть позже добавил четвертый): X++: static void Job_TestFourLoops(Args _args) { ComExcelDocument_RU doc = new ComExcelDocument_RU(); COM xlApp; COM wbook; COM range, range1, range2; int i; #define.xlDown(-4121) #define.xlPasteFormats(-4122) ; doc.NewFile(); wbook = doc.getComDocument(); xlApp = wbook.Parent(); // ВАРИАНТ 1 // тестовая подготовка первой ячейки с именем и форматом range = xlApp.Range('B3'); range.Name('test'); COM::createFromObject( range.Font() ).Bold(true); // все время писать в test, смещая его вниз за счет вставки строк // и перекидывая формат на ячейку выше for (i=1;i<=10;i++) { doc.insertValue('test', i); doc.copyAndInsertRange('test'); } doc.insertValue('test',''); // ВАРИАНТ 2 // тестовая подготовка первой ячейки с именем и форматом range = xlApp.Range('B15'); range.Name('test2'); COM::createFromObject( range.Interior() ).ColorIndex(36); // прописывание значений range = xlApp.Range('test2'); // как если бы букмарк уже существовал в файле for (i=1;i<=10;i++) { // в цикле только пишем значения, не форматируем // адрес зависит от счетчика цикла range1 = COM::createFromVariant( range.Item(i,1) ); doc.insertValue( range1.Address() ,i); } // в конце скопировать формат первой ячейки на все остальные range2 = xlApp.Range(range, range.End(#xlDown)); range.Copy(); range2.PasteSpecial(#xlPasteFormats); xlApp.CutCopyMode(false); // ВАРИАНТ 3 // тестовая подготовка первой ячейки с именем и форматом range = xlApp.Range('B27'); range.Name('test3'); COM::createFromObject( range.Font() ).Bold(true); COM::createFromObject( range.Interior() ).ColorIndex(5); // прописывание значений range = xlApp.Range('test3'); // как если бы букмарк уже существовал в файле range1 = range; for (i=1;i<=10;i++) { // в цикле только пишем значения, не форматируем // адрес не зависит от счетчика цикла doc.insertValue( range1.Address(), i); range1 = range1.Offset(1,0); } // в конце скопировать формат первой ячейки на все остальные range2 = xlApp.Range(range, range.End(#xlDown)); range.Copy(); range2.PasteSpecial(#xlPasteFormats); xlApp.CutCopyMode(false); // ВАРИАНТ 4 // тестовая подготовка первой ячейки с именем и форматом range = xlApp.Range('B39'); range.Name('test4'); COM::createFromObject( range.Borders() ).LineStyle(1); COM::createFromObject( range.Font() ).Bold(true); // прописывание значений range = xlApp.Range('test4'); for (i=1;i<=10;i++) { // вставляем выше 'test4' строку с форматированием doc.copyAndInsertRangeNew('test4'); // получаем объектную переменную для строки на одну выше 'test4' range1 = range.Offset(-1,0); // пишем в строку выше 'test4' doc.insertValue( range1.Address(), i); // range c 'test4' на каждом шаге опускается ниже и ниже // а range1 следует за ним строкой выше, олицетворяя собой новую вставленную строку // которая рождается с исходными (пустыми) значениями 'test4', а потом переписывается текущими } // в конце остается пустая строка с 'test4', которую можно удалить doc.deleteRow(range.Row()); } | 
|  | 
|  14.10.2008, 20:25 | #33 | 
| Модератор | 
			
			хм.. 3 вариант мне понравился. Сейчас с ним что то придумаю.. Спасибо за идею
		 | 
|  | 
|  14.10.2008, 23:47 | #34 | 
| Moderator | 
			
			Думаю, совсем должен понравиться 4-й вариант: X++: // ВАРИАНТ 4 // прописывание значений range = xlApp.Range('test'); for (i=1;i<=10;i++) { // вставляем выше 'test'а строку с форматированием doc.copyAndInsertRange('test'); // получаем объектную переменную для строки на одну выше 'test'а range1 = range.Offset(-1,0); // пишем в строку выше 'test'а doc.insertValue( range1.Address(), i); // range c 'test' на каждом шаге опускается ниже и ниже // а range1 следует за ним строкой выше, олицетворяя собой новую вставленную строку // которая рождается с исходными значениями 'test'а, а потом переписывается текущими } // в конце остается пустая строка с 'test', которую можно удалить | 
|  | 
|  15.10.2008, 10:15 | #35 | 
| Модератор |  вчера вечерком, как и говорил покопался с 3 вариантом. Все удачно получилось. Использовал InsertRow и смещение относительно вставки именованной ячейки. Отчет выглядит как я хотел. Gustav С меня пиво! Спасибо за терпение! | 
|  | 
|  15.10.2008, 10:39 | #36 | 
| Moderator | |
|  | 
|  15.10.2008, 11:05 | #37 | 
| Модератор | 
			
			4 я увидел сегодня утром.  в третий использовал приблизительно так: X++: static void Job107(Args _args) { ComExcelDocument_RU doc = new ComExcelDocument_RU(); COM xlApp; COM wbook; COM range, range1, range2; int i,n; ; doc.NewFile(); wbook = doc.getComDocument(); xlApp = wbook.Parent(); // ВАРИАНТ 3 // тестовая подготовка первой ячейки с именем и форматом range = xlApp.Range('B2'); range.Name('test'); range = xlApp.Range('test'); n=doc.getCellName_RowNum("test"); range1 = range; for (i=1;i<=10;i++) { // в цикле только пишем значения, не форматируем // адрес не зависит от счетчика цикла doc.insertRow(n,1,i); doc.insertValue( range1.Address(), i); range1 = range1.Offset(1,0); } } | 
|  | 
|  15.10.2008, 14:06 | #38 | 
| Moderator | Цитата: 
		
			Сообщение от Poleax
			   X++: range = xlApp.Range('test'); n=doc.getCellName_RowNum("test"); range1 = range; for (i=1;i<=10;i++) { // в цикле только пишем значения, не форматируем // адрес не зависит от счетчика цикла doc.insertRow(n,1,i); doc.insertValue( range1.Address(), i); range1 = range1.Offset(1,0); }  X++: range = xlApp.Range('test'); //n=doc.getCellName_RowNum("test"); n = range.Row(); // раз уж переменную range определили, то чего так далеко за строкой лазить :) for (i=1;i<=10;i++) { // поменял операции местами для удобства понимания: // т.е. сначала записываем значение, а потом добавляем строку ниже doc.insertValue(any2str(COM::createFromVariant(range.Item(i, 1)).Address()), i); doc.insertRow(n, 1, i); } // удаляем последнюю строку - она всегда лишняя (здесь i=11) doc.deleteRow(any2int(COM::createFromVariant(range.Item(i, 1)).Row())); // после цикла ячейка test так и остается первой (верхней) ячейкой обработанного диапазона | 
|  |