Pchełki VBA – odcinek 11: Odbijany

In Pchełki VBA by xpil14 Comments

W dzisiejszym numerze „Pchełek” pokażę jak w prosty sposób zrobić „odbijankę”. A więc: prostokąt X na Y pikseli, zaczynamy z górnego lewego rogu, rysujemy linię ukośną w dół w prawo aż trafimy na bok prostokąta, wtedy „odbijamy” się na zasadzie promienia świetlnego i tak w kółko Macieju aż dotrzemy do któregokolwiek z narożników.

Aha, i chcemy, żeby to było widoczne dla użytkownika, a więc nie kończymy zabawy w 10 milisekund tylko chcemy widzieć jak się ów „promień” przemieszcza.

Dla niecierpliwych, najpierw gotowe rozwiązanie. Szczegóły omówię, jak zwykle, później.

W osobnym module:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Const BottomRight As String = "BF47"

Sub Preformatuj()
  Range("A1:" & BottomRight).ColumnWidth = 1
  Range("A1:" & BottomRight).RowHeight = 8
  Range("A1:" & BottomRight).ClearFormats
  Range("A1:" & BottomRight).ClearContents
  Range("A1:" & BottomRight).BorderAround LineStyle:=xlContinuous, Weight:=xlMedium, Color:=RGB(200, 100, 100)
End Sub

Sub Lissa()
  Dim x As Integer, y As Integer, maxx As Integer, maxy As Integer, stepx As Integer, stepy As Integer

  maxx = Range(BottomRight).Column - 1
  maxy = Range(BottomRight).Row - 1

  x = 0
  y = 0

  stepx = 1
  stepy = 1

  Do
    x = x + stepx
    y = y + stepy
    If x = maxx Then stepx = -1
    If x = 0 Then stepx = 1
    If y = maxy Then stepy = -1
    If y = 0 Then stepy = 1
    Range("A1").Offset(y, x).Value = "."
    Range("A1").Offset(y, x).Interior.Color = RGB(10,20,100)
    Sleep 10
    DoEvents
  Loop While Not ((x = 0 Or x = maxx) And (y = 0 Or y = maxy))
End Sub

W module Skoroszytu („ThisWorkbook”):

Private Sub Workbook_Open()
  Preformatuj
  Lissa
End Sub

Zapisujemy to jako Macro-enabled workbook (czyli .xlsxm chyba że ktoś ma starszego Excela wtedy standardowe .xls)

Zamykamy dokument, otwieramy, podziwiamy 😉

Teraz wyjaśnienie krok po kroku:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Ta linia kodu wymaga odrobiny uwagi. Otóż, uwaga, deklarujemy tutaj procedurę o nazwie Sleep, z jednym parametrem dwMilliseconds typu Long (duży, całkowitoliczbowy), a także wskazujemy skąd definicja owej procedury pochodzi: z biblioteki kernel32.dll, która jest biblioteką systemową Windows.

Jeszcze raz: importujemy tutaj zewnętrzną względem naszego kodu procedurę, która została zdefiniowana w systemowej bibliotece DLL o nazwie kernel32, i która przyjmuje na wejściu jeden parametr typu liczba całkowita.

Tu objawia się cała magia VBA, a właściwie nawet nie VBA tylko modelu COM (Common Objects Model). Otóż można w ten sposób zaimportować do własnego kodu dowolną funkcję bądź procedurę z zewnętrznej biblioteki, a następnie używać jaj we własnym kodzie. Piękna sprawa.

Procedura Sleep czeka zadaną ilość milisekund. Przyda się potem przy „spowalnianiu” naszego odbijanego „promienia światła”.

Const BottomRight As String = "BF47"

Deklarujemy tutaj adres dolnego prawego narożnika naszego prostokąta. Górny lewy narożnik to zawsze komórka A1.

Sub Preformatuj()
  Range("A1:" & BottomRight).ColumnWidth = 1
  Range("A1:" & BottomRight).RowHeight = 8
  Range("A1:" & BottomRight).ClearFormats
  Range("A1:" & BottomRight).ClearContents
  Range("A1:" & BottomRight).BorderAround LineStyle:=xlContinuous, Weight:=xlMedium, Color:=RGB(200, 100, 100)
End Sub

Ta mała procedura ustawia szerokości kolumn i wysokości wierszy w zakresie naszego prostokątnego „pudełka”, a także usuwa wszelkie wartości i formaty komórek. Czyli taki „reset” systemu przed początkiem właściwym.

Sub Lissa()

