1

У меня есть файл Excel, где я хочу, чтобы люди заполняли конкретные материалы. Я хочу сделать диапазон ячеек в строке обязательным, если первая ячейка в строке заполнена. Например, если заполнена ячейка A7, необходимо заполнить ячейки B7-O7. И это повторяется до тех пор, пока в столбце А не будет ячейка, которая не заполнена.

Я попробовал не очень хорошее VBA кодирование здесь

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

    If Sheets("Sheet1").Range("A7").Value <> "" And Sheets("Sheet1").Range("B7").Value = "" Or Range("C7").Value = "" Or Range("D7").Value = "" Or Range("E7").Value = "" Or Range("F7").Value = "" Or Range("G7").Value = "" Or Range("H7").Value = "" Or Range("I7").Value = "" Or Range("J7").Value = "" Or Range("K7").Value = "" Or Range("L7").Value = "" Or Range("M7").Value = "" Or Range("N7").Value = "" Or Range("O7").Value = "" Then
        MsgBox "Alla celler i en rad måste vara ifyllda för att du skall kunna spara. Kontrollera detta och spara igen."
        Cancel = True

    ElseIf Sheets("Sheet1").Range("A8").Value <> "" And Sheets("Sheet1").Range("B8").Value = "" Or Range("C8").Value = "" Or Range("D8").Value = "" Or Range("E8").Value = "" Or Range("F8").Value = "" Or Range("G8").Value = "" Or Range("H8").Value = "" Or Range("I8").Value = "" Or Range("J8").Value = "" Or Range("K8").Value = "" Or Range("L8").Value = "" Or Range("M8").Value = "" Or Range("N8").Value = "" Or Range("O8").Value = "" Then
        MsgBox "Alla celler i en rad måste vara ifyllda för att du skall kunna spara. Kontrollera detta och spara igen."
        Cancel = True

    ElseIf Sheets("Sheet1").Range("A9").Value <> "" And Sheets("Sheet1").Range("B9").Value = "" Or Range("C9").Value = "" Or Range("D9").Value = "" Or Range("E9").Value = "" Or Range("F9").Value = "" Or Range("G9").Value = "" Or Range("H9").Value = "" Or Range("I9").Value = "" Or Range("J9").Value = "" Or Range("K9").Value = "" Or Range("L9").Value = "" Or Range("M9").Value = "" Or Range("N9").Value = "" Or Range("O9").Value = "" Then
        MsgBox "Alla celler i en rad måste vara ifyllda för att du skall kunna spara. Kontrollera detta och spara igen."
        Cancel = True

    End If

End Sub

Это работает, пока я не доберусь до:

ElseIf Sheets("Sheet1").Range("A9").Value <> "" And Sheets("Sheet1").Range("B9").Value = "" Or Range("C9").Value = "" Or Range("D9").Value = "" Or Range("E9").Value = "" Or Range("F9").Value = "" Or Range("G9").Value = "" Or Range("H9").Value = "" Or Range("I9").Value = "" Or Range("J9").Value = "" Or Range("K9").Value = "" Or Range("L9").Value = "" Or Range("M9").Value = "" Or Range("N9").Value = "" Or Range("O9").Value = "" Then
    MsgBox "Alla celler i en rad måste vara ifyllda för att du skall kunna spara. Kontrollera detta och spara igen."
    Cancel = True
End If

Затем MsgBox выскакивает, даже если A9 не заполнен.

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

1 ответ1

2

У вас есть ошибка в вашей цепочке условий:

cond1 And cond2 Or cond3 Or cond4 всегда будут иметь значение True если один (или оба) из cond3 или cond4 имеют значение True . Это потому, что And будет оцениваться до Or . Смотрите документацию для получения дополнительной информации.

Вы можете использовать скобки для корректировки порядка оценки:

cond1 And (cond2 Or cond3 Or cond4)

Это выражение будет иметь значение True только если cond1 и любой из cond2, cond3, cond4 имеют значение True .


