Nawigacja bloga

Najnowsze posty

Niebieski ekran Windows 11 25H2 — diagnostyka i naprawa kodów STOP
Niebieski ekran Windows 11 25H2 — diagnostyka i naprawa kodów STOP
3 wyświetlenia 0 Lubię

Niebieski ekran 25H2 w Windows 11 najczęściej oznacza problem ze sterownikiem, pamięcią, zasilaniem urządzenia,...

Czytaj więcej
Konwersja PDF na Word bez utraty formatowania — najlepsze metody 2026
Konwersja PDF na Word bez utraty formatowania — najlepsze metody 2026
4 wyświetlenia 0 Lubię

W erze cyfrowej, gdzie obieg dokumentów jest nieustanny i dynamiczny, potrzeba konwersji plików PDF do edytowalnego...

Czytaj więcej
Backup serwera Windows — zasada 3-2-1 i pełny przewodnik
Backup serwera Windows — zasada 3-2-1 i pełny przewodnik
2 wyświetlenia 0 Lubię

Backup serwera 3-2-1 to najprostsza reguła, która oddziela zwykłą kopię zapasową od realnego planu odzyskiwania firmy...

Czytaj więcej
SQL Server — optymalizacja wydajności i tuning zapytań
SQL Server — optymalizacja wydajności i tuning zapytań
2 wyświetlenia 0 Lubię

SQL Server optymalizacja zaczyna się nie od dodawania kolejnych indeksów, ale od ustalenia, które zapytania, plany...

Czytaj więcej
Dual boot Windows 11 i Linux — instalacja krok po kroku 2026
Dual boot Windows 11 i Linux — instalacja krok po kroku 2026
3 wyświetlenia 0 Lubię

Dual boot windows linux w 2026 roku nie polega już na nadpisywaniu jednego sektora rozruchowego i walce z klasycznym...

Czytaj więcej

Excel VBA — kurs od podstaw z 25 praktycznymi makrami

2 Odsłony 0 Polubiony
 

Excel VBA — czym jest i dlaczego warto uczyć się go w 2026 roku?

Excel VBA (Visual Basic for Applications) to wbudowany język programowania Microsoftu, który pozwala automatyzować powtarzalne zadania, tworzyć własne funkcje i budować zaawansowane rozwiązania bezpośrednio w arkuszach kalkulacyjnych. Jeśli codziennie ręcznie kopiujesz dane, piszesz te same raporty, formatujesz tabele czy wysyłasz maile z Excela — ten kurs excel vba od podstaw zmieni Twój sposób pracy raz na zawsze. W jednym artykule znajdziesz kompletne wprowadzenie: od konfiguracji środowiska, przez typy danych i pętle, aż po 25 gotowych makr excel z pełnym, skomentowanym po polsku kodem, który możesz skopiować i uruchomić natychmiast.

W tym przewodniku otrzymasz: krok po kroku konfigurację edytora VBE (Visual Basic Editor), tabelę wszystkich typów danych VBA, tabelę ustawień bezpieczeństwa makr, omówienie pętli i obsługi błędów oraz — co najważniejsze — 25 działających makr podzielonych na kategorie: formatowanie, zarządzanie plikami, raporty, tabele przestawne, czyszczenie danych i wysyłka przez Outlook. Każde makro zawiera polskie komentarze wyjaśniające każdą linię kodu.

Zanim przejdziesz dalej: makra VBA dostępne są w desktopowej wersji Excela wchodzącej w skład pakietów Office, a nie w Excelu uruchamianym wyłącznie w przeglądarce. Jeśli korzystasz ze starszej wersji, rozważ przejście na Microsoft Office 2024 Professional Plus lub Microsoft Office 2024 Standard. Jeżeli pracujesz w modelu subskrypcyjnym, sprawdź też Microsoft 365 z aplikacjami klasycznymi pakietu Office.

Dlaczego Excel VBA wciąż ma sens w 2026 roku?

Pojawiają się głosy, że Python czy Office Scripts zastąpią VBA. Prawda jest prostsza: Excel VBA dla początkujących to wciąż najszybsza ścieżka do automatyzacji pracy biurowej w środowiskach korporacyjnych. Dziesiątki tysięcy firm w Polsce opierają swoje procesy na rozwiązaniach VBA pisanych przez lata. Umiejętność ich utrzymania i rozwijania to jedna z najbardziej pożądanych kompetencji analityków finansowych, pracowników działów HR, logistyki i controllingu.

Według oficjalnej dokumentacji Microsoft Learn dostępnej pod adresem learn.microsoft.com/pl-pl/office/vba/api/overview/excel — VBA dla Excela daje dostęp do ponad 900 obiektów, właściwości i metod umożliwiających pełną kontrolę nad arkuszem.

Jak uruchomić edytor VBA w Excel 2024 — konfiguracja krok po kroku

Jak włączyć edytor VBA w Excelu — krok po kroku

Krok 1: Włącz kartę Deweloper

Otwórz Excel i przejdź do Plik → Opcje → Dostosowywanie Wstążki. Na liście po prawej stronie zaznacz pole Deweloper i kliknij OK. Od tej chwili karta Deweloper będzie widoczna na górnej wstążce Excela.

Krok 2: Otwórz edytor VBE

Kliknij kartę Deweloper, a następnie przycisk Visual Basic lub użyj skrótu klawiszowego ALT + F11. Otworzy się edytor Visual Basic Editor (VBE) — tutaj będziesz pisać cały swój kod.

Krok 3: Wstaw nowy moduł

W edytorze VBE kliknij w górnym menu Insert → Module. Pojawi się puste okno kodu — to tutaj piszesz swoje makra. Każdy plik Excela (Projekt VBA) może zawierać wiele modułów.

Krok 4: Włącz Option Explicit

Na samej górze każdego modułu wpisz Option Explicit. Ta instrukcja wymusza deklarowanie wszystkich zmiennych i chroni przed trudnymi do wykrycia błędami (np. literówkami w nazwach zmiennych). Możesz ją włączyć automatycznie: Tools → Options → zaznacz "Require Variable Declaration".

Krok 5: Zapisz plik jako .xlsm

Pliki z makrami muszą być zapisane w formacie .xlsm (Skoroszyt programu Excel z obsługą makr). Zwykły format .xlsx automatycznie usuwa cały kod VBA przy zapisie — pamiętaj o tym! Użyj Plik → Zapisz jako → Typ: Skoroszyt Excel z obsługą makr (*.xlsm).

Bezpieczeństwo makr — ustawienia Centrum Zaufania

Przed uruchamianiem makr musisz skonfigurować ustawienia bezpieczeństwa. Znajdziesz je w Plik → Opcje → Centrum zaufania → Ustawienia Centrum zaufania → Ustawienia makr. Microsoft opisuje zmianę ustawień makr w Excelu w oficjalnej pomocy Zmienianie ustawień zabezpieczeń makr w programie Excel oraz ostrzega, aby włączać makra tylko w plikach, których działanie i pochodzenie rozumiesz. Poniższa tabela wyjaśnia różnice między dostępnymi poziomami:

Ustawienie bezpieczeństwa makrDziałanieZaletyWady / RyzykoZalecane dla
Wyłącz wszystkie makra bez powiadomieniaBlokuje każdy kod VBA bez żadnego komunikatuMaksymalne bezpieczeństwoBrak możliwości automatyzacji; makra po cichu nie działająKomputery ogólnodostępne, kiosk
Wyłącz wszystkie makra z powiadomieniem (domyślne)Przy otwarciu pliku z makrami pojawia się żółty pasek z pytaniem o zezwolenieKontrola nad uruchamianiem; standard branżowyWymaga kliknięcia „Włącz zawartość" przy każdym nowym plikuWiększość użytkowników biznesowych
Wyłącz wszystkie makra z wyjątkiem podpisanych cyfrowoAutomatycznie uruchamia makra od zaufanych wydawców z certyfikatem cyfrowymWysoki poziom bezpieczeństwa; brak ręcznego zezwalania na znane makraWymaga zakupu i konfiguracji certyfikatu cyfrowegoDziały IT, korporacje, developerzy narzędzi VBA
Włącz wszystkie makra (niezalecane)Uruchamia natychmiast każdy kod, bez pytaniaWygoda podczas własnego programowaniaBardzo wysokie ryzyko uruchomienia złośliwego kodu; absolutnie nie używać na plikach z zewnątrzTylko izolowane środowisko testowe
Zaufane lokalizacje (Trusted Locations)Foldery na dysku, z których makra uruchamiają się bez ostrzeżeniaWygoda + kontrola: tylko z wybranego miejscaTrzeba pilnować, co trafia do folderu zaufanegoFirmy z centralnym folderem dla narzędzi VBA

