【问题标题】:My VBA for loop in MS word 2016 is not working我在 MS Word 2016 中的 VBA for 循环不起作用
【发布时间】:2018-10-02 00:52:18
【问题描述】:

我在 MS word VBA 中遇到以下代码问题

For i = 6 To ActiveDocument.Tables(2).Rows.Count
    z = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
    x = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
    b = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText

    If (z = 0 And x = 0) Then
        If b = True Then
            MsgBox "Please do error 1!"
            If vbOK Then
                Exit Sub
            End If
        Else
            MsgBox "Please do error 2!"
            If vbOK Then
                Exit Sub
            End If
        End If
    Else
        If b = True Then
            MsgBox "Please do error 3!"
            If vbOK Then
                Exit Sub
            End If
        Else
            Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
            If Confirm = vbNo Then
                Exit Sub
            End If
        End If
    End If
Next i

for 循环不会进入第二行检查 z 或 x 是否有值

【问题讨论】:

  • 解决了这个问题。 Next i 应该放在 If 语句之前以便循环。

标签: vba for-loop ms-word


【解决方案1】:

我怀疑移动 Next i 会解决任何问题。这段代码充满了恶意。

我的印象是您的代码旨在检查表中的三列(从第 6 行向下) - 这似乎是一致性检查。

命名zxb 的描述性不是很好。使用lengthCol2lengthCol3hasPlaceHolderText 之类的名称将帮助您更紧密地遵循您的逻辑。

使用Option Explicit。总是。

您使用标准的MsgBox 调用,默认情况下只有一个按钮(“确定”)。 MsgBox 是一个阻塞代码元素,因此在用户单击“确定”之前宏不会进行。

vbOK 是一个枚举值(值 = 1)。所以If vbOK then 总是正确的。总是。您似乎正在寻求某种用户输入,但您不清楚该输入是什么。

解决这些简单的步骤给我们:

For i = 6 To ActiveDocument.Tables(2).Rows.Count
    lengthCol2 = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
    lengthCol3 = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
    hasPlaceHolderText = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText

    If (lengthCol2 = 0 And lengthCol3 = 0) Then
        If hasPlaceHolderText = True Then
            MsgBox "Please do error 1!"
            Exit Sub
        Else
            MsgBox "Please do error 2!"
            Exit Sub
        End If
    Else
        If hasPlaceHolderText = True Then
            MsgBox "Please do error 3!"
            Exit Sub
        Else
            Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
            If Confirm = vbNo Then
                Exit Sub
            End If
        End If
    End If
Next i

你的逻辑是消极的——也就是说,打算找理由不做某事而不是做某事。正偏逻辑通常更容易理解和维护 - 编码人员的意图更清晰。

改写逻辑给我们:

For i = 6 To ActiveDocument.Tables(2).Rows.Count
    lengthCol2 = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
    lengthCol3 = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
    hasPlaceHolderText = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText

    If (lengthCol2 > 0 OR lengthCol3 > 0) AND hasPlaceHolderText Then
         Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
         If Confirm = vbYes Then
             'Do submission code here - or call the submission procedure
         End If  ' Just do nothing if they say "No" - this is what your current code does.
    Else
        ' The next line could be used instead of the nested IF-the-else statements following.
        'MsgBox " Table contents are not valid, please ensure columns 2,3 and 5 are completed"
        If hasPlaceHolderText then
            If (lengthCol2 = 0 And lengthCol3 = 0) Then
                MsgBox  "Please do error 1!"
            Else
                MsgBox  "Please do error 2!"
            EndIF
        Else
            MsgBox  "Please do error 3!"
        End If
    End If
Next i

请注意,在您的逻辑中,第 2 列或第 3 列可以为空,并且(只要未显示占位符文本)您的文档已准备好提交。也许你的意思是AND 而不是OR(即所有列都应该填满)。

还有一个问题。你的循环。如当前所写,您循环逻辑,因此您要求用户检查错误或根据每行中的错误检查次数提交文档 x 次。但是,仅移动 Next i 并不能解决问题,因为唯一保留的结果是最后一行中的结果。换句话说,之前的所有行都可能是错误的/无效的,但您仍然可以提交。

我们可以通过创建累积逻辑来修复最后一点。换句话说,我们在一个短循环中跟踪错误,然后进入主逻辑。这似乎有点复杂,但它确实是相对简单的。但是,我们确实需要更多 Booleans 才能使其正常工作。

Dim rowsOK as Boolean
'explicit initialisation - I am working on a positive bias here.
    rowsOK = True

For i = 6 To ActiveDocument.Tables(2).Rows.Count
    Dim lengthCol2OK as Boolean  ' Use these just to make the logic clearer and the code cleaner
    Dim lengthCol3OK as Boolean
    Dim hasPlaceHolderTextOK as Boolean
    lengthCol2OK = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) > 2
    lengthCol3OK = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) > 2
    hasPlaceHolderTextOK = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText
    rowsOK = rowsOK And ((lengthCol2OK Or lengthCol3OK) And hasPlaceHolderTextOK)  ' Note: Using "Or" here as per original code logic
    ' Extra logic could go here to message the user if any of the above are false.
Next i

If rowsOK Then
    Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
    If Confirm = vbYes Then
        'Do submission code here - or call the submission procedure
    End If  ' Just do nothing if they say "No" - this is what your current code does.
Else
    MsgBox " Table contents are not valid, please ensure columns 2,3 and 5 are completed"
End If

但是,此逻辑适用于所有行,因此无法在主循环中识别单个行错误。您可以在 For-Next 循环中使用额外的逻辑来向用户发送错误消息。

现在代码是可维护的,更有可能做你想做的事。

关键点:

  • 使用Option Explicit。这样可以防止拼写错误,并确保您以您想要的方式使用变量。
  • 使用有意义的变量名。使您更容易遵循您想做的事情。
  • 不要将枚举值与函数返回值混淆。不要将常量与变量混淆。
  • 花一些时间检查您的逻辑链,以确保它们做您想做的事情,而不是不做您不想做的事情。后者更有可能错过无效路径。

【讨论】:

    猜你喜欢
    • 2018-04-22
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2018-12-03
    • 2015-10-18
    • 1970-01-01
    相关资源
    最近更新 更多