Serwis Edukacyjny Nauczycieli w I-LO w Tarnowie ![]() Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy
Wałaszek |
©2023 mgr Jerzy Wałaszek
|
SPIS TREŚCI |
Podrozdziały |
Zakładam, że zainstalowałeś środowisko CodeBlocks oraz skonfigurowałeś je do współpracy z SDL2. Jeśli nie, to wróć tutaj i wykonaj wszystko wg podanych instrukcji.
Uruchom CodeBlocks.
Utwórz nowy projekt sdl2.
Do edytora skopiuj poniższy program:
C++#include <SDL.h> #include <iostream> using namespace std; int main() { return 0; } |
Spróbuj skompilować ten program. W Windows otrzymasz raport błędu, w którym
pojawi się undefined reference to 'SDL_main', czyli
niezdefiniowane odwołanie do 'SDL_main'. Oznacza to, że nie znaleziono
funkcji
Skopiuj do edytora poniższy program:
C++#include <SDL.h> #include <iostream> using namespace std; int main(int argc, char* args[]) { return 0; } |
Teraz kompilacja przebiegnie bez problemów. Argumenty argc i args służą do pobierania parametrów z wiersza poleceń. Jeśli uruchomisz swój program z okna konsoli/terminala przez wpisanie jego nazwy, to za nazwą możesz umieścić różne dodatkowe parametry. Na przykład: załóżmy, że twój program nazywa się sdl2. Wpisałeś w oknie konsoli:
sdl2 grafika w SDL2
Wtedy do argc (ang. argument count, liczba argumentów) trafi wartość 4, bo tyle słów zostało wpisane:
słowo nr 1: sdl2
słowo nr 2: grafika
słowo nr 3: w
słowo nr 4: SDL2
Parametr args (ang. argument strings, łańcuchy argumentów) jest tablicą wskaźników, które adresują teksty poszczególnych słów wpisanych w wierszu polecenia, z tym, że słowo nr 1 (o indeksie 0 w tablicy args) zostaje dodatkowo wzbogacone o ścieżkę dostępu do pliku programu:
arg[0] → "ścieżka\sdl2.exe"
arg[1] → "grafika"
arg[2] → "w"
arg[3] → "SDL2"
Teksty są standardowo zakończone znakiem EOT (ang. End Of Text, koniec tekstu) o kodzie 0 wg konwencji języka C.
Skopiuj do edytora poniższy program:
C++#include <SDL.h> #include <iostream> using namespace std; int main(int argc, char* args[]) { cout << "LICZBA ARGUMENTOW = " << argc << endl; for(int i = 0; i < argc; i++) cout << "ARGUMENT NR " << i << " = " << args[i] << endl; return 0; } |
Z menu wybierz opcję: Project → Set programs' arguments.
W okienku dialogowym wpisz argumenty dla programu (przy uruchomieniu zostaną one przekazane do programu tak, jakbyś je wpisał za nazwą programu w wierszu poleceń):
Zatwierdź okno, skompiluj i uruchom program. Otrzymasz informację o liczbie wpisanych słów oraz same słowa.
Kiedyś, w czasach systemu DOS, był to powszechnie stosowany sposób przekazywania parametrów do programów. Dzisiaj, w dobie Windows 10, korzysta się z tego prawie wyłącznie w programach konsolowych. Programy graficzne też mogą ten sposób wykorzystywać. W każdym razie zapamiętaj: w SDL2 funkcja main() musi posiadać dwa argumenty: inc argc i char * args[ ] (w Linuxie nie jest to konieczne). Pierwszy określa liczbę parametrów wraz z nazwą programu, a drugi wskazuje słowa tworzące poszczególne argumenty. Oczywiście argumenty te nie mają nic wspólnego z SDL2 i możesz je wykorzystywać w każdym programie w C++. Po prostu biblioteka SDL2 spodziewa się funkcji main() z tymi argumentami, zatem jeśli je pominiesz (co jest dozwolone w programach w języku C++), to powstanie błąd w czasie konsolidacji.
Gdy mamy za sobą parametry funkcji main(), przejdźmy do jej zawartości.
Do edytora wpisz poniższy program:
C++#include <SDL.h> #include <iostream> using namespace std; int main(int argc, char * args[]) { if(SDL_Init(SDL_INIT_VIDEO)) { cout << "SDL_Init Error: " << SDL_GetError() << endl; return 1; } SDL_Quit(); return 0; } |
Aby rozpocząć pracę z biblioteką SDL2, należy ją odpowiednio zainicjować. Do tego celu służy funkcja SDL_Init(). Parametrem tej funkcji jest stała, która określa, co ma zostać zainicjowane. SDL2 składa się z kilku podsystemów. Każdy z nich posiada swoją stałą dla funkcji SDL_Init():
Stała | Opis |
SDL_INIT_TIMER | podsystem licznika czasu, tzw. timera (czytaj: tajmera) |
SDL_INIT_AUDIO | podsystem audio |
SDL_INIT_VIDEO | podsystem wideo; inicjalizuje również podsystem zdarzeń |
SDL_INIT_JOYSTICK | podsystem dżojstika; inicjuje również podsystem zdarzeń |
SDL_INIT_HAPTIC | podsystem kontrolera gier z siłowym sprzężeniem zwrotnym |
SDL_INIT_GAMECONTROLLER | podsystem kontrolera gier; inicjalizuje również podsystem joysticka |
SDL_INIT_EVENTS | podsystem zdarzeń |
SDL_INIT_EVERYTHING | wszystkie podsystemy |
Stałe można łączyć ze sobą operatorem alternatywy bitowej o symbolu |. Na przykład chcemy zainicjować podsystemy wideo i audio. Stosujemy wywołanie:
SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)
Jeśli inicjalizacja się powiedzie, to funkcja SDL_Init() zwraca wartość 0. W przypadku błędu zwracana jest wartość ujemna.
W języku C++ wartość 0 traktowana jest jako fałsz, a wartość różna od 0 jako prawda. Instrukcja:
if(SDL_Init(SDL_INIT_VIDEO)) { ... }
inicjuje podsystem wideo. Jeśli inicjalizacja się powiedzie, to funkcja SDL_Init() zwróci zero, które zostanie potraktowane przez instrukcję if jako fałsz. Zatem nie zostaną wykonane operacje w klamerkach, program przejdzie do wykonania instrukcji za klamrą zamykającą. W przypadku błędu SDL_Init() zwróci wartość różną od 0, co zostanie zinterpretowane przez instrukcję if jako prawda. Instrukcje w klamerkach zostaną wtedy wykonane. W klamerkach mamy dwie instrukcje:
cout << "SDL_Init Error: " << SDL_GetError() << endl; return 1;
Pierwsza przesyła do strumienia wyjściowego konsoli cout (ang. console output) napis informujący o błędzie inicjalizacji biblioteki SDL. Opis zaistniałego błędu zwróci funkcja SDL_GetError().
Drugą instrukcją jest return 1, czyli wyjście z funkcji main() z wartością 1. Wyjście z głównej funkcji programu w C++ kończy działanie programu. Zatem w przypadku błędu w oknie konsoli pojawi się odpowiednia wiadomość i program zakończy działanie. To ważne! Nie możesz kontynuować działania programu, jeśli wystąpi jakiś błąd. Należy na niego odpowiednio zareagować. W przypadku błędu inicjalizacji dany podsystem staje się niedostępny dla programu, więc dobrym pomysłem jest po prostu zakończenie działania aplikacji.
Po zainicjowaniu biblioteki SDL możesz korzystać z jej zasobów. W naszym przykładowym programie z niczego nie korzystamy, ale to się szybko zmieni.
Gdy program ma zakończyć działanie, należy wywołać funkcję SDL_Quit(), która odpowiednio pozamyka użyte podsystemy. Dopiero po tym wywołaniu kończymy działanie programu za pomocą return 0.
Podsumujmy:
Uruchom CodeBlocks i utwórz nowy projekt sdl2.
Skopiuj do edytora poniższy program:
C++// Okno graficzne w SDL2 //---------------------- #include <SDL.h> #include <iostream> using namespace std; int main(int argc, char * args[]) { if(SDL_Init(SDL_INIT_VIDEO)) { cout << "SDL_Init Error: " << SDL_GetError() << endl; return 1; } // Tutaj umieszczamy kod dla SDL2 // Koniec pracy z SDL2 SDL_Quit(); return 0; } |
Jest to szablon aplikacji SDL2. Na początku zostaje zainicjowana biblioteka SDL2 i jej podsystem wideo. Jeśli wystąpi błąd, to w oknie konsoli pojawi się odpowiedni komunikat i program zakończy działanie.
Teraz wstawimy fragment kodu, który ma za zadanie utworzyć okno. W miejsce komentarza skopiuj do edytora poniższy fragment programu:
C++// Tutaj umieszczamy kod dla SDL2 SDL_Window * w = SDL_CreateWindow("Okno SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 320, 0); if(!w) { cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl; SDL_Quit(); return 1; } // Czekamy 5 sekund SDL_Delay(5000); // Usuwamy okno SDL_DestroyWindow(w); |
Gdy skompilujesz program, na ekranie pojawi się okno, a po upływie 5 sekund zniknie i program zakończy działanie.
Okno tworzy wywołanie funkcji SDL_CreateWindow(). Parametry są następujące:
SDL_Window * SDL_CreateWindow(t, x, y, w, h, f)t
– tytuł okienka,
x,y – współrzędne lewego górnego narożnika okna,
w – szerokość obszaru graficznego w pikselach
(rzeczywiste okienko może być poszerzone o
ramki, które tworzy system operacyjny),
h – wysokość obszaru graficznego okna
(wysokość okna jest większa, ponieważ
system dodaje jeszcze ramki i pasek tytułowy),
f – znaczniki
Układ współrzędnych ekranu rozpoczyna się w jego lewym górnym narożniku. Współrzędne y przebiegają w dół, a nie w górę.
Przyjęto takie rozwiązanie, ponieważ w sposób naturalny odzwierciedla ono zawartość bufora ekranowego, który zawiera treść ekranu w postaci linii obrazowych. Linie obrazowe przebiegają kolejno od góry w dół obrazu. Zatem to, co jest u góry ekranu, znajduje się na początku bufora.
Współrzędne x i y odnoszą się do lewego górnego narożnika okna. Możesz je podać w postaci liczbowej lub skorzystać ze zdefiniowanych stałych:
Stała | Opis |
SDL_WINDOWPOS_CENTERED | okno zostanie wycentrowane w osi x lub y |
SDL_WINDOWPOS_UNDEFINED | położenie okna nie będzie zdefiniowane w programie, ustali to system operacyjny |
W naszym przykładzie użyliśmy stałej SDL_WINDOWPOS_CENTERED dla obu współrzędnych x i y. Okienko pojawi się zatem na środku ekranu.
Ostatnim parametrem funkcji SDL_CreateWindow() są znaczniki. Określają one różne własności tworzonego okna za pomocą stałych, które można łączyć operatorem alternatywy bitowej |. Poniżej zestawiłem te stałe. Nie przejmuj się ich liczbą lub tym, że nie rozumiesz teraz ich funkcji. Wszystko wyjaśni się w dalszej części kursu.
Stała | Opis |
SDL_WINDOW_FULLSCREEN | okno zajmie cały ekran, tzw. tryb pełnoekranowy |
SDL_WINDOW_FULLSCREEN_DESKTOP | okno zajmie cały ekran wykorzystując bieżącą rozdzielczość pulpitu |
SDL_WINDOW_OPENGL | okno do współpracy z OpenGL |
SDL_WINDOW_HIDDEN | okno będzie ukryte |
SDL_WINDOW_BORDERLESS | okno bez krawędzi |
SDL_WINDOW_RESIZABLE | okno z możliwością zmiany rozmiaru |
SDL_WINDOW_MINIMIZED | okno zminimalizowane na pasku zadań |
SDL_WINDOW_MAXIMIZED | okno zmaksymalizowane |
SDL_WINDOW_INPUT_GRABBED | okno z przechwyceniem skupienia |
SDL_WINDOW_INPUT_FOCUS | okno ze skupieniem wejścia |
SDL_WINDOW_MOUSE_FOCUS | okno ze skupieniem myszki |
SDL_WINDOW_FOREIGN | okno utworzone poza SDL2 |
Funkcja SDL_CreateWindow() zwraca wskaźnik do struktury SDL_Window. Zwykle nie musisz się tą strukturą przejmować, ponieważ służy ona do wewnętrznych celów w SDL2 i jej definicja jest ukryta przed programistą. Jeśli okno zostanie otwarte, to struktura SDL_Window zostanie utworzona w pamięci i funkcja zwróci wskaźnik (czyli adres) tej struktury. Wskaźnik zapamiętujemy w zmiennej w.
W języku C++ obowiązuje umowa, że wskaźnik o wartości 0 nie wskazuje żadnego obiektu w pamięci. Jeśli zatem funkcja SDL_CreateWindow() zwróci wskaźnik zerowy, to oznacza to błąd utworzenia okna. Aby wychwycić ten fakt, w instrukcji if stosujemy negację (0 jest w C++ traktowane jako fałsz):
if(!w) { cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl; SDL_Quit(); return 1; }
Instrukcje w klamerkach pod if wykonają się, gdy wskaźnik w będzie miał wartość NULL. W takim przypadku zostanie wypisany komunikat o błędzie, biblioteka SDL zostanie zamknięta i program zakończy swoje wykonanie.
Jeśli tworzenie okna się powiedzie, to wskaźnik w będzie miał wartość różną od NULL. Program przejdzie do wykonania instrukcji pod klamerką zamykającą if.
SDL_Delay(5000);
Funkcja SDL_Delay() czeka przez zadaną liczbę milisekund. 5000 oznacza 5 sekund oczekiwania. W tym czasie utworzone okno jest widoczne na ekranie. Jednak nic z nim nie możesz zrobić, ponieważ SDL_Delay() blokuje obsługę zdarzeń (zdarzeniami zajmiemy się w dalszej części kursu).
Gdy upłynie czas wyznaczony przez SDL_Delay(), wywołujemy funkcję SDL_DestroyWindow(), która usunie okno z ekranu i z pamięci komputera. Jako parametr przesyłamy do tej funkcji wskaźnik w, który został ustawiony przez SDL_CreateWindow(). Po usunięciu okna kończymy współpracę z SDL2 wywołaniem funkcji SDL_Quit() i rozkazem return 0 kończymy działanie programu.
Cel został osiągnięty. Stworzyliśmy program, który utworzył proste okno. W dalszej części kursu będziemy opanowywać różne operacje graficzne w oknie.
Pełna wersja programu z tego rozdziału powinna wyglądać następująco:
C++// Okno graficzne w SDL2 //---------------------- #include <SDL.h> #include <iostream> using namespace std; int main(int argc, char * args[]) { if(SDL_Init(SDL_INIT_VIDEO)) { cout << "SDL_Init Error: " << SDL_GetError() << endl; return 1; } // Tutaj umieszczamy kod dla SDL2 SDL_Window * w = SDL_CreateWindow("Okno SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 320, 0); if(!w) { cout << "SDL_CreateWindow Error: " << SDL_GetError() << endl; SDL_Quit(); return 1; } // Czekamy 5 sekund SDL_Delay(5000); // Usuwamy okno SDL_DestroyWindow(w); // Koniec pracy z SDL2 SDL_Quit(); return 0; } |
f – znaczniki określające inicjowane podsystemy
SDL_GetError() – zwraca krótki opis ostatniego błędu w postaci tekstu.
SDL_CreateWindow(t,x,y,w,h,f) – tworzy okno graficzne. Zwraca wskaźnik do struktury SDL_Window lub NULL przy błędzie.
t – tytuł okienka,
x,y – współrzędne lewego górnego narożnika okna,
w – szerokość obszaru graficznego w pikselach,
h – wysokość obszaru graficznego okna,
f – znaczniki
SDL_Delay(d) – wstrzymuje wykonanie programu na zadaną liczbę milisekund.
d – liczba milisekund (1000 oznacza jedną sekundę).
SDL_DestroyWindow(w) – usuwa okno graficzne.
w – wskaźnik struktury SDL_Window
SDL_Quit() – kończy współpracę z SDL2.
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2023 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.