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
İlk olarak basit For döngüsü ile başlayalım

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:

post-thumb

Ö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ç:

post-thumb
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