Programovací jazyk Ada: jednoduchá aplikace v GtkAda

Jaromír Vojtaj 23. 7. 2015

V minulém dílu jsme si ukázali, jak upravit vývojové prostředí pro použití GPS s nejnovější verzí GNAT. Zahájili jsme popis nástrojů pro vývoj aplikací s grafickým rozhraním GtkAda včetně vytvoření první jednoduché aplikace. V dnešním dílu se budeme věnovat dalším úpravám aplikace v GtkAda.

Na začátku dnešního dílu si znovu uvedeme kód ze souboru main.adb, tentokrát i s číslováním řádků:

with Gtk.Box;         use Gtk.Box;                                      --1
with Gtk.Button;      use Gtk.Button;                       --2
with Gtk.Label;       use Gtk.Label;                            --3
with Gtk.Widget;      use Gtk.Widget;                           --4
with Gtk.Main;                                      --5
with Gtk.Window;      use Gtk.Window;                           --6
with Gtkada.Handlers;    use Gtkada.Handlers;                   --7

procedure main is                               --8

   Win : Gtk_Window;                                --9
   Label : Gtk_Label;                               --10
   Box : Gtk_Vbox;                              --11

begin                                       --12

   -- Initialize GtkAda                             --13
   Gtk.Main.Init;                               --14

   -- Create a window with a size of 400x400                    --15
   Gtk_New (Win);                               --16
   Win.Set_Default_Size (400, 400);                     --17

   -- Create a box to organize vertically the contens of the window     --18
   Gtk_New_Vbox (Box);                                              --19

   -- Add a label                               --20
   Gtk_New (Label, " Hello world.");                        --21
   Win.Add (Label);                                 --22

   -- Show the window                               --23
   Win.Show_All;                                --24

   -- Start the Gtk+ main loop                          --25
   Gtk.Main.Main;                                   --26
end Main;                                   --27

Na prvních sedmi řádcích kódu se specifikují jednotlivé součásti (třídy) Gtk, tzv. widgety (viditelné či neviditelné komponenty, ze kterých se skládá uživatelské prostředí aplikace). V našem konkrétním případě jsou zde k dispozici pro další využití widgety Box, Button, Label a Window. Pak je definován obecný Widget a také nástroj, který zatím necháme stranou – Handlers. Poslední bychom zmínili nejdůležitější definici, bez které není možné žádný GtkAda projekt vytvořit – Gtk.Main. Pokud bychom o této funkci (či ostatních, které jsme uvedli nebo neuvedli) chtěli získat více informací, je možné se s důvěrou obrátit na referenční manuál GtkAda na AdaCore: GtkAda referenční manuál. Zde si můžeme najít všechny potřebné informace o tom, jaké další funkce či procedury daná třída obsahuje, co dělají a jak je třeba je volat. Podrobněji to ale necháme na další text článku.

Řádek osm je jasný a nezajímavý.

Na řádcích 9 – 11 jsou deklarované tři proměnné, které mají typy tříd Window, Label a Box. Konkrétně se jedná o typy Gtk_Window, Gtk_Label a Gtk_Vbox. Pokud se na ně podíváme do referenčního manuálu, tak zjistíme, že se jedná o typy ukazatelů (Access). To pro nás zatím není nijak důležité.

Velmi důležitý je řádek 14. Tento příkaz musí být vždy umístěn v kódu jako první, hned po příkazu begin těla příslušné procedury. Bez něj by se totiž kód nedal přeložit. Pokud si opět tuto funkci najdeme v manuálu, dozvíme se následující:

Init
89  procedure Init;

Initialize GtkAda's internal structures. This subprogram should be called before any other one in GtkAda. If GtkAda could not be initialized (no access to the display, etc.), the application exits with an error

Více komentářů snad již není třeba…

Na řádku 16 se volá procedura Gtk.Window.Gtk_New a přiřadí se jí parametr z deklarované proměnné Win na řádku 9.

Na řádku 17 se nově vytvořené instanci třídy Window přiřadí jeden z možných parametrů Set_Default_Size. Jedná se samozřejmě o parametr, který určuje základní velikost okna jako kombinaci hodnot šířka x výška.

Na řádku 19 se volá procedura Gtk.Box.Gtk_New_Vbox s parametrem proměnné Box.

