Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Piotr Szawdyński
Biblioteki C++

Wyświetlanie tekstu

[lekcja] Rozdział 9. Tekst w SFML - wczytywanie czcionek i ich wyświetlanie. Ponadto rozdział opisuje jak zapewnić obsługę polskich czcionek w aplikacji SFML.
Celem niniejszego rozdziału jest nauczenie się wyświetlania tekstu w bibliotece SFML. W celu wyświetlenia tekstu oczywiście potrzebna jest jakaś czcionka - zazwyczaj w bibliotekach tego typu sprowadza się to do użycia standardowej czcionki, którą dostarcza biblioteka, a wszelkie inne czcionki trzeba sobie mozolną pracą zaimplementować. W przypadku biblioteki SFML dostępna jest standardowa czcionka, która w sumie jest wygodna w użyciu i pozwala szybko wejść w temat związany z wyświetlaniem tekstu. Finezja biblioteki SFML nie uleciała w przypadku wyświetlania tekstu w powietrze, a wręcz przeciwnie - czcionki są kolejnym dowodem na to, że biblioteka SFML jest po prostu zaprojektowana tak by czas programisty nie był trwoniony na rzeczy błache. Zanim jednak zaznamy tej subtelności i wyrafinowania, skupmy się najpierw na podstawach, które niewątpliwie są obiektem Twoich zainteresowań :)

Klasa do tekstu

Podstawową kwestią związaną z tekstem w bibliotece SFML jest możliwość jego przechowywania oraz wyświetlania. Zazwyczaj warstwy te w bibliotekach są od siebie oddzielone, tj. tekst żyje swoim życiem, a wyświetlenie tekstu wiąże się z wywołaniem odpowiedniej funkcji czy też metody oraz przekazaniu do niej tekstu, który ma zostać wyświetlony. W bibliotece SFML jest to jednak rozwiązane inaczej - klasa, która przechowuje tekst jednocześnie służy do jego renderowania. Tą klasą jest sf::String. Takie rozwiązanie niesie ze sobą pewne konsekwencje, które w sumie w ogólnym rozrachunku wypadają całkiem przyzwoicie i nawet potrafią bardziej cieszyć aniżeli martwić programistę :)

Ustawianie tekstu

W celu ustawenia tekstu tworzymy najpierw obiekt, który będzie przechowywał nam tekst:
C/C++
sf::String tekst;
Następnie za pomocą metody SetText możemy nadać tekst jaki ma przechowywać ten obiekt:
C/C++
tekst.SetText( L"Kurs SFML, C++ - http://cpp0x.pl" );
Zauważ, że tekst jest poprzedzony dużą literą L, która informuje kompilator, że tekst ten ma być unikodowy. Każdy tekst, który przekazujemy do obiektu typu sf::String powinien być w postaci unikodowej. Z jednej strony może być to dla Ciebie uciążliwe jeżeli nie masz zbyt dużego obycia w używaniu tekstu unikodowego, jednak w praktyce zastosowanie tego kodowania rozwiązuje Ci wszelkie problemy z obsługą polskich czcionek, o czym szerzej będę pisał w dalszej części niniejszego rozdziału.

Klasa sf::String umożliwia podawanie tekstu w tradycyjny sposób, tj. bez konieczności poprzedzania tekstu literą L. Tekst ten zostanie jednak przekonwertowany do postaci unikodowej.

Skoro jesteśmy nadal przy ustawianiu tekstu to dodam jeszcze, że możemy go również ustawić za pomocą konstruktora i wówczas wyglądałoby to tak:
C/C++
sf::String tekst( L"Kurs SFML, C++ - http://cpp0x.pl" );

Pobieranie tekstu

Do odczytywania tekstu służy metoda GetText. Zapewne nie prędko przyjdzie Ci korzystać z tej metody, jednak warto wiedzieć, że ona istnieje. Wspomniana metoda zwraca tekst w postaci unikodowej.

Wyświetlanie tekstu

To co na chwilę obecną najbardziej Ciebie interesuje to jak wyświetlić tekst. Klasa sf::String dziedziczy po klasie sf::Drawable, a więc możliwe jest renderowanie czcionki w taki sam sposób jak to miało miejsce zarówno ze sprajtami jak i prymitywami. Tym samym wyświetlenie tekstu sprowadza się do napisania:
C/C++
oknoAplikacji.Draw( tekst );
Tym sposobem ukaże się nam na ekranie tekst, który zawiera obiekt przekazany poprzez argument do metody Draw.

