Excel vba только видимые ячейки в excel

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#1

21.02.2019 16:53:42

Здравствуйте.

Имеется файл с двумя листами — «НетФильтра» и «ЕстьФильтр».

На первом листе имеется таблица и кнопка с кодом:

Код
Sub НетФильтра()
    Range([A1].Offset(1, 2).Resize(2, 1).Address).Select
End Sub

Он выделяет две ячейки сразу под надписью «Числитель».

На втором листе имеется аналогичная первому листу таблица, но с фильтром (скрыты некоторые строки) и кнопка с кодом:

Код
Sub ЕстьФильтр()
    Range([A1].Offset(1, 2).Resize(2, 1).SpecialCells(xlCellTypeVisible).Address).Select
End Sub

Мною подразумевалось, что

SpecialCells(xlCellTypeVisible)

будет выделять только видимые ячейки, но это не так — выдается ошибка, мол нет ячеек по условию.

Подскажите плиз, как произвести выделение по видимым ячейкам на втором листе в рамках текущего кода (это важно, т.к. код будет использоваться в формуле)? При условии, что начальная ячейка — А2 (как и видно в коде), и что фильтр может быть разным, то есть вместо

Resize(2, 1)

в коде должно быть выделение до конца видимых ячеек столбца.

Итоговый вид, как я предполагаю, должен быть примерно таким:

Код
Range([A1].Offset(1, 2).Selection.End(xlDown).SpecialCells(xlCellTypeVisible).Address).Select

Да, он неправильный, но суть, надеюсь понятна — смещение от ячейки A1 вправо на два столбца и одну ячейку вниз, и дальнейшее выделение вниз до первой пустой видимой ячейки.

Прикрепленные файлы

  • Книга1.xlsm (21.11 КБ)

Изменено: andronus21.02.2019 17:21:53

 

ocet p

Пользователь

Сообщений: 438
Регистрация: 24.03.2018

#2

21.02.2019 17:36:31

Попробуйте:

Код
Sub естьфильтр()
    'Range([A1].Offset(1, 2).Resize(2, 1).SpecialCells(xlCellTypeVisible).Address).Select
    
    With ActiveSheet.Range("A1").CurrentRegion
        .Offset(1, 2).Resize(.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible).Select
    End With
End Sub
 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

ocet p, а вы пробовали? У меня ошибка «Object Required».
К тому же, ваш код не подходит по условию, что я писал. По сути, важен код именно между скобками

Range().Select

, потому что, повторюсь, значение из скобок будет использоваться в формуле. Селект тут просто для проверки, что выделяется верная область.

Изменено: andronus21.02.2019 17:45:54

 

Anchoret

Пользователь

Сообщений: 1059
Регистрация: 01.01.1970

Anchoret

#4

21.02.2019 18:26:15

andronus, в пошаговом режиме выполните след.код:

Код
Sub aaa()
Set aa = Intersect(Columns("A:C"), ActiveSheet.UsedRange).SpecialCells(xlCellTypeVisible)
For Each bb In Intersect(aa, Columns(1))
t = bb.Address
Next
End Sub

Изменено: Anchoret21.02.2019 18:28:56

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#5

21.02.2019 18:34:35

Anchoret, прошу, прочтите еще раз внимательнее мои слова — нужно изменить код только в скобках Range().Select, потому что это значение будет применяться в формуле. Он должен выглядеть как-то так:

Код
Range([A1].Offset(1, 2).Selection.End(xlDown).SpecialCells(xlCellTypeVisible).Address).Select

Вот с

Range([A1].Offset(1, 2).Address).Select

всё нормально. Нужно всего лишь (просто я не знаю как):
1. После

Offset(1, 2)

добавить выделение вниз до окончания непрерывных данных.
2. После №1 добавить условие выделения только видимых ячеек. Без этого, кстати, можно обойтись, если в №1 всё нормально будет.

Я не верю, что нельзя сделать макросом то, что я могу сделать руками. Я перерыл гугл, кучу зарубежных сайтов, справок и прочего. На вас последняя надежда…

