Hlavní navigace

Knihovna Clanlib (3)

Petr Kavánek 24. 5. 2004

V tomto dílu, jak jsem již slíbil, vytvoříme první aplikaci. Přiblížíme si přitom celkovou logiku knihovny. Chybět samozřejmě nebude ani návod, jak nastavit některá vývojová prostředí (Kdevelop 2.1.3, VisualStudio 6.0). Ti z vás, kteří budou psát makefile ručně, možná odcení uvedený příklad.

První aplikace

Naším cílem bude vytvoření jednoduchého okna vyplněného černou barvou s titulkem „Ahoj, svete!“ a s logem knihovny uprostřed. Okno se zavře po stisknutí klávesy escape.

Aplikace se bude skládat z jednoho hlavičkového souboru Ahoj.h a jednoho zdrojového souboru Ahoj.cpp.

Hlavičkový soubor bude vypadat následovně:

#ifndef AHOJ_H
#define AHOJ_H

// hlavickove souhory ClanLibu
#include <ClanLib/core.h>
#include <ClanLib/application.h>
#include <ClanLib/gl.h>
#include <ClanLib/display.h>


/************************************************
*              T_AhojSveteApp                   *
************************************************/

// Potomek CL_ClanApplication nutny pro fungovani
// knihovny ClanLib. Bude nutne vytvorit jednu
// globalni instanci teto tridy!!! Nikde v programu
//  nebudeme deklarovat klasickou funkci main()
// nebo WinMain() jak jsme byli dosud zvykli!!!

class T_AhojSveteApp : public CL_ClanApplication {

// verejne metody:
public:

  // Zastupuje klasickou funkci main. Prebira
  // parametry z prikazoveho radku.
  virtual int main(int argc, char** argv);

}; // T_AhojSveteApp ****************************

#endif

V hlavičkovém souboru nejprve includujeme jednotlivé části knihovny, které budeme potřebovat pro náš program (core.h, application.h, gl.h a display.h). Dále následuje hlavička třídy T_AhojSveteApp, odvozené od CL_ClanApplication, s jedinou virtuální metodou main().

Jelikož existuje nejednotnost v pojmenování první spuštěné funkce (např. Main(), WinMain()) a jelikož ClanLib je multiplatformová knihovna, rozhodli se autoři řešit tento problém tím, že první funkci zapouzdří přímo do knihovny.

Pro nás to znamená prostě ten příjemný fakt, že naše virtuální metoda main() se bude na všech platformách chovat jako první funkce programu. Proto bude nutné vytvořit právě jednu globální instanci naší třídy T_AhojSveteApp a nikde nepsat klasickou funkci main() (příp. WinMain() a podobně).

Podívejme se tedy na vlastní implementaci v souboru Ahoj.cpp:

#include "Ahoj.h"

#include <iostream>
#include <string>

// nezbytna globalni instance teto tridy
T_AhojSveteApp AhojSveteApp;

//-----------------------------------------------
// main()
//-----------------------------------------------
int T_AhojSveteApp::main(int argc, char** argv) {

  using namespace std;

  // vytvorime okno konzole kvuli textovemu vystupu
  // jako jsou zpravy o chybach
  CL_ConsoleWindow Console("Konzole");

  // presmerujeme na konsoli standardni vstup a vystup
  Console.redirect_stdio();

  try {

    // nutna inicializace pouzivanych casti knihovny
    CL_SetupCore::init();
    CL_SetupDisplay::init();
    CL_SetupGL::init();

    // vytvorime okno 640 x 480 pixelu s titulkem Ahoj, Svete!
    const string Titulek = "Ahoj, Svete!";
    const int SirkaOkna = 640;
    const int VyskaOkna = 480;
    const bool FullScreen = false;
    CL_DisplayWindow NaseOkno(Titulek, SirkaOkna, VyskaOkna, FullScreen);

    // vytvorime obrazek (logo knihovny ClanLib)
    const string CestaKObrazku = "clanlib.png";
    CL_Surface Logo(CestaKObrazku);

    // souradnice Loga
    const int LogoX = 170;
    const int LogoY = 180;

    // pockame si na stisteni klavesy escape
    while (! CL_Keyboard::get_keycode(CL_KEY_ESCAPE)) {

      // invariant: Dosud nebyl stisten escape pri get_keycode()

      // vyplnime okno cernou barvou
      CL_Display::clear(CL_Color::black);

      // vykreslime logo, souradnice udavaji polohu
      // leveho horniho rohu
      Logo.draw(LogoX, LogoY);

      // zobrazime nakreslene zmeny (prehozeni
      // predniho a zadniho bufferu)
      CL_Display::flip();


      // uspime aplikaci na deset milisekund,
      // abychom zbytecne neblokovali procesor
      const int DobaObnoveni = 10;
      CL_System::sleep(DobaObnoveni);

      // probudime aplikaci resp. knihovnu aby
      // byla aktualni
      CL_System::keep_alive();

    } // while

    // deinicializujeme drive inicializovane casti knihovny
    CL_SetupGL::deinit();
    CL_SetupDisplay::deinit();
    CL_SetupCore::deinit();

  } // try
  catch (CL_Error Chyba) {

    cout << "Zachycena chyba: " << Chyba.message.c_str() << endl;

    // zavreme okno konzole a pockame na stisk klavesy
    Console.display_close_message();

    // ukoncime aplikaci, jedna signalizuje neuspech
    return 1;

  } // catch

  // ukoncime nasi aplikaci, nula signalizuje uspech
  return 0;

} // main() ------------------------------------- 