Zalecenie praktyczne: korzystaj z ustawienia domyślnego (z powiadomieniem) i klikaj „Włącz zawartość" tylko w plikach, których pochodzenie znasz i którym ufasz. Nigdy nie włączaj makr w plikach przysłanych e-mailem przez nieznanych nadawców.

Typy danych VBA — kompletna tabela z przykładami

Deklarowanie zmiennych z właściwym typem danych to jeden z najważniejszych nawyków dobrego programisty VBA. Szczegółowe omówienie wszystkich typów znajdziesz w oficjalnej dokumentacji Microsoft Learn: Data Type Summary (learn.microsoft.com).

Typ danych VBARozmiar w pamięciZakres wartościPrzykład deklaracjiKiedy używać
Boolean2 bajtyTrue lub FalseDim czyAktywny As BooleanFlagi logiczne, przełączniki stanu
Byte1 bajt0 do 255Dim kolor As ByteMałe liczby bez znaku, wartości RGB
Integer2 bajty-32 768 do 32 767Dim licznik As IntegerMałe liczniki pętli (dziś zastępowany przez Long)
Long4 bajty-2 147 483 648 do 2 147 483 647Dim wiersz As LongNumery wierszy w Excelu (ponad 32K), duże liczniki — preferowany zamiast Integer
LongLong8 bajtów±9,2 × 10¹⁸Dim bigNum As LongLong64-bitowe systemy; bardzo duże liczby całkowite
Single4 bajty±3,4 × 10³⁸ (6–7 cyfr precyzji)Dim temp As SinglePomiary naukowe, gdy precyzja nie jest krytyczna
Double8 bajtów±1,8 × 10³⁰⁸ (15–16 cyfr precyzji)Dim kwota As DoubleObliczenia finansowe, matematyczne — najczęściej używany dla liczb zmiennoprzecinkowych
Currency8 bajtów±922 biliony (4 miejsca po przecinku)Dim cena As CurrencyWartości pieniężne, eliminacja błędów zaokrąglania
Decimal14 bajtów±7,9 × 10²⁸ (28 cyfr precyzji)Dim podatek As Variant (tylko jako podtyp Variant)Bardzo precyzyjne obliczenia podatkowe
Date8 bajtów1 stycznia 100 r. do 31 grudnia 9999 r.Dim dataRaportu As DateDaty, godziny, terminy płatności, różnice czasowe
StringZmienny (do ~2 mld znaków)Ciągi tekstoweDim nazwaKlienta As StringTekst, ścieżki plików, nazwy arkuszy
Object4 bajtyReferencja do dowolnego obiektuDim ws As ObjectGdy typ obiektu nie jest znany w trakcie kompilacji
Variant16–22 bajtyDowolny typ danychDim x As VariantUnikaj jeśli możesz — wolny, zużywa dużo pamięci; użyj gdy typ jest naprawdę nieznany

Podstawy składni VBA — zmienne, pętle i obsługa błędów

Ta część kursu opiera się na oficjalnych rozdziałach Microsoft Learn: Option Explicit statement, Declaring variables, Understanding scope and visibility, For Each...Next statement, On Error statement i Err object. W praktyce oznacza to trzy zasady: deklaruj zmienne jawnie, wybieraj typ danych świadomie i zawsze kończ makro ścieżką obsługi błędów, która przywraca ustawienia Excela.

Deklarowanie zmiennych i stałych

Option Explicit  ' Wymuszaj deklarowanie wszystkich zmiennych

' Makro 01: Podstawy deklarowania zmiennych i typów danych
Sub Makro01_TypyDanych()
    ' --- DEKLARACJE ZMIENNYCH ---
    Dim nazwaFirmy As String       ' tekst
    Dim liczbaKlientow As Long     ' liczba całkowita (preferuj Long nad Integer)
    Dim przychodMiesieczny As Double ' liczba zmiennoprzecinkowa
    Dim czyAktywny As Boolean      ' wartość logiczna (True/False)
    Dim dataKontraktu As Date      ' data
    
    ' --- PRZYPISANIE WARTOŚCI ---
    nazwaFirmy = "Kowalski Sp. z o.o."
    liczbaKlientow = 1250
    przychodMiesieczny = 98750.50
    czyAktywny = True
    dataKontraktu = #1/15/2026#  ' Daty w VBA zapisujemy w formacie #MM/DD/YYYY#
    
    ' --- STAŁE (wartości niezmienne) ---
    Const STAWKA_VAT As Double = 0.23  ' Stała dla stawki VAT 23%
    Const NAZWA_FIRMY As String = "KluczeSoft.pl"  ' Stała tekstowa
    
    ' --- WYŚWIETLENIE WYNIKU ---
    MsgBox "Firma: " & nazwaFirmy & vbCrLf & _
           "Klientów: " & liczbaKlientow & vbCrLf & _
           "Aktywna: " & czyAktywny & vbCrLf & _
           "Kontrakt od: " & Format(dataKontraktu, "dd.mm.yyyy"), _
           vbInformation, "Dane firmy"
End Sub

Instrukcje warunkowe If…Then i Select Case

' Makro 02: Instrukcje warunkowe — przykład oceny wyników sprzedaży
Sub Makro02_WarunkiIfCase()
    Dim wynikSprzedazy As Double
    Dim ocena As String
    
    ' Pobierz wartość z aktywnej komórki (zakładamy liczbę w A1)
    wynikSprzedazy = CDbl(ActiveSheet.Range("A1").Value)
    
    ' --- PRZYKŁAD 1: If...Then...ElseIf...Else ---
    If wynikSprzedazy >= 100000 Then
        ocena = "Platynowy"
    ElseIf wynikSprzedazy >= 50000 Then
        ocena = "Złoty"
    ElseIf wynikSprzedazy >= 20000 Then
        ocena = "Srebrny"
    Else
        ocena = "Standardowy"
    End If
    
    ' --- PRZYKŁAD 2: Select Case (czytelniejszy dla wielu opcji) ---
    Select Case ocena
        Case "Platynowy"
            ActiveSheet.Range("B1").Interior.Color = RGB(200, 200, 255) ' jasnoniebieski
        Case "Złoty"
            ActiveSheet.Range("B1").Interior.Color = RGB(255, 215, 0)   ' złoty
        Case "Srebrny"
            ActiveSheet.Range("B1").Interior.Color = RGB(192, 192, 192) ' srebrny
        Case Else
            ActiveSheet.Range("B1").Interior.Color = RGB(255, 255, 255) ' biały
    End Select
    
    ActiveSheet.Range("B1").Value = ocena  ' Wpisz ocenę do komórki B1
    MsgBox "Wynik: " & wynikSprzedazy & " PLN" & vbCrLf & "Poziom: " & ocena, vbInformation, "Ocena sprzedawcy"
End Sub

Pętle — For Next, For Each, Do While

' Makro 03: Pętle — trzy najważniejsze typy w praktyce
Sub Makro03_PetleRodzaje()
    Dim i As Long          ' licznik pętli For
    Dim ws As Worksheet    ' zmienna arkusza dla For Each
    Dim wynik As Long      ' akumulator
    
    ' --- PĘTLA 1: For...Next — klasyczna pętla z licznikiem ---
    ' Wpisuje liczby 1-10 do kolumny A arkusza "Arkusz1"
    For i = 1 To 10
        Sheets("Arkusz1").Cells(i, 1).Value = i     ' kolumna A, wiersz i
        Sheets("Arkusz1").Cells(i, 2).Value = i ^ 2  ' kolumna B, kwadrat liczby
    Next i
    
    ' --- PĘTLA 2: For Each...Next — iteracja po kolekcji obiektów ---
    ' Wypisuje nazwy wszystkich arkuszy do okna Immediate (Ctrl+G w VBE)
    For Each ws In ThisWorkbook.Worksheets
        Debug.Print "Arkusz: " & ws.Name  ' Debug.Print = wydruk w oknie Immediate
    Next ws
    
    ' --- PĘTLA 3: Do While...Loop — pętla warunkowa ---
    ' Sumuje wartości w kolumnie C dopóki komórka nie jest pusta
    i = 1      ' zaczynamy od wiersza 1
    wynik = 0  ' inicjalizujemy sumę
    
    Do While Sheets("Arkusz1").Cells(i, 3).Value <> ""
        wynik = wynik + CLng(Sheets("Arkusz1").Cells(i, 3).Value)
        i = i + 1  ' przejdź do kolejnego wiersza
    Loop
    
    MsgBox "Suma wartości w kolumnie C: " & wynik, vbInformation, "Wynik sumowania"