Изменено: andronus21.02.2019 18:35:15

 

Anchoret

Пользователь

Сообщений: 1059
Регистрация: 01.01.1970

Anchoret

andronus, Вы лучше скажите зачем Вам формула через макрос, когда все можно сделать макросом?

Ну и как предположил в прошлой Вашей теме структура файла примера явно отличается от структуры файла, где это все планируется применить.
Вместо попыток почесать левую ногу через голову лучше расскажите (если действительно хотите решить свою задачу) что Вы пытаетесь добиться всеми этими манипуляциями. Лично я пока смысла в них не вижу…

Изменено: Anchoret21.02.2019 18:48:48

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#7

21.02.2019 18:55:29

Anchoret, это совсем неважно, но поясняю. Есть задача, в рамках которой в ячейки столбца А будут вставляться формулы, содержащие в себе суммы значений выделенных диапазонов, вот так:

Код
FormulaResult.Range("A2").Value = "Выделение числителя / Выделение знаменателя"

Но т.к. могут отфильтровываться некоторые строки, то нельзя использовать жестко объявленные диапазоны типа

Range(«C1:C2»)

или изменение размеров выделения типа

Resize(2, 1)

.

Изменено: andronus21.02.2019 18:56:06

 

Anchoret

Пользователь

Сообщений: 1059
Регистрация: 01.01.1970

Anchoret

#8

21.02.2019 19:00:50

andronus,не правильный ответ. Какую задачу Вы пытаетесь решить с помощью этих манипуляций?

Для указанного выше действа (точкой отсчета является активная ячейка):

Код
Sub bbb()
Dim aa As Range, a&, bb As Range
Set aa = Intersect(ActiveCell.EntireRow, Columns(3))
a = aa.Row + 1: Set bb = aa.Offset(, -1)
Do While Cells(a, 3).EntireRow.Hidden = True
  a = a + 1
Loop
Set aa = Union(aa, Cells(a, 3)): aa.Select
bb.Offset(, -1).Formula = "=" & "(" & "sum(" & aa.Address & "))" & "/" & bb.Address
End Sub

Изменено: Anchoret21.02.2019 19:19:40

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

Anchoret, вставка формулы в столбец. В формуле значения числителя и знаменателя берутся из выделений.
У меня уже готово решение, если на листе нет строк, скрытых фильтром. А если с фильтром, то беда, посему осталось только выяснить, как в

Range([A1].Offset(1, 2).Address).Select

:
1. После

Offset(1, 2)

добавить выделение вниз до окончания непрерывных данных.
2. После №1 добавить условие выделения только видимых ячеек. Без этого, кстати, можно обойтись, если в №1 всё нормально будет.

Я уже повторяюсь.

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

Anchoret, у вас прям целый саб, но он не нужен, к сожалению.
Вы знаете, как в Range([A1].Offset(1, 2).Address).Select добавить после оффсета выделение вниз до окончания непрерывных данных?
Или это в принципе невозможно? В чем я сильно сомневаюсь.

 

Anchoret

Пользователь

Сообщений: 1059
Регистрация: 01.01.1970

Anchoret

#11

21.02.2019 20:03:29

andronus, все по последнему вопросу. наслаждайтесь:

Код
Set bb = Range(Cells([A1].Offset(1, 2).Row, [A1].Offset(1, 2).Column), Cells([A1].Offset(1, 2).Row + Range(Cells([A1].Offset(1, 2).Row, [A1].Offset(1, 2).Column), Cells(Cells(Rows.Count, [A1].Offset(1, 2).Column).End(xlUp).Row, [A1].Offset(1, 2).Column)).SpecialCells(xlVisible).Rows.Count - 1, [A1].Offset(1, 2).Column))
t = bb.Address

Но если строка

Код
[A1].Offset(1, 2).Row

