Я переписал ваш код с объяснениями, которых, я надеюсь, достаточно, чтобы вы поняли, почему.Я могу сказать гораздо больше.Я надеюсь, что это хороший баланс между слишком маленьким и слишком большим.
Однако я должен отметить, что есть несколько отличных инструментов управления проектами.Я не считаю, что это хорошее использование вашего времени.
Случайные точки
На 32-разрядных компьютерах Long лучше, чем Integer.
Не объявляйте свои переменные внутри цикла.Область действия переменной, объявленной внутри подпрограммы, является подпрограммой, поэтому объявляйте их в верхней части подпрограммы.
Вы можете объявить все свои переменные в одном операторе Dim
, но янайти это запутанным, если нет реальной связи между двумя или более переменными.Я мог бы иметь:
Dim RodRate As Long, GarthRate As Long, DerekRate As Long
, потому что эти переменные связаны.Однако проблема этого подхода в том, что вам нужно будет добавить MaryRate
и JohnRate
и AngelaRate
, когда эти люди присоединятся к вашему проекту.
Вам нужен массив:
Dim PersonRate(1 To 3) As Long
где PersonRate(1)
= ставка для Жезла, PersonRate(2)
= ставка для Гарта и PersonRate(3)
= ставка для Дерека.
Но это вряд ли лучше.Вам нужен стол, который может расти.Итак, сегодня:
Name Rate
Rod 20
Garth 25
Derek 15
На следующей неделе:
Name Rate
Rod 20
Garth 25
Derek 15
Mary 30
С этим вы выбираете имя Получателя, бегаете по столу, пока не найдете его имя, а затем просмотрите его рейтинг.
Полагаю, у вас есть таблица, подобная этой, на Листе 2.Вы можете продолжать возвращаться к Sheet2, но лучше загрузить таблицу в массив.
Мы могли бы иметь:
Dim PersonName() As String
Dim PersonRate() As Long
, поэтому PersonRate(2)
дает скорость для PersonName(2)
.
Обратите внимание, в моей первой декларации массива я написал: PersonRate(1 To 3)
.На этот раз скобки пусты.С PersonRate(1 To 3)
я говорю, что я хочу ровно три записи в массиве, и это нельзя изменить.С PersonRate()
я говорю, что хочу массив, но я не буду знать, сколько записей до времени выполнения.
Я сказал, что у нас может быть два массива, PersonName()
и PersonRate()
, и это то, что ясделано.Это простой для понимания подход, но я не думаю, что это лучший подход.Я предпочитаю структуры.Когда у вас есть этот макрос, работающий и перед тем, как вы начнете, посмотрите в следующий раз User Types
, который является именем VBA для структуры.
Учтите:
With Sheets("Sheet2")
RowMax = .Cells(Rows.Count, "A").End(xlUp).Row
End With
Здесь есть много объяснений.
Cells
означает, что я хочу обратиться к ячейке в активной книге..Cells
означает, что я хочу обратиться к ячейке на листе, указанном в операторе With.Это означает, что мне не нужно выбирать Sheet1 или Sheet2, чтобы посмотреть их содержимое.Выбор таблиц происходит медленно, а код становится более трудным для понимания.
.Cells(Row, Column)
идентифицирует ячейку.Строка должна быть числом, но столбец может быть числом или кодом столбца: A = 1, B = 2, Z = 26, AA = 27 и т. Д.
Rows.Count
возвращает количество строк влист для версии Excel, которую вы используете.Таким образом, .Cells(Rows.Count, "A")
обозначает нижнюю часть столбца «A».
End(xlUp)
является эквивалентом VBA нажатия Ctrl
+ UpArrow
.Если вы не знакомы с Ctrl
+ Arrow
, я предлагаю вам поиграть с этими четырьмя элементами управления.Обратите внимание, что эти элементы управления дают легко понять результаты с прямоугольной таблицей.Однако, если есть пустые ячейки, результаты могут быть странными.
Собираем это вместе: .Cells(Rows.Count, "A").End(xlUp).Row
означает начало внизу столбца A, поднимайтесь вверх, пока не дойдете до ячейки со значением и не вернете ее строкучисло.Таким образом, это устанавливает RowMax
в последнюю строку таблицы тарифов.Когда вы добавляете строку 5 с именем и рейтингом Мэри, этот код будет автоматически корректироваться.
Исправленный код
Этого должно быть достаточно для начала работы.Добро пожаловать в радости программирования.
' * Require all variables to be declared which means a misspelt name
' is not taken as an implicit declaration
Option Explicit
Sub GetCost()
Dim Estimate As Integer
Dim Assignee As String
Dim TotalCost As Integer
Dim PersonName() As String
Dim PersonRate() As String
Dim InxPerson As Long
Dim RowCrnt As Long
Dim RowMax As Long
' You can declare constants and use them in place of literals.
' You will see why later. I could have made these strings and
' used "A", "B", "D", "E" and "F" as the values. Change if that
' is easier for you.
Const ColS2Name As Long = 1
Const ColS2Rate As Long = 2
Const ColS1Estimate As Long = 4
Const ColS1Assignee As Long = 5
Const ColS1Total As Long = 6
' Before doing anything else we must load PersonName and PersonRate from
' Sheet2. I assume the structure of Sheet2 is:
' A B
' 1 Name Rate
' 2 Rod 20
' 3 Garth 25
' 4 Derek 15
With Sheets("Sheet2")
RowMax = .Cells(Rows.Count, ColS2Name).End(xlUp).Row
' I now know how big I want the the name and rate arrays to be
ReDim PersonName(1 To RowMax - 1)
ReDim PersonRate(1 To RowMax - 1)
' Load these arrays
For RowCrnt = 2 To RowMax
' I could have used 1 and 2 or "A" and "B" for the column
' but this is easier to understand particularly if you come
' back to this macro in six month's time.
PersonName(RowCrnt - 1) = .Cells(RowCrnt, ColS2Name).Value
PersonRate(RowCrnt - 1) = .Cells(RowCrnt, ColS2Rate).Value
Next
End With
With Sheets("Sheet1")
' I am using the same variable for rows in sheets Sheet1 and Sheet2.
' This is OK because I never look at Sheet1 and Sheet2 at the same time.
RowCrnt = 2
Do Until IsEmpty(.Cells(RowCrnt, ColS1Estimate))
Estimate = .Cells(RowCrnt, ColS1Estimate).Value
Assignee = .Cells(RowCrnt, ColS1Assignee).Value
.Cells(RowCrnt, ColS1Total).Value = 0
' Locate the Assignee in the PersonName array and
' extract the matching rate
For InxPerson = 1 To UBound(PersonName)
If PersonName(InxPerson) = Assignee Then
.Cells(RowCrnt, ColS1Total).Value = Estimate * PersonRate(InxPerson)
Exit For
End If
Next
RowCrnt = RowCrnt + 1
Loop
End With
End Sub