Pozycja tekstu, rotacja i jego skalowanie

Zaletą biblioteki SFML jest niewątpliwie fakt, że wszystkie obiekty, które mogą być wyświetlane na ekranie dziedziczą po klasie sf::Drawable. Dzięki temu wszystkie obiekty mają ten sam interfejs do ustalania położenia, rotacji i skalowania, co czyni bibliotekę SFML bardzo łatwą do nauki i nie wymaga od nas zbyt wielu rzeczy do pamiętania. Wszelkie kwestie związane z rotacją, skalowaniem i położeniem zostały już omówione w rozdziale » Kurs SFML 1.6, C++Tworzenie i wyświetlanie sprajtów lekcja dlatego też nie ma potrzeby ich tu ponownie przytaczać. Sens metod jest bowiem ten sam, a jedyne co się zmienia to ostatecznie renderowany obiekt, który nie jest sprajtem lecz tekstem.

Wysokość czcionki, a jej jakość

Jednym z ciekawszych zagadnień, które mają bezpośredni wpływ na jakość renderowanego tekstu jest ustalanie rozmiaru tekstu. Wysokość tekstu możemy ustalać bowiem na dwa sposoby: pierwszym z nich jest skalowanie czcionki, natomiast drugim - wczytanie czcionki, której rozmiar będzie zgodny tym, który jest przez nas oczekiwany. Jak zapewne się domyślasz, skalowanie czcionki będzie powodowało uszczerbki na jakości wyświetlanych czcionek. O ile czasami jakość w wyniku dokonania skalowania potrafi być zadowalająca i nie odczujemy żadnego dyskomfortu związanego z tą operacją o tyle zdarzają się sytuacje, gdzie skalowanie nie jest pożądane i wówczas wypadałoby wczytać czcionkę, która zaprezentuje się znacznie lepiej aniżeli ta skalowana. Teraz zamiemy się tekstem uzyskanym w wyniku skalowania, natomiast w dalszej części niniejszego rozdziału omówimy czcionkę 'doskonałą' oraz cenę jaką się ponosi za jej używanie.

Czcionka skalowana

Na początek warto wiedzieć, że każdy wyświetlany tekst w bibliotece SFML jest skalowany. Jakość wyświetlanego tekstu zależy od rozmiaru czcionki w jakim została załadowana, w stosunku do rozmiaru w jakim chcemy ją wyświetlić. Jakość idealną uzyskujemy oczywiście wtedy gdy rozmiar czcionki wczytanej jest taki sam jak rozmiar czcionki jaki chcemy wyświetlić - wówczas współczynnik skalowania wynosi 1.0 i wszelkie efekty uboczne schodzą na drugi plan, a dokładniej rzecz ujmując to w zasadzie nie mają one miejsca.
Czcionkę skaluje się za pomocą znanej już Ci metody Scale, która należy do klasy sf::String. Ponadto do dyspozycji mamy metodę SetSize za pomocą której możemy określić rozmiar czcionki, który wyrażamy w pikselach. Jeżeli chcemy pobrać aktualny rozmiar czcionki to możemy do tego celu wykorzystać metodę GetSize klasy sf::String. Tak więc jeżeli zechcemy wyświetlić czcionkę 5 razy większą niż aktualna to wystarczy napisać:
C/C++
tekst.SetSize( tekst.GetSize() * 5 );
Czcionka podczas renderowania zostanie przeskalowana do rozmiaru jaki chceliśmy i będziemy się teoretycznie cieszyć z uzyskania pożądanego efektu. Radość niestety długo trwać nie będzie i uleci z nas gdy zobaczymy efekt 5-krotnego powiększenia czcionki:

Czcionka powiększona 5-krotnie w stosunku do oryginału
Czcionka powiększona 5-krotnie w stosunku do oryginału

Czcionka wektorowa