End Sub

Obsługa błędów — On Error GoTo

' Makro 04: Profesjonalna obsługa błędów w VBA
Sub Makro04_ObslugaBledow()
    Dim wynik As Double
    Dim dzielnik As Double
    
    ' Włącz obsługę błędów — przekieruj do etykiety "UchwycBlad"
    On Error GoTo UchwycBlad
    
    dzielnik = CDbl(InputBox("Podaj dzielnik (wpisz 0, aby zobaczyć obsługę błędu):", "Test"))
    
    ' Ta linia wywoła błąd "Division by zero" jeśli dzielnik = 0
    wynik = 100 / dzielnik
    
    MsgBox "Wynik: 100 / " & dzielnik & " = " & wynik, vbInformation, "Wynik"
    
    ' Instrukcja Exit Sub kończy normalny przepływ — pomija blok błędu
    Exit Sub

UchwycBlad:
    ' Obsługa błędu — Err.Number to kod błędu, Err.Description to opis
    Select Case Err.Number
        Case 11   ' Division by zero
            MsgBox "Błąd: Nie można dzielić przez zero!" & vbCrLf & _
                   "Kod błędu: " & Err.Number, vbCritical, "Błąd matematyczny"
        Case 13   ' Type mismatch
            MsgBox "Błąd: Wpisano nieprawidłowy typ danych (oczekiwano liczby)." & vbCrLf & _
                   "Kod błędu: " & Err.Number, vbCritical, "Błąd typu"
        Case Else
            MsgBox "Nieoczekiwany błąd: " & Err.Description & vbCrLf & _
                   "Kod: " & Err.Number, vbCritical, "Błąd VBA"
    End Select
    
    ' Wznów wykonanie od następnej linii po tej, która spowodowała błąd
    Resume Next
End Sub

25 praktycznych makr Excel — gotowy kod do użycia od zaraz

Kategoria 1: Formatowanie i estetyka arkuszy

' Makro 05: Automatyczne dopasowanie szerokości kolumn i wysokości wierszy
Sub Makro05_DopasujKolumnyWiersze()
    Dim ws As Worksheet
    
    ' Wyłącz odświeżanie ekranu — kod wykona się wielokrotnie szybciej
    Application.ScreenUpdating = False
    
    ' Iteruj po wszystkich arkuszach w tym skoroszycie
    For Each ws In ThisWorkbook.Worksheets
        ws.Cells.EntireColumn.AutoFit  ' Dopasuj szerokość wszystkich kolumn
        ws.Cells.EntireRow.AutoFit     ' Dopasuj wysokość wszystkich wierszy
    Next ws
    
    ' Przywróć odświeżanie ekranu
    Application.ScreenUpdating = True
    
    MsgBox "Dopasowano kolumny i wiersze we wszystkich " & _
           ThisWorkbook.Worksheets.Count & " arkuszach.", vbInformation, "Gotowe"
End Sub
' Makro 06: Dynamiczne formatowanie warunkowe wierszy na podstawie wartości w kolumnie
Sub Makro06_FormatowanieWarunkowe()
    Dim ws As Worksheet
    Dim lastRow As Long    ' ostatni wiersz z danymi
    Dim i As Long          ' licznik wierszy
    Dim statusKomorki As String
    
    Application.ScreenUpdating = False  ' Wyłącz ekran dla szybkości
    
    Set ws = ActiveSheet  ' Pracuj na aktywnym arkuszu
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row  ' Znajdź ostatni wiersz w kolumnie A
    
    ' Iteruj po wierszach od 2 (pomijając nagłówek) do ostatniego wiersza
    For i = 2 To lastRow
        statusKomorki = ws.Cells(i, 3).Value  ' Odczytaj status z kolumny C
        
        Select Case statusKomorki
            Case "Opłacone"
                ' Zielone tło dla opłaconych faktur
                ws.Rows(i).Interior.Color = RGB(198, 239, 206)
                ws.Rows(i).Font.Color = RGB(0, 97, 0)
            Case "Oczekuje"
                ' Żółte tło dla faktur oczekujących
                ws.Rows(i).Interior.Color = RGB(255, 235, 156)
                ws.Rows(i).Font.Color = RGB(156, 87, 0)
            Case "Przeterminowane"
                ' Czerwone tło dla przeterminowanych
                ws.Rows(i).Interior.Color = RGB(255, 199, 206)
                ws.Rows(i).Font.Color = RGB(156, 0, 6)
            Case Else
                ' Brak koloru — biały
                ws.Rows(i).Interior.ColorIndex = xlNone
                ws.Rows(i).Font.ColorIndex = xlAutomatic
        End Select
    Next i
    
    Application.ScreenUpdating = True  ' Przywróć ekran
    MsgBox "Formatowanie zastosowane dla " & (lastRow - 1) & " wierszy.", vbInformation, "Gotowe"
End Sub
' Makro 07: Podświetlanie duplikatów w wybranej kolumnie
Sub Makro07_PodswietlDuplikaty()
    Dim zakres As Range     ' zakres do sprawdzenia
    Dim komorka As Range    ' pojedyncza komórka
    Dim slownik As Object   ' słownik do liczenia wystąpień
    Dim klucz As String
    
    ' Utwórz obiekt słownika (Scripting.Dictionary) do zliczania wartości
    Set slownik = CreateObject("Scripting.Dictionary")
    slownik.CompareMode = 1  ' Porównuj bez uwzględnienia wielkości liter
    
    ' Pobierz zaznaczony zakres od użytkownika lub użyj kolumny A
    If TypeName(Selection) = "Range" And Selection.Cells.Count > 1 Then
        Set zakres = Selection
    Else
        ' Domyślnie: cała kolumna A z danymi na aktywnym arkuszu
        Set zakres = ActiveSheet.Range("A1:A" & ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row)
    End If
    
    ' PRZEJŚCIE 1: Zlicz wystąpienia każdej wartości
    For Each komorka In zakres
        klucz = CStr(komorka.Value)
        If klucz <> "" Then  ' Pomiń puste komórki
            If slownik.Exists(klucz) Then
                slownik(klucz) = slownik(klucz) + 1  ' Zwiększ licznik
            Else
                slownik.Add klucz, 1  ' Dodaj nowy klucz
            End If
        End If
    Next komorka
    
    ' PRZEJŚCIE 2: Pokoloruj duplikaty
    For Each komorka In zakres
        klucz = CStr(komorka.Value)
        If klucz <> "" And slownik.Exists(klucz) Then
            If slownik(klucz) > 1 Then
                komorka.Interior.Color = RGB(255, 153, 51)  ' Pomarańczowe tło dla duplikatów
            End If
        End If
    Next komorka
    
    MsgBox "Duplikaty podświetlone.", vbInformation, "Gotowe"
End Sub

Kategoria 2: Zarządzanie danymi i ich czyszczenie

' Makro 08: Usuwanie pustych wierszy z aktywnego arkusza
Sub Makro08_UsunPusteWiersze()
    Dim lastRow As Long  ' ostatni wiersz z danymi
    Dim i As Long        ' licznik — iterujemy OD DÓŁ żeby nie pominąć wierszy
    Dim licznikUsunietych As Long
    
    Application.ScreenUpdating = False  ' Wyłącz ekran dla szybkości
    
    lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
    licznikUsunietych = 0
    
    ' WAŻNE: iteruj od ostatniego wiersza w górę!
    ' Jeśli idziesz od góry i usuniesz wiersz, numeracja się przesuwa i pomijasz wiersze.
    For i = lastRow To 1 Step -1
        ' Sprawdź, czy cały wiersz jest pusty (CountA liczy niepuste komórki)
        If Application.WorksheetFunction.CountA(ActiveSheet.Rows(i)) = 0 Then
            ActiveSheet.Rows(i).Delete  ' Usuń pusty wiersz
            licznikUsunietych = licznikUsunietych + 1
        End If
    Next i
    
    Application.ScreenUpdating = True  ' Przywróć ekran
    MsgBox "Usunięto " & licznikUsunietych & " pustych wierszy.", vbInformation, "Gotowe"
