VBA #23 — Jak wykorzystać funkcje makr 4.0 w VBA

W poradzie 305 wspominałem o funkcjach makr 4.0. Pomogły mi wyciągnąć listę plików z katalogu, ale był z nimi jeden problem dla Polaków. Ciężko było znaleźć ich nazwę po Polsku.

Mi przyszedł do głowy jeden pomysł na poprawne tłumaczenie ich nazw za pomocą króciutkiego kodu VBA. Zadaniem tego kodu jest po prostu dodanie nazwy, która będzie odwoływać się do przykładowej funkcji makr 4.0.

Ponieważ VBA jest angielsko języczny, więc funkcję makr 4.0 wpisujemy w nim po angielsku (listę funkcji makr 4.0 z dokładnym opisem po angielsku możesz pobrać na stronie:
https://www.myonlinetraininghub.com/excel-4-macro-functions).


Sub Makro1()
ActiveWorkbook.Names.Add Name:="Test1", RefersToR1C1:="=FILES(Sheet1!R2C1)"
ActiveWorkbook.Names.Add Name:="Test2", RefersToR1C1:="=GET.CELL(42)"
End Sub

Po uruchomieniu tego makra do nazw Excela (patrz Menadżer nazw na karcie Formuły) dodadzą się dwie nazwy korzystające już z polskich nazw funkcji makr 4.0, gdyż mój Excel ‘mówi’ po polsku 😉 Po prostu między VBA, a Excelem funkcje zostały przetłumaczone. Dzięki temu będziemy już mogli korzystać z potrzebnych nam funkcji makr 4.0 już bez pomocy VBA.

Pozdrawiam
Adam Kopeć
Miłośnik Excela
Microsoft MVP

Odświeżanie zapytań PowerQuery za pomocą VBA #22

W tym wpisie chcemy napisać kod VBA, który odświeża wszystkie zapytania albo tylko pojedyncze zapytanie PowerQuery. Odświeżanie wszystkich zapytań jest prostsze, ponieważ możesz nagrać ten kod sam i później podpiąć go do przycisku.
Najpierw musimy włączyć rejestrowanie makr — polecenie Zarejestruj makro z karty Deweloper.

VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 01

W oknie, które się otworzy

VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 02

nadajesz nazwę makru (np.: Refresh), ewentualnie podpinasz skrót klawiszowy. To trochę bez sensu ponieważ polecenie odśwież wszystko z karty Dane (rys. 3) ma już przypisany do siebie skrót klawiszowy (Ctrl + Alt + F5). Upewniasz się, że makro zostanie zapisane do tego skoroszytu i naciskasz klawisz OK. Teraz ważne, żebyś nie klikał nigdzie w komórki arkusza, tylko od razu przeszedł do karty Dane i kliknął polecenie odśwież wszystko.

VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 03

Teraz możesz już wyłączyć rejestrację makra – polecenie Zatrzymaj rejestrowanie z karty Deweloper.
VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 04

Teraz nawet bez zaglądania do kodu makra możesz wstawić dowolny kształt lub obraz i kliknąć na niego prawym przyciskiem myszy, by z podręcznego menu wybrać opcję przypisz makro.

VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 05

Następnie z listy dostępnych makr wybierasz to, które zarejestrowałeś.

VBA 22 - Odświeżanie zapytań PowerQuery za pomocą VBA 06

I już możesz odświeżać wszystkie zapytania PowerQuery (oraz tabele przestawne i inne połączenia) za pomocą kliknięcia w ‘przycisk’ (kształt/obraz).

Cały kod makra wygląda tak:

Sub Refresh()
ActiveWorkbook.RefreshAll
End Sub

Jeśli chciałbyś odświeżać tylko pojedyncze zapytanie to trudniejsze zadanie i rejestrator makr Ci raczej w tym nie pomoże (patrz film), za to możesz skorzystać z kodu poniżej.

Sub Makro1()
ActiveWorkbook.Connections("Zapytanie — tProdukty_k").Refresh
End Sub

Ważne, że do nazwy zapytania dodajesz prefiks "Zapytanie — " (w innych język ten prefiks jest inny), a i myślnik nie jest standardowy, więc najlepiej, żebyś skopiować cały kod VBA (w Excelu ten myślnik ma KOD = 151).

Na koniec jeszcze pętla (jaką możesz znaleźć na różnych portalach w internecie), która pomoże Ci odświeżyć wszystkie zapytania PowerQuery w pliku (zmieniłem tylko prefiks na polski):

Sub Makro1()

Dim con As WorkbookConnection
Dim Cname As String

For Each con In ActiveWorkbook.Connections
If Left(con.Name, 12) = "Zapytanie — " Then
Cname = con.Name
With ActiveWorkbook.Connections(Cname).OLEDBConnection
.BackgroundQuery = False 'or true, up to you
.Refresh
End With
End If
Next

End Sub

Pozdrawiam
Adam Kopeć
Miłośnik Excela
Microsoft MVP

Kwota słownie liczba słownie — odcinek #21

Chyba każdy program księgowy ma taką funkcjonalności, że potrafi zamienić liczbową reprezentację kwoty na jej reprezentację słowną, czyli przykładowo:

123, 45zł -> sto dwadzieścia trzy złote i czterdzieści pięć groszy

Jak to zrobić w Excelu? Potrzeba odpowiedni kod. Niestety nie jest znany mi jego autor, bo na żadnej stronie, gdzie go widziałem nikt nie wiedział kto go napisał. Mi on się bardzo podoba, bo jak się go odpowiednio podzieli jest naprawdę prosty do zrozumienia.
Ja żeby lepiej go zrozumieć dołożyłem do niego jeszcze część odpowiedzialną za przekształcenie miliardów.

Kod składa się z dwóch funkcji, które z komentarzami zamieszczam poniżej:

Function Słownie(x As Variant) As String 'dla liczb od -999 999 999 999.99 do 999 999 999 999.99
'Sprawdzamy czy podana kwota jest mniejsza od zera jeśli jest to dopisujemy do kwoty słownie słowo minus
If x 0 Then w = w & "minus " 'Konwertujemy liczbę na zapis, który będzie pokazywał zawsze miliardy miliony, tysiące i jednostki 'nawet jeśli będą to same zera x = Format(Abs(x), "000 000 000 000.00") 'części odpowiedzialne za miliardy, miliony itd. przypisujemy do oddzielnych zmiennych 3 cyfrowych 'wiodące zera również są w nich brane pod uwagę, a do groszy musimy dodać jedna zero na początku 'żeby później działało odpowiednio z funckją trzy mld = Left(x, 3): m = Mid(x, 5, 3): t = Mid(x, 9, 3): j = Mid(x, 13, 3): g = "0" & Right(x, 2) 'Sprawdzamy miliardy i w zależności od ich ilości nadajemy inne końcówki 'analogicznie robimy z milionami, tysiącami, jednościami i groszami Select Case mld Case 0 Case 1 w = "jeden miliard " Case Else 'za pomocą funkcji trzy sprawdzamy jaka jest liczba miliardów, a późniejszych częściach milionów itd. w = w & trzy(mld) 'dodajemy odpowiedni "końcówek" na podstawie połączeniu odpowiednich warunków If Mid(mld, 2, 1) > 1 And (Right(mld, 1) = 2 Or Right(mld, 1) = 3 Or Right(mld, 1) = 4) Then w = w & "miliardy " Else w = w & "miliardów "
End Select

'Sprawdzanie milionów analogicznie jak miliardów
Select Case m
Case 0
Case 1
w = "jeden milion "
Case Else
w = w & trzy(m)
If Mid(m, 2, 1) > 1 And (Right(m, 1) = 2 Or Right(m, 1) = 3 Or Right(m, 1) = 4) Then w = w & "miliony " Else w = w & "milionów "
End Select

'Sprawdzanie tysięcy analogicznie jak miliardów
Select Case t
Case 0
Case 1
w = w & "jeden tysiąc "
Case Else
w = w & trzy(t)
If Mid(t, 2, 1) > 1 And (Right(t, 1) = 2 Or Right(t, 1) = 3 Or Right(t, 1) = 4) Then w = w & "tysiące " Else w = w & "tysięcy "
End Select

'Sprawdzanie jedności analogicznie jak miliardów
Select Case j
Case 0
If mld = 0 And m = 0 And t = 0 Then w = w & "zero złotych " Else w = w & "złotych "
Case 1
If mld = 0 And m = 0 And t = 0 Then w = w & "jeden złoty " Else w = w & "jeden złotych "
Case Else
w = w & trzy(j)
If Mid(j, 2, 1) > 1 And (Right(j, 1) = 2 Or Right(j, 1) = 3 Or Right(j, 1) = 4) Then w = w & "złote " Else w = w & "złotych "
End Select

'sprawdzanie groszy analogicznie jak miliardów
Select Case g
Case 0
w = w '& "zero groszy"
Case 1
w = w & "jeden grosz"
Case Else
w = w & trzy(g)
If Mid(g, 2, 1) > 1 And (Right(g, 1) = 2 Or Right(g, 1) = 3 Or Right(g, 1) = 4) Then w = w & "grosze" Else w = w & "groszy"
End Select

Słownie = w
End Function

Function trzy(x As Variant) As String
'dzielimy trzy cyfry na część odpowiedzialną za setki, dziesiątki i jedności
x3 = Val(Left(x, 1)): x2 = Val(Mid(x, 2, 1)): x1 = Val(Right(x, 1))
'Spradzamy jaka to setka
If x3 = 9 Then w = w & "dziewięćset "
If x3 = 8 Then w = w & "osiemset "
If x3 = 7 Then w = w & "siedemset "
If x3 = 6 Then w = w & "sześćset "
If x3 = 5 Then w = w & "pięćset "
If x3 = 4 Then w = w & "czterysta "
If x3 = 3 Then w = w & "trzysta "
If x3 = 2 Then w = w & "dwieście "
If x3 = 1 Then w = w & "sto "
'Sprawdzamy jaka to dziesiątka łącząc z ewentualną setką
If x2 = 9 Then w = w & "dziewięćdziesiąt "
If x2 = 8 Then w = w & "osiemdziesiąt "
If x2 = 7 Then w = w & "siedemdziesiąt "
If x2 = 6 Then w = w & "sześćdziesiąt "
If x2 = 5 Then w = w & "pięćdziesiąt "
If x2 = 4 Then w = w & "czterdzieści "
If x2 = 3 Then w = w & "trzydzieści "
If x2 = 2 Then w = w & "dwadzieścia "
'Sprawdzamy czy to nie jest nastka łącząc z ewentualną setką
If x2 = 1 Then
If x1 = 9 Then w = w & "dziewiętnaście "
If x1 = 8 Then w = w & "osiemnaście "
If x1 = 7 Then w = w & "siedemnaście "
If x1 = 6 Then w = w & "szesnaście "
If x1 = 5 Then w = w & "piętnaście "
If x1 = 4 Then w = w & "czternaście "
If x1 = 3 Then w = w & "trzynaście "
If x1 = 2 Then w = w & "dwanaście "
If x1 = 1 Then w = w & "jedenaście "
If x1 = 0 Then w = w & "dziesięć "
End If
'Sprawdzamy jaka to cyfra jedności i dołączamy do ewentualnej wcześniejszej części
If x2 > 1 Then
If x1 = 9 Then w = w & "dziewięć "
If x1 = 8 Then w = w & "osiem "
If x1 = 7 Then w = w & "siedem "
If x1 = 6 Then w = w & "sześć "
If x1 = 5 Then w = w & "pięć "
If x1 = 4 Then w = w & "cztery "
If x1 = 3 Then w = w & "trzy "
If x1 = 2 Then w = w & "dwa "
If x1 = 1 Then w = w & "jeden "
End If
trzy = w
End Function

Pozdrawiam
Adam Kopeć
Miłośnik Excela
Microsoft MVP

Jak cofnąć makro — odcinek #20

Ogólnie jeśli chcesz Twoje makro ruszy arkusz, czy też dane w komórkach, to również wyczyści bufor cofania i nie będziesz mógł cofnąć, ani czynności, które wykonało makro, ani czynności, które wcześniej wykonywałeś — Ctrl + Z nie zadziała.

Jeśli Twoje makro nie rusza arkusza, np: wyświetla komunikat za pomocą funkcji Msgbox, to bufor cofania nie jest czyszczony i dalej możesz cofnąć swoje wcześniejsze czynności za pomocą skrótu klawiszowe.

Niektórzy chcieliby móc cofać swoje makra, dlatego został stworzony kod, który wykorzystuje pewną sztuczkę, a mianowicie w swoim makrze na samym jego początku dodajesz linijkę kodu, która zapisuje Twój plik:
ActiveWorkbook.Save

Następnie jeśli Twoje makro zadziałało niepoprawnie uruchamiasz makro, które powinieneś przechowywać w innym pliku np: skoroszycie makr osobistych, które pobiera nazwę Twojego pliku (aktywnego pliku), zamyka go bez zapisywania, a następnie ponownie uruchamia:

Sub Cofanie()
Dim AktualnyArkusz As String
'Zapisujemy nazwę aktywnego skoroszytu/pliku
AktualnyArkusz = ActiveWorkbook.FullName
'zamykamy go bez zapisywania zmian
ActiveWorkbook.Close SaveChanges:=False
'ponownie go otwieramy
Workbooks.Open Filename:=AktualnyArkusz
End Sub

Czyli symuluje to co musiałbyś zrobić ręcznie, żeby odzyskać swoje dane 😉

Pozdrawiam
Adam Kopeć
Miłośnik Excela

Jak zmienić kolor słowa w zaznaczonych komórkach — odcinek #19

Krótki opis problemu

Potrzebujemy zmienić kolor tylko wybranych słów/fraz w zaznaczonych komórkach Excela. Sam Excel sobie z tym nie poradzi dlatego musimy napisać odpowiedni kod VBA.

VBA 19 - Jak zmienić kolor słowa w zaznaczonych komórkach (Walentynki) 01

Kod

Sub ZmieńKolor()

Dim MojeSłowo As String, Długość As Integer, i As Integer
Dim r As Range, SF As Integer
'Jakie słowo frazę chcesz zmienić
MojeSłowo = InputBox("Podaj słowo jakie chcesz pomalować na czerwono")
'Długość słowa/frazy, którą chcesz zmienić
Długość = Len(MojeSłowo)
'Pętla po wszystkich komórkach ® w zaznaczonym obszarze (Selection)
For Each r In Selection

'Pętla po znakach w aktualnej komórce
For i = 1 To Len(r.Value)

'Ponieważ może nie znaleźć słowa w komórce potrzebujemy obsługiwać
'błąd wystarczy, że każemy VBA przejść dalej
On Error Resume Next
SF = 0
'rozróżnia wielkość liter
SF = WorksheetFunction.Find(MojeSłowo, r.Value, i)
'Nie zwraca uwagi na małe wielkie
'SF = WorksheetFunction.Find(UCase(MojeSłowo), UCase(r.Value), i)
'Wracamy do normalnej obsługi błędu
On Error GoTo 0
'Jeśli zmienna SF większa od zera to znaczy, że tekst został
'odnaleziony, czyli zmieniamy kolor części tekstu
If SF > 0 Then
r.Characters(Start:=SF, Length:=Długość).Font.Color = RGB(255, 0, 0)
i = SF + 1
'jeśli nie to kończymy pętlę i przechodzimy do sprawdzania następnej komórki
Else
Exit For
End If

Next i

Next r

End Sub

Pozdrawiam
Adam Kopeć
Miłośnik Excela

Jak pobrać dane przycisku, który uruchomił makro — odcinek #18

Dziś chcemy poznać kod, który umożliwi nam odczytanie danych przycisku, który uruchomił makro, dzięki czemu będziemy mogli odczytać informacje bezpośrednio np: z tekstu przechowywanym w przycisku, a nie zamieszczać tych informacji w kodzie VBA.
Dodatkowo będziemy mogli podpiąć to samo makro pod wiele przycisków/kształtów i w zależności od tego, który przycisk klikniesz wpiszą się inne informacje.

Zrobimy to na uproszczonym przykładzie akcji, jakie mogą wykonywać koszykarze z kosmicznego meczu. Mamy 3 przyciski akcji i 5 przycisków zawodników. Odpowiednio przyciski akcji są podpięte pod makro Akcja, a przyciski zawodników pod makro Zawodnik.

VBA 18 - Jak pobrać dane przycisku, który uruchomił makro 01

Dwie najważniejsze dla nas linijki kodu z tych dwóch makr to:
Przycisk = Application.Caller
NazwaPrzycisku = ActiveSheet.Shapes(Przycisk).TextFrame.Characters.Text

Najpierw pobieramy "wewnętrzną" nazwę przycisku (obiektu) który uruchomił makro, a później wykorzystujemy tą nazwę, żeby wyciągnąć dokładną informację o tekście przechowywanym w kształcie/przycisku. Ot i cała filozofia. Reszta kodu służy temu, żeby informacje wstawiały się w odpowiednich miejscach.

Przy tym kodzie ważna jest jeszcze informacja, że warto, żeby tekst w kształtach nie był wpisywany ręcznie tylko pobierany z komórek Excela.

VBA 18 - Jak pobrać dane przycisku, który uruchomił makro 02

Dzięki temu szybko możemy zmienić np: drużynę i jej wszystkich zawodników po prostu przekopiowując w komórki powiązane zawodników z drugiej drużyny.

Sub Zawodnik()
Dim Przycisk As String, NazwaPrzycisku As String
'Pobiera "wewnętrzną" nazwę przycisku/kształtu
Przycisk = Application.Caller
'na podstawie tej nazwy wyciągamy tekst wpisany w tym kształcie
NazwaPrzycisku = ActiveSheet.Shapes(Przycisk).TextFrame.Characters.Text

If Range("C2").Value = "" Then
Range("C2").Value = NazwaPrzycisku
Else
Range("C1").End(xlDown).Offset(1, 0).Value = NazwaPrzycisku
End If
End Sub

Pozdrawiam
Adam Kopeć
Miłośnik Excela