Delphi, cz. 12
Hello :) No to co, zaczynamy? Jeśli myśleliście, że to koniec omawiania grafiki to baardzo się pomyliliście :)) Najpierw miałem omówić zadanie, które zadałem w poprzednim rozdziale :) I jak? Udało się? Nim to zrobie trochę słów na temat odtwarzania dźwięków.
Dzwięki w Delphi
Na samym początku musisz do listy uses dodać slowo "MMSystem". To ten moduł umożliwia odtwarzanie dźwięków, a konkretniej funkcja "PlaySound". Oto przykład odegrania pliku muzycznego WAV znajdującego się na dysku:
PlaySound('C:\plik.wav', 0, SND_FILENAME);
Tylko jedna linia :) Gotowe. Pierwszym parametrem tej funkcji jest oczywiście nazwa pliku dźwiękowego, który ma być odtworzony. Kolejny to informacja, czy plik jest odtwarzany z zasobów czy z dysku. Jeżeli z dysku należy wstawić 0. Ostatni parametr to flaga. Możliwe są do wykorzystania takie flagi:
- SND_FILENAME - odtwarzanie odbywa się z dysku
- SND_ALIAS - dzięki temu możliwe jest odtworzenie dźwięków typowych dla Windows (np. odpalenia Windowsa ). Szczegóły w dalszej części.
- SND_PURGE - polecenie zakończenia odtwarzania.
- SND_RESOURCE - odtwarzanie odbywa się z zasobów programu;
- SND_ASYNC - odtwarzanie odbywa się równocześnie z działaniem aplikacji;
- SND_LOOP - odtwarzanie w sposób ciągły
- SND_NODEFAULT - jeżeli plik nie może być odnaleziony nie generuj sygnału ostrzegawczego;
- SND_SYNC - zwraca sterowanie dopiero po zakończeniu odtwarzania
Możliwe jest także odtwarzanie dźwięków Windowsa. Jak wiesz Windows posiada swoje dźwięki i je generuje ( np. uruchamianie Windowsa, klikniecie itp. ). Spis tych dźwięków znajduje się w rejestrze Windows. Oto przykład odtworzenia dźwięku 'SystemStart':
PlaySound('SystemStart', 0, SND_ALIAS);
Zauważ obecność flagi "SND_ALIAS"!
Jeżeli chcesz np. wyciszyć wszystkie dźwięki to należy zrobić tak:
PlaySound(Nil, 0, SND_PURGE);
Ooops. Chyba nie powiedziałem co to znaczy to NIL? Otóż jest to tzw. wskaźnik pusty, czyli wskazuje on na nic. Nie wskazuje nic. Wcześniej wspomniałem o możliwości umieszczenia w zasobach dźwięku typu WAV. Ponieważ standardowy edytor zasobów Delphi tego nie umożliwia trzeba to zrobić ręcznie. W katalogu z Twoim programem stwórz plik wave.rc. Otwórz go za pomocą Notatnika i wpisz taki tekst:
STRINGTABLE
BEGIN
101, "Cześć!"
102, "Jak się masz?"
END
ID_WAVE WAVE "hover.wav"
Zacznę od końca: ostatnia linia informuje o włączeniu do zasobów pliku o nazwie "hover.wav" i podstawienie go pod nazwą "ID_WAVE". Ponieważ jest to dźwięk typu WAV musimy zadeklarować typ pliku, czyli "WAVE". Oczywiście zakładając, że umieściłeś w katalogu z programem dźwięk i nazwałeś go "hover.wav". Ok, co robią linie na samej górze. Włączają one do zasobu dwie linie tekstu. Najpierw pomiędzy liniami BEGIN i END trzeba wpisać tzw., identyfikator, czyli pod jaką nazwą Delphi ma rozpoznawać linię tekstu. Najpierw piszemy liczbę ( jaka ona będzie? Zależy od Ciebie ), a następnie w cudzysłowie wpisujemy tekst, który ma być do zasobów włączony. Ufff. Gotowe, zapisz plik. Teraz trzeba go skompilować. W tym celu musisz użyć kompilatora brcc32.exe. Jest to program DOS'owy więc musisz go uruchomić w okienku MS-DOS. W DOS'ie do katalogu przechodzi się poprzez polecenie:
cd NazwaKatalogu
Natomiast przechodzenie o jeden katalog wyżej umożliwia polecenie:
cd..
Jeżeli już jesteś w katalogu wpisz:
brcc32.exe wave.rc
Spowoduje to utworzenie pliku wave.res. Zasoby są już gotowe - teraz pozostało wpisywanie kodu. Mam wrażenie, że przebrnąłem przez to jakoś tak szybko :) Nie za szybko??? No cóż. Uwierz mi, że tak samo będziemy pisać instalator. Nie w tym rozdziale, ale kiedy indziej :) No dobra. Teraz do zasobów dołączyliśmy dzwięk typu WAV oraz tekst! Tak, tak do zasobów można włączyć także tekst. W przyszłości będziemy do zasobów włączać pliki EXE. Jeżeli nie możesz się tego doczekać to zajrzyj na stronę: www.programowanie.of.pl. Tam masz odpowiednie FAQ-i i artykuły. Miałem podać kod animacji. Dobrze. Będzie to jednak unowocześniona animacja gdyż będzie umożliwiać odtwarzanie dźwięków oraz wczytywanie z zasobów tekstu. Oto kod. Cały kod.
(**********************************************************)
(* Resource Test programme for Delphi 5 *)
(* Copyright © 2001 by Adam Boduch *)
(* All rights reserved *)
(* Build: 17 luty 2001 r. *)
(* E-mail: boduch@poland.com *)
(* SERVICE FOR PROGRAMMERS: *)
(* HTTP://WWW.PROGRAMOWANIE.OF.PL *)
(**********************************************************)
unit MainForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, MMSystem {moduł umożliwiającey odtwarzanie muzyki };
{ Oto zasoby zawierajace bitmapki oraz muzyke }
{$R FILES.RES}
{$R WAVE.RES}
type
TMainFrm = class(TForm)
Button1: TButton;
Panel1: TPanel;
Image1: TImage;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainFrm: TMainFrm;
Done : Boolean; // zmienna informująca, czy animacja jest w ruchu
const
BName = 'ID_BITMAP'; // pierwszy człon nazwy bitmapek
STRING1 = 101; // wartość liczbowa pierwszego Stringa umieszczonego w zasobach
STRING2 = 102; // wartość liczbowa drugiego Stringa umieszczonego w zasobach
implementation
{$R *.DFM}
procedure TMainFrm.Button1Click(Sender: TObject);
var
i : Integer;
Buff: array [0..MAX_PATH] of Char; // ta zmienna musi mieć taka postać...
begin
while not (Done) do // Jeżeli zmienna Done = False tzn., ze animacja
//jest uruchomiona
begin
{
Petla ta powoduje ladowanie po kolei obrazkow z zasobow. Dzieki temu
odnosi sie wrazenie animacji. Stala "BNAME" okresla slowo "ID_BITMAP" do
ktorego dodawane sa cyfry oznaczajace numery bitmapy.
}
for i:=1 to 4 do
begin
Application.ProcessMessages; // daj odetchnąć systemowi
Sleep(100); // czekaj 100 milisekund ( 1000 milisekund = 1 sek. )
Image1.Picture.Bitmap.LoadFromResourceName( // załaduj bitmape z zasobów
hInstance, BName + IntToStr(i));
end;
{
Ponizsze polecenia kolejno odgrywaja oraz laduja tekst z zasobow.
Pierwsza funkcja "PlaySound" powoduje zaladowanie z zasobow muzyki i
odtworzenie jej.
Druga funkcja laduje z zasobow tekst i przypisuje go do zmiennej
"Buff". Nastepnie tekst ten wyswietlony jest na pasku formy.
"STRING1" to stala oznaczajaca cyfre 101. Pod to cyfra kryje sie
tekst, ktory ma byc zladowany z zasobow.
}
PlaySound('ID_WAVE', hInstance, SND_ASYNC or SND_RESOURCE);
LoadString(hInstance, STRING1, Buff, SizeOf(Buff));
Caption := Buff;
Sleep(50); // czkej 50 milisekund
{
Teraz ta pętla odtwarza animacje od tylu tzn., idea jest taka
sama jak w poprzedniej pętli tyle ze bitmapy ładowane są od
tylu.
}
for i:=4 downto 1 do
begin
Application.ProcessMessages;
Sleep(100); // czekaj 100 milisekund
Image1.Picture.Bitmap.LoadFromResourceName( // załaduj bitmapki
hInstance, BName + IntToStr(i));
end;
{ To samo co wyzej tyle, ze ladowany jest inny tekst.... }
PlaySound('ID_WAVE', hInstance, SND_ASYNC or SND_RESOURCE);
LoadString(hInstance, STRING2, Buff, SizeOf(Buff));
Caption := Buff;
end;
end;
procedure TMainFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Done := True; // zakończ animacje i zamknij program....
end;
end.
No... nie przerażaj się. Większość tej procedury stanowią komentarze. Całość stanowi jedna pętla while w której wnętrzu znajdują się dwie pętle for. Jeżeli zmienna "Done" nie przybierze wartości False to animacja odtwarzana będzie w nieskończoność :) Aha! Do listy uses dodaj nazwę modułu MMSystem - to ten moduł odpowiedzialny jest za odtwarzanie dźwięków poprzez funkcję PlaySound. W funkcji tej podawana jest nazwa identyfikatora pod którą kryje się dźwięk. Kolejna linia ładuje z zasobów tekst. Służy do tego linia "LoadString", która przypisuje linię z zasobów do zmiennej Buff. Następnie ta zmienna przypisana jest na pasku stanu formy. Drugi człon to kolejna pętla, która ładuje bitmapy od tyłu co daje efekt animacji. Na samym końcu także następuje załadownie dźwięku i testu.
Teraz pozostaje jeszcze uzupełnienie procedury "OnClose" formy. Zmienia ona wartość zmiennej Done na True co powoduje zakończenie animacji. Zwróć uwagę na konstrukcję funkcji "PlaySound". Jeżeli ładujesz dźwięk z zasobów jako drugi parametr musisz nadać słowo "hInstance", które oznacza ładowanie z zasobów. Ostatnii parametr to połączenie dwóch flag poprzez operator "or". Jeżeli ładujesz dźwięk z zasobów musisz programowi nadać tę flagę.
Naturalnie możliwe jest także łączenie innych parametrów - np:
PlaySound('SystemAsterisk', 0, SND_ALIAS or SND_NODEFAULT);
W tym wypadku następuje odtworzenie dźwięku z rejestru, a właściwie tylko lokalizacji, a następnie odtworzenie go. Jeżeli dźwięk nie istnieje ( tj. jeżeli Ty go sobie usunąłeś lub nie przypisałeś do systemu odpowiedniego dźwięku to program generowałby by charakterystyczne dla Windows dźwięk. Ostatnia flaga "SND_NODEFAULT" temu zapobiega.
Jeżeli czegoś nadal nie rozumiesz pisz: boduch@poland.com lub odwiedź stronę: www.programowanie.of.pl
Dobra, teraz zrobimy coś fajnego, czyli....
Piszemy wygaszacz ekranu
Standardowy wygaszacz Windows posiada rozszerzenie *.scr. Musi je posiadać :) Nic prostszego. Wystarczy zmienić rozszerzenie na *.scr i skopiować program do katalogu Windows. Nie jest to takie łatwe. Trzeba bowiem oprogramować zdarzenie "OnMouseMove" odpowiadające za ruchy myszką oraz "OnKeyPress" odpowiadające za naciśnięcie przycisku klawiatury. Nasz wygaszacz ekranu będzie się nazywał "Matrix". Pokazywał on będzie i zsuwał napisany tak jak w Matrixie :)
Zacznijmy więc:
1. Przede wszystkim zmień właściwość "WindowState" formy na "wsMaximized". Spowoduje to, że forma będzie wyświetlana na całym ekranie.
2. Zmień właściwość "BorderStyle" na "bsNone". To powoduje ukrycie paska głównego formy.
3. Teraz trzeba się zabezpieczyć przed ponownym uruchamianiem tego samego egzemplarza programu. W "OnCreate" wpisz na początek taki tekst:
procedure TMainFrm.FormCreate(Sender: TObject);
var
H : THandle;
begin
H := CreateFileMapping(THANDLE($FFFFFFFF),nil,
PAGE_READONLY,0,32,'Screen');
{ Jezeli aplikacja jest uruchomiona ( ALREADY_EXISTS ) to zamknij
druga }
if GetLastError=ERROR_ALREADY_EXISTS then
begin
Application.Terminate;
CloseHandle(H);
end;
Color := clBlack; // kolor tla
ShowCursor(FALSE); // ukryj kursor
end;
Omówienie początku tej procedury wykracza poza obszar niniejszego kursu. :) Następuje tutaj utworzenie obiektu. Gdyż jeynim błędem wykorzystania tej funkcji to może być błąd: "ERROR_ALREADY_EXISTS" ( program jest już w pamięci ) to dzięki temu można kontrolować ponowne uruchamianie programu. Jeżeli chcesz możesz o tym poczytać w Helpie ( wiem, że nie wszyscy znają perfekto anglika, ale.. ). Ta funkcja nazywa się tworzenie "obiektu odwzorowującego". O tym być może będziemy mówić kiedyś w Kurs Delph dla zaawansowanych" :)) A więc dzięki tej funkcji możesz kontrolować ponowne uruchamianie tego samego programu i odpowiednio zareagować. W tym wypadku zamykany zostaje program, który ponownie próbujesz uruchomić.
Na samym końcu tej funkcji następuje zmiana koloru tła oraz ukrycie kursora. Tak funkcja "ShowCursor" pokazuje kursor ( parametr: True ) lub ukrywa ( False ).
Teraz kolejna, a zarazem ostatnia funkcja "OnActivate". Uzupełnij więc procedurę "OnActivate" formy - wpisz taki text:
procedure TMainFrm.FormActivate(Sender: TObject);
var
X, I, Count : Integer;
Chars : Char; // zmienna oznaczajca znak ( pojedynczy )
begin
Count := 0; // wyzeruj licznik
while not (Done) do // Jezeli animacja jest uruchomiona...
begin
Canvas.Brush.Color := clBlack; // ustaw kolor tła
Randomize; // wylosuj
X := Random(Screen.DesktopWidth); // losuj pozycje
Canvas.Font.Color := RGB(25, 255, 0); // ustaw kolor czcionki
Canvas.Font.Size := 12; // rozmiar czcionki
Inc(Count); // podnieś o jeden
if Count = 30 then // Jezeli licznik rowna sie cyfrze 30...
begin
Repaint; //... odswiez ekran
Count := 0; // wyzeruj licznik
end;
{ Wykonuj petle. Zacznij od zera i kontynuuj do wylosowanego punktu }
For I := 0 to Random(Screen.DesktopHeight) + 100 do
BEGIN
Application.ProcessMessages;
Sleep(2);
Chars := Chr(Random(255)); // losuj znak
Canvas.TextOut(X, I, Chars); // spuszczaj :) znak
if (Done) then // Jezeli Done = True to przerwij...
Break;
END;
end;
end;
Ta procedura odpowiada za rysowanie znaku i odpowiednie go spuszczanie :)) z góry na dół. W procedurze zadeklarowany został także licznik który zlicza ilość wykonanych pętli ( czyli mówiąc inaczej: ilość spuszczonych pasków liter ). Aha! Byłbym zapomniał: musisz jeszcze zadeklarować zmienną "Done", która będzie typu "Boolean". Będzie ona odpowiadała za to, czy animacja jest uruchomiona, czy też nie. No, ale przejdźmy do omawiania naszej procedury. Następuje tam odpowiednie ustawianie rozmiarów czcionki. Później uruchomiona jest procedura losowania ( Randomize ), a następnie losowana zostaje pozycja "X". Zmienna "X" przechowuje wylosowaną liczbę. Liczba ta określa położenie X paska, który będzie zsuwany. Ta liczba losowana jest z zakresu szerokości pulpitu. Następnie wybierany będzie kolor czcionki. Kolor będzie tak jak w Matrixie. Tak jak mówiłem wykorzystany tutaj jest parametr RGB, który oznacza kolory ( czerwony, zielony, niebieski ). W nawiasach podawane są odcienie tychże kolorów. Kolor czerwony ustawiłem o małe natężenie. Kolor zielony na jak najbardziej jaskrawy, a niebieski na 0. Później funkcja "Inc". Ta funkcja to odpowiednik:
X := X + 1 znaczy to samo co Inc(x);
X := X - 1 znaczy to samo co Dec(x);
Czyli krótko mówiąc podnosi ona cyfrę w nawiasie o jeden. Następnie następuje sprawdzenie jaki jest parametr zmiennej "Count". Jeżeli wynosi ona 30 tzn., że spuszczono już 30 pasków. Wtedy odśwież obraz i wyzeruj licznik.
Na samym końcu wykonaj pętle. Następuje tutaj spuszczanie pasku od 0 do wylosowanej pozycji Y. Pozycja Y losowana jest z zakresu wysokości pulpitu. Do tej wartości dodawana jest cyfra 100, która zapewnia odpowiednią długość paska. Zmienna "Chars" to zmienna typu "Char", która przechowuje pojedynczy znak. Następnie procedura "Chr" [ mówiłem o niej w poprzednim rozdziale ]. Czyli do zmiennej "Char" przypisany jest losowany z zakresu 255 znak. Następnie znak ten jest spuszczany na dół.
Oto cały kod wygaszacza:
(**********************************************************)
(* Borland Delphi Screen Saver *)
(* The Matrix Screen Saver *)
(* Copyright © 2001 by Adam Boduch *)
(* Build: 23 lutego 2001 21:35 *)
(* SERVICE FOR PROGRAMMERS: *)
(* HTTP://WWW.PROGRAMOWANIE.OF.PL *)
(* e - Mail: boduch@poland.com *)
(**********************************************************)
//
// Przykładowy wygaszacz ekranu do kursu:
// " Delphi dla poczatkujacych "
// http://www.programowanie.of.pl
unit MainFrmU;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TMainFrm = class(TForm)
procedure FormActivate(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
procedure FormCreate(Sender: TObject);
end;
var
MainFrm: TMainFrm;
Done : Boolean;// animacja jest w ruchu?
implementation
{$R *.DFM}
procedure TMainFrm.FormActivate(Sender: TObject);
var
X, I, Count : Integer;
Chars : Char; // zmienna oznaczajca znak ( pojedynczy )
begin
Count := 0; // wyzeruj licznik
while not (Done) do // Jezeli animacja jest uruchomiona...
begin
Canvas.Brush.Color := clBlack; // ustaw kolor tła
Randomize; // wylosuj
X := Random(Screen.DesktopWidth); // losuj pozycje
Canvas.Font.Color := RGB(25, 255, 0); // ustaw kolor czcionki
Canvas.Font.Size := 12; // rozmiar czcionki
Inc(Count); // podnieś o jeden
if Count = 30 then // Jezeli licznik rowna sie cyfrze 30...
begin
Repaint; //... odswiez ekran
Count := 0; // wyzeruj licznik
end;
{ Wykonuj petle. Zacznij od zera i kontynuuj do wylosowanego punktu }
For I := 0 to Random(Screen.DesktopHeight) + 100 do
BEGIN
Application.ProcessMessages;
Sleep(2);
Chars := Chr(Random(255)); // losuj znak
Canvas.TextOut(X, I, Chars); // spuszczaj :) znak
if (Done) then // Jezeli Done = True to przerwij...
Break;
END;
end;
end;
procedure TMainFrm.FormKeyPress(Sender: TObject; var Key: Char);
begin
Done := True; // przerwij
Close; // zamknij program
end;
procedure TMainFrm.FormCreate(Sender: TObject);
var
H : THandle;
begin
H := CreateFileMapping(THANDLE($FFFFFFFF),nil,
PAGE_READONLY,0,32,'Screen');
{ Jezeli aplikacja jest uruchomiona ( ALREADY_EXISTS ) to zamknij
druga }
if GetLastError=ERROR_ALREADY_EXISTS then
begin
Application.Terminate;
CloseHandle(H);
end;
Color := clBlack; // kolor tla
ShowCursor(FALSE); // ukryj kursor
end;
end.
No to już wszystko na dziś. Idę oglądać "Różową landrynkę". :)) Cześć!
Czekam na pytania! |