Aby uzyskać czcionkę ładniejszą niż ta, którą przed chwilą otrzymaliśmy, będziemy musieli wczytać czcionkę w lepszej jakości niż ta, którą obecnie stosujemy. Do tego celu będziemy musieli wykorzystać np. plik, który posiada czcionkę zapisaną za pomocą formuł matematycznych i wygenerować ją w takich rozmiarach, które będą dla nas satysfakcjonujące. Choć zabawa z odczytaniem formuł matematycznych brzmi groźnie to w rzeczywistości nic nas one nie będą obchodziły, bowiem biblioteka SFML załatwia tą sprawę za nas. Jedyne czego biblioteka SFML będzie od nas wymagała to podanie nazwy pliku z którego czcionka ma zostać wczytana oraz rozmiar czcionki w jakim chcemy uzyskać idealną jakość. Skoro jesteśmy bogatsi o to jak wyglądają sprawy w teorii, zajmijmy się teraz stroną praktyczną.

Biblioteka SFML dostarcza klasę » SFML 1.6Font. Klasa ta służy do wczytywania czcionek i w sumie posługujemy się nią analogicznie do klasy, którą wykorzystywaliśmy do wczytywania obrazków. Aby załadować czcionkę należy utworzyć obiekt typu » SFML 1.6Font, a następnie wywołać metodę » SFML 1.6 » FontLoadFromFile, której podajemy między innymi nazwę pliku z którego ma zostać odczytana czcionka jak również rozmiar czcionki jaki chcemy otrzymać. Metoda » SFML 1.6 » FontLoadFromFile zwraca wartość true w przypadku gdy załadowanie czcionki się powiodło. W przeciwnym wypadku metoda zwróci wartość false.

Czcionka zazwyczaj nie wczytuje się gdy plik z podaną nazwą czcionki nie istnieje (co jest oczywiste), jednak z tymi oczywistościami najczęściej programiści przychodzą na forum i żalą się, że 'coś nie działa'. Zanim więc podejmiesz się i Ty zakładania takiego tematu sprawdź czy ścieżka do pliku z czcionką jest prawidłowa i czy format pliku jest obsługiwany przez bibliotekę SFML. Nawet jeżeli sprawdzisz i czcionka nie będzie Ci działała to na forum i tak udowodnią Ci, że masz ścieżkę złą i dlatego Ci czcionka nie działa. Pamiętaj o tym :)

Wczytywanie czcionki z katalogu roboczego dla aplikacji może wyglądać tak:
C/C++
sf::Font mojaCzcionka;
mojaCzcionka.LoadFromFile( "arial.ttf", 30 * 5 );

Pamiętaj, że czcionka jest obiektem 'ciężkim' tak samo jak było to w przypadku obrazka. Oznacza to, że tworzenie tego obiektu w pętli głównej aplikacji i ciągłe ładowanie czcionki nie jest trafionym pomysłem, bowiem cała aplikacja zacznie Ci działać po prostu wolno. Ładowanie czcionek z których korzystamy powinno odbywać się przed wejściem w pętlę główną. Nie jest to oczywiście wymogiem, niemniej jednak trzeba być świadomym jak ta klasa działa by nie zaszkodzić wydajności tworzonej aplikacji.

Zmiana czcionki domyślnej

Aby zacząć się cieszyć nowo załadowaną czcionką to wystarczy wskazać obiektowi typu sf::String by ten korzystał z nowej czcionki. Do tego celu wykorzystać możemy metodę SetFont lub drugi argument konstruktora klasy sf::String. Oto fragment kodu, który wyświetli nam tekst za pomocą załadowanej czcionki:
C/C++
//Przed pętlą główną:
sf::Font mojaCzcionka;
mojaCzcionka.LoadFromFile( "arial.ttf", 30 * 5 );

//W pętli głównej:
sf::String tekst( L"Kurs SFML, C++ - http://cpp0x.pl" );
tekst.SetSize( tekst.GetSize() * 5 );
tekst.SetFont( mojaCzcionka );
oknoAplikacji.Draw( tekst );
Teraz nasza czcionka wygląda tak:

Czcionka 5-krotnie większa bez utraty jakości
Czcionka 5-krotnie większa bez utraty jakości

Jeżeli w Twojej aplikacji czcionka się nie wyświetliła to prawdopodobnie nie udało załadować się czcionki, bądź nie wywołałeś metody Display dla okna aplikacji.

