如何在VBA for Excel中的同一循环中循环遍历两个Range对象?

huangapple go评论72阅读模式
英文:

How can I loop through 2 Range-Objects in the same Loop in VBA for Excel?

问题

我试图在下面的代码中注释我尝试做什么。我知道如何保留更改的旧值的选定单元格。它适用于一个单元格,但不适用于多个单元格。我不明白如何在同一个For循环中循环遍历2个范围对象。我不认为使用For-Each会起作用。

Dim OldValue As Range

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  Dim FirstFreeRow As Long
  Dim tCell As Variant
  Dim I As Integer
  
  If Sh.Name = "Changes" Then Exit Sub
  If Sh.Name = "Tabelle2" Then Exit Sub
  If Intersect(Target, Sh.Range("A2:Z550")) Is Nothing Then Exit Sub
  
  Application.EnableEvents = False
  
  For I = 1 To Target.Count '遍历所有更改的单元格
  
    Set tCell = Target.Cells(I, 1)

    With Sheets("Changes")
      FirstFreeRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
      With .Rows(FirstFreeRow)
         .Cells(1) = tCell.EntireColumn.Cells(1)
         .Cells(2) = tCell.EntireRow.Cells(2)
         .Cells(3) = tCell.EntireRow.Cells(3)
         .Cells(4) = OldValue.Cells(I, 1).Value '将旧值放在这里
         .Cells(5) = tCell.Range("A1").Value
         .Cells(6) = Environ("username")
      End With
    End With

  Next I
  
  Application.EnableEvents = True
End Sub

Public Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

  Set OldValue = Target '保存所有选定的单元格

End Sub

边问:如果使用剪切和粘贴,那么显然没有旧值,因为您有一个新的选定单元格。是否有办法?如果没有,也无所谓。

谢谢。

英文:

I tried to comment in the Code below what I try to do. I know how to keep the selected Cells for the old value which got changed. It works with only one cell, but not more. I don't get it how I can loop through the 2 Range-Objects in the same For-Loop. I don't think it will work with a For-Each.

Dim OldValue As Range

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  Dim FirstFreeRow As Long
  Dim tCell As Variant
  Dim I As Integer
  
  If Sh.Name = "Changes" Then Exit Sub
  If Sh.Name = "Tabelle2" Then Exit Sub
  If Intersect(Target, Sh.Range("A2:Z550")) Is Nothing Then Exit Sub
  
  Application.EnableEvents = False
  
  For I = 0 To Target.Count 'Go through all changed Cells
  
  tCell = Target.Cells(I, 1)

  With Sheets("Changes")
    FirstFreeRow = .Cells(Rows.Count, 1).End(xlUp).Row + 1
    With .Rows(ErsteFreieZeile) '.EntireRow
       .Cells(1) = tCell.EntireColumn.Cells(1)
       .Cells(2) = tCell.EntireRow.Cells(2)
       .Cells(3) = tCell.EntireRow.Cells(3)
       .Cells(4) = OldValue(I, 1).Value 'Put the old value in here
       .Cells(5) = tCell.Range("A1").Value
       .Cells(6) = Environ("username")
    End With
  End With

  Next I
  
  Application.EnableEvents = True
End Sub

Public Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

Set OldValue = Target 'Save all selected Cells

End Sub

Sidequestion: If you use Cut and Paste then you don't have the old Value obviously, because you have a new selcted cell. Is there a way too? If not, doesn't matter.

Thanks.

Edit:
I am not allowed yet to post images directly. So it is posted as a link instead. Apologies. The Images shows how the Changes are supposed to be documented.

Does this make it more clear? I only have "Tabelle 1". "Tabelle 2" is something else, doesn't matter here.

答案1

得分: 2

以下是翻译好的内容:

你有几种方法来循环遍历范围的所有单元格:

A) 使用计数循环

Dim i As Long
For i = 1 To target.Count
    Debug.Print "方法 A ", target(i).Address
Next

如你所见,当你使用这种方法时,你只使用一个索引来访问范围内的单元格。

B) 逐行和逐列循环

Dim row As Long, col As Long
For row = 1 To target.Rows.Count
    For col = 1 To target.Columns.Count
        Debug.Print "方法 B ", target(row, col).Address
    Next col
Next row

现在你使用了两个索引来访问范围,分别是行和列。请注意,这些索引代表相对的行数和列数,所以如果你的范围是 "E5:G10",那么 target(1, 1) 是该范围的第一行和第一列,即单元格 E5。

C) 使用 foreach 循环

Dim cell As Range
For Each cell In target
    Debug.Print "方法 C ", cell.Address
Next cell

在大多数情况下,这是最简单的方法。


我在你的代码中至少看到了两个问题:
第一个问题是你在循环中使用了第一种方法(使用计数循环),但是却使用了两个索引来读取目标范围中的单元格。如果你的范围有 3 行 4 列(所以计数 = 12),那么你会从第一行读取 12 个单元格,这不是你想要的。

第二个问题是你缺少了 Set 关键字(而且你声明 tCell 为 Variant 而不是 Range)。现在,如果 tCell = Target.Cells(I, 1),tCell 将获取范围的内容。这会在你的代码后面导致运行时错误(如果 tCell 是一个值,那么 tCell.EntireColumn 将无法工作)。在 VBA 中,你需要使用关键字 Set 将对象的引用分配给变量:Set tCell = Target.Cells(I, 1)

英文:

You have several possibilities to loop over all cells of a Range:

A) Loop using Count (of cells)

Dim i As Long
For i = 1 To target.Count
    Debug.Print "Method A ", target(i).Address
Next

As you can see, you use only a single index into the range when you use this method

B) Loop over rows and columns

Dim row As Long, col As Long
For row = 1 To target.Rows.Count
    For col = 1 To target.Columns.Count
        Debug.Print "Method B ", target(row, col).Address
    Next col
Next row

Now you use 2 indizes into the range, the row and the column. Note that those indizes represent relative numbers, so if your range is "E5:G10", target(1, 1) is the first row and first column of that range, that is cell E5.

C) Using a foreach loop.

Dim cell As Range
For Each cell In target
    Debug.Print "Method C ", cell.Address
Next cell

In most cases that is the easiest way.


I see at least 2 issues in your code:
The first is that you use the first method (using count) for the loop but reads the cell from the target range using 2 indizes. If you have 3 rows by 4 colums in your range (so count = 12), you would read 12 cells from the first row which is not what you want.

Second is that you miss the Set keyword (and you declare tCell as Variant instead of Range. Now id tCell = Target.Cells(I, 1), tCell will get the content of the Range. This will give you a runtime error later in your code (tCell.EntireColumn cannot work if tCell is a value).
In VBA, you need to use the keyword Set to assign a reference to an object to a variable: Set tCell = Target.Cells(I, 1)

huangapple
  • 本文由 发表于 2023年5月25日 13:35:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76329197.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定