Excel VBA Advanced
Excel Object Model
Ochrona arkuszy z poziomu VBA
Sub ochrona()
Cells.Locked = True
Cells.FormulaHidden = True
ActiveSheet.Protect Password:="asdf"
End Sub
Obiekt Workbook, kolekcja Workbooks
Obiekt Workbook
Reprezentuje otwarty skoroszyt Excela
Właściwości i metody
- Activate - uaktywnienie skoroszytu
- Close - zamknięcie skoroszytu
- DisplayDrawingObjects - w jaki sposób wyświetlać obiekty graficzne (obiekt, miejsce, ukrycie)
- FileFormat - format pliku lub typ skoroszytu
- Name - nazwa skoroszytu
- Path - ścieżka dostępu do pliku skoroszytu
- FullName - nazwa pliku skoroszytu ze ścieżką dostępu
- HasPassword - czy skoroszyt jest zabezpieczony hasłem
- HasVBAProject - czy skoroszyt zawiera Microsoft Visual Basic for Applications project
- PrecisionAsDisplayed - czy obliczenia wykonywane są z pokazywaną precyzją
- PrintOut - wydrukowanie skoroszytu
- PrintPreview - wywołanie okna podglądu wydruku
- Protect - ochrona skoroszytu przed modyfikacjami (z możliwością ustawienia hasła)
- ReadOnly - czy zawartość skoroszytu można modyfikować
- RefreshAll - odświeżenie wszystkich zewnętrznych zakresów danych i tabel przestawnych
- Save - zapisuje zmiany w bieżącym skoroszycie
- Saved - czy zmiany w pliku zostały zapisane
- SaveAs - zapisanie skoroszytu do pliku o innej nazwie
- SaveCopyAs - zapisanie kopii skoroszytu do pliku o innej nazwie
Obiekty potomne
- CustomViews - kolekcja widoków skoroszytów
- Names - kolekcja nazw wykorzystywanych w skoroszycie
- Sheets - kolekcja arkuszy roboczych (Worksheet) i wykresów (Chart)
- Styles - kolekcja zestawów opcji formatowania dla zakresu
Kolekcja Workbooks
Użyj właściwości Workbooks by otrzymać kolekcję Workbooks. Przykład poniżej zamyka wszystkie otwarte skoroszyty.
Workbooks.Close
Za pomocą metody Add, tworzymy nowy pusty skoroszyt i dodajemy go do kolekcji. Poniższy przykład dodaje nowy, pusty skoroszyt w programie Microsoft Excel.
Workbooks.Add
Metody Open używamy do otwarcie pliku. Open tworzy nowy skoroszyt w ramach otwartego pliku. Poniższy przykład otwiera Array.xls jako skoroszyt tylko do odczytu.
Workbooks.Open FileName:="Array.xls", ReadOnly:=True
Obiekt Worksheet, kolekcja Worksheets
Obiekt Worksheet
Reprezentuje arkusz roboczy Excela
Właściwości i metody
- Activate - uaktywnienie arkusza
- AutoFilterMode - czy autofiltr jest włączony
- Calculate - przeliczenie wszystkich komórek arkusza
- CodeName - nazwa kodowa arkusza
- Copy - skopiowanie arkusza
- Delete - usunięcie arkusza
- EnableCalculations - czy przeliczanie zostanie dokonane automatycznie po zmianach
- FilterMode - czy arkusz jest w trybie filtrowania (np. autofiltrowanie włączone, ale filtr nie został nałożony)
- Move - przesunięcie arkusza na inne miejsce w skoroszycie
- PasteSpecial - wklejenia danych do arkusza z zastosowaniem wybranego formatu
- PrintOut - wydrukowanie arkusza
- PrintPreview - wywołanie okna podglądu wydruku arkusza
- Protect - zabezpieczenie arkusza przed modyfikacjami (z możliwością ustawienia hasła)
- ProtectionMode - czy tryb ochrony jest włączony
- SaveAs - zapisanie arkusza do wskazanego pliku
- ScrollArea - zakres, w którym dozwolone jest przewijanie
- Select - zaznaczenie arkusza (wiele arkuszy może być jednocześnie zaznaczonych, tylko jeden może być aktywny)
- SetBackgroundPicture - grafika dla tła arkusza
- ShowDataForm - wyświetlenie formularza danych powiązanego z arkuszem
- Unprotect - wyłączenie ochrony arkusza
- UsedRange - najmniejszy prostokątny obszar obejmujący aktualnie używane komórki
- Visible - czy arkusz jest widoczny
Obiekty potomne
- Comments - kolekcja komentarzy zawartych w komórkach arkusza
- Names - kolekcja nazw używanych w arkuszu
- Outline - konspekt
- PageSetup - formatowanie strony dla arkusza
Kolekcja Worksheets
Metoda Move przenosi wszystkie arkusze na koniec skoroszytu
Worksheets.Move After:=Sheets(Sheets.Count)
Metoda Add dodaje do kolekcji Worksheets nowy arkusz. Poniższy przykład dodaje dwa nowe arkusze przed pierwszym arkuszem
Worksheets.Add Count:=2, Before:=Sheets(1)
Użyj Worksheets(index) gdzie 'index' to numer lub nazwa arkusza. Przykład poniżej ukrywa pierwszy arkusz w aktywnym skoroszycie.
Worksheets(1).Visible = False
Obiekt Worksheet jest również elementem kolekcji Sheets. Kolekcja Sheets zawiera wszystkie arkusze w skoroszycie (chart sheets, worksheets).
Walidacja arkuszy
Sub PoprawnoscDanych()
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="a;b;c;d"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = "Wprowadź poprawną wartość"
.ErrorTitle = "Błąd"
.InputMessage = "z listy"
.ErrorMessage = "błędna wartość"
.ShowInput = True
.ShowError = True
End With
End Sub
Praktyczne metody obiektu Range
Obiekt Range
Jeden z najważniejszych obiektów Excela: żeby móc pracować z częścią arkusza roboczego trzeba ją najpierw zidentyfikować jako obiekt Range.
Reprezentuje komórkę, wiersz, kolumnę, zaznaczony obszar zawierający jeden lub więcej ciągłych bloków komórek.
Jednocześnie jest samodzielnym obiektem i kolekcją. Elementami tej kolekcji są obiekty Range (Excel nie posiada typu dla pojedynczej komórki).
sposoby pobierania obiektów typu Range
Range(nazwa), Range(kom1, kom2)
Application.Range, ActiveSheet.Range, Worksheet.Range
Cells(wiersz, kolumna)
Application.Cells, ActiveSheet.Cells, Worksheet.Cells, Range.Cells
Columns(kolumna), Columns(nazwa)
Application.Columns, ActiveSheet.Columns, Worksheet.Columns, Range.Columns
Rows(wiersz), Rows(nazwa)
Application.Rows, ActiveSheet.Rows, Worksheet.Rows, Range.Rows
Offset(przesWiersz, przesKolumna)
Range.Offset
- Activate - uaktywnienie pojedynczej komórki lub zaznaczenie zakresu
- AddComment - dodanie komentarza do zakresu jednokomórkowego
- Address - pobranie adresu w postaci ciągu znaków (względny, bezwzględny, A1, R1C1)
- AutoFill - autowypełnianie komórek zakresu
- AutoFilter - włączenie/wyłączenie autofiltra; ustawienie autofiltra
- AutoFit - dopasowanie wielkości komórek do zawartych w nich danych
- AutoFormat - automatyczne sformatowanie zakresu
- BorderAround - ustawienie obramowanie dookoła zakresu
- Calculate - przeliczenie wszystkich komórek zakresu
- Clear - wyczyszczenie wartości, formuł i formatowania
- ClearContents - wyczyszczenie wartości i formuł
- ClearFormats - wyczyszczenie formatowania
- ColumnDifferences - zwraca obiekt Range reprezentujący wszystkie komórki zakresu, których zawartość jest różna od zadanych *komórek odniesienia (w każdej kolumnie występuje jedna komórka odniesienia)
- RowDifferences - analogicznie do ColumnDifferences, lecz dla wierszy
- Consolidate - połączenie danych z wielu zakresów (także z różnych arkuszy) do pojedynczego zakresu na jednym arkuszu
- CreateNames - utworzenie nazw zakresów opartych na etykietach tekstowych w podanych komórkach
- CurrentRegion - zwraca obiekt Range reprezentujący bieżący region, czyli region otoczony przez najbliższe puste wiersze i kolumny
- Delete - usunięcie komórki
- ColumnWidth - szerokość kolumn w zakresie
- RowHeight - wysokość wierszy w zakresie
- Width - szerokość zakresu w punktach
- Height - wysokość zakresu w punktach
- Top - odległość w punktach od górnej krawędzi pierwszego wiersza arkusza do górnej krawędzi pierwszego wiersza zakresu
- Left - odległość w punktach od lewej krawędzi pierwszej kolumny arkusza do lewej krawędzi pierwszej kolumny zakresu
- Dependents - zwraca obiekt Range reprezentujący wszystkie komórki zależne od danej komórki
- DirectDependents - zwraca obiekt Range reprezentujący wszystkie komórki zależne bezpośrednio od danej komórki
- Precedents - zwraca obiekt Range reprezentujący wszystkie komórki, od których komórki zakresu są zależne
- DirectPrecedents - zwraca obiekt Range reprezentujący wszystkie komórki, od których komórki zakresu są bezpośrednio zależne
- End - zwraca obiekt Range reprezentujący ostatnią komórkę regionu zawierającego zakres w zadanym kierunku
- EntireColumn - zwraca obiekt Range reprezentujący kolumny zawierające zakres
- EntireRow - zwraca obiekt Range reprezentujący wiersze zawierające zakres
- FillDown - wypełnienie komórek zakresu w dół począwszy od komórek w górnym wierszu zakresu poprzez skopiowanie zawartości, *formuł i formatowania z górnego wiersza
- FillUp - analogicznie do FillDown, lecz wypełnienie do góry
- FillLeft - analogicznie do FillDown, lecz wypełnienie do lewej
- FillRight - analogicznie do FillDown, lecz wypełnienie do prawej
- Find - zwraca obiekt Range reprezentujący pierwszą komórkę zakresu spełniającą narzucone kryterium
- FindNext - znalezienie następnej komórki według wyszukiwania rozpoczętego metodą Find
- FindPrevious - znalezienie poprzedniej komórki według wyszukiwania rozpoczętego metodą Find
- Formula - formuła lub wartość każdej komórki w zakresie (formuła musi być w postaci A1 i rozpoczynać się znakiem =)
- FormulaR1C1 - analogicznie do Formula, lecz formuła w notacji R1C1
- FormulaArray - formuła tablicowa zapisana w notacji R1C1
- FormulaHidden - czy formuła komórek zakresu jest ukryta
- HasFormula - czy wszystkie komórki zakresu mają formuły
- HorizontalAlignment - poziome wyrównanie komórek zakresu
- VerticalAlignment - pionowe wyrównanie komórek zakresu
- IndentLevel - lewe wcięcie dla komórek zakresu
- InsertIndent - zwiększenie wcięcia dla komórek zakresu
- Insert - wstawienie zakresu do arkusza
- Locked - czy komórki zakresu są zablokowane
- Merge - scalenie zakresu w jedną komórkę
- UnMerge - podzielenie scalonej komórki
- Next - zwraca komórkę, która stałaby się aktywna po naciśnięciu klawisza Tab
- Previous - zwraca komórkę, która stałaby sie aktywana po naciśnięciu klawisza Shift+Tab
- NumberFormat - ciąg znaków określających formatowanie liczb komórek zakresu
- Parse - przetworzenie danych w kolumnie i rozprowadzenie zawartości z wypełnieniem przystających kolumn
- PasteSpecial - wklejenie danych ze schowka do zakresu
- PrintOut - wydrukowanie zakresu
- PrintPreview - wywołanie okna podglądu wydruku zakresu
- Replace - zastąpienie danych we wszystkich komórkach zakresu
- Select - zaznaczenie zakresu
- ShrinkToFit - czy dostować szerokość tekstu do szerokości kolumn
- Sort - sortowanie zakresu (jeśli zakres jest pojedynczą komórką, sortowany jest bieżący region)
- SpecialCells - zwraca obiekt Range reprezentujący wszystkie komórki pasujące do wskazanego typu i wartości
- TextToColumns - przetworzenie kolumn komórek zawierających tekst na kilka osobnych kolumn
- Value - zwraca wartości komórek zakresu (dwuwymiarowa tablica dla zakresów wielokomórkowych)
- WrapText - czy zawijać tekst w komórkach zakresu
Obiekty potomne
- Areas - kolekcja wszystkich spójnych zakresów komórek zawartych w zakresie
- Borders - kolekcja obiektów Border określających obramowanie zakresu
- Characters - ciągła sekwencja znaków tekstu
- Comments - kolekcja komentarzy komórek zakresu
- Font - czcionka wykorzystywana w zakresie
- FormatConditions - kolekcja formatowań warunkowych
- Interior - charakterystyka wnętrza komórki (kolor tła oraz kolor i wzór wypełnienia)
- Validation - sprawdzanie poprawności zawartości komórki
Kopiuj, wklej, wklej specjalnie
Range("A1").Copy
Sheets("Sheet2").Paste
Range("A1").Copy Sheets("Sheet2").Range("A1")
Range("A1").Copy
Range("A2").PasteSpecial xlPasteValues
Range("A1").Cut Range("A2")
Znajdź, zastąp
Cells.Replace What:="test", Replacement:="TEST", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Dim gdzie As Range
Set gdzie = Range("A1:A100").Find("TEST")
Debug.Print gdzie.Address 'wynik: &A&12
Dim c, firstAddress
With Worksheets(1).Range("a1:a500")
Set c = .Find("test", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
c.Value = "TEST"
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
End With
Sortowanie zakresów
Sub sortowanie()
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange Range("A1:A400")
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Wykresy (Obiekt Chart)
Obiekt Chart
Reprezentuje wykres
- Arkusze wykresów - arkusze zawierające tylko wykres (obiekt Chart jest takim arkuszem)
Workbook.Charts - kolekcja wszystkich arkuszy wykresów w skoroszycie
- Arkusze robocze zawierające wykresy - wykres (obiekt Chart) jest osadzony w specjalnym obiekcie (ChartObject)
Worksheet.ChartObjects - kolekcja wszystkich obiektów zawierających wykresy osadzone w arkuszu
- Chart.ChartWizard - modyfikuje właściwości wykresu (nie tworzy wykresu). Może modyfikować tylko wybrane (podane jako parametry) właściwości wykresu.
- ChartType - typ wykresu
- ApplyCustomType - ustawienie typu wykresu (w szczególności własnego)
- Export - zapisanie wykresu do pliku graficznego
- PrintOut - wydrukowanie wykresu
Obiekty potomne
- Axes - kolekcja obiektów Axis (osie wykresu)
- ChartArea - obszar wykresu (Border, ChartFillFormat, Font, Interior)
- ChartGroups - kolekcja obiektów ChartGroup reprezentujących jedną lub więcej serii o tym samym typie wykresu
- ChartTitle - tytuł wykresu (Border, ChartFillFormat, Font, Interior)
- DataTable - tabela danych
- Floor - podłoże wykresu trójwymiarowego
- Legend - legenda
- PageSetup - formatowanie strony dla wykresu
- PlotArea - obszar rysowania wykresu
- Series - serie danych wykresu (Point - pojedynczy punkt serii)
Obiekt Axis
Reprezentuje jedną oś wykresu
- Tytuł - tekst i jego formatowanie; obiekt AxisTitle
- Kategorie - nazwy i typy; CategoryNames, CategoryType, BaseUnit
- Przecięcia osi - Crosses, CrossesAt
- Jednostki - HasDisplayUnitLabel, DisplayUnitLabel, DisplayUnit, DisplayUnitCustom
- Linie siatki - HasMajorGridlines, HasMinorGridlines, MajorGridlines, MinorGridlines
- Położenie i rozmiar - Height, Width, Left, Top
- Znaczniki - MajorTickMark, MinorTickMark, TickLabels
- Jednostki - MajorUnit, MinorUnit, MajorUnitIsAuto, MinorUnitIsAuto, MajorUnitScale, MinorUnitScale, MaximumScale, MinimumScale, MaximumScaleIsAuto, MinimumScaleIsAuto, ScaleType
- Kierunek - ReversePlotOrder
- Typ - Type
Zdarzenia
Zdarzenia na poziomie Aplikacji
W module klasy:
Public WithEvents xlApp As Application
Private Sub xlApp_NewWorkbook(ByVal Wb As Workbook)
MsgBox Wb.Name
End Sub
Private Sub xlApp_SheetActivate(ByVal Sh As Object)
MsgBox Sh.Name
End Sub
Private Sub xlApp_SheetChange(ByVal Sh As Object, ByVal Target As Range)
MsgBox Sh.Name & Chr(13) & Target.Address
End Sub
Wewnątrz modułu:
Option Explicit
Public myAppEvent As New clsAppEvents
Sub Trap()
Set myAppEvent.xlApp = Application
End Sub
Tablice
Tablice dynamiczne
Tablice dynamiczne, czyli tablice, które mają nieokreślony rozmiar, który może być dowolnie zmieniany w czasie wykonywanie programu przy pomocy rozkazu ReDim
Dim tblDynamic() As Integer
ReDim tblDynamic(1 To 3)
Każde ponowne użycie instrukcji ReDim powoduje kolejną zmianę rozmiaru/wymiaru tablicy i wyczyszczenie jej zawartości. Aby zmienić rozmiar tablicy z zachowaniem jej dotychczasowej zawartości należy przy instrukcji ReDim użyć dodatkowo polecenie Preserve.
ReDim Preserve tblDynamic(1 To 5)
Tablica dynamiczna typu Variant
Gdy potrzebujesz pobrać dużą ilość danych z arkusza do tablicy, zamiast pętli skorzystaj z tablicy typu Variant.
Dim tblDane() As Variant
tblDane = Range("A1:G10")
Aby przepisać zawartość tablicy do arkusza użyj instrukcji:
Range("A1:G10")= tblDane
Tablice wielowymiarowe
W VBA można zadeklarować maksymalnie 60 wymiarową tablice.
Deklaracja tablicy czterowymiarowej:
Dim Tablica(10,10,10,10)
Funkcje obsługi tablic
- Array - utworzenie zmiennej typu Variant będącej jednowymiarową tablicą, np.
- Array("pierwszy", "drugi", "trzeci", "czwarty", "piąty")
- IsArray - sprawdzenie, czy dana zmienna jest tablicą, np.
- IsArray(tabLiczb)
- Erase - wyczyszczenie tablicy, w przypadku tablicy dynamicznej zwalniana jest przydzielona jej pamięć, np.
- Erase(tabLiczb)
- LBound - podaje najmniejszy indeks tablicy, np.
- LBound(tabLiczb)
- UBound - podaje największy indeks tablicy, np.
- UBound(macierz,2)
Sortowanie tablic
Sortowanie arkuszowe
Sub sortowanieArkuszowe()
Dim tablica(1 To 200)
Dim WS As Worksheet, zakres As Range
Dim N As Long, x As Long, czas
For x = 1 To UBound(tablica)
tablica(x) = Int(Rnd * 1000) + 1
Next
czas = Timer
Application.ScreenUpdating = False
Set WS = ThisWorkbook.Worksheets.Add
Set zakres = WS.Range("A1").Resize(UBound(tablica) - LBound(tablica) + 1, 1)
zakres = Application.Transpose(tablica)
zakres.Sort key1:=zakres, order1:=xlAscending, MatchCase:=False
For N = 1 To zakres.Rows.Count
tablica(N) = zakres(N, 1)
Next N
Application.DisplayAlerts = False
WS.Delete
Application.DisplayAlerts = True
MsgBox Round(Timer - czas, 3) & Chr(13) & Join(tablica, Chr(13))
End Sub
Sortowanie bąbelkowe
Sub sortowanieBabelkowe()
Dim tablica(1 To 100), czas
Dim x, pocz, koniec, i, j, temp
For x = 1 To UBound(tablica)
tablica(x) = Int(Rnd * 1000) + 1
Next
czas = Timer
pocz = LBound(tablica)
koniec = UBound(tablica)
For i = pocz To koniec - 1
For j = i + 1 To koniec
If tablica(i) > tablica(j) Then
temp = tablica(j)
tablica(j) = tablica(i)
tablica(i) = temp
End If
Next j
Next i
MsgBox Round(Timer - czas, 3) & Chr(13) & Join(tablica, Chr(13))
End Sub
Programowanie obiektowe
Klasy i obiekty
Tworząc programy w VBA mamy dostęp do obiektów reprezentujących rzeczywiste elementy danej aplikacji np dla Excela będą to obiekty typu Range, Worksheet czy Workbook. Ale czasem pojawiają się sytuacje że wykonanie konkretnego zadania jest wydajniejsze gdy zdefiniujemy własny obiekt. Użytkownik może tworzyć własne obiekty i używać je w taki sam sposób jak wbudowane obiekty Excela. Obiekty takie tworzymy używając modułów klas. W odróżnieniu od modułów które mogą zawierać luźno powiązany ze sobą kod, klasa stanowi hermetyczną całość ściśle ze sobą powiązaną. Wymaga to bardziej abstrakcyjnego myślenia podczas programowania, niemniej jednak nagrodą są funkcjonalności niedostępne w podejściu modułowym.
Klasa jest swego rodzaju kontenerem na inne elementy odseparowane w ramach tego pojemnika od innych części programu, dzięki czemu taką klasę można później swobodnie wykorzystać w innym projekcie.
Tworzenie klas, metod, właściwości
Gdy chcemy zbudować własny obiekt, moduł klasy staje się szablonem dla właściwości i metod danego obiektu
Przykład
Tworzymy obiekt Car w którym zapiszemy jego nazwę, kolor, ilość drzwi i prędkość z jaką się porusza. Zaczynamy od wstawienia modułu klasy (Insert -> Class Module) Obiekt ClassCar ma cztery właściwości:
Public carName As String
Public carColor As String
Public carSpeed As Integer
Public carNumberOfDoors As Integer
Właściwości czyli zmienne deklarowane z użyciem słów kluczowych Private lub Public. Nasze Zmienne są zadeklarowane z użyciem słowa kluczowego Public ponieważ chcemy aby były dostępne z modułu standardowego.
Metody to 'czynności', które będą wykonywane przez obiekty. W klasach operacje to są procedurami lub funkcjami.
Poniżej kod tworzący metodę Accelerate, która będzie zmieniać prędkość samochodu.
Sub Accelerate(ByVal accelerateBy As Integer)
carSpeed = carSpeed + accelerateBy
End Sub
Używanie własnych obiektów
W module w sekcji deklaracji deklarujemy zmienną z własnym typem obiektowym:
Option Explicit
Dim auto As ClassCar
następnie tworzymy procedurę carInfo wewnątrz której za pomocą słowa kluczowego New tworzymy zmienną obiektową. Do właściwości obiektu przypisujemy wartości oraz komunikat z informacjami o naszym obiekcie.
Sub carInfo()
Set auto = New ClassCar
With auto
.carColor = "białym"
.carName = "Audi"
.carNumberOfDoors = 3
.carSpeed = 10
.Accelerate 40
MsgBox .carNumberOfDoors & " drzwiowy samochód " & _
.carName & " o kolorze " & .carColor & _
" porusza się z prędkością " & .carSpeed
End With
End Sub
Procedury Property Let i Property Get
Zmienne deklarowane z użyciem słów kluczowych Public mają właściwości zarówno do odczytu jak i zapisu, nie mamy więc ograniczeń w ich modyfikacji. Jeżeli natomiast chcielibyśmy ustalić ograniczenia odczytu musimy skorzystać z procedur Property Let i Property Get.
Property Let pozwala na kontrole sposobu w jaki można przypisać wartości.
Property Get daję kontrolę nad sposobem dostępu do właściwości.
Poniższy przykład obrazuje użycie procedur Property Let i Get:
W klasie clsCar zmieniliśmy deklaracje zmiennej carNumberOfDoors z publicznej na prywatną
Option Explicit
Public carName As String
Public carColor As String
Public carSpeed As Integer
Private carNumberOfDoors As Integer
Dzięki temu mamy kontrolę nad modyfikacją jak i odczytem zmiennej.
Public Property Get NumberOfDoors() As Integer
NumberOfDoors = carNumberOfDoors
End Property
Public Property Let NumberOfDoors(ByVal vNewValue As Integer)
If vNewValue >= 2 And vNewValue <= 5 Then
carNumberOfDoors = vNewValue
End If
End Property
Przy próbie wprowadzenia ilości drzwi dla właściwości, procedura Property Let NumberOfDoors weryfikuje czy podana wartość mieści się w wyznaczonym przedziale, dopuszczalne są wartości z przedziału od 2 do 5.
Konstruktor i destruktor
Klasy posiadają mechanizm konstruktora i destruktora czyli podprogramu uruchamianego w momencie tworzenia lub niszczenia obiektu klasy. Konstruktor może nam posłużyć do ustawienia domyślnych wartości dla tworzonego obiektu.
Private Sub Class_Initialize()
carName = "Auto"
carNumberOfDoors = 5
carColor = "biały"
carSpeed = 0
End Sub
Obsługa błędów w klasach
Wewnątrz klasy clsCar zaimplementujemy metodę generującą błąd
Sub testErr()
Debug.Print 2 / 0
End Sub
Teraz spróbujmy wywołać zaimplementowaną procedurę, tak jak przedstawiono poniżej.
Sub carInfo()
Set noweAuto = New ClassCar
noweAuto.testErr
End Sub
W chwili uruchomienia kompilator przenosi nas do lini w której została wywołana metoda testErr, wiemy więc że błąd leży wewnątrz naszej metody, ale nie znamy konkretnej przyczyny. Jeśli procedura jest naprawdę skomplikowana szukane błędu na piechotę nie będzie takie proste, dlatego zmienimy domyślne ustawienia edytora. Z menu wybieramy pozycję Tools -> Options -> wybieramy zakładkę General i pojawia się okienko przedstawione poniżej.
W ramce Error Trapping mamy trzy opcje:
- Break On Unhandled Errors - jest parametrem domyślnym. Niestety powoduje to sytuację o której piszemy czyli w momencie pojawienia się błędu kompilator przeniesie nas do linii w której wywołana jest funkcja generująca błąd. W pomocy możemy znaleźć informacje żę za pomocą tej opcji możemy debugować błędy nie obsługiwane przez polecenie On Error;
- Break In Class Module – jest to opcja która nas interesuje, zaznaczenie tego właśnie guzika spowoduje, że w momencie pojawienia się błędu kompilator przeniesie nas do wnętrza klasy i procedury, do linii która jest powodem wystąpienia błędu wykonania;.
- Break On All Errors – ostatni parametr, jest to najwyższy stopień analizy, przeniesie on nas do miejsca powstania błędu w kodzie programu bez względu na procedury obsługi błędów zamieszczone w kodzie programu. Ustawienie tego parametru spowoduje, że program przestanie się wykonywać nawet wówczas kiedy w kodzie celowo wygenerowano błąd w raz z jego obsługą celem wykonania jakiegoś tam działania. Innymi słowy uaktywnienie tego parametru "zamraża" niejako działanie procedur "On Error GoTo" oraz "On Error GoTo Resume Next", co w określonych przypadkach może być dalece nie pożądane.
Tworzenie i zarządzanie kolekcjami
Kolekcja czyli zbiór elementów do których możemy odwołać się używając indeksu elementu lub klucza po którym zostanie przeszukana zawartość kolekcji i zostanie zwrócony odpowiadający kluczowi element. Kolekcje zapewniają bardzo elastyczny sposób pracy z grupami obiektów, grupa obiektów, z którymi pracujesz może rosnąć i maleć dynamicznie, wraz ze zmianami zapotrzebowań aplikacji. Kolekcja jest klasą, więc należy zadeklarować nową kolekcję, zanim będzie można dodać elementy do kolekcji.
Tworzenie kolekcji
Kolekcje można budować w module klasy, ale w takim przypadku wbudowane metody kolekcji (Add, Remove, Count, Item) są niedostępne - trzeba je utworzyć w module klasy.
Tworzenie kolekcji w module klasy
Private AllCars As New Collection
Public Sub Add(auto As ClassCar)
AllCars.Add auto
End Sub
Public Property Get Count() As Long
Count = AllCars.Count
End Property
Public Property Get Items() As Collection
Set Items = AllCars
End Property
Public Property Get Item(myItem As Variant) As ClassCar
Set Item = AllCars(myItem)
End Property
Public Sub remove(myItem As Variant)
AllCars.remove (myItem)
End Sub
Dla właściwości Count, Item i Items użyto procedury Property Get, ponieważ są to właściwości tylko do odczytu.
Sub Auta()
Dim Cars As New ClassCar
Dim auto As New ClassCar
Dim x As Integer
For x = 1 To 5
Set auto = New ClassCar
With auto
.carColor = "Czarny"
.carName = "Auto" & x
.carSpeed = 5 * x
.NumberOfDoors = 5
End With
Cars.Add auto
Next
MsgBox "ilość samochodów w kolekcji " & Cars.Items.Count & Chr(13) & _
Cars.Item(1).carName & Chr(13) & _
Cars.Item(2).carName & Chr(13) & _
Cars.Item(3).carName & Chr(13) & _
Cars.Item(4).carName & Chr(13) & _
Cars.Item(5).carName & Chr(13)
Set auto = Nothing
End Sub
Tworzenie kolekcji w module standardowym
Sub kolekcjaAut()
Dim kolCars As New Collection
Dim auto As New ClassCar
Dim x As Integer
For x = 1 To 5
Set auto = New ClassCar
With auto
.carColor = "Czerwony"
.carName = "Samochód" & x
.carSpeed = 10 * x
.NumberOfDoors = 3
End With
kolCars.Add auto
Next
MsgBox "ilość samochodów w kolekcji " & kolCars.Count & Chr(13) & _
kolCars(1).carName & Chr(13) & _
kolCars(2).carName & Chr(13) & _
kolCars(3).carName & Chr(13) & _
kolCars(4).carName & Chr(13) & _
kolCars(5).carName & Chr(13)
Set auto = Nothing
End Sub
Dodawanie i usuwanie elementów
Kolekcja czyli obiekt klasy posiada swoje metody. Gdy chcemy dodać bądź usunąć element kolekcji musimy odwołać się do odpowiedniej metody (add, remove)
Add - metoda dodaje nowy element kolekcji, domyślnie na koniec listy)
Add(Item, [Key], [Before], [After])
Remove – metoda usuwa wskazany element z kolekcji. Parametrem wymaganym jest wybranie elementu do usunięcia za pomocą indeksu lub klucza.
Remove(Index)
Odwołania do elementów (za pomocą klucza oraz indeksu)
Podczas dodawania obiektów do kolekcji, jeżeli pominiesz argument key metody Add okaże się że nie będzie możliwości odwołania się do elementu kolekcji po jego kluczu.
Sub kolekcjaAut()
Dim kolCars As New Collection
Dim auto As New ClassCar
Dim x As Integer
For x = 1 To 5
Set auto = New ClassCar
With auto
.carColor = "Czerwony"
.carName = "Samochód" & x
.carSpeed = 10 * x
.NumberOfDoors = 3
End With
kolCars.Add auto, "Samochód" & x 'dodaje obiekt do kolekcji, przypisuje klucz dla każdego elementu kolekcji
Next
Debug.Print kolCars("Samochód2").carName
Debug.Print kolCars(2).carName
Set auto = Nothing
End Sub
Słownik
Po zainstalowaniu biblioteki Microsoft Scripting Runtime uzyskamy możliwość korzystania z ciekawej alternatywy dla kolekcji jaką jest słownik.
Słownik posiada kilka ciekawych zalet, które na pewno znajdą entuzjastów. Poniżej lista:
- metoda Exists - prosty sposób weryfikacji czy dana wartość istnieje w słowniku.
- metoda RemoveAll - to polecenie czyści całą zawartość słownika
- właściwość CompareMode - rozróżnienie wielkości znaków (domyślne)
- prosta zmiana klucza w słowniku
objDict.Key("Pierwszy") = "Jeden"
- Items i Keys to oddzielne tablice z których łatwo możemy przepisać ich wartości do arkusza
Sub dicts()
Dim oDict As Dictionary
Dim ws As Worksheet
Set oDict = New Scripting.Dictionary
oDict.CompareMode = TextCompare
For Each ws In Worksheets
oDict.Add ws.Name, ws
Next
MsgBox oDict.Count & vbCrLf & Join(oDict.Keys, vbCrLf)
End Sub
Zaawansowane struktury i funkcje VBA
Przekazywanie parametrów przez wartość i referencje (ByRef i byVal)
- ByRef (domyślny)
- Przy przekazywaniu argumentu przez referencje do procedury jest przekazana sama zmienna jako argument procedury. Jeżeli wywołana procedura zmienia wartość argumentu ta zmiana pozostanie kiedy sterowanie powróci do procedury wywołującej
Sub Procedura1_ref(ByRef A As String)
A = A & A
End Sub
Sub procedura2_ref()
Dim x As String
x = "1234"
Call Procedura1_ref(x)
Debug.Print x
End Sub
- ByVal
- Przy przekazywaniu argumentu przez wartość, przekazana zostaje kopia zmiennej jako argument procedury.Jeżeli wywoałana procedura zmienia argument ta zmiana nie pozostanie kiedy sterowanie powróci do procedury wywołującej
Sub Procedura1_val(ByVal A As String)
A = A & A
End Sub
Sub procedura2_val()
Dim x As String
x = "1234"
Call Procedura1_val(x)
Debug.Print x
End Sub
Sub Nadrzedna()
Dim Range1 As Range
Dim Range2 As Range
Set Range1 = Range("A1")
Set Range2 = Range("A2")
Range1.Value = 11
Range2.Value = 22
Debug.Print "PRZED:Range1: " & Range1.Address & " = " & Range1.Value
Debug.Print "PRZED:Range2: " & Range2.Address & " = " & Range2.Value
Podrzedna2 R1:=Range1, R2:=Range2
Debug.Print "I PO :Range1: " & Range1.Address & " = " & Range1.Value
Debug.Print "I PO :Range2: " & Range2.Address & " = " & Range2.Value
End Sub
Sub Podrzedna(ByRef R1 As Range, ByVal R2 As Range)
R1.Value = 33
R2.Value = 44
Set R1 = Range("A3")
Set R2 = Range("A4")
End Sub
PRZED:Range1: A1 = 11 PRZED:Range2: A2 = 22 I PO :Range1: A3 = I PO :Range2: A2 = 44
Jak widać dla referencji możliwe jest zarówno zmiana wartości obiektu Range jak i przypisania jej innej komórki. W przypadku drugim możemy zmienić wartość komórki parametru ale nie jesteśmy w stanie przypisać do zmiennej innej komórki, tak żeby zmiana była widoczna na zewnątrz.
Parametry opcjonalne i wartości domyślne
Funkcja w przykładzie poniżej zawiera dwa argumenty, podanie pierwszego jest niezbędne natomiast drugi argument jest opcjonalny z domyślną wartością = "". Jeżeli nie podamy drugiego argumentu funkcja w wyniku zwróci wszystkie nazwy plików z danej lokalizacji. Wprowadzenie wartości do drugiego argumentu np "*.txt" spowoduje wypisanie wszystkich plików o rozszerzeniu txt.
Function listaPlikow(lokalizacja As String, Optional wzor As String = "") As String
Dim plik As String
ChDir lokalizacja
plik = Dir(wzor)
Do Until plik = ""
pliki = pliki & "," & plik
plik = Dir
Loop
End Function
Procedury o nieznanej liczbie parametrów (ParamArray)
Tablica parametrów funkcji
Sposób na przekazywanie do procedury lub funkcji zmiennej liczby parametrów
Parametr typu ParamArray, np.
Function suma(ParamArray liczby() As Variant) As Double Function suma(ParamArray liczby()) As Double
Parametr musi być dynamiczną tablicą elementów typu Variant
Function sumowanie(ParamArray skladnik())
Dim indx, kom As Range
For Each indx In skladnik
If TypeName(indx) = "Range" Then
For Each kom In indx
sumowanie = sumowanie + kom.Value
Next
Else
sumowanie = sumowanie + indx
End If
Next
End Function
Enumeracje, wygodne przekazywanie parametrów
Stałe wyliczeniowe
Stałe, jak wiadomo , są przydatne do poprawy czytelności i poprawiania kodu przez tworzenie samodokumentowania. Jednak nie można zdefiniować stałej publicznej (używając polecenia Public Const) wewnątrz modułu klasy. Jak uczynić jakieś stałe dostępne zarówno dla ciebie jak i innych użytkowników twojej klasy? Odpowiedź leży w zastosowaniu stałych wyliczeniowych. Stałe wyliczeniowe pozwalają tworzyć zbioru stałych, które stały się nieodłącznym elementem aplikacji lub klasy, bardzo podobnie jak stałe wewnętrzne, takie jak vbCrLf i vbRightButton, wewnątrz samego VB. Przez używanie stałych wyliczeniowych wewnątrz klasy, można skojarzyć nazwę stałej i jej wartość z klasą, w procesie dostarczania użytkownikowi klasy ze zbiorem znaczących stałych, które są wewnętrznie dostępne z listy rozwijanej IntelliSense.
Używanie stałych wyliczeniowych
Aby stworzyć zbiór stałych wyliczeniowych, używamy polecenia Enum, które definiuje nazwę zbioru stałych wartości, nazw pojedynczych stałych wewnątrz zbioru i pojedynczych wartości tych stałych. Umieszczamy polecenie Enum w sekcji deklaracji modułu klasy. Na przykład:
Public Enum empTypes empTypeOne = 1 empTypeTwo = 2 empTypeThree = 3 End Enum
Główną wadą stałych wyliczeniowych jest to ,że ich wartości mogą być tylko numeryczne. Innymi słowy, nie możesz deklarować stałych wyliczeniowych które reprezentują łańcuch. Kiedy stworzysz referencję do klasy z aplikacji klienckiej używając okna dialogowego referencji lub automatycznie jeśli moduł klasy w którym zdefiniowany jest empTypes jako część twojego projektu, masz dostęp do stałych wyliczeniowych przez listę rozwijalną IntelliSense. Na przykład możesz mieć dostęp do stałych z powyższego przykładu przez wpisanie emp, potem naciśnięcie klawisza Ctrl i spacji razem; na liście dostępnych pozycji, zobaczysz wszystkie trzy stałe i typ empTypes. Oznacza to, że możesz używać jednej z następujących form składniowych:
If iType = empTypes.empTypeOne Then If iType = empTypeOne Then
Zauważ, że używając stałych wyliczeniowych z wnętrza klasy, nie musisz mieć wystąpienia zmiennej obiektowej tej klasy jeśli chcesz mieć dostęp do właściwości wewnątrz klasy. Jest to ważny punkt i wart powtórzenia. Dostęp do właściwości wewnątrz klasy wymaga zadeklarowania zmiennej obiektu tej klasy, potem używamy zmiennej i notacji kropki aby dostać się do właściwości; na przykład:
Dim oVar As Employee Set oVar = New Employee OVar.Name = "Peter"
Jednak, jeśli moduł klasy zawierający stałe wyliczeniowe jest dołączony do projektu lub referencja do jego klasy jest dodana do projektu, możesz używać tych stałych wewnątrz kodu
Typy użytkownika (User-defined Type)
User-defined type [typ definiowany przez użytkownika] : Pozwala stworzyć pojedynczy typ danej składający się z kombinacji wewnętrznych typów danych VB, tablic, obiektów lub innych typów użytkownika. Tworzy się go przez użycie polecenia Type. Na przykład:
Type udtCustomer Name As String Code As Long Orders(20) As udtOrders RenewalDate As Date End Type
Obsługa wartości Null, Nothing, empty string "", Empty, 0
Konwersja typów (Conversion)
- CBool(expression) Boolean - Any valid string or numeric expression.
- CByte(expression) Byte - 0 to 255.
- CCur(expression) Currency - -922,337,203,685,477.5808 to 922,337,203,685,477.5807.
- CDate(expression) Date - Any valid date expression.
- CDbl(expression) Double - -1.79769313486231E308 to -4.94065645841247E-324 for negative values; 4.94065645841247E-324 to 1.79769313486232E308 for positive values.
- CDec(expression) Decimal - +/-79,228,162,514,264,337,593,543,950,335 for zero-scaled numbers, that is, numbers with no decimal places. For numbers with 28 decimal places, the range is +/-7.9228162514264337593543950335. The smallest possible non-zero number is 0.0000000000000000000000000001.
- CInt(expression Integer - -32,768 to 32,767; fractions are rounded.
- CLng(expression) Long - -2,147,483,648 to 2,147,483,647; fractions are rounded.
- CLngLng(expression) LongLong - -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807; fractions are rounded. (Valid on 64-bit platforms only.)
- CLngPtr(expression) LongPtr - -2,147,483,648 to 2,147,483,647 on 32-bit systems, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 on 64-bit systems; fractions are rounded for 32-bit and 64-bit systems.
- CSng(expression) Single - -3.402823E38 to -1.401298E-45 for negative values; 1.401298E-45 to 3.402823E38 for positive values.
- CStr(expression) String - Returns for CStr depend on the expression argument.
- CVar(expression) Variant - Same range as Double for numerics. Same range as String for non-numerics.
Operacje na plikach
Aby otworzyć lub stworzyć nowy plik użyj instrukcji Open
Open pathname For mode As [#] filenumber
- pathname - nazwa otwieranego pliku podana wraz ze ścieżką dostępu
- mode - tryb dostępu do pliku, Pliki sekwencyjne mogą być otwierane w następujących trybach:
- Output - tryb zapisywania danych. VBA otwiera plik do zapisu danych. Jeżeli plik nie istnieje to zostanie utworzony, natomiast wszystkie dane z istniejącego pliku zostano usunięte.
- Append - tryb dopisywania danych. VBA otwiera istniejący plik i dopisuje do niego nowe dane. Jeżeli plik nie istnieje zostaje utworzony.
- Input - tryb odczytywania danych. Jeśli plik nie istnieje pojawi się komunikat o błędzie.
- filenumber - wartość liczbowa z zakresu od 1 do 511. Jest to identyfikator pliku
Funkcja FreeFile
Pozwala znaleźć pierwszy nie zajęty numer dla instrukcji Open
NumerPliku = FreeFile()
Open "C:\licznik.txt" For Output As #1
Otwieramy plik licznik.txt do zapisu. Plik ten umieszczony jest bezpośrednio na dysku C. Jeśli plik nie istnieje, zostanie utworzony natomiast dane w istniejącym pliku zostaną usunięte. Plikowi został przypisany numer 1.
Open "C:\wpisy.txt" For Append As #2
Otwieramy plik wpisy.txt w trybie do zapisu (dopisywania). Plik ten umieszczony jest na dysku C. Jeżeli plik nie istnieje (w podanej lokalizacji) zostanie utworzony. Jeżeli plik istnieje dane będą dopisywane do istniejących. Plik ten identyfikuje wartość 2.
Open "C:\Dane\adresy.txt" For Input As #3
Otwieramy plik adresy.txt tylko do odczytu. Plik ten umieszczony jest na dysku C w katalogu Dane (oczywiście zakładamy ze katalog Dane istnieje na dysku C). Jeśli plik nie istnieje (w podanej lokalizacji) pojawi się komunikat o błędzie. Identyfikatorem pliku jest wartość 3.
Zapisywanie danych do pliku
Zapis danych w plikach sekwencyjnych można zrealizować jedną z dwóch instrukcji:
- Write #
- Print #
Write #:
- Instrukcja Write # podczas zapisywania danych do pliku wstawia przecinki między kolejnymi elementami i cudzysłowie ograniczające ciągi znaków. Informacje zapisywane za pomocą instrukcji Write # są zwykle odczytywane z pliku za pomocą instrukcji Input #.
Write #NumerPliku, [ListaWartości]
ListaWartości - Poszczególne elementy bloku danych rozdzielamy średnikami lub przecinkami. Element ListaWartości może zawierać dane różnego typu: teksty, liczby, wartości logiczne czy kody błędów. Możemy też użyć zmiennych lub stałych którym przypiszemy odpowiednie dane. Typowe dane tekstowe należy ujmować w cudzysłowy. Jeżeli element ListaWartości zostanie pominięty, to w pliku zostanie wpisany pusty wiersz. Zastosowanie instrukcji Write # zapewnia również poprawny odczyt danych niezależnie od ustawień regionalnych.
Print #:
- instrukcja Print # zapisuje do pliku sekwencyjnego dane w postaci sformatowanej do wydruku. Dane zapisane za pomocą instrukcji Print # są zwykle odczytywane z dysku za pomocą instrukcji Line Input #. Instrukcja Print # lepiej nadaje się do zapisu danych które będziemy odczytywać poprzez otwarcie pliku tekstowego na przykład w Notatniku. Jeżeli zapisywane dane chcemy wykorzystać (odczytać) w kodzie VBA do zapisu lepiej użyć instrukcji Write #.
Print #NumerPliku, [ListaWartości]
ListaZapisywanychWartości - wyrażenie lub lista wyrażeń, które mają być zapisane. Do odpowiedniego sformatowania wyrażeń możemy użyć też funkcji wstawiającej znak spacji np. Spc(1) lub tabulacji Tab. Wszystkie dane pisane do pliku za pomocą instrukcji Print # są formatowane zgodnie z ustawieniami regionalnymi, przy zachowaniu właściwego separatora dziesiętnego.
Przykładowe instrukcje zapisu danych:
Write #1, jakiśTekst
Zapisujemy do pliku dane jakie przechowuje zmienna o nazwie jakiśTekst
Write #1, "Jakiś tekst"; "kolejny tekst"
Zapisujemy do pliku tekst złożony z dwóch elementów
Print #1, "Jakiś tekst"; " "; "kolejny tekst"; Spc(1); "i znowu"
Przykład zapisania tych samych danych za pomocą instrukcji Print #.
Działanie instrukcji Write # i Print # uzależnione jest w pewnym stopniu od sposobu otwarcia pliku. Jeżeli plik jest otwarty w trybie Output, to wskaźnik zapisu jest ustawiony na początku pliku. Co spowoduje skasowanie dotychczasowej zawartości pliku i zapisanie aktualnych danych. Jeżeli zaś plik otwarty jest w trybie Append wskaźnik zapisu jest ustawiony na końcu pliku. W tym przypadku zapisywane dane są dopisywane do danych które już istnieją.
Odczyt danych z pliku
Zawartość plików sekwencyjnych możemy odczytywać za pomocą instrukcji Input # lub Line Input #. Wybór zależy od sposobu zapisu i to w jakiej formie odczytywane dane mają być przedstawione.
Input #:
Instrukcja Input # odczytuje dane z otwartego pliku sekwencyjnego i przypisuje dane do zmiennej (zmiennych). Aby mieć możliwość poprawnego odczytu danych z plików do zmiennych za pomocą instrukcji Input #, należy do zapisu danych do plików wykorzystywać instrukcję Write #, a nie instrukcję Print #. Wykorzystanie instrukcji Write # wymusza poprawne oddzielenie od siebie pól danych.
Input #NumerPliku, ListaZmiennych
ListaZmiennych - element obowiązkowy, jest to lista zmiennych oddzielonych od siebie przecinkami. Zmiennym tym przypisywane są wartości odczytywane z pliku.
Instrukcja Line Input #:
Drugą instrukcją służącą do odczytu danych z pliku sekwencyjnego jest instrukcja Line Input #. Instrukcja Line Input # odczytuje cały pojedynczy wiersz z otwartego pliku i przypisuje go zmiennej.
Line Input #NumerPliku, NazwaZmiennej
NazwaZmiennej - nazwa zmiennej typu Variant lub String do której przypiszemy odczytaną linię.
Dane odczytane za pomocą instrukcji Line Input # są zwykle zapisywane do plików za pomocą instrukcji Print #.
Funkcja Input odczytuje z pliku określoną liczbę znaków. W przeciwieństwie do instrukcji Input #, funkcja Input zwraca wszystkie odczytane znaki, łącznie z przecinkami, znakami powrotu karetki, znakami końca wiersza, cudzysłowami i spacjami wiodącymi.
Input #1, Wpis, Kto Odczytujemy dane i przypisujemy je do dwóch zmiennych o nazwach: Wpis i Kto.
Line Input #1, OdczytywanyWiersz 'Czytamy dane z jednego wiersza i przypisujemy do zmiennej o nazwie OdczytywanyWiersz.
PobraneZnaki = Input(6, #1) 'Pobieramy sześć znaków i przypisujemy do zmiennej o nazwie PobraneZnaki.
Aby odczytać cały plik tekstowy możemy skorzystać z kombinacji kilku elementów: pętli Do Until i funkcji EOF. Funkcję EOF należy wykorzystywać w celu uniknięcia błędów powstałych przy próbie odczytu danych znajdujących się za końcem pliku.
Zamykanie plików
Po wykonaniu zaplanowanych operacji na zawartości pliku należy go zamknąć. Próba ponownego otwarcia pliku który nie został zamknięty spowoduje pojawienie się komunikatu o błędzie. Do zamykania pliku otwartego za pomącą instrukcji Open służy instrukcja Close. Po wykonaniu instrukcji Close powiązanie między plikiem a jego numerem staje się nieaktualne.
Close [NumerPliku]
Jako argument NumerPliku podajemy numer pliku pod jakim ten plik otworzyliśmy za pomocą instrukcji Open. Jeżeli podamy kilka numerów plików wszystkie określone pliki zostaną zamknięte. Jeżeli argument NumerPliku zostanie pominięty, wszystkie aktywne pliki otwarte za pomocą instrukcji Open zostaną zamknięte.
Close #1, 'Zamykamy plik z numerem 1.
Close #1, #3 'Zamykamy pliki o numerach 1 i 3.
Close 'Zamykamy wszystkie otwarte pliki.