будет скрыта (2-я строка) фильтром или руками, то выдаст ошибку.
Можно еще усложнить — от первой не скрытой строки считая от второй строки и до первой скрытой строки по столбцу «C»:

Код
Set bb = Range(Cells(Range(Cells([A1].Offset(1, 2).Row, [A1].Offset(1, 2).Column), Cells(Cells(Rows.Count, _
    [A1].Offset(1, 2).Column).End(xlUp).Row, [A1].Offset(1, 2).Column)).SpecialCells(xlVisible).Row, _
    [A1].Offset(1, 2).Column), Cells([A1].Offset(1, 2).Row + Range(Cells([A1].Offset(1, 2).Row, [A1].Offset(1, 2).Column), _
    Cells(Cells(Rows.Count, [A1].Offset(1, 2).Column).End(xlUp).Row, [A1].Offset(1, 2).Column)).SpecialCells(xlVisible).Rows.Count - 1, [A1].Offset(1, 2).Column))
t = bb.Address: bb.Select

Изменено: Anchoret21.02.2019 20:38:41

 

ocet p

Пользователь

Сообщений: 438
Регистрация: 24.03.2018

andronus, хочете или не хочете, надо это сделать циклом, используя например «Areas», потому что вы никогда не будете знали которые строки будут скрытыми а которые нет, это зависит от критериев фильтрации. Тут для вас инфо как использовать «Areas»:

https://www.planetaexcel.ru/forum/index.php?PAGE_NAME=read&FID=1&TID=114353&…

Смотрите #5 — Jack Famous

… или может #4 — Nordheim … (?) … без «Areas»

Изменено: ocet p21.02.2019 21:16:04

 

RAN

Пользователь

Сообщений: 7091
Регистрация: 21.12.2012

#13

21.02.2019 21:46:16

Код
Sub ЕстьФильтр()
    With ActiveSheet.AutoFilter.Range
        x = Range(.Item(1).Offset(1, 2).Resize(, 1), .Item(1).Offset(1, 2).Resize(, 1).End(xlDown)).SpecialCells(xlCellTypeVisible).Address
    End With
End Sub

Изменено: RAN21.02.2019 23:01:01

 

k61

Пользователь

Сообщений: 2441
Регистрация: 21.12.2012

#14

22.02.2019 05:07:18

Код
Sub ЕстьФильтр_1()
With ActiveSheet.AutoFilter.Range
x = .Columns(3).SpecialCells(2, 1).SpecialCells(12).Address
End With
End Sub
 

Paul Zealand

Пользователь

Сообщений: 97
Регистрация: 01.01.2017

#15

22.02.2019 06:06:39

Код
   1 ActiveSheet.AutoFilter.Range.Offset(1, 2).SpecialCells(xlCellTypeVisible).Select
   2 Selection.Resize(2, 1).Select

такой еще чутка кривовато-страноватый способ. Ну, мало ли. Вдруг подойдет.

Изменено: Paul Zealand22.02.2019 06:07:01

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#16

22.02.2019 11:24:06

Цитата
Anchoret написал:
все по последнему вопросу. наслаждайтесь:

Не работает.
RAN, тоже не работает.
k61, тоже не работает

Всем спасибо за участие. С сожалением для себя узнал, что не всё можно сделать макросами. За ночь приняли решение делать эту часть задачи вручную, благо часть не такая большая ожидается. Еще раз всем спасибо.

 

Anchoret

Пользователь

Сообщений: 1059
Регистрация: 01.01.1970

Anchoret

andronus, не знаю куда Вы добавляли код из предложенных вариантов, но свой я тестировал на Вашем же файле-примере. Полагаю остальные участники тоже.

Тестовый файл с тремя вариантами

Изменено: Anchoret22.02.2019 15:18:20

 

Михаил Лебедев

Пользователь

Сообщений: 2855
Регистрация: 17.01.2013

#18

25.02.2019 10:18:33

Цитата
andronus написал:
Мною подразумевалось, что SpecialCells(xlCellTypeVisible) будет выделять только видимые ячейки, но это не так — выдается ошибка, мол нет ячеек по условию.

