Сначала самое простое:
Если вы собираетесь заниматься разработкой VBA, изучите Rubberduckvba.com Это дополнение, которое значительно упростит кодирование и научит васмного вы не знали, вы хотели бы знать.Полное раскрытие Я являюсь участником этой группы.
Option Explicit
не отображается в вашем коде.Кроме того, поскольку в вашем коде экспорта есть необъявленная переменная cell
, я предполагаю, что она не включена по умолчанию.В верхнем меню Сервис> Параметры> вкладка «Редактор»> группа «Настройки кода»> Требуется объявление переменной, установите этот флажокЭто требует от вас Dim cell As Range
, прежде чем вы сможете использовать переменную.Если опция включена, вы получите ошибку компиляции Переменная не определена , прежде чем вы сможете запустить свой код.Это может показаться незначительным, но включите эту опцию, так как это избавит вас от головной боли позже.
Вы используете check
как результат окна сообщения.Не объявляйте его как Long
, скорее объявляйте его Dim check As VbMsgBoxResult
таким образом, когда вы наберете check=
, вы получите intellisense и доступные вам значения перечисления.
Вы использовали ""
в качестве заполнителя для пустой строки.Используйте vbNullString
вместо этого.Это встроенная константа, которая позволяет вам знать, что эта проверка была преднамеренной.Это потому, что ""
может или может быть строкой со значением "CheckValue"
, в котором слово удалено, оставляя только пустые кавычки.vbNullString
однозначно.
Я оставил большинство имен ваших переменных вместе, чтобы вы могли легче следовать реорганизации, которую я сделал.Обратите внимание, что такие переменные, как r, x, xMax, не предоставляют никакой полезной информации о том, для чего они используются.Используйте описательные имена переменных.Будущее тебя поблагодарит.Описательные переменные делают код самодокументируемым и намного легче читать.
Комментарии.Комментарии могут быть горячей темой для некоторых людей.Я обнаружил, что с описательными переменными вам нужно меньше кода.Сам код должен сказать , что делается.Ваш комментарий "'1. Найдите последний использованный ряд ..." говорит о том, что он снова делает.lastRowInCopyArea = copyWorksheet.Range().FooBar.Row
уже говорит это.Сохраните комментарии для , почему что-то сделано. Что должно быть видно из самого кода.
Венгерская нотация (HN) не нужна.Интегрированная среда разработки (IDE) может определить тип переменной в меню «Правка»> «Краткая информация» Ctrl + I .Наличие буквы, обозначающей тип, ухудшает читабельность и является переносом из предыдущих привычек кодирования.Хорошие имена переменных сами по себе исправят многое.
Вы можете использовать типизированную функцию UCase$()
вместо общей UCase()
в начале для вашего раздела экспорта, так как вы имеете дело со строками.
Вы используете вещи неявно.Ваш Range(Foo)
неявно обращается к активному листу, на котором вы находитесь.Чтобы увидеть это, щелкните правой кнопкой мыши слово Range, чтобы вызвать контекстное меню, и выберите Definition .
. Когда вы сделаете это, вы, вероятно, получите диалоговое окно с надписью «Cannot Перейти к« Range »потому что он скрыт ", под которым теперь отображается Object Browser (зеленый).Закройте диалоговое окно, нажав кнопку «ОК».Щелкните правой кнопкой мыши в области панели «Классы» (красный) или «Участники» (синий) и выберите в контекстном меню Показать скрытых участников .

Закройте браузер объектов, щелкнув внутреннюю кнопку закрытия в верхнем правом углу, или используйте Ctrl + F4 .Ваше окно кода теперь будет отображаться.Снова вызовите контекстное меню, щелкнув правой кнопкой мыши на слове Range и выбрав Show Definition.Вы попали в скрытый класс Global и член Range.

В красном поле отображается имя серого класса Global
, которое обычно скрыто иRange
член - это то, к чему обращаются.Чтобы избежать этого неявного доступа, полностью определите свой Range с рабочим листом или ActiveSheet.Range(Foo)
, если вы хотите получить доступ к активному листу.Повторное выполнение этого однозначно и показывает, что оно сделано намеренно.
У нас есть левая сторона Range(Foo)
, теперь как насчет другой стороны? Вы также неявно обращаетесь к свойству по умолчанию. Как вы это выясните? На изображении выше, внутри оранжевого поля, слово Range имеет зеленый цвет, указывая, что это ссылка. Нажмите на него, и вы попадете в Range на панели Classes, показанной ниже. У объекта Range есть члены, к которым можно получить доступ: Methods (вещи, которые делают действие) или Properties (информация о диапазоне).