V první řadě vytvoříme z výše popsaných důvodů jedinou instanci třídy T_AhojSveteApp.

Následuje implementace metody main(). Hned na začátku vidíme jeden z typických a velice užitečných obratů při programování s ClanLibem. Vytvoříme totiž nejprve textovou konzoli a přesměrujeme na ni standardní vstup a výstup. Využijeme ji k zobrazování informací o chybách a případných ladících výpisů.

ClanLib definuje třídu výjimek CL_Error, které vyvolává v případě chybových stavů. Je tedy velice vhodné zbytek kódu umístit do chráněného bloku try{}, v bloku catch{} odchytávat tyto ClanLibovské výjimky a vypisovat jejich hlášení na konzoli, případně se rozhodovat, co dál. V našem příkladu vypíšeme na konzoli ještě ukončovací zprávu a program ukončíme.

Podívejme se tedy dovnitř chráněného bloku. Nejprve inicializujeme použité části knihovny. Syntaxe inicializace a deinicializace je jednotná:

CL_SetupXXX::init();
CL_SetupXXX::deinit();

Zde XXX zastupuje jméno inicializované (deinicializované) části knihovny. Deinicializaci provádíme na konci chráněného bloku tj. na konci programu.

Po inicializaci vytvoříme hlavní okno s příslušnými parametry v konstruktoru:

CL_DisplayWindow NaseOkno(Titulek, SirkaOkna, VyskaOkna, FullScreen); 

Nyní vytvoříme obrázek loga:

CL_Surface Logo(CestaKObrazku);

Poznamenáme si také souřadnice tohoto obrázku. K podporovaným formátům patří .tga, .png, .pcx, .jpg.

Následuje while smyčka, která končí v momentě, kdy stiskneme klávesu escape. Přesně řečeno příkaz

CL_Keyboard::get_keycode(CL_KEY_ESCAPE)

vrací true, pokud je v momentě jeho provedení stisknut escape. Zanedbáváme tedy jisté riziko, že se někomu podaří escape stisknout na dobu kratsí než deset milisekund a program se neukončí. S tím se však myslím dokážeme nyní smířit :-).

Uvnitř while cyklu nejprve vyplníme okno černou barvou. Ekvivalentně bychom mohli použít příkaz:

// vyplnime okno barvou rgba
CL_Display::clear(CL_Color(0, 0, 0, 0));

Dále vykreslíme obrázek Loga:

Logo.draw(LogoX, LogoY);

Přitom LogoX, LogoY budou souřadnice levého horního rohu.

Jelikož ClanLib používá double buffering, projeví se naše kreslení až po příkazu:

CL_Display::flip();

Double buffering je zjednodušeně řečeno metoda, při níž kreslíme do zadního bufferu, zatímco přední buffer se vykresluje na obrazovku. Tím je umožněna lepší synchronizace s monitorem a rychlejší vykreslování.

Nakonec naši aplikaci na chvilinku, tj. asi na 10 milisekund, uspíme, abychom neblokovali ostatní programy, a poté ji opět probudíme příkazy:

CL_System::sleep(DobaObnoveni);
CL_System::keep_alive();

Nastavení KDevelop

