Установка диапазона для запуска макроса во всех заполненных строках на листе - PullRequest
0 голосов
/ 03 марта 2012

Я собрал макрокоманду, чтобы позволить мне рассчитать стоимость задания по истории, рассчитав конкретную ставку на основе назначенного разработчика. У меня есть таблица тарифов на втором листе. Я могу получить результат для ячейки, для которой установлен макрос (строка 2), но хочу, чтобы он выполнялся во всех строках. Я знаю, что должен установить общий диапазон, но не уверен. Как мне изменить диапазон объявления для запуска на всех строках?
Вот код:

Sub GetCost()
  Range("D2").Select
  ' Set Do loop to stop when an empty cell is reached.
  Do Until IsEmpty(ActiveCell)
    Dim Estimate As Integer, Assignee As String, RodRate As Integer, GarthRate As Integer, DerekRate As Integer, TotalCost As Integer

    Estimate = ThisWorkbook.Worksheets("Sheet1").Range("D2").Value
    Assignee = ThisWorkbook.Worksheets("Sheet1").Range("E2").Value
    RodRate = ThisWorkbook.Worksheets("Sheet2").Range("B2").Value
    GarthRate = ThisWorkbook.Worksheets("Sheet2").Range("B3").Value
    DerekRate = ThisWorkbook.Worksheets("Sheet2").Range("B4").Value

    If Assignee = "Rod" Then
        TotalCost = Estimate * RodRate
    ElseIf Assignee = "Garth" Then
        TotalCost = Estimate * GarthRate
    ElseIf Assignee = "Derek" Then
        TotalCost = Estimate * DerekRate
    Else
        TotalCost = "0"

    End If

    ThisWorkbook.Worksheets("Sheet1").Range("F2").Formula = TotalCost
  ActiveCell.Offset(1, 0).Select
  Loop
End Sub

Ответы [ 2 ]

3 голосов
/ 04 марта 2012

Я переписал ваш код с объяснениями, которых, я надеюсь, достаточно, чтобы вы поняли, почему.Я могу сказать гораздо больше.Я надеюсь, что это хороший баланс между слишком маленьким и слишком большим.

Однако я должен отметить, что есть несколько отличных инструментов управления проектами.Я не считаю, что это хорошее использование вашего времени.

Случайные точки

На 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
1 голос
/ 04 марта 2012

Ответ Тони - отличное решение и введение в программирование, он очень хорошо написан, поэтому я его +1.Однако, если я что-то упускаю, код всегда должен быть последним средством в Excel, поскольку он очень медленный по сравнению с формулами, я бы подумал, что достаточно простого поиска, например:

=D2*(vlookup(E2,'sheet2'!A:B,2,FALSE)) 

Скопированостолбец

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...