Вот как я это сделал. Я бы и близко не подошел к этому сегодня вечером, если бы не mrfluff в MrExcel.
Для справки см. мой вопрос в Mr Excel Я написал с просьбой о помощи по поводу: цикл по столбцам и строкам любого конкретного листа в более ранней версии кода, который я разработал, который стал «использовать usedrange
» благодаря отличной помощи, которую я получил от замечательного @mrfluff.
Находит all refs и активирует каждый по ходу и дает вам возможность для каждого найденного ref остановить программу и обработать ее тут же в этой ячейке. Вы можете перезапустить снова после работы.
Sub FindRefsandErrorsinWorkbookBySheets24()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
'Dim starting_ws As Worksheet
'Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
For Each ws In ThisWorkbook.Worksheets
ws.Activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
myCell.Select '' 1. COMMENT OUT FOR SPEED
myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address
x = x + 1
MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
ElseIf IsError(myCell.Value) Then
myCell.Offset(0, 1) = "Do you know you had different tyoe of error in " & myCell.Address & "???"
End If
Next myCell
'MsgBox ws.Name
Next ws
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
'With sheet
'End With
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
''Dim sheet As Worksheet
''Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
End Sub
Он также находит все ссылки и дает вам список в конце, где они находятся.
Я предполагал, что вы хотите их по одному one, и вы можете остановить макрос на определенном, чтобы исправить это. Но если вы этого не сделаете, закомментируйте все 3 строки, относящиеся к окнам сообщений, где я написал COMMENT OUT THIS ENTIRE LINE IF YOU WANT SPEED .
Каждая из них - '1,' 2 и '3.
Я вставил их в начала, но как только я убедился, что они работают, я удалил их для ускорения моего тестирования, прежде чем вставлять их обратно только сейчас.
Итак, эти 3 раздела имеют в себе комментарий «1 ...» 2 ... '3 ... полностью закомментируйте эти 3 строки, и у вас будет гораздо более быстрый макрос с только заключительным окном сообщения с общим количеством ссылок и выводом всех ссылок в немедленном окне и новым созданным листом в конце.
Я предпочитаю макрос без этих трех строк внутри, так как он работает более плавно и быстро. Но сначала вы размышляли, было бы хорошо редактировать-исследовать ссылки по ходу / по мере их нахождения. Вот почему я только что вернул их обратно. Но вы можете удалить эти 3 строки для гораздо более быстрой и менее прерывистой подпрограммы (и вы все равно получите массив - итого и распечатайте все местоположения ссылок в конце, так что на вашем месте я бы жил без этих 3 строк).
Надеюсь, я помог. У меня это сработало. :)
Вот макрос (я предпочитаю, даже если он не показывает вам ссылки во время выполнения или дает вам варианты остановки.) Без окон сообщений или активации и без вставки смещений (который у меня был только в первом, потому что я нашел их полезными при разработке):
Sub FindRefsandErrorsinWorkbookBySheets245()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
' myCell.Select '' 1. COMMENT OUT FOR SPEED
' myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address(, , , 1) '' THIS GETS YOU THE SPECIFICS (SHEET NUMBER TOO)
x = x + 1
' MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
' If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
' ElseIf IsError(myCell.Value) Then
' myCell.Offset(0, 1) = "Do you know you had different tyoe of error in " & myCell.Address & "???"
End If
Next myCell
Next ws
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
End Sub
Они идентичны. Единственная разница - это '
строк, которые меняют поведение.
Это только что пришло мне в голову (фраза на вашем языке: обнаружить их и активировать ячейки, Где они появляются (optionally one by one)
Это меня достало размышляя, как бы у вас могла быть возможность активировать ячейку, не зная, где эта опция видна, кроме списка, данного вам или окна сообщения (т.е. как вам может быть предоставлена возможность активировать или не активировать, не видя ее?)
Но, строго следуя вашим словам, я переписал исходный макрос (в котором есть эти ненужные и потенциально возможные смещения перезаписи данных), чтобы сделать это именно так.
Ссылка сообщается вам в окне сообщения, а затем второе окно сообщения спрашивает, будете ли вы sh обрабатывать эту ссылку (с адресом) или продолжить. Да, выберите ячейку и завершите макрос / подпункт. Нет, просто продолжите.
SO Это one не активирует какую-либо ячейку или какой-либо рабочий лист, пока вы не решите. Вы получаете свои сообщения одно за другим для каждой ссылки, а любое окно сообщений с определенной ссылкой вас интересует тот, который вы решили активировать - выбрать эту ячейку ref и работать с ней или нет. немного отличается. Лист и ячейка только `` активируются '' (выбираются), и программа останавливается, когда вы решаете, основываясь на сообщении msgbox (я думаю, у вас есть хорошая мысленная карта того, где эти ячейки находятся на ваших листах, и вы уже знаете, какая из них важнее!?).
Благодаря go парню (Джону) в excelcampus и людям из automateexcel здесь
Этот тоже работает. Все 3 делают, немного по-разному, в зависимости от того, как вы читаете свои слова.
Sub FindRefsandErrorsinWorkbookBySheets26()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'excel campus - https://www.youtube.com/watch?v=rCh7ki9yVsM
Dim Answer As VbMsgBoxResult
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
'Dim starting_ws As Worksheet
'Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
For Each ws In ThisWorkbook.Worksheets
''' ws.Activate 'you could comment this out too if you dont need or want to see the sheets, and put it back in the "yes portion" of "i wasnt to deal with" - as you kinda implied you want to be chooser of what ref to activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
'''''myCell.Select '' deleted because your wording kind of suggests you want to choose when to select/activate the cell.
myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address
x = x + 1
MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
''''If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
Answer = MsgBox("Do you want to go to cell" & myCell.Address & " and fix?", vbYesNo)
If Answer = vbYes Then
ws.activate
myCell.Select
Exit Sub
Else
'MsgBox "No"
End If 'must thank also - https://www.automateexcel.com/vba/yes-no-message-box/ - for this
ElseIf IsError(myCell.Value) Then
myCell.Offset(0, 1) = "Do you know you had different type of error in " & myCell.Address & "???"
End If
Next myCell
'MsgBox ws.Name
Next ws
If refcount = 0 Then
MsgBox "Finished Checking. There were " & refcount & " Ref Errors!"
Exit Sub
End If
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
'With sheet
'End With
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
''Dim sheet As Worksheet
''Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
End Sub
Самый быстрый / самый простой способ imo обработать последнюю или единственную потенциальную ошибку в этом коде и завершить работу чисто (то есть, если myarray
был пустым или он не нашел ссылок) и учитывать пустой массив myarray / null, без ошибки ref ситуации, было If refcount = 0 Then
, иначе определение того, является ли массив пустым (myarray) = true, оказалось слишком сложной дополнительной работой и сложным в его время.