For...Next... Döngüleri
VBA dünyasının en temel döngü tipi For döngüleridir. Bir önceki koşullu yapılar konusunda söylediğimiz gibi döngüler de programlamanın olmazsa olmazlarıdır. Onlar olmasaydı belki 3 satırlık kodu onlarca hatta yüzlerce satır şeklinde yazmamız gerekirdi.
For döngülerinin 2 tipi vardır:
- Basit For Next döngüsü
- For Each döngüleri
For...Next...
Genel kullanım şekli şöyledir:
For i=başlangıçsayısı to bitişsayısı
'i'ye bağlı veya i'den bağımsız olarak şunu yap
Next i
Gördüğünüz gibi, sayaç olarak kullandığımız i değişkenini döngü içinde de parametrik olarak kullanabiliriz veya kullanmayabiliriz. İkisine de örnek verelim. Önce i'yi döngü içinde parametrik olarak kullanacağımız örnek olsun. Bu örnekte, A1'den A10'a kadar olan hücrelere sırayla i'nin kendisini yazmış oluruz.
For i=1 to 10
Cells(i,1)=i
Next i
Şimdi de parametrik olmayan örneğe bakalım, bunda ise Excele 10 kez bip sesi çıkarttırıyoruz.
For i=1 to 10
Beep
Next i
i sayacı genelde 0 veya pozitif(ki bu da genelde 1dir) bir sayı olmakla birlikte negatif bir sayı da olabilir, ama bunun pratikte pek kullanıldığını görmedim.
Sayacımız normalde 1er 1er artar, ancak istersek Step ifadesi ise 2'şer, 3'er de arttırabiliriz. Hatta sayacı geriye doğru da saydırabiliriz, ki bunun için Step ifadesinden sonra negatif bir sayı gelir.
For i = 10 To 1 Step -2
Cells(i / 2, 1) = i
Next i
Tüm sayfalarda gezindiğimiz bir kod:
For i = 1 To Sheets.Count
Worksheets(i).Select
'diğer kodlar
Next i
Şimdi bir başka örnekte de ilk hücreden en alt hücreye doğru ilerleyelim.
For i = 2 To Cells(1, 1).End(xlDown).Row
Cells(i,1).Select
'Diğer kodlar buraya
Next i
İçiçe For Döngüleri
For döngülerini de tıpkı koşullu yapılarda olduğu gibi iç içe geçmiş şekilde kullanabiliriz. Aşağıdaki örnekte boş olan hücreleri sarıya boyayalım ve sayısını bulalım:
Öncelikle şunu belirtmekte fayda var. Tek olsun içiçe olsun tüm döngülerde For satırını yazdıktan sonra hemen onunu bitişi olan Next satırını da yazın, aradaki kodları da girintili yazın. İçiçe For Next olacaksa bu ikinci For'u da yine girintli yazın. Şimdi kodumuza bakalım.
Sub bosluksay()
Dim adet As Integer
For i = 1 To Range("A1").End(xlToRight).Column
For k = 1 To Range("A1").End(xlDown).Row
If IsEmpty(Cells(k, i)) Then
Cells(k, i).Interior.Color = vbYellow
adet = adet + 1
End If
Next k
Next i
MsgBox "toplamda " & adet & " adet boş hücre var"
End Sub
ve sonuç:
For Each...Next...
For Each yapısı bir obje grubu ve bir dizi(veya dizimsi) içindeki elemanlar içinde gezinmek için kullanılır.
For Each nesne in nesnegrubu
'nesneyle ilgili bir işlem
Next nesne
For Each elaman in dizi
'dizi elemanıyla ilgili işlem
Next eleman
Diziler hakkında ön bilgi almak için buraya tıklayın.
Şimdi yukardaki boşluk saydırma örneğini For Each ile nasıl yapacağımıza bir bakalım.
Sub bosluksay2()
Dim adet As Integer
Dim hucre As Range, alan As Range
Set alan = Range("A1").CurrentRegion
For Each hucre In alan
If IsEmpty(hucre) Then
hucre.Interior.Color = vbYellow
adet = adet + 1
End If
Next hucre
MsgBox "toplamda " & adet & " adet boş hücre var"
End Sub
Bence For Each ile sanki daha kolay gibi görünüyor. O yüzden böyle bir görevde ben ForEach'i kullanırdım. Ancak eğer döngü içinde i veya k parametrelerinden birini kullanarak da bir işlem yapmam gerekseydi, o zaman basit For döngüsü kullanırdım, gerçi yine For Each kullandığımızda hücrenin row ve column özellikleri ile i ve k'yı dolaylı olarak elde edebilirim ama basit For'da bunlar zaten elimde olacaklardı. Kısacası duruma göre hangisini kullanacağınıza siz karar vereceksiniz. Basit For'un esnek başlangıç ve bitiş değerleri ile hareket yönündeki esnekliği avantaj sayılabilirlken, For Each için daha hızlı olmasını avantaj olarak vurgulayabiliriz.
For Each yapısını, Range'teki hücrelere ek olarak, Workbooktaki sayfalar ve tüm workbooklar arasında dolaşma şeklinde de bol miktarda kullanıyoruz.
'workbooklarda dolaşma
Dim wb As Workbook
For Each wb In Workbooks
MsgBox wb.FullName
Next wb
'worksheetlerde dolaşma
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
MsgBox ws.Name
Next ws
Yine dizi veya dizimsilerin elemanları içinde gezinirken de her iki yapı kullanılabilir. Basit For'da 1 to elemansayısı yapısı kullanılırken ForEach'te each eleman in dizi şeklinde kullanırız. Şimdi kısa bir örnek de dizilerle ilgili yapalım, daha detaylı örnekleri Diziler bölümüne bırakalım.
Mesela sabit bir bölge kodu listeniz olsun ve bunların her birini bir diziye atayalım, sonra da bu bölge kodunu kullanarak bir işlem yapalım.
Sub forarray()
Dim blg() As Variant
blg = Array(5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010)
For Each b In blg
Workbooks.Open ("C:\bölge raporları\" & b & "-netice raporu.xlsx")
'diğer işlemler
Next b
End Sub
Akılda bulundurulması gereken önemli bir husus, ForeEach kullanıldığında read-only bir özellik gösterir. Yani bu yöntemle dizi elemanlarını değiştiremezsiniz. Elamanları değiştirmek istiyorsanız basit For döngüsü kullanmanız lazım. Exlcemacromastery sitesinden aldığım bu iki örnekte fark çok açıkça anlatılmış.
Sub UseForEach()
' Diziyi yaratıp 3 değer ekliyoruz
Dim arr() As Variant
arr = Array("A", "B", "C")
Dim s As Variant
For Each s In arr
' s'nin atadığı değeri değiştirmeye çalışıyoruz
s = "Z"
Next s
' Ama değişmemiş olduğuğnu görüyoruz
For Each s In arr
Debug.Print s
Next s
End Sub
Basit for ile değişimi görelim
Sub UsingForWithArray()
Dim arr() As Variant
arr = Array("A", "B", "C")
Dim i As Long
For i = LBound(arr) To UBound(arr)
arr(i) = "Z"
Next
For i = LBound(arr) To UBound(arr)
Debug.Print arr(i)
Next
End Sub
Son bir örnek daha yapalım. Bu sefer, toplu bir goalseek(hedef ara) işlemi yapalım.
Sub toplugoalseek()
Dim h As Range
For Each h In Range("E8:E2294")
h.Select
h.goalseek Goal:=h.Offset(0, 4).Value2, ChangingCell:=h.Offset(0, 2)
Next h
End Sub
Döngüden Çıkış
Yukarıdaki kod örneklerinden de gördüğünüz üzere, For döngüleri genellikle kaç kez çalıştırılacağını bildiğiniz durumlarda kullanılır. Ör: For i=1 to 10 dersek, 10 kez çalışacağını biliriz veya For Each item in dizi dersek dizideki tüm elemanlar için çalışacağını biliriz. Tabiki üst limitin değişken olduğu bazı durumlarda, o limite başka VBA kodları ile de ulaşabilir ve yine For döngülerini kullanabiliriz, mesela en alt satırın kaç olduğunu bilmiyoruzdur ama Range("A1").End(xlDown).Row ile bunu bilip döngüyü buraya kadar götürebiliriz, gerçi bu tür durumlarda diğer döngü türlerini kullanmak daha kullanışlıdır.
Ancak bazen, döngüyü erken terketmeniz gerekebilir. Yani döngüye girdiniz diye ille sonuna kadar gitmeniz gerekmiyor. Bunun için GoTo ifadesi kullanılabileceği gibi, Exit For yapısı da kullanılabilir. GoTo kullanımında doğrudan belli bir etikete yönledirilirken Exit For ile döngünün hemen arkasından devam edilir.
Mesela yukardaki örneğimizi, boşluğa ilk rastlanılan hücrenin adresini verecek şekilide değiştrelim.
Sub bosluksay3()
Dim a As String
Dim hucre As Range, alan As Range
Set alan = Range("A1").CurrentRegion
For Each hucre In alan
If IsEmpty(hucre) Then
a = hucre.Address
Exit For
End If
Next hucre
If a <> vbNullString Then
MsgBox "ilk olarak " & a & " adresinde boşluğa rastlanmıştır"
Else
MsgBox "herhangi bir boş hücre bulunmamaktadır"
End If
End Sub