Нельзя выделить видимые ячейки, если все ячейки — невидимые. Естественно, что выдается ошибка.

Цитата
andronus написал:
В формуле значения числителя и знаменателя берутся из выделений.

… м.б. Вам просто воспользоваться функцией =ПРОМЕЖУТОЧНЫЕ.ИТОГИ() ? Она как раз использует только видимые ячейки.

Цитата
andronus написал:
С сожалением для себя узнал, что не всё можно сделать макросами. За ночь приняли решение делать эту часть задачи вручную

Вы просто не всё узнали. И отказались найти ответ на свой вопрос. А ночь — не лучшее время для принятия решений.

Изменено: Михаил Лебедев25.02.2019 10:20:38

Всё сложное — не нужно. Всё нужное — просто /М. Т. Калашников/

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#19

25.02.2019 11:58:50

Думаю, вопрос решен, найден воркараунд на зарубежных сайтах. Можно выделять первую видимую ячейку под фильтром, а дальше уже перемещаться по диапазонам.

Вариант раз:

Код
Option Explicit

Sub move_right()
NextVisible "Right"
End Sub

Sub move_left()
NextVisible "Left"
End Sub

Sub move_up()
NextVisible "Up"
End Sub

Sub move_down()
NextVisible "Down"
End Sub

Private Sub NextVisible(direction As String)
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False

Dim i As Long
Dim r As Range
Set r = ActiveCell
For i = 1 To Rows.Count
    On Error Resume Next 'If you're in A1 and try to go up one, it'll error. This skips that error.
    Select Case direction
        Case "Up"
            Set r = r.Offset(-1, 0)
        Case "Down"
            Set r = r.Offset(1, 0)
        Case "Left"
            Set r = r.Offset(0, -1)
        Case "Right"
            Set r = r.Offset(0, 1)
        Case Else
            Set r = r
    End Select
    On Error Goto 0

    If r.EntireRow.Hidden = False And r.EntireColumn.Hidden = False Then
        r.Select
        Exit Sub
    End If
Next i

Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
End Sub

Но он слишком громоздок и несколько сабов это не дело.

Вариант два, наиболее подходящий (перемещает на одну ячейку вниз даже при наличии фильтра):

Код
Dim rng As Range
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))

Изменено: andronus25.02.2019 11:59:59

 

Михаил Лебедев

Пользователь

Сообщений: 2855
Регистрация: 17.01.2013

#20

25.02.2019 12:37:56

Цитата
andronus написал:
Думаю, вопрос решен, найден воркараунд на зарубежных сайтах

смешно… :)

Цитата
andronus написал:
Вариант два, наиболее подходящий (перемещает на одну ячейку вниз даже при наличии фильтра):

Код
Dim rng As Range
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))

не верю :)

Всё сложное — не нужно. Всё нужное — просто /М. Т. Калашников/

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#21

25.02.2019 13:10:20

Цитата
Михаил Лебедев написал:
смешно…  

Что смешного в том, что интернет не ограничен Россией (по крайней мере, пока. И, как говорится, не дай бог)? На зарубежных сайтах тоже море инфы.

Цитата
Михаил Лебедев написал:
не верю

Так вы проверьте для начала. Вот такой код у меня прекрасно работает:

Код
Sub test2()

Application.DisplayAlerts = False

Dim rng As Range

Range("A3").Select
ActiveSheet.Range("$A$3:$F$23").AutoFilter Field:=1, Criteria1:="1"
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))
rng.SpecialCells(xlCellTypeVisible).Cells(1).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Offset(0, 3).Select
Selection.Merge
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlCenter
End With

Range("A3").Select
ActiveSheet.Range("$A$3:$F$23").AutoFilter Field:=1, Criteria1:="2"
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))
rng.SpecialCells(xlCellTypeVisible).Cells(1).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Offset(0, 3).Select
Selection.Merge
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlCenter
End With

