如何为此 VBA 宏创建循环?

How do I create a loop for this VBA macro?

提问人:ExcelN00b 提问时间:9/6/2023 更新时间:9/6/2023 访问量:49

问:

我有一个训练矩阵,我希望能够单击每个人的姓名,然后将他们的行复制到单独的工作表上的报告样式格式。

我找到了一些有效的东西,但由于我根本不是程序员,我一直在为 excel 表格中的每一行复制和粘贴相同的代码行......我意识到有一种更好的方法可以做到这一点,但我不知道该怎么做。我想我可以侥幸逃脱,直到我遇到“程序太大”错误。

目前,我将每个人的姓名设置为指向文档 (A1) 中单元格的链接,然后我有以下代码:

Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
    If Target.Range.Address = "$A$4" Then
       Sheets("Report").Activate
       Sheets("Data Table").Range("A4:E4").Copy Destination:=Sheets("Report").Range("B2")
       Sheets("Data Table").Range("F3:BAA3").Copy
       Sheets("Report").Range("A4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F1:BAA1").Copy
       Sheets("Report").Range("B4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F2:BAA2").Copy
       Sheets("Report").Range("C4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F4:BAA4").Copy
       Sheets("Report").Range("D4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Report").Range("D4:D1500").Select
       Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
    End If
    If Target.Range.Address = "$A$5" Then
       Sheets("Report").Activate
       Sheets("Data Table").Range("A5:E5").Copy Destination:=Sheets("Report").Range("B2")
       Sheets("Data Table").Range("F1:BAA1").Copy
       Sheets("Report").Range("B4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F3:BAA3").Copy
       Sheets("Report").Range("A4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F2:BAA2").Copy
       Sheets("Report").Range("C4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F5:BAA5").Copy
       Sheets("Report").Range("D4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Report").Range("D4:D1500").Select
       Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
    End If
End Sub

您会注意到每个块中唯一的变化是“If”范围以及第一个和第四个数据表范围,每次增加一个。我总共有 212 行,将来还会添加更多行。

我想要一些可以更有效地做同样事情的东西(比如 LOOP),并且希望在添加另一个人时不需要修改!我有一种感觉,这是很有可能的,并不像我想象的那么难,但正如我所说,我绝对不是一个程序员。

遵循 DRY 理念的任何帮助将不胜感激!!=)

-大卫

TLDR:我尝试输入其中的 212 个 if 语句,但它在大约 70 个条目时停止工作,程序太大了。我想我会在这里问我如何编写一个循环,然后我自己尝试将其拆分为 3 个类似的过程......

Excel VBA 循环 干燥

评论

0赞 cybernetic.nomad 9/6/2023
将目标范围分配给变量,然后将其用作起点。最好避免在代码中使用 Select。

答:

2赞 Tim Williams 9/6/2023 #1

像这样的东西:

Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
    Dim rw As Range, ws As Worksheet
    
    Set rw = Target.EntireRow 'the row with the clicked link
    Set ws = ThisWorkbook.Worksheets("Report")
    
    CopyValues rw.Range("A1:E1"), ws.Range("B2") 'Note: `Range` is *relative* to `rw`
                                                 '  and not to the sheet
    ' `Me` is the worksheet for this code module...
    CopyValues Me.Range("F1:BAA1"), ws.Range("B4"), True 'True=Transpose
    CopyValues Me.Range("F2:BAA2"), ws.Range("C4"), True
    CopyValues Me.Range("F3:BAA3"), ws.Range("A4"), True
    
    CopyValues rw.Range("F1:BAA1"), ws.Range("D4"), True
    
    ws.Range("D4:D1500").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
    
End Sub

'copy values between `rngSrc` and `rngDest`, with optional Transpose (defaults to False)
'  Note: Transpose has an upper limit of about 65k cells....
Sub CopyValues(rngSrc As Range, rngDest As Range, Optional Transpose As Boolean = False)
    With rngSrc
        If Transpose Then
            rngDest.Cells(1).Resize(.Columns.Count, .Rows.Count).Value = Application.Transpose(.Value)
        Else
            rngDest.Cells(1).Resize(.Rows.Count, .Columns.Count).Value = .Value
        End If
    End With
End Sub

评论

