Worksheet
Excel Nesne Modelinde Workbooktan sonraki seviyede sayfalar gelir. Excelde 4 tip sayfa vardır. Bunlar;
- Çalışma sayfası(Worksheet:En çok bunları kullanacağız)
- Chart Sheet(Başlı başına bir sayfa olan grafik sayfaları)
- Macro Sheet(Bildiğimiz makro değil, eskiyle uyumluluk adına duruyor, biz bunlara hiç girmeyeceğiz)
- Dialog Sheet(Eskiyle uyum adına duruyor, bunlara da girmeyeceğiz)
Biz en çok Sheet ve Worksheet nesnelerini kullanacağız. Yukardaki 4 maddeden anlaşıldığı üzere Worksheet nesnesi, Sheet nesnesinin bir alt türü oluyor. Sheet nesnesi, Sheets koleksiyonunun, Worksheet nesnesi de hem Worksheets koleksiyonunun hem de Sheets koleksiyonunun bir üyesidir. Bu koleksiyonlar bir dosyadaki tüm sayfaları ifade eder ve genelde döngülerde (Döngü konusunu hiç bilmiyorsanız en azından bir For Next için buraya bakıp tekrar gelin), veya toplam sayfa adedini saydırma gibi özelliklerle birlikte kullanılır. Diyelim ki dosyamızda 3 çalışma sayfası bir de grafik sayfası varsa Sheets.Count 4 sonucunu döndürürken Worksheets.Count 3 sonucunu döndürür.
Bunu kendiniz de deneyebilrisinz. Yukardaki özelliklerde bir dosya hazırlayın ve VBE'de şu kodları çalışıtırın
Debug.Print ActiveWorkbook.Sheets.Count
Debug.Print ActiveWorkbook.Worksheets.Count
Not:Biz birçok yerde Sheets ve Worksheets'i birbiri yerine kullanacağız.
Sayfalara erişim ve referans
Sayfalar bir koleksiyon üyesi oldukları için onlara koleksiyonun item özelliği ve bu özelliğin index numarası ile ulaşabiliriz. Item özelliği koleksiyonların default özelliği olduğu için tüm diğer koleksiyonlarda olduğu gibi bunda da yazılmadan es geçilebilir.
Yani Worksheets.Item(1) ile Worksheets(1) tamamen özdeştir. Keza Workbooks.Item(1).Sheets.Item(2) ile Workbooks(1).Sheets(2) de özdeştir. Gördüğünüz üzere başka bir Workbooktaki bir sayfaya da Workbook ile sayfa arasına nokta koyarak ulaşıyoruz. Koleksiyonlarda indexler 1'den başlar(En soldaki sayfanın index değeri 1'dir.)
Sayfalara index numarasıyla olduğu gibi sayfa adı ile de, Worksheets("ilksayfa") gibi, ulaşabiliriz.
Mevcutta aktif olan sayfaya da ActiveSheet ifadesi ile ulaşırız. Activesheetle ilgili detaylara aşağıda değineceğiz.
Seçme ve Aktive etme
Range nesnesinde nasıl bir veya birden çok hücreyi seçmek için Select metodu kullanılıyorsa sayfalar için de aynı metod kullanılır. Yine Range'te olduğu gibi tek bir hücreyi aktive etmek için Activate metodu kullanılıyordu, burda da yine aynı metod tek bir sayfayı aktive etmek için kullanılır.
Aşağıdaki kod ile tüm sayfalarda dolaşıyor ve her sayfanın ilk hücresine artan bir şekilde sıra numarası yazıyorum.
For Each ws In ActiveWorkbook.Worksheets
ws.Select
Range("A1").Value=i
i=i+1
Next
Activate gizli olan sayfaların seçimi için de kullanılabilirken, Select ile gizli sayfalar seçilemez. Mesela şimdi bi dosya açın, 5 sayfası olsun, 2.sini gizleyin. Sonra aşağıdaki kodu çalıştırın.
Sub gizlisec_activateli()
Dim ws As Worksheet ' bu sefer ws'yi Worksheet olarak tanımladım
For Each ws In ActiveWorkbook.Sheets
ws.Activate
Range("a1") = ws.Index
Next
End Sub
Bu kod ile tüm sayfalarda A1 hücresinin dolu olduğunu görürsünüz, 2.sayfayı unhide edip kontrol edebilirsiniz.
Sub gizliyisec1()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
ws.Select 'gizli olduğu için hata verir
Range("a1") = ws.Index
Next
End Sub
Bu yukardakini "sayfa visible mı?" diye kontrol ederek de yapalım, bu sefer hata almayız.
Sub gizliyisec2()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
If ws.Visible then
Range("a1") = ws.Index
ws.Select
End If
Next
End Sub
İsimlendirme
Name özelliği ile sayfanın ismini elde eder veya onu değiştiririz. Yani hem okunan hem yazılan(sets and returns) bir özelliktir. Index ise değiştirilemez bir özellik olup sadece okunurdur.
ws.Name="Yeni sayfa"
Yeni sayfa açma(ekleme) ve silme
Yeni sayfa açmak/eklemek için Add metodu kullanılır.
Syntax:Worksheets.Add(Konum) Konum belirtmezsek aktif sayfanın soluna ekler. Konum belirtmek için parametreleriyle birlikte kullanırız. Worksheets.Add Before:=Worksheets("Sheet3")
Sayfayı yaratırken aynı anda ismini de verebiliriz.
Worksheets.Add(Before:=Worksheets("Sheet2")).Name = "Yeni Sayfa"
Sayfaları silmek için Delete metodunu kullanırız.
Worksheets(1).Delete
Silme işlemlerinde Excel bize uyarı çıkarır, silmek istediğimizden emin miyiz diye. Bu tür uyarılar bazen uzun makrolarda sorun çıkarabilir, hele bir de bilgisayarımızın başında değilkenki bir saate ayarlanmış bir kod ise biz gelip müdahale edene kadar ekranın takılı kalmasına neden olur, ve varsa sonrasında ayarlanmış kodların da çalışmasını engellemiş our. Bu tür durumlarla karşılaşmamak için kodların başına Application.DisplayAlerts=False cümleciği yazılır, ilgili kodlar bittikten sonra da True'ya çevrilir. Bunun detaylarına Application konusunda tekrar geleceğiz.
Sayfaları Gizleme ve Gizleneni tekrar gösterme
Sayfaları gizlemek veya tekrar göstermek için beklenenin aksine bir eylem değil Visible adında bir özellik kullanıyoruz. Bu özellik booelan tipinde değer döndürür.
Worksheets("Sheet2").Visible = False/True
Bir diğer yöntem de bu özelliğe True/False atamak yerine XlSheetVisibility enumerationlarını kullanmak olabilir. Alacağı değerle şöyledir.
- xlSheetVisible:Sayfayı gösterir
- xlSheetHidden:Sayfayı gizler
- xlSheetVeryHidden:Sayfayı öyle bir gizler ki, kullanıcılar sayfalara sağ tıklayıp Unhide tuşuna bastıklarında bile gizli sayfa listesinde görünmez. Bunu nerede kullanmak isteyebilirsiniz? Mesela workbook/worksheet koruma şifrenizi veya bir veritabanı bağlantısı için yazdığnız Connection String içindeki bağlantı parolasını VBA kodu içine doğrudan yazmak istemiyorsunuzdur. Bunu bir xlVeryHidden nitelikli sayafanın bir hücresine yazıp buradan okutturabilirsiniz.
Bu konuyla ilgili örnekler için tıklayınız.
Taşıma ve Kopyalama
Move ve Copy metodularını kullanırız. İkisi de Before(Önce) ve After(Sonra) olmak üzere iki parametre alır.
code class="CodeMirror-activeline-background" data-lang="javascript">
Worksheets("Sheet3").Move After:=Worksheets("Sheet1")
Worksheets("Sheet3").Copy Before:=Worksheets("Sheet1")
Worksheets("Sheet1").Copy Before:=Workbooks("ExcelVBA.xlsm").Sheets("Sheet3")
Worksheets("Sheet1").Copy 'yeni bir dosya açıp ve direkt bu dosyaya kopayalar
Bu metodları tek başına kullandığınızda yeni bir dosya açar ve oraya taşır/kopyalar. Aşağıdaki şu örnekte bu özelliği kullanıyoruz.
Birkaç kopyalama ve taşıma örneğini macro recorder ile kendiniz de yapabilirsiniz. Basit bir konu olduğu için daha fazla detaya gerek görmedim.
Sayfalarda koruma (Protection & Unprotection)
Yazdığımız kodlar, Sayfa korumalı bir dosyada işlem yapmaya kalkarsa şöyle bir hata alırız: "Run-time error '1004': Application-defined or object-defined error".
Bu sorunun üstesinden gelmek için, öncesinde sayfanın korumalı olup olmadığını kontrol edebilir, varsa korumayı kaldırabiliriz. Ama bunun da bir sakıncası olabilir, o da şu ki, kodlarda ilerlerken başka bir hata çıkarsa program durur ve sayfamız korumasız kalır. Bunun için bir de Hata Yakalama kodu yazmamız ve ilgili yerde tekrar koruma koymamız gerekir.
Korumaya almak Protect, korumayı kaldırmak Unprotect metodu ile sağlanır.
Şimdi bir örnek yapalım. Yeni bi dosya açın ve ilk sayfasına koruma uygulayın, şifresi de 1234 olsun. Sonra da şu kodu ekleyip çalıştırın.
Sub sayfakoruma1()
Dim ws As Worksheet
Set ws = ActiveSheet
If ws.ProtectContents = True Then 'koruma var mı diye sorguluyoruz
ws.Unprotect Password:="1234"
End If
'On Error GoTo hatayakala 'herhangi bir hatada sayfayı tekrar korumaya almak için ilgili yönlendirmeyi yapıyoruz
Range("A1") = Environ("USERNAME")
'çeşitli işlemler
'0'a bölme olacak ve hata alacak
a = InputBox("Bir sayı girin")
b = InputBox("Bu sayıyı kaça bölelim")
MsgBox "Sonuç: " & a / b
ws.Protect Password:="1234"
Exit Sub
'hatayakala:
'ws.Protect Password:="1234"
End Sub
İlk olarak, a için abc değerini girin, b için bir sayı girin. İkinci denemede de b için 0 değerini girin. İlki sayısal bir değer girmediğmiz için, ikincisi de 0'a bölmeye çalıştığı için hataya neden olacaktır. Hata yakalama kodları commentli olduğu için de dosyamız protectionsız kalacaktır.
Şimdi yukardaki commentli kısımları commentsiz hale getirip tekrar çalıştıralım. Bu sefer hata yakalanacak ve çıkmadan önce tekrar şifreleme yapılacaktır.
NOT:Filtrelemeye izin verme gibi seçeneklerden faydalanmak icin makro kaydetme aracından faydalanabilirsiniz. Ancak bu şekilde protection koymaya çalıştığınızda recorder şifreyi kaydetmez, bunu manuel eklemeniz gerekir.
Protectionlı sayfalara devam
Yukarda korumalı sayfalarda çalışma şeklini görmüştük. Korumalı sayfalarla çalışmanın daha şık bir yolu var aslında. UserInterFaceOnly parametresi.
Bu parametreye True değeri atanırsa, sayfa sadece kullanıcı işlemlerine karşı korumalı olur, VBA kodları için koruma geçersiz olur. Gördüğünüz gibi Microsoft'taki abiler bunu da düşünmüşler. Bu parametrenin default değeri False olup değer atanmaması durumunda tahmin edeceğiniz üzere full koruma sağlanır.
Yanlız unutulmamalıdır ki, bu argüman sadece bir kereliğine koruma sağlar. Dosyayı kapatıp tekrar girdiğinizde, full korumalı açılır. Bu özelliğin daimi olması için Workbook_Open eventi içine uygun kod yazılabilir.
ActiveWorkbook.Worksheets("calculatedlar").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("calculatedlar").Sort.SortFields.Add Key:=Range( _
"F2"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("calculatedlar").Sort
.SetRange Range("A2:F175")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Recorder'ın ürettiği kodda bir iki yeri değiştirmek gerekir, böylece makromuz daha dinamik hale gelir.
- Worksheets("calculatedlar")>ActiveSheet yapalım
- Key:=Range("F2")>Key:=ActiveCell(veya duruma göre kalabilir)
- Range("A2:F175")>Bunu nasıl değiştireceğimizi Range konusunda görmüştük
Keza filtreleme işleminin kodu da basit olup, dinamik hale getirilecek kısımları değiştirmek yeterlidir.
Range("B1").Select
ActiveSheet.Range("$A$1:$F$175").AutoFilter Field:=2, Criteria1:="Şube"
Bu örnekte Range("$A$1:$F$175") yerine Range("A1").CurrentRegion denilebilir. Görüğünüz gibi Sort işleminde başlık hariç tutulurken burada başlık satırı dahildir. O yüzden Resize ve Offset kullanmadan işimizi halledebiliriz.
Filtre modları ve filtreyi kaldırma
Filtrelerle ilgili olarak kafa karışıklığına neden olabilecek iki konur var. Filtrenin açık/kapalı olması ile kriterin uygulanıp/uygulanmamış olması. Bunlardan ilki AutoFilterMode özelliği ile elde edilirken ikincisi FilterMode özelliği ile elde edilir.
Filtreyi uygulamak/kaldırmak Range nesnesinin AutoFilter metodu ile olur.
- Filtre henüz yokken kullanılırsa filre uygulanır
- Yanında parametre yoksa sadece filtre okları görünür
- Parametreyle uygulanırsa direkt ilgili filtreleme yapılmış olur
- Filtre varken kullanılırsa kriterler silinir ve filtre okları kalkar
Kriter uygulanmış bir data kümesinde kriterleri silmek ama filtre oklarını açık bırakmak için Worksheet nesnesinin ShowAllData metodu kullanılır.
Aşağıda bütün bu durumları anlatan güzel bir örnek var. Bu örnekte sayfadaki data kümesinin rasgele olarak 4 durumundan birine girmesini sağlıyoruz, sonra hangi durumdaysa onunla ilgili bir mesaj veriyorum.
Sub filtresub()
a = WorksheetFunction.RandBetween(1, 4)
MsgBox "Case " & a & " gerçekleşecek"
Select Case a
Case 1 'o an kapalıysa kapalı kalmaya devam, açıksa kapanır
ActiveSheet.AutoFilterMode = False 'buna sadece false atanıyor, true atanamaz
Case 2 'açıkken filtre konursa kapanır
If ActiveSheet.AutoFilterMode = True Then Selection.AutoFilter
Case 3 'kapalıyken filtre konursa açılır
If ActiveSheet.AutoFilterMode = False Then Selection.AutoFilter
Case 4 'filtre okları aktif olsa da olmasa da burası çalışır
ActiveSheet.Range("$A$1").CurrentRegion.AutoFilter Field:=2, Criteria1:=Range("b2")
End Select
If ActiveSheet.AutoFilterMode = True Then 'filtre okları açıksa. Case 3 veya 4
If ActiveSheet.FilterMode = False Then
MsgBox "Case 3:Filtre açık ama kriter yok"
Else
MsgBox "Case 4:filtre açık ve kriter var, şimdi kriter kaldırılacak, ama filtre açık kalacak"
ActiveSheet.ShowAllData
End If
Else 'filtre okları yoksa, yani henüz bir autofilter düğmesine basılmamışsa
MsgBox "Case 1 veya 2:filtre yok"
End If
End Sub
Sayfa ayarları
Page Setup, Print v.b işlemleri için macro recorderdan faydalanmanızı öneriyorum.
Calculation
Calculation konusuna Application nesnesine detaylıca değiniyoruz. Önemli bir metod olup Application konusunda mutlaka incelemenizi tavsiye ediyorum.
Sayfalarda gezinme
Sayfalarda dolaşma işini yukarıdaki birçok örnekte gördüğümüz gibi bir döngü aracılığı ile yapabilmekle birlikte, sadece bir sayfa geri veya ileri gitme işini, sayfa adı v.s yazmadan kolayca yapmamızı sağlayan iki özellik var.
Activesheet.Next.Select ' sonraki sayfa
ActiveSheet.Previous.Select ' önceki sayfa
Hafızadan birşey yapıştırma
Hafızadaki(Clipboard) bilgiyi aktif sayfadaki aktif hücreye yapıştırmak için iki metod var. Birincisi Worksheet sınıfının normal Paste metdou, ikincisi Range nesnesinin PasteSpecial metodu. Worksheet.Paste metodu ile Excel arayüzünde yaptığımız gibi içerikte ne varsa yapıştırılır:Veri, formül, format v.s. Range.PasteSpecial ile ise yine Excel arayüzde yaptığımız özel yapıştırma türlerini yapabiliyoruz. Sadece değerleri, sadece formatı v.s.
Aşağıdaki kod ile 1.sayfada aktif hücrenin CurrentRegion'ındaki hücreleri 2.sayfadaki aktif hücreye yapıştırıyoruz.
Sheets(1).Select
ActiveCell.CurrentRegion.Select
Selection.Copy
Sheets(2).Select
ActiveSheet.Paste
Bu arada Worksheet sınıfının da PasteSpecial metodu var ama biz onu çok kullanmayacağız, zira bununla Grafik gibi nesneleri veya Access gibi diğer uygulamalardan birşeyler yapıştırabiliyorsunuz.
ActiveChart.ChartArea.Copy
Range("M2").Select
ActiveSheet.PasteSpecial Format:="Picture (PNG)", Link:=False, _
DisplayAsIcon:=False
Aşağıdaki örneği de MSDN'den aldım, burada diğer format seçeneklerine de bakabilirsiniz. Başka programlarla çalışmayacaksanız çok sık ihtiyacınız olacağını sanmam.
Worksheets("Sheet1").Range("F5").PasteSpecial _
Format:="Picture (Enhanced Metafile)", Link:=False,
DisplayAsIcon:=False
Parent özelliği
Bazen bir sayfanın hangi workbookta olduğunu elde etmek isteriz. Bunun için hiyerarşide bir üst basamağa çıkmamızı sağlayan Parent özelliğini kullanırız.>
Debug.Print TypeName(Activesheet.Parent) 'Workbook
Debug.Print Activesheet.Parent.Name 'ilg
Tüm sayfaları ayrı workbooklar olarak kaydetme
Bu örnekte açık olan bir dosyadaki tüm sayfaları ayrı ayrı dosyalar olarak seçilen bir klasöre kaydediyoruz.
Sub sayfaları_wb_olarak_kaydet()
Dim ws As Worksheet
Dim wb As Workbook
Dim fd As FileDialog
Dim klasör As String
Dim dosya As String
On Error GoTo hata
Application.ScreenUpdating = False
Set wb = Application.ThisWorkbook
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
If fd.Show = True Then
klasör = fd.SelectedItems(1)
Else
Exit Sub
End If
For Each ws In wb.Worksheets
ws.Copy
'Burada bi versiyon kontrolü yapılmasında fayda var, ama örneği basitleştirmek adına onu es geçiyorum ve default formatta kaydetmesine izin veriyorum
dosya = klasör & "\" & Application.ActiveWorkbook.Sheets(1).Name & ".xlsx"
ActiveWorkbook.SaveAs dosya
ActiveWorkbook.Close False
Next
Call Shell("explorer.exe " & klasör, vbNormalFocus)
Application.ScreenUpdating = True
Exit Sub
hata:
Application.ScreenUpdating = True
MsgBox Err.Description
End Sub
Tüm sayfaları Unhide etme
Bu örnekte tüm gizli sayfaları açıyoruz. Buna QuickAccessBardan erişmek isteyebilirsiniz, ben öyle yapıyorum açıkçası.
Sub tümsayfalarunhide()
For i = 1 To Sheets.Count
Sheets(i).visible = True
Next i
Sheets(1).Select
End Sub
İlk sayfa hariç tümünü hide etme
Diyelim ki bir sayfasında Karne, diğer sayfalarında bu karneyi besleyen sayfaların olduğu bir dosyanız var. Sık sık sayfaları Unhide ve tekrar Hide etme ihtiyacınız oluyor. Bir üstteki kod ile tüm sayfaları Unhide etmiştik. Datayla oynadıktan sonra şimdi tekrar gizleyeceğiz. Bunu da QuickAccessBara eklerseniz müthiş pratiklik sağlar. Bu kodu Karne sayfasındayken çalıştırmanız gerekiyor.
Sub aktifhariç_hideall()
Dim ws As Worksheet
Set ws = ActiveSheet
For i = 1 To Sheets.Count
If i <> ws.Index Then
Sheets(i).visible = False
End If
Next i
End Sub
Tüm sayfalarda ilk kolonda A'dan Z'ye sıralama
Diyelim ki size birçok sayfası olan bir dosya geldi. Ama sayfaların hiçbiri sıralı değil. Bu örnekte tüm sayfalarda A'dan Z'ye sıralama işlemini tek seferde yapıyoruz
Sub tümsayfalarda_sırala()
For i = 1 To Sheets.Count
Sheets(i).Select
ActiveWorkbook.Sheets(i).Sort.SortFields.Clear
ActiveWorkbook.Sheets(i).Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Sheets(i).Sort
.SetRange Range(Range("A2"), Range("a2").End(xlDown).End(xlToRight))
.header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Next i
End Sub