На панели «Члены» отображаются эти участники, к которым у вас есть доступ. Прокрутите страницу вниз до тех пор, пока не появится элемент _Default
. Если вы не включили членский доступ IE Range(Foo)
, то вы получаете доступ к _Default
члену. Поскольку вы проверяете значение ячейки, используйте Range(Foo).Value2
для определения вашего членского доступа.
Ваш цикл может и должен быть консолидирован. Возьмите первый цикл и сравните его с другими. Каждый раз, когда вы копируете / вставляете и добавляете числовой идентификатор к переменной, вы чувствуете запах кода. Стартовая строка для каждого из них равна 10, меняется только столбец.
Dim r As Range, tabel As Range, xTabel As Range
Dim x As Integer, xMax As Long
'y As Long, yMax As Long
Dim textTabel As String
Set tabel = wsCopy.Range("d10:d" & lCopyLastRow)
Set r = wsDest2.Range("d" & lDestLastRow2)
xMax = tabel.Rows.Count
For x = 1 To xMax
Set xTabel = tabel.Range(Cells(x, 1), Cells(x, 1))
textTabel = Trim(xTabel.Text)
If x = 1 Then
textTabel = textTabel
'r.Offset(x - 1, 0).ClearContents
Else
textTabel = "& " & textTabel
End If
r = r & textTabel
Next x
Вам нужно включить это в свою собственную функцию, которая описывает, что он делает. Это позволит устранить дублирующийся код. Еще одним преимуществом этого является то, что если вы поймаете ошибку и исправите ее везде, где вызывается / использует функцию, то это также будет исправлено.
Что делает ваш код? Он объединяет ячейки в диапазоне, чтобы создать текстовую метку. Давайте начнем с этого для имени ConcatenateLabelFrom
. Я видел, что ваша переменная r
назначается каждый раз в цикле. Вам не нужно делать это, только после того, как вся конкатенация сделана. Помните, что это будет диапазон, который используется для пункта назначения. Логика цикла может быть сокращена до
Private Function ConcatenateLabelFrom(ByVal concatenateArea As Range) As String
Dim rowInArea As Integer
For rowInArea = 1 To concatenateArea.Rows.Count
Dim textTabel As String
textTabel = Trim(concatenateArea.Cells(rowInArea).Text)
If rowInArea = 1 Then
textTabel = textTabel
Else
textTabel = textTabel & "& " & textTabel
End If
Next
ConcatenateLabelFrom = textTabel
End Function
Функция вызывается с помощью аргумента параметра следующим образом. Отступы предназначены только для удобства чтения.
wsDest2.Cells(lDestLastRow2, "d").Value2 = ConcatenateLabelFrom( _
wsCopy.Range( _
wsCopy.Cells(10, "d"), _
wsCopy.Cells(lCopyLastRow, "d") _
) _
)
Ваши прыжки с GoTo не нужны. Лучше, чтобы вы реструктурировали свой код, чем прыгали с GoTo. В результате вы получите более логичный код. Также потребуется подумать о том, как вы хотите восстановить свойства Application.ScreenUpdating/Calculation
.
Вы можете сделать это, заключив разделы в свои собственные подпрограммы. Ваша подпрограмма Protect будет выглядеть следующим образом и вызываться через Protect wsCopy, protectBook
. И то же самое можно сделать с Экспортом.
Private Sub Protect(ByVal worksheetToProtect As Worksheet, ByVal workbookToSave As Workbook)
worksheetToProtect.Protect "pass", _
AllowFormattingCells:=True, _
DrawingObjects:=True, _
contents:=True, _
Scenarios:=True
workbookToSave.Save
End Sub
Ваш раздел с
Ваше мерцание экрана выглядит происходящим, потому что вы восстанавливаете обновление экрана и автоматический расчет перед экспортом. У вас там есть копия и вставка, и это то, что показывают. Помните мой комментарий о назначении r
в цикле? Это часть этого. Вы можете использовать Application.Calculate , чтобы вычислить все открытые книги перед повторным включением ScreenUpdating. Как и в случае рефакторинга ваших переходов GoTo, подумайте, как вы хотите, чтобы произошла серия событий из ваших книг, и соответствующим образом кодируйте их.
Можно предложить еще кое-что, но этого должно быть достаточно для начала.