excel VBA For Next循环不起作用的问题

9njqaruj  于 2022-12-01  发布在  其他
关注(0)|答案(2)|浏览(264)

我正在尝试理解一段代码,这段代码在过去对我有效,但现在在另一个应用程序中不起作用。基本上,它需要删除包含特定列中信息的所有行,并保持其余行不变。当我运行宏时,代码执行没有问题,但只是删除了一些有值的行。不是所有的。当连续运行代码几次时,它最终会完成预期的任务,但这真的很不方便。代码如下:

Sub Delete_Signoffed()

Dim rCell As Range
Dim iCol As Integer
Dim iRow As Integer

Worksheets("MilestoneDueDate").Activate
If ActiveSheet.AutoFilterMode Then Cells.AutoFilter
ActiveWindow.FreezePanes = False
Columns.EntireColumn.Hidden = False

If WorksheetFunction.CountA(Columns("A")) = 0 Then
    Columns("A").Delete
    Rows("1:6").Delete
End If

iCol = Cells.Find("Sign-Off By", LookAt:=xlWhole).Column

For iRow = 2 To Cells(Rows.Count, iCol).End(xlUp).Row
    Cells(iRow, iCol).Select
    If Not IsEmpty(Cells(iRow, iCol).Value) Then Rows(iRow).EntireRow.Delete
Next iRow

End Sub

源文件存在一些格式问题,在为iCol指定列值之前的所有操作都是为了修复格式,因此请忽略。iRow从2开始以避免删除文件标题。
对于为什么For循环不能正常工作有什么想法吗?
提前感谢!

gijlo24d

gijlo24d1#

我更新了你的脚本。我还添加了评论,以便你能够更好地理解它,并能够在未来改进它。

Sub Delete_Signoffed()

'Goto CleanUp if there are errors
On Error GoTo CleanUp

Dim wsMilestoneDueDate As Worksheet

Dim rCell As Range
Dim iCol As Integer
Dim iRow As Integer

Set wsMilestoneDueDate = ActiveWorkbook.Worksheets("MilestoneDueDate")

'Disable temporarily Screen Updating
Application.ScreenUpdating = False

With wsMilestoneDueDate
    
    .Activate   'No need, but if you prefer you can
    
    'Activate Auto Filter
    If .AutoFilterMode Then Cells.AutoFilter
    
    'Remove FreezePanes
    ActiveWindow.FreezePanes = False
    
    'Unhide Columns
    .Columns.EntireColumn.Hidden = False
    
    'Delete Empty Columns/Rows if they are all empty
    If WorksheetFunction.CountA(.Columns("A")) = 0 Then
        Columns("A").Delete
        Rows("1:6").Delete
    End If
    
    'Get the last Column
    iCol = .UsedRange.Find("Sign-Off By", LookAt:=xlWhole).Column
    
    'Start Deleting but from the last to the first (Backward)
    For iRow = Cells(Rows.Count, iCol).End(xlUp).Row To 2 Step -1
        
        Set rCell = Cells(iRow, iCol)
        
        'Delete the entire row if it is NOT empty
        If Not IsEmpty(rCell.Value) Then
            'Deletion
            Rows(iRow).EntireRow.Delete
        End If
    Next iRow
    
End With

CleanUp:
    'Purge Memory
    Set wsMilestoneDueDate = Nothing
    Set rCell = Nothing

    'Restore Screen Updating
    Application.ScreenUpdating = True

End Sub
c2e8gylq

c2e8gylq2#

正如在注解中已经指出的,代码中的缺陷不是向后循环
但我在此给出一个解决方案,它不需要循环,只使用一行代码,这要归功于Range对象的SpecialCells方法,它指定它过滤具有某个“常量”(即不是从公式中派生的)值的单元格

Range(Cells(2, iCol), Cells(Rows.Count, iCol).End(xlUp)).SpecialCells(xlCellTypeConstants).EntireRow.Delete

这假定您始终在第1行下面至少有一个值
如果不是这种情况,则只需添加一个检查:

If Cells(Rows.Count, iCol).End(xlUp).Row > 1 Then Range(Cells(2, iCol), Cells(Rows.Count, iCol).End(xlUp)).SpecialCells(xlCellTypeConstants).EntireRow.Delete

在查看整个代码时,您应该采用避免Select/Selection, Activate/ActiveXXX模式的良好做法,并始终完全限定直到其工作表(如果不是工作簿)父对象的范围,如下所示:

Sub Delete_Signoffed()

    Dim iCol As Long

    With Worksheets("MilestoneDueDate") ' reference wanted sheet

        If .AutoFilterMode Then .Cells.AutoFilter
        ActiveWindow.FreezePanes = False

        .Columns.EntireColumn.Hidden = False

        If WorksheetFunction.CountA(.Columns("A")) = 0 Then
            .Columns("A").Delete
            .Rows("1:6").Delete
        End If

        iCol = .Range("A1", .Cells(1, .Columns.Count).End(xlToLeft)).Find("Sign-Off By", LookAt:=xlWhole, LookIn:=xlValues).Column

        .Range(.Cells(2, iCol), .Cells(.Rows.Count, iCol).End(xlUp)).SpecialCells(xlCellTypeConstants).EntireRow.Delete

    End With   

End Sub

如你所见

  • 所有测距对象(Columns()RowsRangeCells)通过它们前面点(.)引用Worksheets("MilestoneDueDate")
  • iCol正在运行Find()方法设置,范围尽可能受限制

相关问题