Proč?
Jaký smysl má vytvářet programy pro grafické prostředí? Grafické prostředí používají všichni, ať už to jsou začátečníci nebo profesionálové. Jediný rozdíl spočívá v tom, že jakmile začátečníkovi řeknete ať zadá příkaz xy, pak se vás zeptá kam ho má napsat, nebo to rovnou odmítne provést, protože to není dostatečně klikací operací.
Z toho je jasné, že tyto aplikace pomáhají především začátečníkům, zejména pak těm zvyklých např. na MS Windows. Je to ovšem opravdu tak? I když je použití řady konzolových programů snadné, zpravidla dříve či později donutí svého uživatele k přečtení manuálové stránky programu, která nemusí být zrovna lehkým čtením před spaním. Tady i pokročilý uživatel jistě sáhne po grafické nadstavbě konzolových aplikací, zejména pokud je tento program dostatečně kvalitní - tzn. především intuitivní a pokrývá běžné potřeby většiny uživatelů.
V následujícím textu se podíváme na to, jak se vytváří taková grafická aplikace s použitím programovacího jazyka Ruby. Omezíme se přitom na jednu z možností - na komponenty GTK, které používá desktopové prostředí GNOME. Toto zpřístupnění GTK jazyku Ruby je součástí projektu Ruby-GNOME2.
O programovacím jazyku Ruby jsme už psali. Pokud Ruby neznáte, pak se s námi můžete Ruby naučit. Vše najdete v seriálu Naučte se Ruby. Pokud vás bude naopak zajímat programování pro desktopové prostředí KDE, pak se podívejte na projekt QtRuby. To však přesahuje rozsah našeho článku a tak se mu věnovat nebudeme.
Nejsem programátor
Nevadí, já také ne. Chtěli byste se podívat jak vzniká program, nebo si rovnou nějaký napsat? Nikdo vám v tom bránit nebude, naopak. Stačí mít dobrou myšlenku (jak by měl takový program vypadat a co by měl všechno umět) a chuť do programování. Zbytek přijde sám. Pravděpodobně váš první program nebude kancelářskou sadou programů, ani populárním prohlížečem webových stránek, ale třeba bude dělat to co jiný program v příkazové řádce, třeba ho k tomu bude i používat, ale bude to dělat na první pohled jinak, lépe a v pěkném kabátku desktopové aplikace.
Je zcela jedno jestli program vytvoříte v neděli po obědě, nebo bude vznikat postupně po večerech, tak jak budete mít volnou chvíli a bude se vám chtít. Stejně jako ve sportu, i na programování se dají vydělat velké peníze, nebo to celé můžete dělat jen proto, protože chcete a že vás to baví.
Jsem programátor, má cenu číst dál? Pokud neznáte Ruby, pak ano. Pokud znáte Ruby, pak rozhodně ano. Nejsem programátor tak je docela možné, že můj postup je příliš naivní a složitý, pak hledejte chyby a pište připomínky.
Pojďme programovat
K tomu budeme potřebovat Ruby. Kromě něj i nějaké další knihovny. Jaké to jsou se dozvíte jakmile vám překladač Ruby zahlásí chybu, že vám něco chybí. Co to přesně je se dozvíte zpravidla po chvíli hledání na Internetu. Abych vám to trochu usnadnil, tak si určitě nainstalujte ruby-gnome2, pro podporu grafických komponent GTK a také libgettext-ruby pro lokalizaci vašich aplikací.
Nevím jak vy, ale já nemám rád takové ty aplikace typu Hello World!, které sice ukáží, že to funguje a základ toho, jak to funguje, ale program na tom stavět nelze. Z tohoto důvodu se pusťme rovnou do něčeho složitějšího. Bude to grafická nadstavba programu convert. Convert je součástí ImageMagick a jeho síla tkví především v tom, že vám převede snad cokoliv na jedné straně, na cokoliv na straně druhé. Prakticky tak můžete třeba převádět dokument PDF na sadu obrázků JPG nebo naopak. Těch podporovaných formátů je více než 100 a tak nemá smysl se zde o tom rozepisovat, ani jich tolik nebudeme potřebovat.
Abychom to neměli tak složité, udělejme grafickou nadstavbu příkazu convert, které bude dělat jediné - zmenšovat/zvětšovat obrázky JPG na požadovanou velikost. Není to nic úchvatného a celé by to zvládl jediný příkaz zhruba v této podobě:
convert -resize ŠířkaxVýška adresář/s/obrázky/*.jpg cílový/adresář
Skromnost až na druhém místě - je to úchvatné. Kdo tento příkaz zná, ten ho určitě použije a je s převodem obrázků hotov raz dva. Kdo ho nezná a není kamarád s příkazovou řádkou, ten to bude muset udělat jinak. Třeba pomocí našeho programu. Navíc když se vaše myšlenka zalíbí, někdo napíše další funkci, druhý přijde s novým nápadem a komplexní program pro práci s obrázky je téměř hotov. ;-)
Když píšete program, snažte se držet zdrojový kód v čitelné podobě. Dělejte tedy vhodné mezery, odražení a zdrojový kód také komentujte. Pokud pak chcete program zpřístupnit programátorům z celého světa, volte raději standardní/anglicky psané názvy proměnných, stejně tak i komentářů. Jestliže neumíte anglicky nevadí, pro začátek bude stačit slovník a trocha dobré vůle. Zdrojový kód programu by tedy neměl být nějakou tajnou šifrou, ale příjemným čtením večer před spaním.
Při těchto slovech si vždy vzpomenu na jeden výborný návod v angličtině, pod kterým nějaký rodilý Angličan uvedl, že návodu sotva rozuměl, protože použitý jazyk má do angličtiny stejně daleko jako normální člověk na měsíc. Ostatní ne-anglicky mluvící čtenáři si však návod pochvalovali, a to především díky jeho srozumitelnosti. Co z toho vyplývá? Nebojte se psát komentáře v angličtině, "naučíte" se cizí jazyk a pomůžete ostatním. ;-)
První porce kódu - hlavní okno programu
Na následujícím obrázku můžete vidět jak bude náš program vypadat. Dál se podívejme na zdrojový kód programu. Soubor si přitom nějak vhodně pojmenujte a pro úplnost mu přidejte koncovku .rb.
#!/usr/bin/ruby require 'gtk2'
Na první řádek můžete uvést v jakém programu se skript spouští (v našem případě ruby). Také nesmíme zapomenout vložit podporu komponent GTK2, to se dělá pomocí klíčového slova require.
Reference API Ruby-GNOME2 se nachází na webu této knihovny. Námi používané grafické komponenty (odborně widgety) najdete v části Ruby/GTK zmiňované dokumentace. V textu se budeme na dokumentaci jednotlivých komponent pravidelně odkazovat. Není to nadarmo, právě sem byste měli zamířit v okamžiku kdy budete hledat nějakou novou funkci této komponenty.
Pro umístění komponent do okna programu lze použít pevné umístění jednotlivých komponent (widgetů) pomocí třídy Gtk::Fixed nebo lépe kontejnery. Ty jsou horizontální (Gtk::HBox) a vertikální (Gtk::VBox). Oba obsahují stejné volby, ale liší se v uspořádání komponent vedle sebe, nebo pod sebou. Po pravdě je možností ještě víc, dostupné je také umístění do tabulky (Gtk::Table), Gtk::Notebook a další. My k tomu použijeme kombinaci HBox a VBox.
Postupovat budeme nejprve třeba po sloupcích. Pro vytvoření textového popisku se používá komponenta Gtk::Label.
vbox1 = Gtk::VBox.new(false,5) vbox1.pack_start_defaults(Gtk::Label.new("Zdrojový adresář:")) vbox1.pack_start_defaults(Gtk::Label.new("Cílový adresář:")) vbox1.pack_start_defaults(Gtk::Label.new("Šířka x výška obrázku"))
Zdrojový kód můžete postupně vkládat do textového souboru a po nastavení práv pro spuštění programu (např. pomocí chmod u+x jméno_souboru.rb
) i spustit. Spuštění můžete provést také zadáním příkazu ruby jméno_souboru.rb
. Pokud nechcete program postupně vytvářet a studovat, tak si ho rovnou stáhněte. 1.rb
Do druhého sloupce pak umístíme vstupní pole v podobě komponenty Gtk::Entry. Protože z nich budeme číst a také do nich budeme zapisovat, označíme tyto proměnné jako proměnné instance pomocí znaku zavináč před jejich jménem. Tím se na ně budeme moci odvolávat v metodách.
@sdirectory = Gtk::Entry.new @sdirectory.width_chars = 40 @ddirectory = Gtk::Entry.new
Proměnná @sdirectory
je odvozena od slov "source directory" (zdrojový adresář) a @dddirectory
znamená "destination directory" (cílový adresář). Ne-angličtináři i angličtináři nechť mi mé způsoby pojmenování i komentářů prominou. ;-)
Zadáním počtu znaků v prvním vstupním poli se v podstatě určí i vlastní šířka tohoto sloupce. Dál to opět spojíme do jednoho vertikálního boxu spolu s menším HBoxem pro poslední řádek.
vbox2 = Gtk::VBox.new(false,5) vbox2.pack_start_defaults(@sdirectory) vbox2.pack_start_defaults(@ddirectory) @width = Gtk::Entry.new @height = Gtk::Entry.new @width.text = "1024" @width.xalign = 1 @height.text = "768" @height.xalign =1 hboxsmall = Gtk::HBox.new(false,5) hboxsmall.pack_start_defaults(@width) hboxsmall.pack_start_defaults(Gtk::Label.new(" X ")) hboxsmall.pack_start_defaults(@height) vbox2.pack_start_defaults(hboxsmall)
Poslední sloupec je opět snadný. Nejprve vytvoříme jednotlivá tlačítka, k tomu se používá komponenta Button.
button = Gtk::Button.new("Převést!") sbutton = Gtk::Button.new("Zdrojový adresář") dbutton = Gtk::Button.new("Cílový adresář")
A pak je opět umístíme pod sebe:
vbox3 = Gtk::VBox.new(false,5) vbox3.pack_start_defaults(sbutton) vbox3.pack_start_defaults(dbutton) vbox3.pack_start_defaults(button)
Aby to nebylo zas tak snadné, celé to nyní spojíme dohromady, do jediného HBoxu, který později přidáme do hlavní okna programu.
hbox = Gtk::HBox.new(false,5) hbox.pack_start_defaults(vbox1) hbox.pack_start_defaults(vbox2) hbox.pack_start_defaults(vbox3)
Ještě před vytvořením hlavního okna bych si dovolil trochu odbočit, i když následující není bezpodmínečně nutné pro správnou funkci programu. Na druhou stranu jistě se vám někdy stalo, že jste před kliknutím na nějaké tlačítko, napsáním nějakého textu do textového pole nebo před vybráním nějaké volby přemýšleli na tím, zda to udělá právě to co si myslíte, zda není nutné provést ještě něco před danou operací a tak dál. Z toho důvodu je dobré ještě přidat některým komponentám jejich tipy. Ty se zobrazují jakmile na danou komponentu uživatel ukáže myší. V našem případě tyto tipy mohou vypadat třeba takto:
help = Gtk::Tooltips.new help.set_tip(@sdirectory,"Jméno adresáře, \nkde máte uloženy obrázky.", nil) help.set_tip(@ddirectory,"Jméno adresáře, \nkam se uloží vytvořené obrázky.", nil) help.set_tip(sbutton,"Zobrazí dialogové okno \npro výběr zdrojového adresáře.", nil) help.set_tip(dbutton,"Zobrazí dialogové okno \npro výběr cílového adresáře.", nil) help.set_tip(@width,"Maximální šířka obrázku.", nil) help.set_tip(@height,"Maximální výška obrázku.", nil) help.set_tip(button,"Převede obrázky na požadovanou velikost.", nil)
K tomu se používá komponenta Gtk::Tooltips. Speciální znak "\n" znamená symbol nového řádku a používá se pro zalomení příliš dlouhého textu.
Nyní máme vše připravené a tak zbývá zadat poslední a nejdůležitější část programu, která provede zobrazení hlavního okna aplikace. K tomu se používá třída Gtk::Window.
@window = Gtk::Window.new # zachytí signál destroy (zavření okna) a na jeho základě provede ukončení # programu @window.signal_connect("destroy") { Gtk.main_quit } @window.add(hbox) # přidá mezeru mezi hbox a okraj okna @window.border_width = 10 # nastaví titulek okna a zobrazí všechny komponenty na něm obsažené @window.set_title "Obrázko-konvertor (verze 0.1 ;-)" @window.show_all # spustí hlavní smyčku programu, tzn. vlastní program Gtk.main
Jen pro úplnost dodejme, že symbol "#" na začátku řádku představuje komentář a tak je obsah tohoto řádku překladačem ignorován. Tím máme připravený vzhled programu. Příště budeme přiřazovat tlačítkům jednotlivé akce.