End Sub
' Makro 09: Czyszczenie danych — usuwanie zbędnych spacji i znaków specjalnych
Sub Makro09_CzyscDane()
    Dim ws As Worksheet
    Dim zakres As Range
    Dim komorka As Range
    Dim wartoscOryg As String
    Dim wartoscPo As String
    Dim licznikZmian As Long
    
    Application.ScreenUpdating = False
    
    Set ws = ActiveSheet
    ' Sprawdź, co użytkownik zaznaczył — jeśli nic, weź UsedRange (cały obszar danych)
    If Selection.Cells.Count = 1 Then
        Set zakres = ws.UsedRange
    Else
        Set zakres = Selection
    End If
    
    licznikZmian = 0
    
    For Each komorka In zakres
        ' Przetwarzaj tylko komórki z tekstem (nie formuły, nie liczby)
        If komorka.HasFormula = False And VarType(komorka.Value) = vbString Then
            wartoscOryg = komorka.Value
            
            ' TRIM: usuwa spacje na początku i końcu oraz wielokrotne spacje wewnątrz
            ' CLEAN: usuwa niedrukowane znaki (np. znaki nowej linii)
            wartoscPo = Application.WorksheetFunction.Trim( _
                        Application.WorksheetFunction.Clean(wartoscOryg))
            
            ' Zapisz zmienioną wartość tylko jeśli faktycznie jest różnica
            If wartoscOryg <> wartoscPo Then
                komorka.Value = wartoscPo
                licznikZmian = licznikZmian + 1
            End If
        End If
    Next komorka
    
    Application.ScreenUpdating = True
    MsgBox "Oczyszczono " & licznikZmian & " komórek ze zbędnych spacji i znaków.", _
           vbInformation, "Czyszczenie zakończone"
End Sub
' Makro 10: Konwersja formuł na wartości (zamrożenie wyników obliczeń)
Sub Makro10_FormulaNaWartosc()
    Dim zakres As Range
    
    ' Konwertuj tylko zaznaczony zakres lub cały UsedRange
    If Selection.Cells.Count > 1 Then
        Set zakres = Selection
    Else
        Set zakres = ActiveSheet.UsedRange
    End If
    
    ' Kopiuj-wklej specjalnie: tylko wartości (usuwa formuły, zostawia wyniki)
    zakres.Copy
    zakres.PasteSpecial Paste:=xlPasteValues  ' xlPasteValues = wklej tylko wartości
    
    Application.CutCopyMode = False  ' Usuń migającą ramkę kopiowania
    
    MsgBox "Formuły zamienione na wartości w zakresie " & zakres.Address, _
           vbInformation, "Konwersja zakończona"
End Sub

Kategoria 3: Zarządzanie arkuszami i plikami

' Makro 11: Tworzenie spisu treści z hiperłączami do wszystkich arkuszy
Sub Makro11_SpisTresci()
    Dim wsSpis As Worksheet     ' arkusz ze spisem treści
    Dim ws As Worksheet         ' iterowany arkusz
    Dim i As Long               ' licznik wierszy
    Const NAZWA_SPISU As String = "Spis Treści"
    
    Application.ScreenUpdating = False
    
    ' Usuń stary arkusz ze spisem jeśli istnieje
    On Error Resume Next  ' Ignoruj błąd jeśli arkusz nie istnieje
    Application.DisplayAlerts = False  ' Nie pytaj o potwierdzenie usunięcia
    ThisWorkbook.Sheets(NAZWA_SPISU).Delete
    Application.DisplayAlerts = True
    On Error GoTo 0  ' Wznów normalną obsługę błędów
    
    ' Dodaj nowy arkusz spisu na pierwszą pozycję
    Set wsSpis = ThisWorkbook.Sheets.Add(Before:=ThisWorkbook.Sheets(1))
    wsSpis.Name = NAZWA_SPISU
    
    ' Nagłówek spisu treści
    With wsSpis.Range("A1")
        .Value = "Spis treści — " & ThisWorkbook.Name
        .Font.Bold = True
        .Font.Size = 14
    End With
    wsSpis.Range("A2").Value = "Kliknij nazwę arkusza, aby do niego przejść:"
    
    ' Dodaj hiperłącza do każdego arkusza (pomijając sam spis)
    i = 4  ' Zacznij od wiersza 4 (2 wiersze na nagłówek + 1 pusty)
    For Each ws In ThisWorkbook.Worksheets
        If ws.Name <> NAZWA_SPISU Then
            ' Dodaj hiperłącze: kliknięcie przenosi do arkusza ws, komórki A1
            wsSpis.Hyperlinks.Add _
                Anchor:=wsSpis.Cells(i, 1), _
                Address:="", _
                SubAddress:="'" & ws.Name & "'!A1", _
                TextToDisplay:=ws.Name
            i = i + 1
        End If
    Next ws
    
    wsSpis.Columns("A").AutoFit  ' Dopasuj szerokość kolumny
    Application.ScreenUpdating = True
    MsgBox "Spis treści gotowy! Dodano " & (i - 4) & " hiperłączy.", vbInformation, "Gotowe"
End Sub
' Makro 12: Ochrona wszystkich arkuszy hasłem jednocześnie
Sub Makro12_ChronWszystkieArkusze()
    Dim ws As Worksheet
    Dim haslo As String
    
    ' Poproś o hasło (InputBox zwraca pusty string jeśli kliknięto Anuluj)
    haslo = InputBox("Podaj hasło do ochrony wszystkich arkuszy:" & vbCrLf & _
                     "(Uwaga: zapamiętaj hasło! Bez niego nie odblokujesz arkuszy)", _
                     "Ustaw hasło ochrony", "")
    
    If haslo = "" Then
        MsgBox "Anulowano. Żaden arkusz nie został zabezpieczony.", vbInformation, "Anulowano"
        Exit Sub  ' Wyjdź z makra
    End If
    
    ' Chroń każdy arkusz tym samym hasłem.
    For Each ws In ThisWorkbook.Worksheets
        ws.Protect Password:=haslo, _
                    DrawingObjects:=True, _
                    Contents:=True, _
                    Scenarios:=True
    Next ws
    
    MsgBox "Wszystkie " & ThisWorkbook.Worksheets.Count & _
           " arkusze zostały zabezpieczone hasłem.", vbInformation, "Ochrona włączona"
End Sub
' Makro 13: Zdejmowanie ochrony ze wszystkich arkuszy jednocześnie
Sub Makro13_ZdejmijOchroneWszystkich()
    Dim ws As Worksheet
    Dim haslo As String
    Dim bladHasla As Boolean
    
    haslo = InputBox("Podaj hasło, aby odblokować wszystkie arkusze:", "Zdejmij ochronę", "")
    
    If haslo = "" Then
        MsgBox "Anulowano.", vbInformation, "Anulowano"
        Exit Sub
    End If
    
    bladHasla = False
    
    ' Próbuj odblokować każdy arkusz — obsłuż błąd jeśli hasło jest złe
    For Each ws In ThisWorkbook.Worksheets
        On Error Resume Next  ' Ignoruj błąd złego hasła — złapiemy go ręcznie
        ws.Unprotect Password:=haslo
        If Err.Number <> 0 Then  ' Błąd = złe hasło
            bladHasla = True
            Err.Clear
        End If
        On Error GoTo 0  ' Wróć do normalnej obsługi
    Next ws
    
    If bladHasla Then
        MsgBox "Błąd: Hasło nieprawidłowe dla jednego lub więcej arkuszy.", vbCritical, "Błąd hasła"
    Else
        MsgBox "Ochrona zdjęta ze wszystkich arkuszy.", vbInformation, "Gotowe"
    End If
End Sub
' Makro 14: Zapisz aktywny arkusz jako PDF z datą w nazwie pliku
Sub Makro14_EksportujDoPDF()
    Dim sciezkaPDF As String      ' pełna ścieżka pliku PDF
    Dim nazwaPliku As String      ' nazwa pliku bez ścieżki
    Dim folderDocelowy As String  ' folder zapisu
    
    ' Folder docelowy: ten sam, co plik Excel lub Pulpit jeśli plik niezapisany
    If ThisWorkbook.Path <> "" Then
        folderDocelowy = ThisWorkbook.Path & "\"
    Else
        folderDocelowy = Environ("USERPROFILE") & "\Desktop\"  ' Pulpit użytkownika
    End If
    
    ' Zbuduj nazwę pliku: NazwaArkusza_RRRR-MM-DD.pdf
    nazwaPliku = ActiveSheet.Name & "_" & Format(Now(), "yyyy-mm-dd") & ".pdf"
    sciezkaPDF = folderDocelowy & nazwaPliku
    
    ' Eksportuj aktywny arkusz do PDF.
    ActiveSheet.ExportAsFixedFormat _
        Type:=xlTypePDF, _
        Filename:=sciezkaPDF, _
        Quality:=xlQualityStandard, _
        IncludeDocProperties:=True, _
        IgnorePrintAreas:=False, _
        OpenAfterPublish:=True
    
    MsgBox "PDF zapisany jako:" & vbCrLf & sciezkaPDF, vbInformation, "Eksport zakończony"