Range("A3").Select
ActiveSheet.Range("$A$3:$F$23").AutoFilter Field:=1, Criteria1:="3"
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))
rng.SpecialCells(xlCellTypeVisible).Cells(1).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Offset(0, 3).Select
Selection.Merge
With Selection
    .HorizontalAlignment = xlCenter
    .VerticalAlignment = xlCenter
End With

End Sub

Осталось его в цикл запихнуть, а вот это я не знаю как.

Изменено: andronus25.02.2019 13:10:49

 

Paul Zealand

Пользователь

Сообщений: 97
Регистрация: 01.01.2017

#22

28.02.2019 09:30:31

andronus, не понимаю чего Вы мучаетесь, найти первую видимую ячейку после фильтра не составляет большого труда. Дальше если Вам нужно использовать формулу в этих ячейках, то просто объявите переменную. У меня идеентичная необходимость была на днях. Решил подобным примитивным способом.

Код
1 Dim x As Range
2 Set x = Range("A5").End(xlDown) 'в 5 строке у меня автофильтр. x в итоге всегда будет первой ячейкой когда активен фильтр
3
4 Range("A5").End(xlDown).Select 'встаешь на любой столбец, где есть автофильтр. Опускаешься на первую ячейку после фильтра
5 ActiveCell.Offset(0, 5).Select 'дальше оффсетишь куда тебе надо  
6 ActiveCell.Formula = "=VLOOKUP(" & x.Address & ",'SHEET2'!$A:$BM,19,0)" 'если в формуле надо использовать просто сделай ее переменной
7 End If

Изменено: Paul Zealand28.02.2019 09:31:27

 

Paul Zealand

Пользователь

Сообщений: 97
Регистрация: 01.01.2017

#23

28.02.2019 09:42:59

andronus, в Вашем файле такой код работает.

Код
1 Dim x, y As Range
2 Set x = Range("A1").End(xlDown)
3 Set y = x.Offset(-1, 2)
4 Set Z = y.Offset(1, 0)
5 Z.Select
6
7 Range(y, Z).Select

Изменено: Paul Zealand28.02.2019 09:43:21

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

Paul Zealand, спасибо, решение уже было найдено выше.

 

Jack Famous

Пользователь

Сообщений: 10846
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#25

28.02.2019 12:09:10

OFF:

Цитата
andronus: найден воркараунд

почему не просто «костыль» (слэнг) или дословно «обходной приём»  :D
но даже это не настолько забавно, как как эти процедуры  :D

По «задаче»:

неуменеие/нежелание правильно сформулировать проблему не даёт получить решение. С другой стороны, работает и ладно — но это путь тёмной стороны силы  ;)

Изменено: Jack Famous28.02.2019 12:11:53

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

БМВ

Модератор

Сообщений: 21376
Регистрация: 28.12.2016

Excel 2013, 2016

Jack Famous,  «костыль» (слэнг) это не обходной прием, а что-то рабочее, но ненадежное. Прямой аналог с обычным медицинским костылем, когда это помогает двигаться, но неполноценно.

По вопросам из тем форума, личку не читаю.

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#27

28.02.2019 12:26:14

Jack Famous, окей, я использовал неверный термин, по вашему мнению. Тем не менее, решение найдено, и оно рабочее на 100%, можно применять его в дальнейшем. Вот оно, повторюсь:

Код
Dim rng As Range
Set rng = Range(Cells(ActiveCell.Row + 1, ActiveCell.Column), Cells(Rows.Count, ActiveCell.Column))

Изначально задача звучала так — выделять определенные ячейки. Как — неважно. Ни один из предложенных вариантов не подошел. Зато подошел вариант, который позволяет выделить ячейку сразу под фильтром, а дальше уже от нее плясать по диапазонам. И это решение оказалось идеальным в данном случае.
Задача была, решение найдено — это ли не результат?

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

БМВ, в данном случае, абсолютно надежное и работающее решение. Я не могу показать вам код целиком (конфиденциальность на проекте), но тем не менее, всё прекрасно работает.

 

