Interaktivite
Makrolar kullanıcı ile belli başlı 4 şekilde iletişim kurar.
- Mesaj kutuları(MsgBox)
- Bilgi sorma kutuları (InputBox)
- Formlar(Userforms)
- File/Folder dialog kutuları
Son ikisini ayrı bölümlerde işleyeceğiz, biz şimdilik burada MsgBox ve InputBox ile haşır neşir olacağız.
Inputbox ile kullanıcıya çeşitli sorular sorar, ondan bir şeyler yazmasını veya sayfa üzerinde birşeyleri seçmesini bekleriz. Kullanıcının bu girdiği değeri de bir değişken içinde depolarız. O yüzden Inputboxları tek başına kullanmak yerine her zaman bir değişkene atama şeklinde kullanırız.
Dim ad As String
ad = InputBox("Adınızı girin")
Inputbox'a girilen her değer bir metindir, sayı olsa bile bu metin olarak depolanır. Girilen değeri sayı olarak kullanmak istiyorsanız bunu Valveya buna benzer bir dönüştürme metodu (Int, CInt, CLng, CDbl gibi) ile sayıya çevirmeniz gerekir. Aksi halde istenmeyen sonuçlar ortaya çıkabilir. Bir örnekle bakalım
Sub input1()
a = InputBox("bir sayı girin")
b = InputBox("ikinci bir sayı girin")
Range("A1").Value = a + b
End Sub
Kodu çalıştıralım, a için 5, b için 7 girelim. A1 hücresinde 12 rakamını görmeyi bekleriz ama 57 yazar. Çünkü VBA metinler için birleştirme operatörü olarak + işaretini de kullanılır(bir de & işareti var).
Şimdi aynı kodu aşağıda gibi çalıştıralım, aynı değerleri girelim, bu sefer 12 sonucunu görebiliriz.
Sub input2()
a = InputBox("bir sayı girin")
b = InputBox("ikinci bir sayı girin")
Range("A1").Value = Val(a) + Val(b)
End Sub
Bir diğer alternatif de, numerik olmasını istediğimiz değişkenleri baştan numerik olarak tanımlamaktır.
Sub input3()
Dim a As Integer
Dim b As Integer
a = InputBox("bir sayı girin")
b = InputBox("ikinci bir sayı girin")
Range("A1").Value = a + b '12 yazar
End Sub
Kullanım şekli ve diğer InputBox
Nesne Modelini anlatırken Classlardan ve Library'lerden bahsetmiştim. İşte bu yukarda gördüğümüz InputBox da VBA Library'si içinde Interaction class'ına ait bir fonksiyondur. Birçok fonksiyon gibi bu da parametre alır.
Syntax'ı şöyledir: InputBox(Prompt[,title][,default][,xpos][,ypos][,helpfile,context])
Bu parametrelerden sadece köşeli parantez içine alınmamış olan Prompt parametresi zorunlu olup diğerleri opsiyonedir. Önemlilerin açıklaması ise şöyledir:
- Prompt:Kullanıcıya ne girişi yapmasını söyleyeceğimiz ifade. Ör:Adınızı giriniz.
- Title:Inputbox kutusunun başlığını set edebilirsiniz
- Default:Faydalı bir özelliktir, kullanıcıya bazı durumlarda kutu içinde hazır bir değer sunabilirsiniz. Genelde, en çok girilen değerleri tahmin ederek girebilirsiniz. Örneğin "Bir il kodu girin" diyip, default değer olarak da İstanbul'un kodu olan 34ü yazabilirsiniz.
Yukarda Inputbox'ın bize aktif sayfadan bir seçim de yaptırabileceğini söylemiştim. Ancak yukardaki kodları çalıştırdığınızda bunu yapamazsınız, isterseniz bi deneyin, sonra tekrar gelin. Peki neden böyle söyledim. Çünkü bir Inputbox'ımız daha var, bu işlemi o yapar ve kendisi Excel Library'sindeki Application nesnesinin bir metodudur. Terminoloji sayfasında belirttiğimiz gibi, bu Inputbox metodu diğer metodlar gibi bir nesneye ihtiyaç duyar, yani tek başına kullanılamaz, o nesne de Application nesnesidir. İlki function iken ikincisi metoddur.
Zaten aşağıdaki resimden de görüleceği üzere bağlı oldukları classların iconları bile farklı.
İkinci Inputbox'ımızın syntax'ı ise şöyledir:Application.InputBox(Prompt,Title,Default,Left,Top,HelpFile,HelpContextID,Type)
Bir önceki InputBox'tan farklı olarak en sonda bir Type parametresi görüyoruz. Bu parametrenin alabileceği değerleri ve anlamları aşağıda verilmiştir. En sık kullanacaklarımız koyu gösterilmiştir.
Değer | Anlam |
---|---|
0 | Formül |
1 | Sayı |
2 | Metin |
4 | True/False |
8 | Range(Bir hücre grubu) |
16 | Hata değeri |
64 | Dizi |
Tablodan da görüleceği üzere kullanıcıya bir hücre grubu seçtirmek için Type parametresini 8 tipinde belirtmemiz gerekiyor. Eğer kullanıcı hem metin hem sayısal birşey girebilecekse Type değerine toplam değer olan 3(1+2) yazılır.
Hemen bir örnek yapalım.
Dim sonHucre As Range
Set sonHucre = Application.InputBox(Prompt:="Son hücreyi seçin", Type:=8)
Değişkenlerle ilgili sayfadan hatırlayacağınız üzere nesnelere değer atamak için Set ifadesini kullanıyorduk, burada da öyle yaptık.
Boş geçilen kutular(Cancel veya Esc ile iptal)
Bazen kullanıcılar hiçbir değer girmeden çıkmak ister, o zaman ne olur.
- Klasik Inputbox'ın dönüş değeri olan Stringtir ve bu durumda ilgili değişkene String tipinin default değeri atanır, yani "". O yüzden değişkenin değerinin "" olup olmadığı kontrol edilir.
- Application.Inputbox metodununu dönüş değeri Varianttır, o yüzden default değer olarak Empty bekleriz ancak MSDN bize bu Inputbox'ta boş geçilen değerler için atanan değerin False olduğunu söylüyor. O yüzden değişkenin değerini False olup olmadığı kontrol edilir, ama bu klasik Inputboxa göre biraz daha alengirlidir. Aşağıdaki örneklere bakalım.
Kodumuzda hatalı birşey olmaması için bazı kontroller yapmamız gerekiyor. Bundan sonrasına devam etmeden önce koşullu yapıları bildiğinizden emin olun, bilmiyorsanız buradan kısa bir bilgi edinip tekrar buraya gelin.
'klasik Inputbox
a=Inputbox("Bir değer girin")
If a<>"" Then
Msgbox "Giriş yapıldı"
'Diğer kodlar buraya
Else
Msgbox "Bir giriş yapılmadan çıkmayı tercih ettiniz"
End If
'Application'lı, String
Dim a As String
a=Application.Inputbox("Adınızı girin", Type:=2)
If a<>"False" Then 'False'ın tırnak içinde yazıldığına dikkat edin
Msgbox "Giriş yapıldı"
'Diğer kodlar buraya
Else
Msgbox "Bir giriş yapılmadan çıkmayı tercih ettiniz"
End If
'Application'lı, Integer(değişken tanımlanmaz, yani Varianttır)
a=Application.Inputbox("Yaşınızı girin", Type:=1)
If a<>False Then 'Variant her değeri alabilecğei için False ifadesi aynen yazılır
Msgbox "Giriş yapıldı"
'Diğer kodlar buraya
Else
Msgbox "Bir giriş yapılmadan çıkmayı tercih ettiniz"
End If
'Application'lı, Integer(değişken tanımlanır)
Dim a As Integer
a=Application.Inputbox("Yaşınızı girin", Type:=1)
If a<>0 Then 'Sayısal ifadelerde False veya False'ın rakamsal karşılığı olan 0 kullanılabilir
Msgbox "Giriş yapıldı"
'Diğer kodlar buraya
Else
Msgbox "Bir giriş yapılmadan çıkmayı tercih ettiniz"
End If
'Applicationlu, Range
'Range seçiminde eğer kullanıcı seçim yapmazsa hata oluşur, bu yüzden bir hata kontrol mekanizması da ekleriz
've ayrıca bir seçim yapıp yapmadığını da Nothing ile kontrol ederiz
On Error Resume Next 'burayı yazmassak hata alırız. Hata yönetim mekanizmaları için ilgili sayfaya gidip bilgi edinebilirsiniz
Dim a As Range
Set a = Application.InputBox("Bir hücre seçin", Type:=8)
If Not a Is Nothing Then
Msgbox "Seçim yapıldı"
'Diğer kodlar buraya
Else
Msgbox "Bir seçim yapılmadan çıkmayı tercih ettiniz"
End If
Şimdi son olarak tam bir örnek yapalım. Bu örnekte kullanıcıdan açık olan dosyaya kaç sayfa eklemek istediğini soracağız, detaylara takılmayın, sadece yukardaki anlatılanları pekiştirmeye çalışın.
Sub Sayfaekle()
Dim i As Integer, syf As Integer
syf = Application.InputBox("Kaç sayfa ekleyelim", Default:=3, Type:=1)
If syf = False Then 'escape'e baıslıysa veya Cancel'a tıklandıysa. Bunu ayrıca if syf= 0 diye de yapabilrdik
Exit Sub
Else
For i = 1 To syf
Worksheets.Add
Next i
End If
End Sub
MsgBox ile ya bilgilendirme yaparız, ya da cevabı Evet/Hayır gibi sorular sorup bilgi ediniriz. Bilgilendirme yaptığımızda bunu bir değişkene atamaya gerek yoktur, ancak bilgi topladığımızda Inputboxta olduğu gibi bir değişkene atamamız lazım.
MsgBox da InputBox gibi VBA Library'sindeki Interaction sınıfı içinde yer alır ve syntax'ı şöyledir: MsgBox(prompt[, buttons] [, title] [, helpfile, context])
Burda prompt ve title InputBoxtaki gibidir, son iki parametreden bahsetmeyeceğim, arzu eden araştırabilir. Burda önemli bir parametre var: buttons parametresi. Bu parametrenin alabileceği değerler şöyledir(Liste daha uzun ama çoğu gereksiz olduğu için buraya almadım, hatta bunlardan da en çok YesNo ve YesNoCancel düğmelerini kullanacağımızı söyleyebilirim)
Aşağıda bilgilendirmeye örnek bir kod var
Sub MessageBox()
'Uzunca bir kod bloğu
MsgBox "İşlem tamamdır"
End sub
Bilgi edinme örneği ise şöyle birşey olabilir.
Sub MessageBox()
cvp = MsgBox("Ana diskinizde(Ör:'C:') 'böl' isminde bir klasörünüz var mı?", vbYesNo) ' bu bilgi toplama mesajı
If cvp= 6 Then 'yes demek oluyor
GoTo ilerle
Else
MsgBox "O ZAMAN O KLASÖRÜ YARATIP TEKRAR ÇALIŞTIR" 'bu bilgi mesajı
Exit Sub
End If
ilerle:
'diğer kodlar
End sub
Gördüğünüz üzere cvp değerinin değerini 6 gibi bir sayıyla ölçtük. İşte VBA'da bazı sabitlerin(constant) böyle sayısal değerleri vardır, ikisi de kullanılabilir. Tüm düğmeler ve değerleri şöyle.
Sabit | Değer |
---|---|
vbOK | 1 |
vbCancel | 2 |
vbAbort | 3 |
vbRetry | 4 |
vbIgnore | 5 |
vbYes | 6 |
vbNo | 7 |
InputBox'ta olduğu gibi MsgBox'ın da iptal edilmesi sözkonusu olabilmektedir. Tabi eğer buton türü olarak Cancel varsa. Aksi halde Esc tuşu da işe yaramamaktadır.
Bu örnekten çıkış mümkün değilken,
Sub msgbox1()
On Error GoTo hata
a = MsgBox("Cevap verirmisin", vbYesNo)
'Diğer kodlar
Exit Sub
hata:
Debug.Print Err.Description
End Sub
Ama bunu iptal edebilirsiniz.
Sub msgbox1()
On Error GoTo hata
a = MsgBox("Cevap verirmisin", vbYesNoCancel)
If a = vbYes Then
MsgBox "Evet denildi"
ElseIf a = vbNo Then
MsgBox "Hayır denildi"
Else
MsgBox "Seçimi iptal ettiniz"
End If
Exit Sub
hata:
Debug.Print Err.Description
End Sub
Önemli bir detay da, MsgBox'ın bilgi toplama formundayken mutlaka ()'ler içinde kullanılmasıdır. Mesaj verirken ise genelde () olmadan kullanılır, ama parantezli kullanımı da sorunsuz çalışır.
Şimdi kod yazmada biraz deneyim kazandığımıza göre uzun kodlar yazarken nelere dikkat etmemiz gerekir ona bir bakalım.
Kullanıcı dostu kodlama
Kullanıcılara bazen MsgBox ile bazen Inputbox ile çeşitli mesajlar yayınlamak gerekecek. Kullanıcı bu mesajları rahat okusun diye gerekli yerlerde satır geçişlerini yapmanız lazım. Bir örnekle ne demek istediğimiz daha iyi anlatabilirim.
Şimdi aşağıdaki kodu, bir modül içine yazıp F5 ile çalıştıralım. Görüntü aşağıdaki gibi olup, kullancının okuması açısından çok kolay değildir.
Sub satırgeçiş()
a = InputBox("Müşteri segmenti için bir değer giriniz. Bireysel müşteriler için 1, Ticari müşteriler için 2, Kurumsal müşteriler için 3")
End Sub
Şimdi bir de bu kod nasıl daha düzenli hale getirilir ona bakalım: Her cümle ve seçenek arasına bir ifade koyarak. Bu ifade vbCrLf ifadesidir ve cümleleri bir alt satıra taşır, bunun yerine vbCr veya vbLf veya vbNewLine veya Chr(10) ifadeleri de kullanılabilir. (Bunların dördü de Msgbox ve InputBox kullanımında aynı etkiye sahiptir, ancak hücre içine birşey yazdırırken farklı etkilere sahiptir, bunu deneyip görebilrisiniz.)
Sub satırgeçiş2()
a = InputBox("Müşteri segmenti için bir değer giriniz. " & vbCrLf & "Bireysel müşteriler için 1," & vbCrLf & "Ticari müşteriler için 2," & vbCrLf & "Kurumsal müşteriler için 3")
End Sub
Kodlamacı dostu kodlama
Şimdi yeri gelmişken bir de kullancı dostu olmakla ilgili değil ama kodlamacı dostu olmakla ilgili bir notum olacak. Yine yukardaki kodu örnek alalım, bu kod biz kodlamacılar için de okuması zor, çünkü VBE içinde kod sağa doğru uzuyor, ama kodlamacı olarak benim bunu ekranda, scroolbarı sağa sürüklemeden görebilmem lazım. Hadi gelin bunu okunaklı hale getirelim.
Yapacağımız şey basit, cümleyi nerden kesmek istiyorsak oraya bir boşluk ve sonrasında bir alt çizgi(_) koymak. Buna Line Contination Character adı verilir.
Sub satırgeçiş3()
a = InputBox("Müşteri segmenti için bir değer giriniz. " & vbCrLf & _
"Bireysel müşteriler için 1," & vbCrLf & _
"Ticari müşteriler için 2," & vbCrLf & _
"Kurumsal müşteriler için 3")
End Sub
Görüldüğü gibi, kod şimdi bizim için de daha okunaklı hale geldi.
Bunu yapmanın bir yolu daha var, o da metni parçalara ayırmak.
Sub satırgeçiş4()
mesaj = "Müşteri segmenti için bir değer giriniz. " & vbCrLf
mesaj = mesaj + "Bireysel müşteriler için 1," & vbCrLf
mesaj = mesaj + "Ticari müşteriler için 2," & vbCrLf
mesaj = mesaj + "Kurumsal müşteriler için 3"
a = InputBox(mesaj)
End Sub
NOT:mesaj = mesaj + ..... şeklinde sağduyuya aykırı gibi görünen kısım kafanızı karıştırdıysa buradan detaylı bilgi edinebilirsiniz.
Bu iki yöntemi sadece interaktivite sağlayan yerlerde değil başka yerlerde de kullanacağız.
Bu arada hemen iki yöntem arasındaki küçük farka da değinelim. İlk yöntem yani _ yöntemi ile sadece metin birleştirme değil, içinde metin bile olmayan tam bir VB kodunu da parçalara ayırabiliriz, amaç yine aynı: Sağa doğru uzayan kodu tek bir ekranda tutmak. Aşağıdaki gibi.
Sub blabla()
Cells.Find(What:="Volkan", After:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False).Activate
End Sub
İkinci yöntemin ise tek amacı uzun metinleri parçalara ayırmaktır.