Народ, помогите, пожалуйста, "затык настиг" Попросили меня написать макрос, который переберёт по очереди все сгруппированные ячейки в выделенном диапазоне и про каждую из них спросить юзверга: "Разргуппировать или нет?" Написал я с ходу такую фигню:[vba]
Code
Sub FindMergeCells() ' перебрать все сгруппированные ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If TypeName(Selection) <> "Range" Then Exit Sub If Selection.Cells.Count <= 1 Then Exit Sub Dim rCell As Range For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells Then rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell End Sub
[/vba] Когда пользователь соглашается разгруппировать указанную ему сгруппированную ячейку, то всё отлично. А вот если он откажется, то по очереди перебираются все скрытые под группировкой ячейки и про них задаётся вопрос. Это, конечно, как борьба со злом с методологической точки зрения правильно: может быть, всё-таки устанет отказываться и согласится разгруппировать... Но по отношению к юзеру как-то не хорошо получается
Народ, помогите, пожалуйста, "затык настиг" Попросили меня написать макрос, который переберёт по очереди все сгруппированные ячейки в выделенном диапазоне и про каждую из них спросить юзверга: "Разргуппировать или нет?" Написал я с ходу такую фигню:[vba]
Code
Sub FindMergeCells() ' перебрать все сгруппированные ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If TypeName(Selection) <> "Range" Then Exit Sub If Selection.Cells.Count <= 1 Then Exit Sub Dim rCell As Range For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells Then rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell End Sub
[/vba] Когда пользователь соглашается разгруппировать указанную ему сгруппированную ячейку, то всё отлично. А вот если он откажется, то по очереди перебираются все скрытые под группировкой ячейки и про них задаётся вопрос. Это, конечно, как борьба со злом с методологической точки зрения правильно: может быть, всё-таки устанет отказываться и согласится разгруппировать... Но по отношению к юзеру как-то не хорошо получается Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 30.10.2012, 15:49
For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells and Intersect(rCell, LastMergeArea) is nothing Then set LastMergeArea = rCell.MergeArea rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell
[/vba]
Попробуй запоминать MergeArea: [vba]
Code
For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells and Intersect(rCell, LastMergeArea) is nothing Then set LastMergeArea = rCell.MergeArea rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell
Спасибо, Саня. Я уже и сам до точно такого же решения доковырялся. Вот только при первом проходе LastMergeArea = Nothing и, естественно, Intersect(rCell, LastMergeArea) даёт ошибку. Я пока сделал тупо: перед циклом назначенил равным первой ячейке выделения:[vba]
Code
Sub FindMergeCells() ' перебрать все сгруппированные ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If TypeName(Selection) <> "Range" Then Exit Sub If Selection.Cells.Count <= 1 Then Exit Sub Dim rCell As Range, rMergeArea As Range Set rMergeArea = Intersect(Selection, ActiveSheet.UsedRange)(1) For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells And Intersect(rCell, rMergeArea) Is Nothing Then Set rMergeArea = rCell.MergeArea rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell End Sub
[/vba] Но не красиво получается. Хоть и работает, но мне не нравится
Спасибо, Саня. Я уже и сам до точно такого же решения доковырялся. Вот только при первом проходе LastMergeArea = Nothing и, естественно, Intersect(rCell, LastMergeArea) даёт ошибку. Я пока сделал тупо: перед циклом назначенил равным первой ячейке выделения:[vba]
Code
Sub FindMergeCells() ' перебрать все сгруппированные ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If TypeName(Selection) <> "Range" Then Exit Sub If Selection.Cells.Count <= 1 Then Exit Sub Dim rCell As Range, rMergeArea As Range Set rMergeArea = Intersect(Selection, ActiveSheet.UsedRange)(1) For Each rCell In Intersect(Selection, ActiveSheet.UsedRange) If rCell.MergeCells And Intersect(rCell, rMergeArea) Is Nothing Then Set rMergeArea = rCell.MergeArea rCell.Select If MsgBox("Разгруппировать ячейку?", vbYesNo) = vbYes Then rCell.UnMerge End If Next rCell End Sub
[/vba] Но не красиво получается. Хоть и работает, но мне не нравитсяAlex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 30.10.2012, 16:10
Ну, на вкус и цвет все фломастеры разные. И по мне так красивше всё-таки [vba]
Code
If TypeName(Selection) <> "Range" Then Exit Sub
[/vba], тем более, что по количеству буковок почти однофигственно (у меня на 1 больше) ----------------- А по поводу [A1], так я, действительно перемудрил.
Ну, на вкус и цвет все фломастеры разные. И по мне так красивше всё-таки [vba]
Code
If TypeName(Selection) <> "Range" Then Exit Sub
[/vba], тем более, что по количеству буковок почти однофигственно (у меня на 1 больше) ----------------- А по поводу [A1], так я, действительно перемудрил.Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 30.10.2012, 17:06
Фигня какая-то получается: почему-то при отказе от разъединения ячеек выбор несколько раз прыгает с одной объединённой ячейки на другую. При этом, похоже, правильно или нет срабатывает зависит от расположения на листе ячеек, попавших в Selection
Тестаните кто-нибудь примерчик, пожалуйста.
Фигня какая-то получается: почему-то при отказе от разъединения ячеек выбор несколько раз прыгает с одной объединённой ячейки на другую. При этом, похоже, правильно или нет срабатывает зависит от расположения на листе ячеек, попавших в Selection
Нормально работает. Леш, я тут писал для unmerge однострочных ОЯ и выравнивания по центру выделения. Можно легко переделать:) [vba]
Code
Public Sub UnMergeCells() Dim c As Range, s$, fA$ Application.FindFormat.MergeCells = True With ActiveSheet.UsedRange Set c = .Find("", [a1], xlFormulas, 2, SearchFormat:=True) If Not c Is Nothing Then fA = c.Address: Do If UBound(c.MergeArea.Formula) = 1 Then s = c.MergeArea.Address: c.UnMerge Range(s).HorizontalAlignment = 7 End If Set c = .Find("", c, xlFormulas, 2, SearchFormat:=True) Loop While Not c Is Nothing And c.Address <> fA End If End With End Sub
[/vba]
Нормально работает. Леш, я тут писал для unmerge однострочных ОЯ и выравнивания по центру выделения. Можно легко переделать:) [vba]
Code
Public Sub UnMergeCells() Dim c As Range, s$, fA$ Application.FindFormat.MergeCells = True With ActiveSheet.UsedRange Set c = .Find("", [a1], xlFormulas, 2, SearchFormat:=True) If Not c Is Nothing Then fA = c.Address: Do If UBound(c.MergeArea.Formula) = 1 Then s = c.MergeArea.Address: c.UnMerge Range(s).HorizontalAlignment = 7 End If Set c = .Find("", c, xlFormulas, 2, SearchFormat:=True) Loop While Not c Is Nothing And c.Address <> fA End If End With End Sub
Привет, Серёга. У тебя мой пример после выбора всего листа нормально работает? И по несколько раз одну и ту же ячейку не предлагает разгруппировать если всё время отказываться? Я в шоке! А по поводу [vba]
Code
Application.FindFormat.MergeCells
[/vba] так ты это круто сделал. Нужно будет попробовать разобраться (просто я с методами Find не очень дружу )
Привет, Серёга. У тебя мой пример после выбора всего листа нормально работает? И по несколько раз одну и ту же ячейку не предлагает разгруппировать если всё время отказываться? Я в шоке! А по поводу [vba]
Code
Application.FindFormat.MergeCells
[/vba] так ты это круто сделал. Нужно будет попробовать разобраться (просто я с методами Find не очень дружу )Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 30.10.2012, 21:00
Лена, абсолютно точно найдена закономерность! Браво! Если объединённые ячейки имеют общие строки, то глючит. А если нет, то всё нормально! Вот теперь бы понять, где тут собака порылась?
А по поводу метода Find,Серёга, так я с ним обязательно поразбираюсь завтра. Да и я не думаю, что перебор ячеек без селекта так уж долог если учесть, что ячейки объединяются пользователем в ручную и потому их не может быть огромное число. Но хочется понять почему мой метод глючит (ну просто для эрудиции в конце-концов).
Лена, абсолютно точно найдена закономерность! Браво! Если объединённые ячейки имеют общие строки, то глючит. А если нет, то всё нормально! Вот теперь бы понять, где тут собака порылась?
А по поводу метода Find,Серёга, так я с ним обязательно поразбираюсь завтра. Да и я не думаю, что перебор ячеек без селекта так уж долог если учесть, что ячейки объединяются пользователем в ручную и потому их не может быть огромное число. Но хочется понять почему мой метод глючит (ну просто для эрудиции в конце-концов).Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Вторник, 30.10.2012, 21:25
Sub UnMergeInRangeSelection() Dim MAreas As New Collection Dim SRng As Range, Cell As Range ' On Error Resume Next Set SRng = Selection If SRng Is Nothing Then Err.Clear Exit Sub End If Set SRng = Intersect(SRng, ActiveSheet.UsedRange) For Each Cell In SRng If Cell.MergeCells Then MAreas.Add Cell.MergeArea, Cell.MergeArea.Address Next On Error GoTo 0 If MAreas.Count > 0 Then For Each Cell In MAreas Cell.Select If MsgBox(Cell.Address, vbYesNo + vbDefaultButton2, "Разъединить ?") = vbYes Then Cell.UnMerge Next Else MsgBox "В выбранном диапазоне нет объединенных ячеек.", , "" End If End Sub
[/vba]
Вариант: [vba]
Code
Sub UnMergeInRangeSelection() Dim MAreas As New Collection Dim SRng As Range, Cell As Range ' On Error Resume Next Set SRng = Selection If SRng Is Nothing Then Err.Clear Exit Sub End If Set SRng = Intersect(SRng, ActiveSheet.UsedRange) For Each Cell In SRng If Cell.MergeCells Then MAreas.Add Cell.MergeArea, Cell.MergeArea.Address Next On Error GoTo 0 If MAreas.Count > 0 Then For Each Cell In MAreas Cell.Select If MsgBox(Cell.Address, vbYesNo + vbDefaultButton2, "Разъединить ?") = vbYes Then Cell.UnMerge Next Else MsgBox "В выбранном диапазоне нет объединенных ячеек.", , "" End If End Sub
For Each area In Intersect(Selection, ActiveSheet.UsedRange).areas For Each cell In area If cell.MergeCells And cell.Address = cell.MergeArea.Cells(1).Address Then If MsgBox(cell.Address, vbYesNo + vbDefaultButton2, "Unmerge?") = vbYes Then cell.UnMerge End If End If Next Next End Sub
[/vba]
[vba]
Code
Sub UnMerge() Dim area As Range Dim cell As Range
If Not TypeOf Selection Is Range Then Exit Sub
For Each area In Intersect(Selection, ActiveSheet.UsedRange).areas For Each cell In area If cell.MergeCells And cell.Address = cell.MergeArea.Cells(1).Address Then If MsgBox(cell.Address, vbYesNo + vbDefaultButton2, "Unmerge?") = vbYes Then cell.UnMerge End If End If Next Next End Sub
Вот честно говорю: утром по пути на работу так и подумал, что дело скорее всего в Areas и нужно будет делать двойной цикл! Спасибо, nerv, сейчас попробую. (только, естественно, в соответствии с рекомендациями классиков, не буду использовать имён процедур и переменных, совпадающих с названиями свойств и методов объектов VBA )
Вот честно говорю: утром по пути на работу так и подумал, что дело скорее всего в Areas и нужно будет делать двойной цикл! Спасибо, nerv, сейчас попробую. (только, естественно, в соответствии с рекомендациями классиков, не буду использовать имён процедур и переменных, совпадающих с названиями свойств и методов объектов VBA )Alex_ST
Полирнул вариант с Areas. Теперь всё нормально работает[vba]
Code
Sub FindMergeCells() ' перебрать все объединённые ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If Not TypeOf Selection Is Range Then Exit Sub If Intersect(Selection, ActiveSheet.UsedRange) Is Nothing Then Exit Sub Dim rArea As Range, rCell As Range Dim rSel As Range: Set rSel = Selection 'только для того, чтобы можно было восстановить Selection после обработки For Each rArea In Intersect(Selection, ActiveSheet.UsedRange).Areas For Each rCell In rArea If rCell.MergeCells And rCell.Address = rCell.MergeArea.Cells(1).Address Then rCell.Select If MsgBox("Разгруппировать ячейку " & rCell.Address(0, 0) & " ?", vbYesNo + vbQuestion, "Найдена объединённая ячейка") = vbYes Then rCell.UnMerge End If Next rCell Next rArea rSel.Select ' восстановить Selection после обработки End Sub
[/vba] одно маленькое неудобство: при выделении столбца не обрабатываются объединённые ячейки, левая верхняя ячейка которых не входит в выделение (см.пример)
Полирнул вариант с Areas. Теперь всё нормально работает[vba]
Code
Sub FindMergeCells() ' перебрать все объединённые ячейки в выделенном диапазоне и предложить пользователю их разгруппировать If Not TypeOf Selection Is Range Then Exit Sub If Intersect(Selection, ActiveSheet.UsedRange) Is Nothing Then Exit Sub Dim rArea As Range, rCell As Range Dim rSel As Range: Set rSel = Selection 'только для того, чтобы можно было восстановить Selection после обработки For Each rArea In Intersect(Selection, ActiveSheet.UsedRange).Areas For Each rCell In rArea If rCell.MergeCells And rCell.Address = rCell.MergeArea.Cells(1).Address Then rCell.Select If MsgBox("Разгруппировать ячейку " & rCell.Address(0, 0) & " ?", vbYesNo + vbQuestion, "Найдена объединённая ячейка") = vbYes Then rCell.UnMerge End If Next rCell Next rArea rSel.Select ' восстановить Selection после обработки End Sub
[/vba] одно маленькое неудобство: при выделении столбца не обрабатываются объединённые ячейки, левая верхняя ячейка которых не входит в выделение (см.пример)Alex_ST
Кстати, для эстетов , вместо If TypeName(Selection) <> "Range" Then Exit Sub красивше If not TypeOf Selection Is Range Then Exit Sub
никаких "красивше". Так правильно. Потому, что в данном случае нужно проверить тип объекта, а не получить название типа.
Quote (Alex_ST)
что дело скорее всего в Areas и нужно будет делать двойной цикл!
Areas тут не при чем. Это на случай выделения несмежных диапазонов.
Quote (Alex_ST)
(только, естественно, в соответствии с рекомендациями классиков, не буду использовать имён процедур и переменных, совпадающих с названиями свойств и методов объектов VBA
глупости. Если имя не совпадает с глобальным и соответствует правилам наименования, его можно использовать. Т.к. то, что скрыто внутри объекта, там и останется. Зато читаемость твоего кода заметно ухудшилась. Впрочем, даже если имя совпадает с глобальным, его тоже можно использовать, но в этом случае оно (глобальное) будет перекрыто локальным: [vba]
Code
Sub io() Dim Range As Range Range("A1").Select ' err: локальное имя перекрыло глобальное End Sub
[/vba] Жду ваши возражения.
Еще. Alex_ST, ты специально делаешь свой код не читаемым? Зачем лепить все в кучу? Если очень хочется, можно воспользоваться минификатором или обсфукатором.
Quote (Alex_ST)
If Intersect(Selection, ActiveSheet.UsedRange) Is Nothing Then Exit Sub
Нафиг не надо, т.к. в первый цикл по областям уже включена эта проверка.
КЭП: дело в [vba]
Code
cell.Address = cell.MergeArea.Cells(1).Address
[/vba]
всем привет
Quote (Формуляр)
Кстати, для эстетов , вместо If TypeName(Selection) <> "Range" Then Exit Sub красивше If not TypeOf Selection Is Range Then Exit Sub
никаких "красивше". Так правильно. Потому, что в данном случае нужно проверить тип объекта, а не получить название типа.
Quote (Alex_ST)
что дело скорее всего в Areas и нужно будет делать двойной цикл!
Areas тут не при чем. Это на случай выделения несмежных диапазонов.
Quote (Alex_ST)
(только, естественно, в соответствии с рекомендациями классиков, не буду использовать имён процедур и переменных, совпадающих с названиями свойств и методов объектов VBA
глупости. Если имя не совпадает с глобальным и соответствует правилам наименования, его можно использовать. Т.к. то, что скрыто внутри объекта, там и останется. Зато читаемость твоего кода заметно ухудшилась. Впрочем, даже если имя совпадает с глобальным, его тоже можно использовать, но в этом случае оно (глобальное) будет перекрыто локальным: [vba]
Code
Sub io() Dim Range As Range Range("A1").Select ' err: локальное имя перекрыло глобальное End Sub
[/vba] Жду ваши возражения.
Еще. Alex_ST, ты специально делаешь свой код не читаемым? Зачем лепить все в кучу? Если очень хочется, можно воспользоваться минификатором или обсфукатором.
Quote (Alex_ST)
If Intersect(Selection, ActiveSheet.UsedRange) Is Nothing Then Exit Sub
Нафиг не надо, т.к. в первый цикл по областям уже включена эта проверка.
Alex_ST, ты специально делаешь свой код не читаемым?
nerv, ты первый, кто назвал мой код не читаемым. Может, не в коде дело, а в том, кто его читает?
Quote (nerv)
Нафиг не надо
Если бы было не надо, то я бы и не ставил. Попробуй в своём коде выделить на листе диапазон, лежащий вне UsedRange и запусти свой макрос. Вылетишь в дебаггер.
Quote (nerv)
Areas тут не при чем
тут согласен. Просто сравнивать адреса я пробовал изначально, но вместо [vba]
Code
rCell.Address = rCell.MergeArea.Cells(1).Address
[/vba]писАл[vba]
Code
rCell.Address = rCell.Cells(1).Address
[/vba] вот и глючило. . . А вообще-то, смени тон, пожалуйста. Мы с тобой не близкие друзья и в пивняке общаемся.
Quote (nerv)
Alex_ST, ты специально делаешь свой код не читаемым?
nerv, ты первый, кто назвал мой код не читаемым. Может, не в коде дело, а в том, кто его читает?
Quote (nerv)
Нафиг не надо
Если бы было не надо, то я бы и не ставил. Попробуй в своём коде выделить на листе диапазон, лежащий вне UsedRange и запусти свой макрос. Вылетишь в дебаггер.
Quote (nerv)
Areas тут не при чем
тут согласен. Просто сравнивать адреса я пробовал изначально, но вместо [vba]
Code
rCell.Address = rCell.MergeArea.Cells(1).Address
[/vba]писАл[vba]
Code
rCell.Address = rCell.Cells(1).Address
[/vba] вот и глючило. . . А вообще-то, смени тон, пожалуйста. Мы с тобой не близкие друзья и в пивняке общаемся.Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Среда, 31.10.2012, 17:01
Если бы было не надо, то я бы и не ставил. Попробуй в своём коде выделить на листе диапазон, лежащий вне UsedRange и запусти свой макрос. Вылетишь в дебаггер.
был не прав
Quote (Alex_ST)
однако, без перебора по ним почему-то глючит при перекрытии по строкам
все нормально, можешь проверить
Quote (Alex_ST)
И вообще, смени тон, пожалуйста.
сори Я еще не обедал. А когда я голодный, я злой
Quote (Alex_ST)
и в пивняке общаемся
ну, для привняка то как раз нормально
по задаче: только собирать в массив/коллекцию и проверять
Quote (Alex_ST)
Если бы было не надо, то я бы и не ставил. Попробуй в своём коде выделить на листе диапазон, лежащий вне UsedRange и запусти свой макрос. Вылетишь в дебаггер.
был не прав
Quote (Alex_ST)
однако, без перебора по ним почему-то глючит при перекрытии по строкам
все нормально, можешь проверить
Quote (Alex_ST)
И вообще, смени тон, пожалуйста.
сори Я еще не обедал. А когда я голодный, я злой
Quote (Alex_ST)
и в пивняке общаемся
ну, для привняка то как раз нормально
по задаче: только собирать в массив/коллекцию и проверятьnerv
Чебурашка стал символом олимпийских игр. А чего достиг ты? Тишина - самый громкий звук