Jack Famous

Пользователь

Сообщений: 10846
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#29

28.02.2019 12:41:10

Цитата
БМВ: что-то рабочее, но ненадежное

я запомнил это именно как «обходной приём», потому что большинство «костылей», встречавшихся мне, весьма надёжны и, как раз, выполняют свою реальную/жизненную функцию, только не «помогает двигаться, но неполноценно», а «позволяет выполнять повседневные задачи, пока нога не заживёт (читай, «разрабы не подсуетятся»)»  :D
Одними из ярких примеров как раз являются «костыли» в макросах для работы с отфильтрованными диапазонами (в частности, вставка в фильтр и удаление только видимых строк)

Цитата
andronus: Задача была, решение найдено — это ли не результат?

а где вы видите противоречие с

Цитата
Jack Famous: С другой стороны, работает и ладно

Изменено: Jack Famous28.02.2019 12:45:07

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

andronus

Пользователь

Сообщений: 147
Регистрация: 06.06.2017

#30

28.02.2019 12:45:52

Цитата
Jack Famous написал:
а где вы видите противоречие с

Мне показалось, это было сказано с каким-то недоверительным подтекстом.

Впрочем, мы уже в явный оффтоп скатились.

Тему можно закрывать, всем огромное спасибо за участие!

Skip to content

Exceldome

Exceldome

This tutorial shows how to only select visible cells from a selected range using Excel or VBA

METHOD 1. Select visible cells only

EXCEL

Select a range > Home tab > Editing group > Click on Find & Select > Go To Special > Select Visible cells only > Click OK

This image represents the original data that has all of the cells visible. Range in which going hide row
This image shows the same data, however, row 4 is now hidden and is not visible. Therefore, if you select and try to copy or delete this information it will also delete the content in the hidden row. Hidden row in range
1. Select the range, which has hidden cells.
Note: in this example row 3 has been hidden in the selected range.
Select range in which row has been hidden
2. Select the Home tab. Select Home tab - Excel 2016
3. Click Find & Select in the Editing group.
4. Click Go To Special.
Click Find & Select and click Go To Special
5. Select Visible cells only in the Go To Special window..
6. Click OK.
Select Visible cells only and click OK
This image shows the result of the process, which now only has the visible cell selected. Visible cells only selected

METHOD 1. Select visible cells only

VBA

Sub Select_only_visible_cells()

‘declare a variable
Dim ws As Worksheet

Set ws = Worksheets(«Analysis»)

‘select visible cells only in the selected range
ws.Range(«B2:C6»).SpecialCells(xlCellTypeVisible).Select

End Sub

ADJUSTABLE PARAMETERS
Worksheet Selection: Select the worksheet in which you want to apply a restriction to a cell by changing the Analysis worksheet name in the VBA code. You can also change the name of this object variable, by changing the name ‘ws’ in the VBA code.
Range: Select the range from which you only want to select visible cells by changing the range reference («B2:C6») in the VBA code.

Explanation about how to select visible cells only

EXPLANATION

EXPLANATION

This tutorial shows how to only select visible cells from a selected range using Excel or VBA.

This tutorial provides one Excel method and one VBA method that can be applied to only select visible cells from a selected range. The Excel method uses the ‘Visible cells only’ option from the Go To Special menu. The VBA method uses the SpecialCells(xlCellTypeVisible) function to select visible cells only.

Related Topic Description Related Topic and Description
Paste ignoring hidden or filtered cells How to paste values ignoring hidden or filtered cells

I have a database that has in excess on 200,000 rows. When I was writing a VBA script I had a database of about 20,000 rows in mind so I didn’t care whether the database was filtered or not because the VBA script ran quickly. So given the realization that the database is huge and testing the VBA script I was surprised to notice how slowly it ran. So without further to say this is how my code looks like :