End Sub
' Makro 15: Łączenie (konsolidacja) danych ze wszystkich arkuszy do jednego
Sub Makro15_PolaczArkusze()
    Dim wsZbiorczy As Worksheet  ' arkusz docelowy
    Dim ws As Worksheet          ' iterowany arkusz źródłowy
    Dim lastRowSrc As Long       ' ostatni wiersz w arkuszu źródłowym
    Dim lastRowDst As Long       ' ostatni wiersz w arkuszu docelowym
    Const NAZWA_ZBIORCZEGO As String = "KONSOLIDACJA"
    
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual  ' Wyłącz przeliczanie — szybciej
    
    ' Usuń stary arkusz zbiorczy jeśli istnieje
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Sheets(NAZWA_ZBIORCZEGO).Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    
    ' Dodaj nowy arkusz zbiorczy na końcu
    Set wsZbiorczy = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
    wsZbiorczy.Name = NAZWA_ZBIORCZEGO
    
    lastRowDst = 1  ' Zacznij wklejanie od wiersza 1 arkusza zbiorczego
    
    For Each ws In ThisWorkbook.Worksheets
        If ws.Name <> NAZWA_ZBIORCZEGO Then  ' Pomiń arkusz zbiorczy
            lastRowSrc = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
            
            If lastRowSrc > 0 Then  ' Kopiuj tylko jeśli arkusz ma dane
                ' Skopiuj cały zakres danych (od A1 do ostatniego wiersza)
                ws.Range("A1:A" & lastRowSrc).EntireRow.Copy
                wsZbiorczy.Cells(lastRowDst, 1).PasteSpecial xlPasteValues
                lastRowDst = lastRowDst + lastRowSrc  ' Przesuń wskaźnik
            End If
        End If
    Next ws
    
    Application.CutCopyMode = False
    Application.Calculation = xlCalculationAutomatic  ' Przywróć przeliczanie
    Application.ScreenUpdating = True
    
    MsgBox "Konsolidacja zakończona. Dane z " & (ThisWorkbook.Sheets.Count - 1) & _
           " arkuszy skopiowane do '" & NAZWA_ZBIORCZEGO & "'.", vbInformation, "Gotowe"
End Sub

Kategoria 4: Automatyzacja raportów

' Makro 16: Automatyczne wstawianie wiersza z sumami na końcu tabeli
Sub Makro16_DodajWierszSum()
    Dim ws As Worksheet
    Dim lastRow As Long   ' ostatni wiersz z danymi
    Dim lastCol As Long   ' ostatnia kolumna z danymi
    Dim j As Long         ' licznik kolumn
    
    Application.ScreenUpdating = False
    
    Set ws = ActiveSheet
    ' Znajdź ostatni wiersz i kolumnę z danymi w obszarze roboczym
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    
    ' Wiersz sum = jeden poniżej ostatniego wiersza danych
    Dim wierszSum As Long
    wierszSum = lastRow + 1
    
    ' Wpisz etykietę "SUMA" w pierwszej kolumnie
    ws.Cells(wierszSum, 1).Value = "SUMA"
    ws.Cells(wierszSum, 1).Font.Bold = True
    
    ' Dla każdej kolumny (od 2 do ostatniej) wstaw formułę SUMA
    For j = 2 To lastCol
        ' Sprawdź, czy kolumna zawiera liczby (nie tekst)
        If IsNumeric(ws.Cells(2, j).Value) Then
            ' Wstaw formułę sumowania od wiersza 2 do lastRow
            ws.Cells(wierszSum, j).Formula = "=SUM(" & _
                ws.Cells(2, j).Address(True, False) & ":" & _
                ws.Cells(lastRow, j).Address(True, False) & ")"
            ws.Cells(wierszSum, j).Font.Bold = True
        End If
    Next j
    
    ' Sformatuj wiersz sum — gruba górna ramka
    ws.Rows(wierszSum).Borders(xlEdgeTop).LineStyle = xlContinuous
    ws.Rows(wierszSum).Borders(xlEdgeTop).Weight = xlMedium
    
    Application.ScreenUpdating = True
    MsgBox "Wiersz sum dodany w wierszu " & wierszSum & ".", vbInformation, "Gotowe"
End Sub
' Makro 17: Rozdzielanie danych do osobnych arkuszy według wartości w kolumnie
Sub Makro17_RozdzielDane()
    Dim wsDane As Worksheet      ' arkusz źródłowy z danymi
    Dim wsDocel As Worksheet     ' arkusz docelowy dla grupy
    Dim slownik As Object        ' słownik unikalnych wartości
    Dim klucz As Variant         ' klucz słownika (nazwa grupy)
    Dim lastRow As Long          ' ostatni wiersz danych
    Dim i As Long                ' licznik wierszy
    Dim kolumnaGrup As Long      ' numer kolumny z kategoriami
    Dim wartoscKomorki As String
    Dim lastRowDocel As Long
    
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    Set wsDane = ActiveSheet
    kolumnaGrup = 2  ' ZMIEŃ TEN NUMER: która kolumna zawiera kategorie? (B = 2, C = 3 itd.)
    lastRow = wsDane.Cells(wsDane.Rows.Count, 1).End(xlUp).Row
    
    ' Zbierz unikalne wartości z kolumny grup (pomijając nagłówek w wierszu 1)
    Set slownik = CreateObject("Scripting.Dictionary")
    For i = 2 To lastRow
        wartoscKomorki = CStr(wsDane.Cells(i, kolumnaGrup).Value)
        If wartoscKomorki <> "" And Not slownik.Exists(wartoscKomorki) Then
            slownik.Add wartoscKomorki, wartoscKomorki
        End If
    Next i
    
    ' Dla każdej unikalnej wartości — utwórz arkusz i skopiuj do niego odpowiednie wiersze
    For Each klucz In slownik.Keys
        ' Sprawdź czy arkusz o tej nazwie już istnieje
        On Error Resume Next
        Set wsDocel = ThisWorkbook.Sheets(CStr(klucz))
        On Error GoTo 0
        
        If wsDocel Is Nothing Then
            ' Utwórz nowy arkusz
            Set wsDocel = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
            wsDocel.Name = Left(CStr(klucz), 31)  ' Max 31 znaków w nazwie arkusza!
            ' Skopiuj wiersz nagłówka (wiersz 1)
            wsDane.Rows(1).Copy wsDocel.Rows(1)
        End If
        
        ' Skopiuj pasujące wiersze do arkusza docelowego
        For i = 2 To lastRow
            If CStr(wsDane.Cells(i, kolumnaGrup).Value) = CStr(klucz) Then
                lastRowDocel = wsDocel.Cells(wsDocel.Rows.Count, 1).End(xlUp).Row + 1
                wsDane.Rows(i).Copy wsDocel.Rows(lastRowDocel)
            End If
        Next i
        
        Set wsDocel = Nothing  ' Wyzeruj zmienną obiektu dla następnej iteracji
    Next klucz
    
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
    MsgBox "Dane rozdzielone do " & slownik.Count & " arkuszy według kolumny " & kolumnaGrup & ".", _
           vbInformation, "Gotowe"
