Serwis Edukacyjny
Nauczycieli
w I-LO w Tarnowie

obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek
Uaktualniono: 31.07.2022

©2023 mgr Jerzy Wałaszek
I LO w Tarnowie

Okno

SPIS TREŚCI
Podrozdziały

Struktura programu

Programowanie z wykorzystaniem biblioteki SDL2 jest w zasadzie normalnym programowaniem w języku C++. Sterowanie biblioteką odbywa się na zasadzie wywołań odpowiednich funkcji, które musisz poznać, aby móc z nich korzystać. Jednak jest kilka rzeczy, na które należy zwrócić uwagę.

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 main(). A przecież jest w naszym programie. Otóż SDL2 zostało napisane w języku C i wymaga funkcji main() z dwoma parametrami.


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:

Na początek:  podrozdziału   strony 

Okno graficzne

Aby twój program mógł umieszczać grafikę na ekranie, musi posiadać okno graficzne. W tym podrozdziale pokażemy, jak takie okno utworzyć za pomocą funkcji SDL2. Wyjaśnimy również kilka pojęć pomocnych przy pracy z grafiką komputerową.

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.

Podsumowanie

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;
}
Na początek:  podrozdziału   strony 

Podsumowanie

SDL_Init(f) – inicjuje bibliotekę SDL2. Zwraca 0, jeśli inicjalizacja się powiodła lub inną wartość przy błędzie.

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.

Na początek:  podrozdziału   strony 

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.