Set wsDB = ThisWorkbook.Sheets("DB")
Dim nameIndex As Long: nameIndex = Application.Match(name, wsDB.Rows(1), 0)
Dim formula As String
   formula = "=IFERROR(AVERAGEIFS(" + GRA(nameIndex) + "," + GRA(dateIndex) + ",R2C," + GRA(cellNameIndex) + ",RC1" + "),"""")"

where GRA is a function that returns the address of the range of a column.

Private Function GRA(ByRef rngIndex As Long)
   GRA = "DB!" + CStr(Range(Cells(2, rngIndex), Cells(rowNos, rngIndex)).Address(1, 1, xlR1C1, 0, 0))
End Function

So given that I now filter the table beforehand how can I adjust my code so that it ignores all the hidden rows and takes into account only what is visible. Of course I am aware that a simple dirty solution would be to simply copy the filter database and paste it in a new sheet but that will affect the performance which is what I’m trying to improve.

Хитрости »

1 Май 2011              268582 просмотров


Как вставить скопированные ячейки только в видимые/отфильтрованные ячейки

Ни для кого не секрет, что Excel позволяет выделять только видимые строки. Например, если некоторые из них скрыты или к ним применен фильтр.

если кто-то не знает, как это сделать: выделяем диапазон — Alt+;(для английской раскладки);Alt+ж(для русской). Подробнее можно почитать в этой статье

Если после выделения только видимых ячеек их скопировать, то скопируются они как положено. Но при попытке вставить скопированное в отфильтрованный диапазон(либо содержащий скрытые строки) — то результат вставки будет не совсем такой, как Вы ожидали. Данные будут вставлены даже в скрытые строки. Либо как вариант получим ошибку «Данная команда не применима к несвязанному диапазону».

Копируем единый диапазон ячеек и вставляем только в видимые
Чтобы данные вставлялись только в видимые ячейки, можно применить такой макрос:

Option Explicit
Dim rCopyRange As Range
'Этим макросом копируем данные
Sub My_Copy()
    If Selection.Count > 1 Then
        Set rCopyRange = Selection.SpecialCells(xlVisible)
    Else: Set rCopyRange = ActiveCell
    End If
End Sub
'Этим макросом вставляем данные, начиная с выделенной ячейки
Sub My_Paste()
    If rCopyRange Is Nothing Then Exit Sub
    If rCopyRange.Areas.Count > 1 Then MsgBox "Вставляемый диапазон не должен содержать более одной области!", vbCritical, "Неверный диапазон": Exit Sub
    Dim rCell As Range, li As Long, le As Long, lCount As Long, iCol As Integer, iCalculation As Integer
    Application.ScreenUpdating = False
    iCalculation = Application.Calculation: Application.Calculation = -4135
    For iCol = 1 To rCopyRange.Columns.Count
        li = 0: lCount = 0: le = iCol - 1
        For Each rCell In rCopyRange.Columns(iCol).Cells
            Do
                If ActiveCell.Offset(li, le).EntireColumn.Hidden = False And _
                   ActiveCell.Offset(li, le).EntireRow.Hidden = False Then
                    rCell.Copy ActiveCell.Offset(li, le)
                    lCount = lCount + 1
                End If
                li = li + 1
            Loop While lCount >= rCell.Row - rCopyRange.Cells(1).Row
        Next rCell
    Next iCol
    Application.ScreenUpdating = True: Application.Calculation = iCalculation
End Sub

Как использовать: Для начала надо убедиться, что разрешены макросы и при необходимости включить их: почему не работает макрос. Затем копируем код выше, из Excel переходим в редактор VBA(Alt+F11) —InsertModule. Вставляем туда скопированный код. Теперь код можно вызывать нажатием клавиш Alt+F8 -выделяем имя макросаВыполнить(Run).
Для полноты картины, данные макросы лучше назначить на горячие клавиши(в приведенных ниже кодах это делается автоматически при открытии книги с кодом). Для этого приведенные ниже коды необходимо просто скопировать в модуль ЭтаКнига(ThisWorkbook):

Option Explicit
'Отменяем назначение горячих клавиш перед закрытием книги
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    Application.OnKey "^q": Application.OnKey "^w"
End Sub
'Назначаем горячие клавиши при открытии книги
Private Sub Workbook_Open()
    Application.OnKey "^q", "My_Copy": Application.OnKey "^w", "My_Paste"
End Sub

Теперь можно скопировать нужный диапазон нажатием клавиш Ctrl+q, а вставить его в отфильтрованный — Ctrl+w.
Если необходимо переносить только значения(т.е. если в ячейке будут формулы, то в итоге будет перенесен результат вычисления этой формулы), надо заменить строку в коде:

rCell.Copy ActiveCell.Offset(li, le)

на такую:

ActiveCell.Offset(li, le) = rCell.Value

Скачать пример

  Tips_Macro_CopyPasteInHiddenRows.xls (46,5 KiB, 14 213 скачиваний)


Копируем только видимые ячейки и вставляем только в видимые
По многочисленным просьбам доработал код. Теперь возможно копировать любые диапазоны: со скрытыми строками, скрытыми столбцами и вставлять скопированные ячейки также в любые диапазоны: со скрытыми строками, скрытыми столбцами. Работает совершенно так же, как и предыдущий: нажатием клавиш Ctrl+q копируем нужный диапазон(со скрытыми/отфильтрованными строками и столбцами или не скрытыми), а вставляем сочетанием клавиш Ctrl+w. Вставка производится так же в скрытые/отфильтрованные строки и столбцы или без скрытых.
Если в копируемом диапазоне присутствуют формулы, то во избежание смещения ссылок можно копировать только значения ячеек — т.е. при вставке значений будут вставлены не формулы, а результат их вычисления. Или если необходимо сохранить форматы ячеек, в которые происходит вставка — будут скопированы и вставлены только значения ячеек. Для этого надо заменить строку в коде(в файле ниже):

rCell.Copy rResCell.Offset(lr, lc)

на такую:

rResCell.Offset(lr, lc) = rCell.Value

В файле ниже обе эти строки присутствуют, Вам надо лишь оставить ту, которая больше подходит под Ваши задачи.

Скачать пример:

  Tips_Macro_CopyPasteInHiddenCells.xls (54,5 KiB, 12 769 скачиваний)

Так же см.:
Excel удаляет вместо отфильтрованных строк — все?! Как избежать


Статья помогла? Поделись ссылкой с друзьями!

  Плейлист   Видеоуроки


Поиск по меткам



Access
apple watch
Multex
Power Query и Power BI
VBA управление кодами
Бесплатные надстройки
Дата и время
Записки
ИП
Надстройки
Печать
Политика Конфиденциальности
Почта
Программы
Работа с приложениями
Разработка приложений
Росстат
Тренинги и вебинары
Финансовые
Форматирование
Функции Excel
акции MulTEx
ссылки
статистика

В дополнение к моим комментариям ранее, вот метод, который будет работать с некоторыми ограничениями:

Вы не можете иметь более 65536 строк данных; и вы не можете иметь действительно длинный текст (911 символов +) или пустые видимые ячейки; и данные не должны содержать строку «|~|»

Если эти условия соблюдены, вы можете использовать что-то вроде этого:

Dim v
Dim sFormula              As String
With Selection
    sFormula = "IF(SUBTOTAL(103,OFFSET(" & .Cells(1).Address(0, 0) & ",row(" & .Address(0, 0) & ")-min(row(" & .Address(0, 0) & ")),1))," & .Address(0, 0) & ",""|~|"")"
End With
Debug.Print sFormula
v = Filter(Application.Transpose(Evaluate(sFormula)), "|~|", False)

Вы можете адаптировать это для обхода третьего ограничения, изменив альтернативный текст в строке формулы.

Понравилась статья? Поделить с друзьями:
  • Excel vba тип объекта
  • Excel vba тип значения в ячейке
  • Excel vba тип данных массив
  • Excel vba тип данных дата
  • Excel vba тип variant