2017-08-11 84 views
2

我試圖回答this question當我遇到Excel中的一些奇怪的VBA行爲。我寫了一個非常簡單的子來證明這個問題:非連續範圍的奇怪單元格地址行爲:VBA

Sub debugAddresses(rng As Range) 
    Debug.Print "Whole range: " & rng.Address 
    Dim i As Long 
    For i = 1 To rng.Cells.Count 
     Debug.Print rng.Cells(i).Address 
    Next i 
End Sub 

我遍歷每個單元格在一個範圍對象並打印其地址,簡單吧?

debugAddresses Range("B2:B3") 
' Result as expected: 
' >> Whole range: $B$2:$B$3 
' >> $B$2 
' >> $B$3 

然而,對於非連續的範圍,我得到一些奇怪的行爲:

debugAddresses Range("A1,B2") 
' Strange behaviour when getting addresses of individual cells: 
' >> Whole range: $A$1,$B$2 
' >> $A$1 
' >> $A$2 

任何人都可以擺脫任何光線就這個嗎?具體爲爲什麼,Cells對象可用於索引連續範圍,似乎只是擴展了第一個選中的Area


編輯:這可能是值得指出的是,使用通過實際的單元格區域對象For Each循環給出了預期的結果*

Sub debugAddresses2(rng As Range) 
    Debug.Print "Whole range: " & rng.Address 
    Dim c As Range 
    For Each c In rng 
     Debug.Print c.Address 
    Next c 
End Sub 

* 見我的回答對一個評論對一個更強大的解決方案,因爲這(顯然)可能不總是預期的結果

+1

您正在使用非連續的範圍,所以'rng.Cells(ⅰ).Address'可能用於'rng.Areas(1).Cells(ⅰ).Address'的略寫。 –

+0

這很奇怪,因爲如果你嘗試在這些單元上輸入一些數據。它實際上工作:rng.Cells =「測試」 – danieltakeshi

+0

@FlorentB。 「可能是速記」基於什麼?有什麼文件呢?我也不這麼認爲,因爲'.Areas(1)'中沒有足夠的單元格,你會得到索引超出範圍... – Wolfie

回答

0

似乎弗洛朗的評論是在正確的方向上4行,並且該方法被延伸的範圍對象內的第一Area

在一個連續的範圍(例如"A1:B5""C10:C100")以下方法遍歷在給定的範圍內,rng每個小區。

Dim j As Long 
For j = 1 To rng.Cells.Count 
    Debug.Print rng.Cells(j).Address 
Next j 

然而,在非連續的範圍看來這是等效(或簡寫

For j = 1 To rng.Cells.Count 
    Debug.Print rng.Areas(1).Cells(j).Address 
Next j 

似乎沒有要在此任何直接提the documentation,但通過查看VBA編輯器的本地瀏覽器進行繪製是一個明智的結論。

在範圍對象rng中,有一個Cells屬性,它只包含一個「Item」,它是第一個Area。因此,假定這一項是.Cells(j)有權訪問的是合理的。

cells

rng我們還可以看到Areas屬性,其中包含2項(在本例中)等於Areas在我的非連續範圍的數量。

areas


所以rng.Cells(j)正在訪問的rng在第一區域內的j th元素。因爲.Cells()可以延伸超過rng的原始大小,所以我們看到列在rng之外的單元格的地址。


溶液(S):

  • 要麼確保您通過範圍的物品直接循環內rng使用For Each迴路如圖中的問題。
  • 或循環遍歷每個區域,然後遍歷該區域內的每個單元格。

第一個選項是更簡潔,但沙伊指出,是完全肯定的是,最可靠的方法是做兩個For Each迴路因爲可能存在未與單捕獲更復雜的邊界情況循環。

1

嘗試使用以下的改性Sub debugAddresses代碼:

Sub debugAddresses(rng As Range) 

    Dim RngA As Range 
    Dim C As Range 

    For Each RngA In rng.Areas 
     For Each C In RngA.Cells 
      Debug.Print C.Address 
     Next C 
    Next RngA 

End Sub 
+0

所以這個工作,但你知道*爲什麼*原來沒有工作?即使在不同的地區,地址不應該改變?它不是像單元格在他們自己的區域內都是'$ A $ 1' ... – Wolfie

+0

也看到我的編輯,一個更簡單的'For Each'循環的作品,只是沒有單元格索引... – Wolfie

+0

@Wolfie關於你的第一個問題,我總是加倍爲每個循環,一個通過區域,另一個爲單元格。 –

0

這裏是你的代碼「固定」。通過就可以通過輸入單元格地址的前多加一個For循環

Sub debugAddresses(rng As Range) 

    Debug.Print "Whole range: " & rng.Address 

    For Each r In rng ' this loops through the range even if separated cells 

    Dim i As Long 
     For i = 1 To r.Cells.Count 'changed to r instead of rng 
      Debug.Print r.Cells(i).Address 'changed to r instead of rng 
     Next i 
    Next r 

End Sub 


所以.Range作品。 "B1",或者使用R1C1表示行列ex。 1,2。

但是你不能在.Range中只使用一個R1C1,因爲這裏的範圍是單元格的範圍。因此要在.Range中正確使用R1C1,您必須指定其中的2個。

所以.Range("B5:B10")等於Range(Cells(5,2),Cells(10,2))

你做的是什麼指定一個範圍,然後從使用細胞產生另一個範圍。非常喜歡偏移量

所以Range("A1,B2")然後加入Cells(1)然後Cells(2)將行添加到第一個範圍是「A1」或偏移量。

Sub selector() 
Set Rng = Range("A1") 
Rng.Select 
Rng.Cells(4, 4).Select 

End Sub 

這抵消4個colums和從A1

+0

我不認爲你說得很對,指定一個範圍是完全有效的,只有一個範圍地址和逗號,與R1C1無關。您可以在第一個調試語句中看到這一點,該語句顯示範圍地址是所需的。當我在*'rng'中包含的單元數量*中進行特定循環時,您在代碼塊中所做的只是爲單個單元複製問題的一部分。 – Wolfie

+0

我不爭論它的有效性,我爭論它的正確使用。你在'.Range'上使用了'.Cells',並期望它保持在'.Range'內?那麼爲什麼不直接使用'.Range'或者'.Cells'?爲什麼使用它們呢? '.Range.Cell'就像一個偏移量。爲了循環遍歷範圍內的單元格,使用範圍內的每個r – fcsr

+0

在一個連續的塊內,'.Range.Cells'就像一個索引工具,在那裏你可以可靠地循環到範圍對象中的單元的數量並期望留在範圍內。這就是爲什麼我的問題具體是爲什麼這種行爲發生在不連續的範圍內,即VBA用來訪問範圍內的「單元」對象的結構。在我的問題中,我表明我知道我可以使用For Each。 – Wolfie