Ночные приключения с макросами: или как простая задача вылилась в ночной марафон из VBA
Привет всем! Поделюсь историей, как я, в который раз, провёл ночь, сражаясь с Excel. Обычная задача раздвинуть диапазоны в файле. Вроде ничего особенного, не правда ли? Зашёл в диспетчер имен, поправил пару диапазонов — и готово. Ха! Ага, сейчас...
Оказалось, что в файле именованных диапазонов столько, что вручную это править — можно успеть выучить китайский язык, а потом всё равно не закончить. Ну ладно, думаю, не беда, надо просто быстренько макрос накатать. Простой, как дверь, макрос, который возьмёт и поменяет диапазоны с одного столбца на другой. Пять минут делов. Кто бы сомневался, да?
Код |
---|
Sub UpdateNamedRanges()
Dim nName As Name
Dim oldAddress As String
Dim newAddress As String
For Each nName In ThisWorkbook.Names
oldAddress = nName.RefersTo
If InStr(1, oldAddress, "$EB$", vbTextCompare) > 0 Then
newAddress = Replace(oldAddress, "$EB$", "$EC$")
nName.RefersTo = newAddress
Debug.Print "Имя: " & nName.Name & " изменено с " & oldAddress & " на " & newAddress
End If
Next nName
MsgBox "Обновление диапазонов завершено!", vbInformation
End Sub |
Пишу макрос, и тут начинается... Какой диапазон менять? На что менять? Давай прогресс-бар добавим, чтобы было видно, как он этот диапазон величественно раздвигает. Ну и, конечно, не забываем о всплывающем окне, которое спросит у пользователя, что вообще менять. Потому что, ну, вы же понимаете — без этого никуда. И так уже два часа ночи, а я всё ещё пишу этот "простой" макрос, который, очевидно, должен был быть готов уже три чашки кофе назад.
Но самое интересное начинается, когда вдруг вспоминаешь, что макрос-то у тебя в "Книга1", а вот работаешь ты в "Книга2". Конечно, Excel должен был догадаться сам и всё сделать правильно, но нет. Так что сидишь и дописываешь, чтобы он работал в активной книге, потому что, естественно, Excel не в состоянии сам понять, что от него хотят. Простая задача, думал я. Пара минут, говорил я.
И вот, когда наконец это всё заработало, чувствую себя настоящим героем. Макрос теперь такой умный, что сам всё заменяет, прогресс показывает, а я уже не помню, зачем вообще это делал. Но результат есть, и теперь могу раздвигать эти диапазоны, как будто это какой-то важный навык в жизни. 🙈
Код |
---|
Sub UpdateNamedRangesWithProgressBar()
Dim nName As Name
Dim oldAddress As String
Dim newAddress As String
Dim totalNames As Long
Dim currentIndex As Long
Dim searchValue As String
Dim replaceValue As String
Dim activeWorkbook As Workbook
Set activeWorkbook = Application.ActiveWorkbook
searchValue = InputBox("Введите значение, которое нужно заменить (например, $EB$):", "Значение для замены")
If searchValue = "" Then Exit Sub ' Отмена, если ничего не введено
replaceValue = InputBox("Введите новое значение, на которое нужно заменить (например, $EC$):", "Новое значение")
If replaceValue = "" Then Exit Sub ' Отмена, если ничего не введено
totalNames = activeWorkbook.Names.Count
currentIndex = 0
'прогресс-бар
Set ProgressForm = VBA.UserForms.Add("ProgressForm")
ProgressForm.ProgressBar.Width = 0
ProgressForm.ProgressLabel.Caption = "Обновление диапазонов..."
ProgressForm.Show vbModeless
For Each nName In activeWorkbook.Names
currentIndex = currentIndex + 1
UpdateProgressBar currentIndex, totalNames
oldAddress = nName.RefersTo
' Проверяем, содержит ли диапазон искомое значение и меняем его на новое
If InStr(1, oldAddress, searchValue, vbTextCompare) > 0 Then
newAddress = Replace(oldAddress, searchValue, replaceValue)
nName.RefersTo = newAddress
Debug.Print "Имя: " & nName.Name & " изменено с " & oldAddress & " на " & newAddress
End If
Next nName
' Закрываем форму прогресс-бара после завершения
Unload ProgressForm
MsgBox "Обновление диапазонов завершено!", vbInformation
End Sub
Sub UpdateProgressBar(currentIndex As Long, totalNames As Long)
' Обновление ширины прогресс-бара и текста на форме
If Not ProgressForm Is Nothing Then
With ProgressForm
.ProgressBar.Width = (.ProgressFrame.Width - 2) * (currentIndex / totalNames)
.ProgressLabel.Caption = "Обновление: " & currentIndex & " из " & totalNames & _
" (" & Format(currentIndex / totalNames, "0%") & ")"
DoEvents ' Обновление интерфейса
End With
End If
End Sub
|
Чтобы это всё заработало, нужно создать форму --> еще небольшая инструкция:
Скрытый текст |
---|
Добавьте новый UserForm
- В редакторе VBA выберите Insert > UserForm. Это создаст новый UserForm в проекте.
Настройте UserForm: 2. Перейдите в окно свойств и задайте Name для формы как ProgressForm. 2.1 Добавьте Label и Frame на форму: Label (для текста с информацией о прогрессе): 2.1.1 Name: ProgressLabel 2.1.2 Caption: Обновление... Frame (контейнер для прогресс-бара): 2.1.3 Name: ProgressFrame 2.1.4 Установите размер и расположение фрейма по вашему усмотрению. 2.2 Внутри Frame, добавьте еще один Label (прогресс-бар): 2.2.1 Name: ProgressBar 2.2.2 Задайте цвет фона (например, зелёный). 2.2.3 Установите Width в 0, чтобы она начиналась пустой |