V KDevelop 2.1.3 můžeme postupovat následovně. Nejprve vytvoříme nový Terminal C++ projekt (Project → New → Terminal C++ ->… zadáme jméno projektu a další údaje, pokud chceme … vypneme automatické generování generate sources and headers" → Create → Exit).

Nyní v menu Project Options (Project → Options) v záložce Configure-Settings zatrhneme use exception handling. Knihovna používá výjimky a nám se budou hodit.

Ve stejnem menu v záložce Compiler Options ve Flags and Warnings napíšeme do textového pole C Preprocessor flags (CPPFLAGS) následující řetězec:

`pkg-config --cflags clanCore-0.7 clanDisplay-0.7 clanApp-0.7 clanGL-0.7` 

Podobně v Linker Flags napíšeme do textového pole:

`pkg-config --libs clanCore-0.7 clanDisplay-0.7 clanApp-0.7 clanGL-0.7` 

Zde máme tedy jeden ze slibovaných příkladů využití Pkg-configu popsaného v minulém dílu.

Nyní vytvoříme nový hlavičkový soubor Ahoj.h (File → New ->… OK). Podobně vytvoříme nový zdrojový soubor Ahoj.cpp. Tyto soubory budou obsahovat výše uvedený kód.

Pokud jsme již soubory Ahoj.h a Ahoj.cpp vytvořili dříve, můžeme je rovnou vložit do projektu (Project → Add existing file(s) → … nalistujeme vytvořené soubory a potvrdíme – je možné vybrat několik souborů najednou). Tento postup se nám může hodit například při portování rozsáhlejší aplikace z Windows.

Nyní už nic nebrání tomu, abychom náš program zkompilovali a spustili. V menu Build provedeme postupně Autoconf and Automake,Confi­gure…, Compile File a Execute.

Nastavení Visual Studia 6.0

Nejprve vytvoříme nový projekt (New->Projects->Win32 Application) pojmenovaný třeba „Ahoj“.

V menu Project Settings (Project → Settings) v záložce C/C++ vybereme kategorii (Category:) Code Generation a ujistíme se, že pod Use run-time library je zadáno Debug Multithreaded v případě debug verze, neboMultithreaded v případě release verze.

Pokud máme dobře nastavené cesty k hlavičkovým souborům a knihovnám ClanLibu, jak bylo popsáno v minulém dílu (Tools → Options → Directories), stačí již jen vytvořit příslušný hlavičkový a zdrojový soubor s obsahem popsaným výše a program zkompilovat.

Ručně psaný makefile

Nakonec se ještě podíváme, jak by mohl vypadat ručně napsaný makefile našeho programu:

PACKAGES = clanCore-0.7 clanDisplay-0.7 clanApp-0.7 clanGL-0.7
CPPFLAGS = `pkg-config --cflags $(PACKAGES)`
LIBS = `pkg-config --libs $(PACKAGES)`
OBJS = Ahoj.o
GCC = g++

all: $(OBJS)
      $(GCC) $(CPPFLAGS) -o Ahoj $(OBJS) $(LIBS)

ahoj.o: Ahoj.cpp Ahoj.h
      $(GCC) $(CPPFLAGS) -c Ahoj.cpp $(LIBS)
clean:
      -rm -rf *.o
      -rm Ahoj 

Závěrem

Na konci tohoto dílu bych ještě rád podotkl, že je na světě ClanLib verze 0.7.8, a také, že vývojáři ClanLibu začali intenzivně pracovat na podpoře MacOS.

Zdrojové kódy zahrnující i KDevelopí project file dnes vytvořeného programu si můžete stáhnout zde. Logo knihovny použité v programu je zde.

V příštím dílu se podíváme na to, jak se v ClanLibu pracuje se soubory pro definování zdrojů, což je můj překlad resource definition files. Ty nám umožní velmi pohodlně psát programy konfigurovatelné zvenčí, tj. bez nutnosti kompilovat program kvůli změně nějakého konfiguračního ú­daje.

Našli jste v článku chybu?

27. 5. 2004 23:28

mYr0Ch (neregistrovaný)

jednoznaczne sqelee...
jeste navod pro KDevelop 3.0:
Project - New project - Simple hello world program - napsat nazev, zde ahoj. potom jiz jen nastavit v Project - Project Options - Configure Options vyse uvedene hodnoty (CPPFLAGS a LDFLAGS). Pokud vam program hlasi chybu pri kompilaci zapnete si plny vypis hlaseni (prave tlacitko mysi na vypisu a polozka Full Compiler Output)



26. 5. 2004 18:30

Petr Kavanek (neregistrovaný)

Ano presne tak. Tedy presneji receno 10 ms plus doba vykonavani kodu, coz je samozrejme zanedbatelne v tomto pripade. U vetsich vypoctu uz by to mohlo hrat jitou roli. Smycka tak jak je napsana zarucuje ze se okno prekresli maximalne 100x za sekundu.
Jistou roli ve skutecnem poctu vykresleni muze hrat i to, ze prikaz flip() se nejakym zpusobem synchronizuje s frekvenci monitoru tj. pokud se nas monitor 100x za sekundu neprekresli, tak se na nem tezko 100x za sekundu bude prekreslovat okno, ale…

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: ČRo rozšiřuje DAB do Berouna

ČRo rozšiřuje DAB do Berouna

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Vitalia.cz: 9 největších mýtů o mase

9 největších mýtů o mase

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Lupa.cz: Google měl výpadek, nejel Gmail ani YouTube

Google měl výpadek, nejel Gmail ani YouTube

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře