#excel #vba #identifier #worksheet
Вопрос:
Во-первых, извините за мой плохой английский
Таким образом, у меня есть макрос, который задает листы моей книги в качестве имен переменных, чтобы предотвратить необходимость отладки предупреждений, когда пользователь использует книгу и изменяет имя или положение листа.
Например, если имя моего листа «BDD», когда я кодирую, я буду ссылаться на этот лист как на листы («BDD»).xxxxxx или листы(1).xxxxxxx, то если пользователь изменит имя листа, мои макросы больше не будут работать
Вот почему в worbook_open я установил:
WB00 = activeworkbook
WB00WS01 = first sheet
WB00WS02 = second sheet
снова и снова
Поэтому, когда я кодирую, я называю его WB00WS01.xxxx
Итак, мой макрос:
Sub initWB00()
Set WB00 = ActiveWorkbook
For Each W In WB00.Worksheets
On Error Resume Next
If W.CodeName = "Sheet1" Then
Set WB00WS01 = W
End If
If W.CodeName = "Feuil2" Then
Set WB00WS02 = W
End If
If W.CodeName = "Feuil3" Then
Set WB00WS03 = W
End If
If W.CodeName = "Feuil4" Then
Set WB00WS04 = W
End If
If W.CodeName = "Feuil5" Then
Set WB00WS05 = W
End If
If W.CodeName = "Feuil6" Then
Set WB00WS06 = W
End If
If W.CodeName = "Feuil7" Then
Set WB00WS07 = W
End If
If W.CodeName = "Feuil8" Then
Set WB00WS08 = W
End If
If W.CodeName = "Feuil9" Then
Set WB00WS09 = W
End If
If W.CodeName = "Feuil10" Then
Set WB00WS10 = W
End If
Next W
End Sub
Это работает как есть, но, как вы можете видеть, оно довольно ограничено (например, если я хочу перейти на WB00WS100) и очень тривиально
Затем у меня возникла идея зациклить переменную «i», которая даст номер листа "WB00WS" amp; i = "sheet" amp; I
Sub initWB00()
Dim i As Integer
Set WB00 = ActiveWorkbook
For Each W In WB00.Worksheets
For i = 1 To 20
If W.CodeName = "Feuil" amp; i Then
Set "WB00WS0"amp;i = W
End If
Next i
Next W
End Sub
Если я сделаю это так, у меня будет ожидаемая ошибка с идентификатором
Я предполагаю, что это потому, что я поместил строку и переменную слева от равенства, но в противном случае я не могу представить, как я могу написать цикл, который делает то, что мне нужно
У тебя есть какие-нибудь идеи?
Заранее спасибо!!
Комментарии:
1. Добро пожаловать в SO! Поздравляю с довольно хорошо написанным первым вопросом! Кстати, твой английский кажется вполне приличным. К сожалению, вы не можете создать имя переменной из строки, поэтому то, что вы пытаетесь сделать, не может работать. Может быть, вместо этого использовать массивы. Но, честно говоря, это не кажется отличным решением… ИМО, либо доверяйте своим пользователям не переименовывать листы, либо защищайте их.
2. Хорошо, Виктор, спасибо за очень приятный прием и за ответ, хорошего вам дня !
3. Если вы посмотрите на панель проекта в VBE, у каждого
Sheet
из них есть 2 имени — внутреннее имя и отображаемое имя в скобках (которое отображается и может быть отредактировано пользователем). Вы можете ссылаться на внутреннее имя в своем коде, и не имеет значения, переименует ли пользователь лист или нет.4. Разве решение массива просто не заменяет
Worksheets
коллекцию? Является ли лучшим подходом функция, которая извлекает числовоеWB00WS099
значение и преобразует его вworksheets("Feuil99")
возврат рабочего листа?5. @Raymond на самом деле я попробовал этот метод (меняет кодовое имя) : « Sub initWB00() Dim я Как Целое Число Установил WB00 = ActiveWorkbook Для каждого W В WB00. Рабочие Листы Для i = От 1 До 2, Если W. Кодовое Имя = «Feuil» И i, То W. Родитель. Vbпроект. VBКомпоненты(кодовое имя W.). Свойства(«_CodeName») = «WB00WS» и я Заканчиваю, Если Следующий я Следующий W Заканчиваю Sub « Это работало почти для всех моих макросов, но такие, как WB00WS01, не могли запуститься, знаете почему
Ответ №1:
Это один из методов заполнения массива ссылками на рабочие листы и эмуляции попыток, которые вы предприняли в своем коде. Однако замечание Раймонда Ву, возможно, является более правильным решением.
Option Explicit
Public Function initWB00(ByRef ipWB As Workbook) As Variant
Dim myWorksheetArray As Variant
ReDim myworksheet(1 To ipWB.Worksheets.Count)
Dim myItem As Variant
Dim mySheet As Worksheet
For Each myItem In ipWB.Worksheets
' The next line just allow intellisense
Set mySheet = myItem
If InStr(mySheet.CodeName, "Sheet1") Then
Set myWorksheetArray(1) = mySheet
Else
Set myWorksheetArray(CLng(Split(mySheet.CodeName, "l")(1))) = mySheet
End If
Next
initWB00 = myWorksheetArray
End Function
Комментарии:
1. Спасибо, я попробую и доберусь до тебя !
2. Хорошая идея. Это небольшая опечатка (
ReDim myworksheet
вместоReDim myWorksheetArray
) в коде. И, если между номерами листов имеются пробелы из-за удаления листа(ов), будет трудно ссылаться на правильный лист с помощью массива. Но, в любом случае, мне нравится идея кода… Проголосовали за.3. @FaneDuru Упс, извините за опечатку. Тестирование на пустоту перед доступом к листу через массив было бы разумным и безопасным способом.
4. Я боюсь, что ничто не будет пустым… Если есть пробелы,
Worksheets.Count
возвращает 10 и есть листы с именем «Sheet12». ПостроениеSet myWorksheetArray(CLng(Split(mySheet.CodeName, "l")(1))) = mySheet
завершится неудачей из-за превышения массиваUbound
. Лучше всего использовать переменную и увеличивать ее после каждой загрузки каждого элемента массива. И, похоже, это другой тип:, "l")(1))
работает для таких имен, как «Feuil», и код все еще сохраняет «Sheet1», вероятно, с тех пор, как вы его протестировали.5. @FaneDuru Мой ответ был демонстратором технологий, чтобы помочь оператору понять, как использовать и использовать массив для захвата ссылок на рабочие листы. Он скомпилировался без ошибок, но я не запустил его, потому что у меня нет рабочей книги хоста. Я буду рад предоставить дополнительную помощь, если это понадобится оператору.
Ответ №2:
Пожалуйста, попробуйте использовать следующий подход. Вы запустите код один раз, и все кодовые имена листов будут изменены. Тогда вы должны использовать только их:
Sub initWB00()
Dim i As Long, w As Worksheet, WB00 As Workbook
Set WB00 = ActiveWorkbook 'if the active workbook is not ThisWorkbook, it will change the names of he active workbook sheets.
'but they can be used only running codes inside them
'In order to not have such problems, you should use ThisWorkbook instead of ActiveWorkbook
For Each w In WB00.Worksheets
For i = 1 To 20
If w.CodeName = "Feuil" amp; i Then
ChangeCodeName w, WB00, "WB00WS0" amp; i
End If
Next i
Next w
End Sub
Private Sub ChangeCodeName(sh As Worksheet, WB As Workbook, strCodeName As String)
Dim shCModule As Object
Set shCModule = WB.VBProject.VBComponents(sh.CodeName)
shCModule.Name = strCodeName
End Sub
Комментарии:
1. Я попытался изменить кодовое название своих листов. Это работало почти для всех моих макросов, но такие, как WB00WS01, не могли запуститься, знаете почему ?
2. @babozo Нет причин для того, чтобы какой-либо лист не был распознан в соответствии с таким именем. Я протестировал сейчас это имя, и оно работает. Но вы должны знать, что этот способ вызова работает только для этой рабочей книги. Как вы пытались его использовать?
3. Вот так: Sub Opener() WB00WS01.Снять защиту паролем:=»РАЗБЛОКИРОВАТЬ» Заблокировано = Ложный конец Sub У меня ошибка с отсутствующим объектом
4. @babozo
WB00WS01
принадлежит книге, в которой выполняется приведенный выше код?5. безусловно, я использовал макросы, которые вы мне дали
Ответ №3:
Ооооооооооооооо Благодаря @FaneDuru я нашел решение ! Мне просто нужно было удалить глобальное приложение в начале моего кода (у меня был глобальный WB00WS01, Глобальный WB00WS2…) , и это сработало !
Моя единственная проблема заключается в том, что где-то в своем коде я установил WB00 в качестве этой рабочей книги, и я не могу ссылаться на нее позже в своем коде. Даже когда я затемняю WB00 как рабочую книгу в заголовке моего кода. Когда я использую WB00.Windows(1).VisibleRange(2, 2).Top
, у меня возникает ошибка неопределенной переменной
В любом случае, спасибо всем вам за то, что помогли мне !!
Комментарии:
1. Вы должны просто использовать
ThisWorkbook
, так как это одно и то же. состояние переменной может быть потеряно при сбросе или завершении в случае ошибки, в тоThisWorkbook
время как оно всегда присутствует.2. Я не уверен, какова цель вашего файла, но я предлагаю вам удалить его, так как нет необходимости делиться им для отладки. В нем могут быть конфиденциальные данные?