0赞 ExcelN00b 9/6/2023
我现在没有太多时间看这个,但我看到了你关于 65k 单元格转置限制的说明,我有 200 名员工(行)和 1100 个程序(列)。我确实抓住了我们的 SOP 计数 x4(数字、姓名、修订信、匹配的员工培训数据),所以最多 4000 个单元格,然后可能有几百个新的 SOP,所以我认为我尝试转置的最大单元格数是 5000。
0赞 Tim Williams 9/6/2023
限制仅针对每次调用,(例如)F:BAA 为 1374 列,所以我认为那里没有问题......
0赞 Tim Williams 9/6/2023
在上面做了一些编辑:rw.Range(...)Me.Range(...)
0赞 taller 9/6/2023 #2

如果目标在 A 列中且行号在 4 到 100 之间(根据需要更新),则将执行复制/粘贴。

Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
    Dim c As Range
    Set c = Target.Range
    If c.Column = 1 And (c.Row >= 4 And c.Row <= 100) Then
       Sheets("Report").Activate
       Sheets("Data Table").Range("A" & c.Row).Resize(1, 5).Copy Destination:=Sheets("Report").Range("B2")
       Sheets("Data Table").Range("F3:BAA3").Copy
       Sheets("Report").Range("A4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F1:BAA1").Copy
       Sheets("Report").Range("B4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Data Table").Range("F2:BAA2").Copy
       Sheets("Report").Range("C4").PasteSpecial Transpose:=True, Paste:=xlPasteValues       
       Sheets("Data Table").Range("F" & c.Row).Resize(1, 1374).Copy 
       Sheets("Report").Range("D4").PasteSpecial Transpose:=True, Paste:=xlPasteValues
       Sheets("Report").Range("D4:D1500").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
    End If
End Sub

0赞 VBasic2008 9/6/2023 #3

工作表 FollowHyperlink:将值复制到另一个工作表

enter image description here

工作表模块,例如Sheet1(数据表)

Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
    
    'Debug.Print Target.Range.Address
    
    ' Reference the source worksheet.
    Dim sws As Worksheet: Set sws = Me ' Data Table
    'Set sws = Target.Range.Worksheet
    
    ' Reference the target range in the source worksheet.
    Dim trg As Range:
    Set trg = sws.Range("A4", sws.Cells(sws.Rows.Count, "A").End(xlUp))
    
    ' Attempt to reference the target cell.
    Dim tCell As Range: Set tCell = Intersect(trg, Target.Range)
    If tCell Is Nothing Then Exit Sub ' no intersection (no target cell)
    
    ' Reference the destination worksheet.
    Dim dws As Worksheet: Set dws = sws.Parent.Sheets("Report")
    'Set dws = ThisWorkbook.Sheets("Report")
    'Set dws = Target.Range.Worksheet.Parent.Sheets("Report")
    
    ' Declare variables.
    Dim srg As Range, drg As Range
    
    ' Copy 'A:E'
    Set srg = tCell.EntireRow.Columns("A:E")
    Set drg = dws.Range("B2")
    srg.Copy drg
    
    ' Copy 'F:BAA'
    Set srg = sws.Columns("F:BAA")
    Dim cCount As Long: cCount = srg.Columns.Count
    Set drg = dws.Range("A4:D4").Resize(cCount)
    With Application
        drg.Columns(1).Value = .Transpose(srg.Rows(3).Value)
        drg.Columns(2).Value = .Transpose(srg.Rows(1).Value)
        drg.Columns(3).Value = .Transpose(srg.Rows(2).Value)
        drg.Columns(4).Value = .Transpose(srg.Rows(tCell.Row).Value)
    End With
    
    ' Attempt to reference the empty cells in destination column 'D'.
    Set drg = Nothing ' reset
    On Error Resume Next ' prevent error if no empty cells
        Set drg = dws.Range("D4", dws.Cells(dws.Rows.Count, "D").End(xlUp)) _
            .SpecialCells(xlCellTypeBlanks)
    On Error GoTo 0
    
    ' Delete entire rows of the empty cells.
    If Not drg Is Nothing Then ' there are empty cells
        drg.EntireRow.Delete
    'Else ' no empty cells; do nothing
    End If

End Sub