End Sub
' Makro 18: Automatyczne tworzenie tabeli przestawnej (Pivot Table)
Sub Makro18_UtworzPivot()
    Dim wsDane As Worksheet       ' arkusz ze źródłem danych
    Dim wsPivot As Worksheet      ' arkusz z tabelą przestawną
    Dim zakresDanych As String    ' adres zakresu źródłowego
    Dim pt As PivotTable          ' obiekt tabeli przestawnej
    Dim pc As PivotCache          ' pamięć podręczna tabeli
    Const NAZWA_PIVOT_SHEET As String = "Raport Pivot"
    
    Application.ScreenUpdating = False
    
    Set wsDane = ActiveSheet
    ' Pobierz zakres danych (zakładamy, że dane zaczynają się od A1)
    zakresDanych = wsDane.Name & "!" & wsDane.UsedRange.Address(True, True)
    
    ' Usuń stary arkusz pivot jeśli istnieje
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Sheets(NAZWA_PIVOT_SHEET).Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    
    ' Dodaj arkusz dla tabeli przestawnej
    Set wsPivot = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
    wsPivot.Name = NAZWA_PIVOT_SHEET
    
    ' Utwórz pamięć podręczną (PivotCache) — punkt danych dla tabeli
    Set pc = ThisWorkbook.PivotCaches.Create( _
        SourceType:=xlDatabase, _
        SourceData:=zakresDanych, _
        Version:=xlPivotTableVersion15)  ' xlPivotTableVersion15 = Excel 2013+
    
    ' Utwórz tabelę przestawną w arkuszu wsPivot, od komórki A3
    Set pt = pc.CreatePivotTable( _
        TableDestination:=wsPivot.Range("A3"), _
        TableName:="PivotRaport")
    
    ' Skonfiguruj pola tabeli — dostosuj nazwy kolumn do swoich danych!
    ' UWAGA: "Kategoria" i "Wartość" to przykładowe nazwy kolumn z arkusza źródłowego
    With pt
        ' Pole wierszy — grupowanie (np. handlowiec, kategoria produktu)
        On Error Resume Next  ' Pomiń błąd jeśli kolumna o tej nazwie nie istnieje
        .PivotFields("Kategoria").Orientation = xlRowField
        .PivotFields("Kategoria").Position = 1
        
        ' Pole wartości — co sumujemy?
        .AddDataField .PivotFields("Wartość"), "Suma wartości", xlSum
        On Error GoTo 0
    End With
    
    Application.ScreenUpdating = True
    MsgBox "Tabela przestawna utworzona w arkuszu '" & NAZWA_PIVOT_SHEET & "'." & vbCrLf & _
           "Dostosuj pola w zakładce 'Lista pól przestawnych'.", vbInformation, "Gotowe"
End Sub

Kategoria 5: Operacje na plikach i folderach