Procedurę nazwałem Lissa (bez parametrów) bo początkowo chciałem napisać pchełkę rysującą krzywe Lissajou. Niestety, wrodzone lenistwo, a także brak czasu, spowodowały, że poszedłem po najmniejszej linii oporu i zamiast tego zrobiłem „odbijanego”.

Dim x As Integer, y As Integer, maxx As Integer, maxy As Integer, stepx As Integer, stepy As Integer

Sześć zmiennych, wszystkie typu całkowitoliczbowego. Po kolei:
x,y – aktualna pozycja
maxx, maxy – ograniczniki (czyli prawa oraz dolna krawędź prostokąta – krawędzie lewa i górna to zawsze pierwszy wiersz i pierwsza kolumna arkusza)
stepx, stepy – odpowiednio 1 lub -1, czyli kierunek przemieszczania się „promienia” w wymiarze poziomym (lewo/prawo) i pionowym (góra / dół).

maxx = Range(BottomRight).Column - 1
maxy = Range(BottomRight).Row - 1

Ustawiamy prawą krawędź „pudełka” na numer kolumny, w której znajduje się komórka „BF47”, a dolną na odpowiedni numer wiersza. Odejmujemy jedynkę, a więc numeracja wierszy / kolumn będzie zaczynać się od zera.

x = 0
y = 0

Startujemy z górnego lewego narożnika.

stepx = 1
stepy = 1

Początkowo przemieszczamy się po skosie w dół i w prawo.

Do
  ...
Loop While Not ((x = 0 Or x = maxx) And (y = 0 Or y = maxy))

Główna pętla. Rysujemy „promień” dopóki nie trafimy na narożnik.

A w pętli…

x = x + stepx
y = y + stepy

Przesuń x o jeden w pionie (w dół lub w górę, w zależności od bieżącego kierunku), przesuń y o jeden w poziomie (w lewo lub w prawo, zależy od bieżącego kierunku)

If x = maxx Then stepx = -1
If x = 0 Then stepx = 1
If y = maxy Then stepy = -1
If y = 0 Then stepy = 1

Jeżeli trafiłeś na krawędź, zmień kierunek ruchu.

Range("A1").Offset(y, x).Value = "."
Range("A1").Offset(y, x).Interior.Color = RGB(10,20,100)

Wstaw kropkę oraz sformatuj tło na niebiesko. Przy okazji, funkcja RGB generuje liczbę całkowitą odpowiadającą 24-bitowemu kolorowi o składowych ośmiobitowych odpowiednio R (składowa czerwona, pierwszy parametr), G (zielona składowa, drugi parametr) i B (niebieska składowa, trzeci parametr). Tak więc RGB(255,0,0) to „czysta czerwień na maksa”, RGB(0,128,0) to „zieleń na pół gwizdka” a RGB(120, 120, 0) to typowa „gęsia kupa”, czyli mieszanka zieleni z czerwienią.

Sleep 10

Tutaj wołamy zaimportowaną uprzednio funkcję systemową Sleep, czyli wstrzymujemy wykonywanie kodu na 10 milisekund. Większa wartość spowolni „promień światła”, mniejsza przyspieszy go.

DoEvents

Procedura DoEvents powoduje chwilowe przerwanie wykonywania kodu oraz wykonanie „zaległych” zdarzeń aplikacji, takich jak kliknięcia myszą, zdarzenia timerów i tak dalej. Dzięki temu DoEvents możemy w trakcie wykonywania naszego kodu zaznaczać inne komórki arkusza, wybierać opcje z menu aplikacji i tak dalej.

Wreszcie:

Private Sub Workbook_Open()
  Preformatuj
  Lissa
End Sub

Tutaj obsługujemy zdarzenie _Open naszego skoroszytu, w którym wołamy obydwie uprzednio pracowicie napisane procedury. A więc, „odbijanka” zadziała zaraz po otwarciu dokumentu.

Nudy, panie…

Dodaj komentarz

14 komentarzy do "Pchełki VBA – odcinek 11: Odbijany"

Powiadom o
avatar
Sortuj wg:   najnowszy | najstarszy | oceniany
agnieszka_sto
Gość

Odcinek 11 rownie ciekawy, jak poprzednie odcinki serii. 🙂

Malina
Gość

..mnie nie działa.. 😀

ale już późno, jutro pomyślę, gdzie zrobiłEŚ błąd 😀 znaczy się dziś, ale za dnia ;]

pozdrawiam 🙂

Krzysiek
Gość

Mi zrobiło tylko szachownicę – chyba nie o to chodziło?

wpDiscuz