Kod, który demonstruje różnice w jakości czcionek:
C/C++
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow oknoAplikacji( sf::VideoMode( 800, 600, 32 ), "Kurs SFML - http://cpp0x.pl" );
    sf::Font mojaCzcionka;
    mojaCzcionka.LoadFromFile( "arial.ttf", 30 * 5 );
   
    while( oknoAplikacji.IsOpened() )
    {
        sf::Event zdarzenie;
        while( oknoAplikacji.GetEvent( zdarzenie ) )
        {
            if( zdarzenie.Type == sf::Event::Closed )
                 oknoAplikacji.Close();
           
        } //while
       
        oknoAplikacji.Clear( sf::Color::White );
        sf::String tekst( L"cpp0x.pl" );
        tekst.SetColor( sf::Color::Black );
        tekst.SetSize( tekst.GetSize() * 5 );
        oknoAplikacji.Draw( tekst );
        tekst.SetPosition( 0, 200 );
        tekst.SetFont( mojaCzcionka );
        oknoAplikacji.Draw( tekst );
        oknoAplikacji.Display();
    } //while
    return 0;
}

Polskie litery

Jeżeli przyjdzie taki dzień w którym zechcesz wyświetlać polskie litery w swojej aplikacji to natrafisz na problem, który będzie się objawiał niewyświetlaniem polskich liter. Problem ten wynika z faktu, że domyślnie SFML wczytuje znaki należące tylko i wyłącznie do strony kodowej ISO-8859-1, a w niej polskich liter niestety nie ma. Nie jest to oczywiście dla Ciebie żaden powód do paniki, czy też do rozpaczania, bowiem SFML umożliwa określenie znaków jakie chcemy by były wczytane przy ładowaniu czcionki. Znaki, których chcemy posiadać reprezentację graficzną należy podać jako trzeci argument metody » SFML 1.6 » FontLoadFromFile, która należy do klasy » SFML 1.6Font. Przykładowo możemy wczytać reprezentację tylko 3 wybranych znaków w następujący sposób:
C/C++
sf::Font mojaCzcionka;
mojaCzcionka.LoadFromFile( "arial.ttf", 30 * 5, L"ąXć" );
Znaki, które nie zostały wczytane nie będą się po prostu wyświetlały.

Przykład

Oto przykład podsumowujący niniejszy rozdział:
C/C++
#include <SFML/Graphics.hpp>

const sf::Unicode::Text ZnakiPL()
{
    std::wstring znaki;
    znaki = L"abcdefghijklmnopqrstuvwxyz";
    znaki += L"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    znaki += L"0123456789";
    znaki += L"ąćęłńóśźż";
    znaki += L"ĄĆĘŁŃÓŚŹŻ";
    znaki += L" !@#$%^&*()_-=+\\|[]{}:;\"',./<>?~`";
    //tu można dopisać jeszcze inne znaki, które chcemy mieć zaimportowane
    return znaki;
}

int main()
{
    sf::RenderWindow oknoAplikacji( sf::VideoMode( 800, 600, 32 ), "Kurs SFML - http://cpp0x.pl" );
    sf::Font mojaCzcionka;
    mojaCzcionka.LoadFromFile( "arial.ttf", 30 * 5, ZnakiPL() );
   
    while( oknoAplikacji.IsOpened() )
    {
        sf::Event zdarzenie;
        while( oknoAplikacji.GetEvent( zdarzenie ) )
        {
            if( zdarzenie.Type == sf::Event::Closed )
                 oknoAplikacji.Close();
           
        } //while
       
        oknoAplikacji.Clear( sf::Color::Black );
        sf::String tekst( L"abcd ąłĆ" );
        tekst.SetSize( tekst.GetSize() * 5 );
        oknoAplikacji.Draw( tekst );
        tekst.SetPosition( 0, 200 );
        tekst.SetFont( mojaCzcionka );
        oknoAplikacji.Draw( tekst );
        oknoAplikacji.Display();
    } //while
    return 0;
}

Pozostałe informacje

W niniejszym rozdziale nie zostały omówione wszystkie możliwości obsługi tekstu jakie są dostępne w bibliotece SFML. Więcej informacji na temat możliwości poszczególnych klas biblioteki SFML możesz znaleźć w dokumentacji, która znajduje się na łamach niniejszego serwisu w dziale » DokumentacjaSFML 1.6, a także na oficjalnej stronie biblioteki SFML.
Poprzedni dokument Następny dokument
Wyświetlanie prymitywów Ograniczanie obszaru modyfikowania sceny