Na řádku 21 se volá procedura Gtk.Label.Gtk_New, kam se přidávají dva parametry – proměnná Label a text, který bude v tomto widgetu zobrazen.

Na řádku 22 je nový příkaz, který přidává na minulém řádku definovaný widget do hlavního okna. To je nutné proto, aby byl v okně viditelný, samotná definice k tomu nestačí.

Na řádku 24 je pak příkaz, který provede zobrazení hlavního definovaného okna aplikace.

Na řádku 26 je poslední zajímavý příkaz. Manuál o něm praví toto:

Main
224 procedure Main;

Runs the main loop until Gtk.Main.Main_Quit is called. You can nest calls to Gtk.Main.Main. In that case Gtk.Main.Main_Quit will make the innermost invocation of the main loop return.

Tento příkaz spouští tzv. hlavní smyčku, tedy vlastně vytvořenou aplikaci. Zmíněným příkazem pro ukončení běhu se zatím nebudeme zabývat.

Tímto bychom mohli považovat krátkou analýzu generovaného kódu za ukončenou. Ještě než se pustíme dál, zkusíme zjistit ještě něco víc o našem projektu.K tomu by asi bylo dobré si zobrazit i kód, který je v souboru gtkada1.gpr. V minulém dílu byl pouze na obrázku, takže dnes si ho ukážeme v kódu:

with "gtkada";

project Gtkada1 is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");
   type Gtkada_Kind_Type is
      ("static", "relocatable");
   Library_Type : Gtkada_Kind_Type := external ("LIBRARY_TYPE");

   --  Enable Ada 2005.
   package Compiler is

      case Library_Type is

         when "static" =>
            for Default_Switches ("ada") use ("-g", "-gnat12");

         when "relocatable" =>
            for Default_Switches ("ada") use ("-gnat05");
      end case;
   end Compiler;

   package Builder is

      case Library_Type is

         when "static" =>
            for Default_Switches ("ada") use ("-s", "-g", "-j4");

         when "relocatable" =>

      end case;
   end Builder;

   package Linker is

      case Library_Type is

         when "static" =>
            for Default_Switches ("ada") use ("-g");

         when "relocatable" =>

      end case;
   end Linker;

end Gtkada1;

Kód nebudeme zatím nijak rozebírat, protože se jedná o soubor automaticky generovaný prostředím GPS.

Avizovaná úprava projektu bude pouze jedna a bude se jednat o opravdu jednoduchou úpravu kódu – zakomentujeme 2. a 7. řádek. Změnu uložíme a zkusíme překlad. Ten proběhne bez problémů a spuštění aplikace také. Ve druhé fázi zakomentujeme ještě 4. řádek, takže celý začátek procedury bude vypadat následovně:

with Gtk.Box;         use Gtk.Box;                                      --1
--with Gtk.Button;      use Gtk.Button;                     --2
with Gtk.Label;       use Gtk.Label;                            --3
--with Gtk.Widget;      use Gtk.Widget;                         --4
with Gtk.Main;                                      --5
with Gtk.Window;      use Gtk.Window;                           --6
--with Gtkada.Handlers;    use Gtkada.Handlers;                     --7

Pokud by se někdo nad původním kódem trochu zamyslel, tak jsou naše dvě úpravy asi zřejmé. Žádné proměnné typu Button a Handlers nejsou v proceduře použité, takže není ani nutná definice odkazů na ně. V případě typu Widget už to sice tak úplně jasné není, ale přece jenom nebyl nikde v kódu explicitně použit. Na překlad a funkčnost aplikace nemají provedené změny žádný vliv. Jedinou pozorovatelnou změnou je velikost spustitelného souboru, která se po zakomentování všech tří řádků zmenší o cca 3.5 %. Není to sice nic světoborného, ale někdy může hrát roli každá maličkost a je dobré vědět, že zbytečné odkazy na knihovny také „něco stojí“.

Několikrát už jsme narazili na spuštění aplikace: aplikace se samozřejmě spustí a zobrazí okno, jak je vidět na prvním obrázku v galerii. Okno je samozřejmě možné zavřít klasickým způsobem pomocí ikony v pravém horním rohu. Okno se tímto způsobem (jiný zatím nemáme definovaný) sice poslušně zavře, ale to ještě neznamená, že došlo k ukončení aplikace. To je velmi dobře poznat přímo v GPS. Na druhém obrázku v galerii tak vidíme, že na horní liště mezi akčními ikonami a editačním polem pro hledání zůstala „viset“ akce Run Main. Spuštěnou aplikaci je možné řádně ukončit pomocí ikony křížku za názvem spuštěné aplikace v této sekci. Pokud bychom provedli spuštění aplikace znovu (bez ohledu na to, jestli došlo ke změně kódu a novému překladu), objeví se zde již jenom počet stále běžících úloh – viz třetí obrázek. Když je zde zobrazeno více spuštěných úloh, není možné je ukončit pomocí malých ikonek s křížky. Je nutné použít hlavní menu Tools → Interrupt nebo kombinaci kláves Shift+Ctrl+C (samozřejmě opakovaně podle počtu běžících úloh).

Popisovaná skutečnost souvisí s posledním příkazem v kódu:

--  Start the Gtk+ main loop
   Gtk.Main.Main;

Vysvětlení z referenčního manuálu bylo uvedeno výše v textu. Příkazem spuštěná smyčka tedy běží do té doby, než je vyvolán příkaz pro její ukončení. To my jsme ale zatím neprovedli, a proto se aplikace řádně neukončí.

Další úpravy aplikace z minulého dílu budeme směřovat na dva úseky: přidání a nastavení dalších widgetů a reakce widgetů na uživatelské podněty. Jako první si ukážeme přidání důležitého widgetu – tlačítka. Za tímto účelem upravíme kód aplikace následovně:

widgety

  • odkomentujeme druhý řádek s odkazem na knihovnu Gtk.Button
  • změníme a doplníme deklaraci proměnných:
       VBox   : Gtk_Vbox;
       Button1, Button2, Button3 : Gtk_Button;
       HBox : Gtk_Hbox;
  • změníme kód pro vytvoření V-Boxu:
    Gtk_New_Vbox (VBox);
  • změníme kód pro vytvoření Labelu:
    Gtk_New (Label, "Hello world.");
       VBox.Add(Label);
  • přidáme nový widget typu Button :
    Gtk_New(Button1,"Button1");
    VBox.Add(Button1);
  • V-Box přidáme do hlavního okna:
    Win.Add (VBox);

Změny uložíme a spustíme překlad. Překladač sice hlásí nevyužití některých deklarovaných proměnných, ale proběhne bez problémů. Spuštěná aplikace je pak vidět na posledním obrázku v galerii.

V dnešním dílu jsme si ukázali a okomentovali kód jednoduchého příkladu v GtkAda. Vygenerovaný kód jsme velmi jednoduše upravili a ukázali si přidání dalšího widgetu. V dílu příštím pak přidáme další widgety a hlavně se podíváme na možnosti vytvoření jejich reakcí na uživatelské podněty.

Našli jste v článku chybu?
DigiZone.cz: DVB-T2 ověřeno: seznam TV zveřejněn

DVB-T2 ověřeno: seznam TV zveřejněn

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

Vitalia.cz: Dostal malý pivovar ze Slovenska do Tesca

Dostal malý pivovar ze Slovenska do Tesca

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

DigiZone.cz: Funbox 4K v DVB-T2 má ostrý provoz

Funbox 4K v DVB-T2 má ostrý provoz

DigiZone.cz: Numan Two: rozhlasový přijímač s CD

Numan Two: rozhlasový přijímač s CD

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Lupa.cz: Hackeři mají data z půlmiliardy účtů Yahoo

Hackeři mají data z půlmiliardy účtů Yahoo

DigiZone.cz: O2 Sport zbrojí na derby pražských S

O2 Sport zbrojí na derby pražských S

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

DigiZone.cz: Koncesionářské poplatky pro RTVS

Koncesionářské poplatky pro RTVS

Lupa.cz: Jak se prodává firma za miliardu?

Jak se prodává firma za miliardu?

Podnikatel.cz: Chystá se smršť legislativních novinek

Chystá se smršť legislativních novinek

DigiZone.cz: Mordparta: trochu podchlazený 87. revír

Mordparta: trochu podchlazený 87. revír