' Makro 19: Masowe tworzenie folderów na podstawie listy w Excelu
Sub Makro19_TworzFoldery()
    Dim folderNadrzedny As String  ' folder, w którym tworzymy podfoldery
    Dim nazwaFoldera As String     ' nazwa tworzonego podfolderu
    Dim i As Long                  ' licznik wierszy
    Dim lastRow As Long
    Dim licznikUtworzone As Long
    
    ' Poproś użytkownika o wskazanie folderu nadrzędnego
    folderNadrzedny = InputBox("Podaj pełną ścieżkę folderu nadrzędnego:" & vbCrLf & _
                               "Przykład: C:\Projekty\Klienci", _
                               "Tworzenie folderów", "C:\")
    
    If folderNadrzedny = "" Then Exit Sub
    
    ' Upewnij się, że ścieżka kończy się ukośnikiem
    If Right(folderNadrzedny, 1) <> "\" Then folderNadrzedny = folderNadrzedny & "\"
    
    ' Sprawdź czy folder nadrzędny istnieje
    If Dir(folderNadrzedny, vbDirectory) = "" Then
        MsgBox "Folder nadrzędny nie istnieje: " & folderNadrzedny, vbCritical, "Błąd"
        Exit Sub
    End If
    
    lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
    licznikUtworzone = 0
    
    ' Czytaj nazwy folderów z kolumny A (od wiersza 2, pomijając nagłówek)
    For i = 2 To lastRow
        nazwaFoldera = CStr(ActiveSheet.Cells(i, 1).Value)
        
        If nazwaFoldera <> "" Then
            Dim pelnaSciezka As String
            pelnaSciezka = folderNadrzedny & nazwaFoldera
            
            ' Utwórz folder tylko jeśli jeszcze nie istnieje
            If Dir(pelnaSciezka, vbDirectory) = "" Then
                MkDir pelnaSciezka  ' VBA wbudowana funkcja tworzenia katalogu
                ActiveSheet.Cells(i, 2).Value = "Utworzono"  ' Zapisz status w kol. B
                licznikUtworzone = licznikUtworzone + 1
            Else
                ActiveSheet.Cells(i, 2).Value = "Już istnieje"  ' Folder już był
            End If
        End If
    Next i
    
    MsgBox "Utworzono " & licznikUtworzone & " nowych folderów w:" & vbCrLf & folderNadrzedny, _
           vbInformation, "Gotowe"
End Sub
' Makro 20: Pętla po wszystkich plikach Excel w folderze i zbieranie danych
Sub Makro20_PetlaPoPlikach()
    Dim folderSciezka As String    ' ścieżka do przeszukiwanego folderu
    Dim nazwaPliku As String       ' nazwa aktualnie przetwarzanego pliku
    Dim wbZewnetrzny As Workbook   ' otwierany plik Excel
    Dim wsZbior As Worksheet       ' arkusz zbiorczy wyników
    Dim wiersz As Long             ' bieżący wiersz w arkuszu zbiorczym
    
    ' Wyświetl okno wyboru folderu
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "Wybierz folder z plikami Excel"
        If .Show <> -1 Then Exit Sub  ' Użytkownik anulował
        folderSciezka = .SelectedItems(1) & "\"
    End With
    
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False  ' Wyłącz alerty przy otwieraniu plików
    
    ' Przygotuj arkusz zbiorczy — użyj aktywnego arkusza
    Set wsZbior = ActiveSheet
    ' Dodaj nagłówki
    wsZbior.Range("A1:C1").Value = Array("Nazwa pliku", "Arkusze", "Wartość A1 (Arkusz1)")
    wsZbior.Range("A1:C1").Font.Bold = True
    wiersz = 2  ' zacznij wpisywać od wiersza 2
    
    ' Wyszukaj wszystkie pliki .xlsx i .xlsm w folderze
    nazwaPliku = Dir(folderSciezka & "*.xls*")  ' Gwiazdka pasuje do xlsx, xlsm, xlsb
    
    Do While nazwaPliku <> ""  ' Pętla dopóki Dir() zwraca nazwy
        On Error Resume Next  ' Obsłuż błędy otwierania
        ' Otwórz plik zewnętrzny bez makr, bez aktualizacji linków, tylko do odczytu
        Set wbZewnetrzny = Workbooks.Open( _
            Filename:=folderSciezka & nazwaPliku, _
            UpdateLinks:=False, _
            ReadOnly:=True, _
            EnableMacros:=False)
        
        If Err.Number = 0 Then  ' Jeśli otwarcie się powiodło
            ' Zbierz dane: nazwa pliku, liczba arkuszy, wartość komórki A1 z pierwszego arkusza
            wsZbior.Cells(wiersz, 1).Value = nazwaPliku
            wsZbior.Cells(wiersz, 2).Value = wbZewnetrzny.Sheets.Count
            wsZbior.Cells(wiersz, 3).Value = wbZewnetrzny.Sheets(1).Range("A1").Value
            wiersz = wiersz + 1
            
            wbZewnetrzny.Close SaveChanges:=False  ' Zamknij bez zapisywania
        End If
        Err.Clear
        On Error GoTo 0
        
        nazwaPliku = Dir()  ' Dir() bez argumentu = następny plik w katalogu
    Loop
    
    wsZbior.Columns("A:C").AutoFit  ' Dopasuj kolumny
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
    
    MsgBox "Przetworzono " & (wiersz - 2) & " plików z folderu:" & vbCrLf & folderSciezka, _
           vbInformation, "Gotowe"
End Sub
' Makro 21: Importowanie danych z pliku CSV do aktywnego arkusza
Sub Makro21_ImportCSV()
    Dim sciezkaCSV As String    ' pełna ścieżka do pliku CSV
    Dim numerPliku As Integer   ' numer strumienia pliku (FreeFile)
    Dim linia As String         ' odczytana linia tekstu
    Dim kolumny() As String     ' tablica wartości po podziale linii
    Dim wiersz As Long          ' numer bieżącego wiersza w arkuszu
    Dim j As Long               ' licznik kolumn
    
    ' Okno wyboru pliku CSV
    sciezkaCSV = Application.GetOpenFilename( _
        FileFilter:="Pliki CSV (*.csv),*.csv,Pliki tekstowe (*.txt),*.txt", _
        Title:="Wybierz plik CSV do importu")
    
    If sciezkaCSV = "False" Then Exit Sub  ' Anulowano
    
    Application.ScreenUpdating = False
    
    ' Wyczyść aktywny arkusz przed importem
    ActiveSheet.Cells.ClearContents
    
    ' Otwórz plik do odczytu
    numerPliku = FreeFile()  ' FreeFile() zwraca wolny numer strumienia
    Open sciezkaCSV For Input As #numerPliku
    
    wiersz = 1  ' zacznij od wiersza 1
    
    Do While Not EOF(numerPliku)  ' EOF = End Of File
        Line Input #numerPliku, linia  ' Odczytaj jedną linię tekstu
        
        ' Podziel linię po przecinku (CSV = Comma Separated Values)
        ' UWAGA: dla polskich plików z średnikiem jako separatorem zamień "," na ";"
        kolumny = Split(linia, ",")
        
        ' Wpisz każdą kolumnę do odpowiedniej komórki w bieżącym wierszu
        For j = 0 To UBound(kolumny)  ' UBound = ostatni indeks tablicy
            ActiveSheet.Cells(wiersz, j + 1).Value = Trim(kolumny(j))  ' Trim usuwa spacje
        Next j
        
        wiersz = wiersz + 1  ' Przejdź do następnego wiersza
    Loop
    
    Close #numerPliku  ' ZAWSZE zamknij plik po pracy!
    
    ActiveSheet.Columns.AutoFit  ' Dopasuj szerokość kolumn
    Application.ScreenUpdating = True
    
    MsgBox "Zaimportowano " & (wiersz - 1) & " wierszy z pliku CSV.", vbInformation, "Import zakończony"
End Sub

Kategoria 6: Integracja z Outlook i pobieranie danych zewnętrznych

' Makro 22: Wysyłanie emaila przez Microsoft Outlook z aktywnym arkuszem jako załącznik
' WYMAGANIE: Zainstalowany i skonfigurowany Outlook w tym samym systemie co Excel
Sub Makro22_WyslijEmailOutlook()
    Dim aplikacjaOutlook As Object  ' obiekt aplikacji Outlook
    Dim email As Object             ' obiekt wiadomości MailItem
    Dim sciezkaZalacznika As String ' ścieżka do pliku PDF / Excel
    Dim adresOdbiorcy As String
    Dim tematWiadomosci As String
    Dim trescWiadomosci As String
    
    ' Sprawdź czy plik został zapisany (potrzebujemy ścieżki do tworzenia załącznika)
    If ThisWorkbook.Path = "" Then
        MsgBox "Zapisz plik przed wysłaniem. Używamy jego kopii PDF jako załącznika.", _
               vbExclamation, "Uwaga"
        Exit Sub
    End If
    
    ' Dane email — można dynamicznie pobierać z arkusza
    adresOdbiorcy = InputBox("Adres e-mail odbiorcy:", "Wyślij raport", "")
    If adresOdbiorcy = "" Then Exit Sub
    
    tematWiadomosci = "Raport: " & ActiveSheet.Name & " — " & Format(Now(), "yyyy-mm-dd")
    trescWiadomosci = "Witaj," & vbCrLf & vbCrLf & _
                      "W załączeniu przesyłam raport: " & ActiveSheet.Name & "." & vbCrLf & _
                      "Data: " & Format(Now(), "dd.mm.yyyy HH:MM") & vbCrLf & vbCrLf & _
                      "Pozdrawiam"
    
    ' Najpierw wyeksportuj arkusz do PDF (żeby mieć plik do załączenia)
    sciezkaZalacznika = ThisWorkbook.Path & "\" & ActiveSheet.Name & "_" & _
                        Format(Now(), "yyyymmdd") & ".pdf"
    ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:=sciezkaZalacznika
    
    ' Utwórz obiekt Outlook (Late Binding — działa bez referencji do biblioteki)
    Set aplikacjaOutlook = CreateObject("Outlook.Application")
    Set email = aplikacjaOutlook.CreateItem(0)  ' 0 = olMailItem (wiadomość e-mail)
    
    ' Skonfiguruj wiadomość
    With email
        .To = adresOdbiorcy
        .Subject = tematWiadomosci
        .Body = trescWiadomosci
        .Attachments.Add sciezkaZalacznika  ' Dodaj PDF jako załącznik
        .Display  ' Pokaż wiadomość w Outlooku zamiast wysyłać automatycznie
        ' Zamień .Display na .Send jeśli chcesz wysyłać bez podglądu!
    End With
    
    MsgBox "Wiadomość przygotowana w Outlooku. Sprawdź i kliknij Wyślij.", _
           vbInformation, "Email gotowy"
    
    ' Zwolnij obiekty COM
    Set email = Nothing
    Set aplikacjaOutlook = Nothing
End Sub
' Makro 23: Pobieranie aktualnego kursu walut z API NBP (JSON via XMLHTTP)
Sub Makro23_KursWalutNBP()
    Dim http As Object          ' obiekt żądania HTTP
    Dim url As String           ' URL do API NBP
    Dim odpowiedz As String     ' surowa odpowiedź JSON
    Dim kursStr As String       ' kurs jako tekst
    Dim kurs As Double          ' kurs jako liczba
    Dim waluta As String
    
    ' Pobierz kod waluty od użytkownika (np. EUR, USD, GBP, CHF)
    waluta = UCase(InputBox("Podaj kod waluty (np. EUR, USD, GBP, CHF):", _
                            "Kurs NBP", "EUR"))
    If waluta = "" Then Exit Sub
    
    ' URL API NBP: https://api.nbp.pl/api/exchangerates/rates/a/{waluta}/?format=json
    url = "https://api.nbp.pl/api/exchangerates/rates/a/" & waluta & "/?format=json"
    
    ' Utwórz obiekt XMLHTTP (Late Binding)
    Set http = CreateObject("MSXML2.XMLHTTP")
    
    On Error GoTo BladAPI
    
    ' Wykonaj synchroniczne żądanie GET
    http.Open "GET", url, False    ' False = synchroniczne (czekaj na odpowiedź)
    http.Send                       ' Wyślij żądanie
    
    If http.Status = 200 Then  ' 200 = OK (sukces HTTP)
        odpowiedz = http.ResponseText  ' Pobierz treść odpowiedzi
        
        ' Proste wyodrębnienie kursu z JSON-a (szukamy "mid":)
        ' Bardziej zaawansowane parsowanie JSON wymaga biblioteki lub regex
        Dim pozycja As Long
        pozycja = InStr(odpowiedz, """mid"":")
        If pozycja > 0 Then
            kursStr = Mid(odpowiedz, pozycja + 7, 8)  ' Pobierz 8 znaków po "mid":
            kursStr = Left(kursStr, InStr(kursStr, "}") - 1)  ' Utnij po pierwszym }
            kursStr = Trim(Replace(kursStr, ",", "."))  ' Zamień przecinek na kropkę
            kurs = CDbl(kursStr)  ' Konwertuj na liczbę Double
            
            ' Wpisz kurs do aktywnej komórki
            ActiveCell.Value = kurs
            ActiveCell.NumberFormat = "0.0000"  ' 4 miejsca po przecinku
            
            MsgBox "Kurs " & waluta & "/PLN z NBP: " & Format(kurs, "0.0000") & " PLN" & vbCrLf & _
                   "Wpisano do komórki: " & ActiveCell.Address, vbInformation, "Kurs NBP"
        Else
            MsgBox "Nie można odczytać kursu z odpowiedzi API.", vbExclamation, "Błąd parsowania"
        End If
    Else
        MsgBox "Błąd API NBP. Kod HTTP: " & http.Status & vbCrLf & _
               "Sprawdź czy kod waluty jest poprawny: " & waluta, vbCritical, "Błąd HTTP"
    End If
    
    Set http = Nothing  ' Zwolnij obiekt
    Exit Sub

BladAPI:
    MsgBox "Błąd połączenia z API NBP." & vbCrLf & _
           "Sprawdź połączenie internetowe." & vbCrLf & _
           "Kod błędu: " & Err.Number & " — " & Err.Description, vbCritical, "Błąd połączenia"
    Set http = Nothing
End Sub

Kategoria 7: Zaawansowane narzędzia i event handling

' Makro 24: Logowanie zmian w komórkach do arkusza historii (Event Handling)
' UWAGA: To makro umieść w module ARKUSZA (nie w module ogólnym), np. kliknij prawym
' na nazwę arkusza w Project Explorer → View Code → wklej tam ten kod
Private Sub Worksheet_Change(ByVal Target As Range)
    ' Target = komórka (lub zakres), która właśnie zmieniła wartość
    
    Dim wsHistoria As Worksheet   ' arkusz z historią zmian
    Dim lastRow As Long           ' ostatni wiersz w historii
    Dim nazwaUzytkownika As String
    
    ' Ignoruj zmiany w całym arkuszu lub dla komórek w obszarze historii (pętla)
    If Target.Cells.Count > 10 Then Exit Sub  ' Zbyt duże zaznaczenie — pomiń
    
    ' Spróbuj uzyskać lub stworzyć arkusz historii
    On Error Resume Next
    Set wsHistoria = ThisWorkbook.Sheets("Historia zmian")
    On Error GoTo 0
    
    If wsHistoria Is Nothing Then
        Set wsHistoria = ThisWorkbook.Sheets.Add
        wsHistoria.Name = "Historia zmian"
        ' Nagłówki kolumn historii
        wsHistoria.Range("A1:E1").Value = Array("Data i godzina", "Użytkownik", "Arkusz", "Komórka", "Nowa wartość")
        wsHistoria.Range("A1:E1").Font.Bold = True
    End If
    
    ' Pobierz nazwę zalogowanego użytkownika Windows
    nazwaUzytkownika = Environ("USERNAME")
    
    ' Wyłącz obsługę zdarzeń żeby uniknąć nieskończonej pętli
    Application.EnableEvents = False
    
    lastRow = wsHistoria.Cells(wsHistoria.Rows.Count, "A").End(xlUp).Row + 1
    
    ' Iteruj po każdej zmienionej komórce (może być kilka naraz)
    Dim komorka As Range
    For Each komorka In Target.Cells
        wsHistoria.Cells(lastRow, 1).Value = Now()                 ' Znacznik czasu
        wsHistoria.Cells(lastRow, 1).NumberFormat = "dd.mm.yyyy hh:mm:ss"
        wsHistoria.Cells(lastRow, 2).Value = nazwaUzytkownika      ' Użytkownik
        wsHistoria.Cells(lastRow, 3).Value = Me.Name               ' Nazwa arkusza (Me = bieżący arkusz)
        wsHistoria.Cells(lastRow, 4).Value = komorka.Address(False, False)  ' Adres komórki np. B5
        wsHistoria.Cells(lastRow, 5).Value = komorka.Value         ' Nowa wartość
        lastRow = lastRow + 1
    Next komorka
    
    ' Przywróć obsługę zdarzeń
    Application.EnableEvents = True
End Sub
' Makro 25: Przycisk "Resetuj wszystkie filtry" — jednym kliknięciem przywróć pełny widok
Sub Makro25_ResetujFiltry()
    Dim ws As Worksheet
    Dim lt As ListObject  ' obiekt tabeli Excel (Table/ListObject)
    
    Application.ScreenUpdating = False
    
    Set ws = ActiveSheet
    
    ' METODA 1: Usuń AutoFilter jeśli jest aktywny na zwykłym zakresie
    If ws.AutoFilterMode Then
        ' ShowAllData wyłącza filtrowanie ale zostawia strzałki
        If ws.FilterMode Then ws.ShowAllData
    End If
    
    ' METODA 2: Wyczyść filtry we wszystkich tabelach Excel (ListObjects) na arkuszu
    For Each lt In ws.ListObjects
        If Not lt.AutoFilter Is Nothing Then
            lt.AutoFilter.ShowAllData  ' Pokaż wszystkie wiersze tabeli
        End If
    Next lt
    
    ' METODA 3: Usuń filtr grupowania (jeśli dane były pogrupowane)
    On Error Resume Next
    ws.Cells.Rows.Hidden = False   ' Odkryj wszystkie ukryte wiersze
    ws.Cells.Columns.Hidden = False ' Odkryj wszystkie ukryte kolumny
    On Error GoTo 0
    
    Application.ScreenUpdating = True
    
    ' Powiadom użytkownika
    MsgBox "Wszystkie filtry zostały zresetowane. Widoczne są wszystkie dane.", _
           vbInformation, "Filtry wyczyszczone"
End Sub

Najczęściej zadawane pytania — Excel VBA kurs dla początkujących

Czy Excel VBA zostanie wycofany i zastąpiony przez Python lub Office Scripts?

Nie ma oficjalnego komunikatu Microsoft zapowiadającego wycofanie VBA z klasycznego Excela. Python w Excelu i Office Scripts to uzupełnienia, nie bezpośrednie zamienniki. VBA pozostaje potrzebny do automatyzacji interfejsu Excela, integracji z Outlookiem, Wordem i Accessem, operacji na plikach Windows oraz obsługi zdarzeń arkusza. Excel w przeglądarce nie uruchamia klasycznych projektów VBA; do automatyzacji webowej służą Office Scripts. Dlatego w firmach z istniejącymi plikami .xlsm nauka VBA nadal ma praktyczny sens.

Dlaczego moje makro Excel działa bardzo wolno? Jak je przyspieszyć?

Najczęstsze przyczyny wolnych makr to: 1) odświeżanie ekranu przy każdej zmianie komórki — wyłącz je przez Application.ScreenUpdating = False na początku makra, 2) automatyczne przeliczanie formuł podczas wpisywania danych — wyłącz przez Application.Calculation = xlCalculationManual, 3) wielokrotny odczyt/zapis do komórek zamiast pracy na tablicach w pamięci — załaduj dane do tablicy VBA (Dim arr() As Variant: arr = Range("A1:Z1000").Value), przetwarzaj w tablicy i wpisz z powrotem jednym przypisaniem. Zastosowanie tych trzech technik może przyspieszyć makro od 10 do 100 razy.

Jaki format pliku wybrać dla pliku z makrami — .xlsm czy .xlsb?

Format .xlsm (Skoroszyt Excel z obsługą makr) to standard branżowy — czytelny przez większość narzędzi i kompatybilny ze wszystkimi wersjami Excel od 2007. Format .xlsb (Skoroszyt binarny Excel) jest szybszy przy otwieraniu i mniejszy na dysku dla bardzo dużych plików (setki tysięcy wierszy), ale trudniejszy do integracji z systemami zewnętrznymi i kontrolą wersji (Git). Dla 99% projektów używaj .xlsm. Dla plików powyżej 50 MB z dużymi ilościami danych rozważ .xlsb. Nigdy nie zapisuj kodu VBA w formacie .xlsx — Excel automatycznie usunie cały kod VBA przy zapisie.

Jak sprawdzić, czy makro bezpiecznie otwiera pliki i ma dostęp do folderów?

Przed otwarciem pliku sprawdź jego istnienie funkcją Dir(sciezka) — jeśli zwraca pusty string "", plik nie istnieje. Przed zapisem do folderu sprawdź folder przez Dir(folder, vbDirectory). Dla operacji HTTP (API, web scraping) zawsze dodaj blok On Error GoTo obsługujący brak połączenia. Pamiętaj o zamykaniu strumieni plików — Close #numerPliku po każdym Open. Niezamknięty strumień blokuje plik aż do zamknięcia Excela. Oficjalna dokumentacja operacji na plikach w VBA: learn.microsoft.com/pl-pl/office/vba/language/concepts/getting-started.

Jak uruchomić makro? Czy mogę przypisać je do przycisku w arkuszu?

Makro możesz uruchomić na kilka sposobów: 1) z edytora VBE — kliknij wewnątrz procedury Sub i wciśnij F5, 2) z zakładki Deweloper → Makra → wybierz makro → Uruchom, 3) skrótem klawiszowym — w oknie Makra kliknij Opcje i przypisz skrót (np. Ctrl+Shift+M), 4) przyciskiem w arkuszu — zakładka Deweloper → Wstaw → Kontrolki formularza → Przycisk → narysuj przycisk na arkuszu → w oknie Przypisz makro wybierz swoje makro → OK. Przycisk to najwygodniejsza opcja dla użytkowników nieznających VBE.

Podsumowanie — od czego zacząć naukę Excel VBA?

Masz teraz w rękach kompletny excel vba tutorial po polsku — od konfiguracji środowiska przez typy danych, instrukcje warunkowe, pętle i obsługę błędów, aż po 25 gotowych makr z pełnym, skomentowanym kodem.

Pamiętaj: VBA działa wyłącznie w desktopowej wersji Excela. Jeśli korzystasz ze starego pakietu biurowego, czas na upgrade. Microsoft Office 2024 Professional Plus i Office 2024 Standard dostępne są w konkurencyjnych cenach w sklepie kluczesoft.pl — zarówno jako licencje wieczyste, jak i w ramach subskrypcji Microsoft 365. Inwestycja w licencję zwróci się już po kilku godzinach zaoszczędzonych dzięki automatyzacji VBA.

 
Czy ten wpis na blogu był dla Ciebie pomocny?
Opublikowano w: Poradniki

Dodaj komentarz

Kod zabezpieczający
z VAT
🛒 Do koszyka