В вашем случае я бы порекомендовал следующие улучшения вашего кода:

  • Во-первых, прочитайте о циклах в VBA. For ... Next и Do ... Loop - это два типа, о которых вам нужно знать.
  • Затем, чтобы сделать вещи немного понятнее (то есть, чтобы ваши намерения были видны в коде), поместите этот проверочный код в свою собственную подпрограмму / функцию.
  • И наконец, чтобы сделать еще более очевидным, что происходит, вы можете разделить эти длинные цепочки условий.

Если мы сейчас посмотрим на процедуру Workbook_BeforeSave , то не сразу понятно, что она там делает (возможно, вам это нужно, потому что вы просто поместили туда код, и он свеж у вас в голове - но вернитесь к этому листу в 3/6/12 месяцев и вам сначала нужно понять что он делает). Давайте исправим это:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

    Cancel = IsUserInputMissing

End Sub

Private Function IsUserInputMissing() as Boolean

    ' Validation code goes in here

End Function

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

Эта линия

If Sheets("Sheet1").Range("A7").Value <> "" And Sheets("Sheet1").Range("B7").Value = "" Or Range("C7").Value = "" Or Range("D7").Value = "" Or Range("E7").Value = "" Or Range("F7").Value = "" Or Range("G7").Value = "" Or Range("H7").Value = "" Or Range("I7").Value = "" Or Range("J7").Value = "" Or Range("K7").Value = "" Or Range("L7").Value = "" Or Range("M7").Value = "" Or Range("N7").Value = "" Or Range("O7").Value = "" Then

не очень дружелюбен на глазах. Дословно говорится, что If FirstCellIsNotEmpty And AnyFollowingCellIsEmpty Then Давайте закодируем это так.

Dim FirstCellIsEmpty as Boolean
FirstCellIsEmpty = Sheets("Sheet1").Range("A7").Value = ""

Dim AnyFollowingCellIsEmpty as Boolean
AnyFollowingCellIsEmpty = WorksheetFunction.CountBlank(Sheets("Sheet1").Range("B7:O7")) > 0

If Not FirstCellIsEmpty And AnyFollowingCellIsEmpty Then
    MsgBox "I don't know any Swedish. But please fill out the necessary cells."
End If

Обратите внимание на использование WorksheetFunction.CountBlank чтобы не вводить каждую ячейку для проверки.


В конце я приведу пример того, как может выглядеть ваша функция IsUserInputMissing . (Тем не менее, есть еще много возможностей для улучшения.)

Private Function IsUserInputMissing() As Boolean

    ' Easy way to set the beginning of the range
    Const FirstRowToBeChecked As Long = 7
    ' Set a reference to the sheet that needs checking
    Dim Ws As Worksheet
    Set Ws = ThisWorkbook.Worksheets("Sheet1")

    Dim iRow As Long
    iRow = FirstRowToBeChecked

    Do

        Dim FirstCellIsEmpty As Boolean
        FirstCellIsEmpty = Ws.Cells(iRow, 1).Value = vbNullString ' vbNullString is a clearer way of saying ""
        ' Exit loop at the first empty row
        If FirstCellIsEmpty Then Exit Do

        Dim AnyFollowingCellIsEmpty As Boolean
        AnyFollowingCellIsEmpty = WorksheetFunction.CountBlank(Ws.Range(Ws.Cells(iRow, 2), Ws.Cells(iRow, 15))) > 0

        If AnyFollowingCellIsEmpty Then
            ' Any time the requirements are not met, notify user and abort checking and saving
            ' This is not as elegant as checking the whole range and collecting info about all missing inputs
            ' But it's way easier to code :)
            MsgBox "I don't know any Swedish. But please fill out the necessary cells. Tack!"
            IsUserInputMissing = True
            Exit Function
        End If
        ' Don't forget to increment the counter, otherwise you've got yourself an endless loop
        iRow = iRow + 1

    Loop

    ' If execution reaches this line, all rows fulfil the requirement
    ' IsUserInputMissing will have its Default value: False
End Function

Не торопитесь и работайте через это. Я пытался сделать вещи как можно более ясными. Но если что-то не совсем понятно. Не стесняйтесь спрашивать. :)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .