Ночные приключения с макросами: или как простая задача вылилась в ночной марафон из 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
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, чтобы она начиналась пустой |