Příklad práce v OpenStepu
OpenStep for Windows, v4.2



Abychom názorně ukázali eleganci vývojového prostředí Openstepu for Enterprise, uvedeme malý a relativně jednoduchý příklad -- krok za krokem čtenáře provedeme vytvořením textového editoru. Nebojte se, nepůjde o únavný kurs programování; v OpenStepu se jedná o příjemnou několikaminutovou zábavu. Pro představu můžeme porovnat možnosti editoru, který se chystáme vytvořit, s WordPadem, jenž je standardně k dispozici ve Windows. Náš editor bude tomuto programu více než rovnocenným soupeřem -- oproti němu bude mít mnohem rozsáhlejší formátovací a typografické schopnosti a podporu obrázků, na druhou stranu postrádá preference a některé marginální funkce WordPadu (například "vložit datum"). Náš editor však naprogramujeme během pěti minut; kolik času asi zabralo vytvoření WordPadu?



Srdcem vývojového prostředí je aplikace ProjectBuilder; ten se stará o všechny soubory projektu, poskytuje přístup k dokumentaci, nabízí velmi silné prohledávací možnosti, obsahuje pohodlný editor kódu, poskytuje grafické rozhraní ke kompileru i debuggeru... Začneme tedy tím, že v ProjectBuilderu vytvoříme nový projekt aplikace se jménem, řekněme, PisTo a v inspektoru nastavíme základní atributy aplikace: požadované jméno, ikonu, seznam typů souborů, které aplikace zpracovává, a odpovídajících ikon, typ uživatelského rozhraní (zde OPENSTEP for Windows, stylů je ale k dispozici více, protože OpenStep se vzhledem svých ovladačů vždy přizpůsobuje hostitelskému prostředí) a podobně.

Za zmínku stojí položka "Main NIB File" -- zde specifikujeme jméno souboru NIB, který obvykle obsahuje kompletní grafické uživatelské rozhraní aplikace. Na první pohled tedy trochu připomíná klasické resource soubory; nic však není dále od pravdy -- OpenStep je plně objektový systém, a jeho vývojové prostředí toho zcela využívá. NIB soubory proto obsahují přímo skutečné objekty, které aplikaci slouží jako GUI -- bude-li mít např. aplikace okno s textovým objektem (jak tomu je v našem případě), je v NIB souboru uložen objekt "okno", objekt "text" a samozřejmě i jejich vzájemné vazby. S prostředky, které OpenStep nabízí pro tvorbu a editaci NIBů, se seznámíme za chvilinku.


Povšimněme si na obrázku ještě toho, že v hlavním okně ProjectBuilderu je zobrazen klasický soubor Makefile, dobře známý programátorům v unixu. ProjectBuilder totiž dokazuje, že v příkrém kontrastu ke známému anglickému přísloví lze mít obojí výhodu a zbavit se obou nevýhod: podobně, jako integrovaná prostředí pod DOSem nebo pod Windows, umožňuje ProjectBuilder bezproblematickou tvorbu aplikací těm, kdo v životě o nějakém "make" neslyšeli -- prostě vybereme z menu "Build", a systém se o vše postará sám. Zkušení programátoři, kteří by naopak rádi využili nesmírnou flexibilitu systému "make", k níž se služby výše zmíněných integrovaných prostředí ani zdaleka neblíží, v OpenStepu také nepřijdou zkrátka: ProjectBuilder totiž sám nic nepřekládá; namísto toho prostě automaticky udržuje naprosto standardní Makefile a pro tvorbu aplikace volá "make". "Make" je tedy zde, a kdo chce, může si jej snadno najít a jeho služby jsou mu plně k dispozici.



Vraťme se zatím k uživatelskému rozhraní (UI) aplikace. OpenStep podporuje oddělený návrh UI a "vnitřností" (můžeme jim říkat odborně "engine"), což přináší řadu výhod -- u většího projektu mohou na obou pracovat různé týmy, navržené rozhraní můhou budoucí uživatelé testovat, zatímco se na implementaci engine pracuje (nezapomínejme, že v NIBu jsou skutečné, plnohodnotné objekty, nikoli jen nějaké formuláře, takže rozhraní lze samo o sobě spustit). Navíc je rozhraní mezi UI a engine jasně definované, a není problém z aplikace v budoucnosti např. zcela triviální změnou udělat systém klient/server.

Editor NIBů se jmenuje InterfaceBuilder. Jedná se o pohodlný a intuitivní grafický nástroj pro vytváření a správu obecných objektových sítí; zvláště luxusní služby nabízí pro práci s objekty, které mají nějaký vlastní vzhled -- jinými slovy, s objekty uživatelského rozhraní. ProjectBuilder nám pro zjednodušení práce připravil prázdné okno, a vložil do něj standardní menu. Náš hlavní nib ovšem nebude obsahovat nic jiného než menu -- za chvilinku si ukážeme, proč se vyplatí umístit okno s textovým objektem do samostatného NIBu -- okno tedy jen zmenšíme, a do menu přidáme položku "Format". Ani to není žádná práce; položku prostě vezmeme myší z palety vpravo nahoře a přetáhneme ji na žádanou pozici.

Připomeňme znovu, že nevytváříme nějaký resource soubor, ale kombinujeme skutečné objekty a jejich vzájemné vazby; díky tomu jsme právě aplikaci "naprogramovali" velmi rozsáhlé možnosti formátování textu, od práce s fonty přes práci s barevným textem až po takové exotické záležitosti jako řízení kerningu či slitků. Věc je jednoduchá -- objekty, které se starají o odpovídající sloužby, jsou vázány na položku menu "Format", a uložením položky do NIBu jsme do něj přidali i tyto standardní objekty. Podobně např. položka "Print" umožní tisknout obsah libovolného aktivního textového objektu -- ponecháme ji tedy v menu (kam ji, jako zcela standardní, umístil automaticky již ProjectBuilder), a náš editor bude schopen tisku... Hotové menu vypadá takto:

Náš hlavní nib je "namalován", je čas připravit vazbu na engine aplikace. I na to nabízí InterfaceBuilder grafické a pohodlné služby: vytvoříme novou třídu, nazveme ji třeba Controller. To bude později náš engine. Stále v InterfaceBuilderu specifikujeme rozhraní mezi UI a engine: k tomu slouží kombinace tzv. outletů a actions. Outlety jsou odkazy na objekty -- má-li engine mít k dispozici odkaz na některý objekt UI (např. textové pole), poslouží k tomu outlet. Naopak action je akce, kterou engine nabízí, a objekty UI -- na základě interakce s uživatelem -- vyvolávají.

Náš Controller tedy bude mít jeden outlet, pojmenujeme jej třeba textView; sestavíme aplikaci tak, aby tento outlet vždy obsahoval odkaz na nejnovější, naposledy vytvořený, textový objekt. Akce budeme potřebovat tři: jednu pro každou z položek menu "New/Open/Save" (o akce pro standardní položky, jako "Format" nebo "Print", se díky standardně zavedeným objektům nemusíme starat). Celá věc je jednoduchoučká, podívejme:



Nyní musíme naznačit InterfaceBuilderu, jaká bude vazba mezi položkami menu a akcemi; to zařídíme prostě tak, ze myší za současného stisku klávesy CTRL táhneme z položky menu na objekt Controller (reprezentovaný malou krychličkou vlevo dole -- viz následující obrázek), a zvolíme požadovanou akci. Tento mechanismus funguje naprosto obecně; stejně dobře bychom mohli třeba umístit do okna tlačítko ("button"), a propojit myší s akcí toto tlačítko -- pak by se akce vyvolala stisknutím tlačítka. Můžeme klidně udělat obojí, a vyvolávat pak akci podle potřeby jak z menu, tak i tlačítkem. Takové variace lze dělat snadno v InterfaceBuilderu, aniž by bylo třeba sebeméně zasáhnout do engine; to kromě ostatních zjevných výhod také prakticky zamezuje možnosti zavléct nové chyby při drobných úpravách uživatelského rozhraní aplikace.

Propojíme všechny tři položky se třemi akcemi, a s touto částí jsme hotovi -- v rámci engine budeme muset naprogramovat vlastní obsah akcí, ale tomu již se můžeme věnovat jindy. Teď ještě musíme připravit pro naši aplikaci dokument -- nějaké okno, obsahující textový objekt. Mohli bychom jej snadno přidat do hlavního NIBu, ale my to provedeme chytřeji: vytvoříme samostatný NIB, obsahující právě jen objekty, týkající se jednoho dokumentu. Proč? Je to jednoduché, stačí si jen znovu připomenout, že NIB není jen nějaký formulář, ale plnohodnotná síť skutečných objektů. Z toho plyne, že kdykoli načteme NIB, z hlediska aplikace se jakoby vytvoří všechny objekty, které byly v NIBu uloženy. To je ale přesně to, co chceme provést kdykoli při otevření nového textového dokumentu: vytvořit odpovídající objekty. Vidíme tedy, že při vhodném návrhu bude otevření textového souboru obsahovat jen o málo více, než pouhé načtení jednoho NIBu.

Příprava takového NIBu je jednoduchoučká: vytvoříme v InterfaceBuilderu nový prázdný NIB, z paletky vezmeme okno a myší ho přetáhneme do volného prostoru. V dalším kroku rovněž z paletky přetáhneme stejným způsobem do okna objekt NSTextView, a v inspektoru nastavíme atributy pro okno i textový objekt.

Teď se postaráme o to, aby textový objekt (z naposledy otevřeného okna) byl vždy dosažitelný prostřednictvím outletu textView, který jsme si pro tento účel připravili v objektu Controller. Nihil novi sub sole -- opět použijeme "drátování" pomocí myši a tlačítka CTRL: nejprve informujeme InterfaceBuilder, že ten, kdo NIB bude zavádět -- jeho vlastník -- je objektem třídy Controller; pak už jen tohoto vlastníka, reprezentovaného ikonkou "File Owner", propojíme s požadovaným objektem:

Tím je uživatelské rozhraní aplikace kompletně hotové. Chceme-li, můžeme jej otestovat v interaktivním režimu, nebo jej ke stejným testům předat budoucím uživatelům aplikace: jistě, zatím nebude možné otevírat soubory a podobně, ale můžeme používat menu, můžeme psát do textového objektu v dokumentovém okně a podobně.



Je načase dokončit práci naprogramováním engine. InterfaceBuilder nám ještě jednou usnadní život -- na požádání totiž dokáže vygenerovat kostry potřebných zdrojových souborů v Objective C a uložit je do projektu; ProjectBuilder -- který s ním samozřejmě umí spolupracovat -- nám je hned nabídne ve svém editoru. Nám již zbývá jen doplnit implementace tří akcí -- v následujícícm výpisu jsou zobrazeny normálně, zatímco automaticky vygenerovaný zdrojový text je šedý:

#import "Controller.h"

@implementation Controller
-(void)new:(id)sender
{
[NSBundle loadNibNamed:@"Doc.nib" owner:self];
[[textView window] makeKeyAndOrderFront:self];
[[textView window] setTitle:@"~/UNTITLED"];
}
-(void)open:(id)sender
{
NSArray *fileTypes=[NSArray arrayWithObjects:@"rtf",@"rtfd",nil];
NSOpenPanel *openPanel=[NSOpenPanel openPanel];

[openPanel setAllowsMultipleSelection:YES];
if ([openPanel runModalForDirectory:NSHomeDirectory() file:nil types:fileTypes]==NSOKButton) {
NSEnumerator *en=[[openPanel filenames] objectEnumerator];
NSString s;

while (s=[en nextObject]) {
[self new:self];
[textView readRTFDFromFile:s];
[[textView window] setTitle:s];
}
}
}
-(void)save:(id)sender
{
NSSavePanel *savePanel=[NSSavePanel savePanel];
int result = ;

if ([savePanel runModalForDirectory:NSHomeDirectory() file:@""]==NSOKButton) {
[textView writeRTFDToFile:[savePanel filename] atomically:YES];
[[textView window] setTitle:[savePanel filename]];
}
}
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self new:self];
}
@end

Poslední metodu jsme si přidali navíc; OpenStep zajistí, že metoda tohoto jména -- existuje-li -- je zavolána hned po spuštění aplikace. My v ní otevřeme nový prázdný soubor (aplikace jen vyvolá vlastní službu "new:"). A to je celé! Můžeme aplikace nechat vytvořit příkazem "Build"; pokud bychom snad udělali při programování nějakou chybu, máme pro její nalezení k dispozici luxusní debugger:

Stojí za to poznamenat, že podobně, jako pro kompilaci se pod elegantním grafickým rozhraním ProjectBuilderu skrývá nesmírně silné a flexibilní "make", je grafický debugger také jen slupka -- pod ní je ukryt špičkový debuger gdb, jehož speciální služby -- jako je např. možnost ladění multithreadových programů -- má zkušený programátor snadno k dispozici.



Po odladění -- bylo-li jaké vůbec zapotřebí -- máme před sebou editor, který umí pracovat s textem ve standardním formátu RTF a zvládá všechny základní způsoby zarovnávání, nastavování tabelátorů, práci s fonty a barvami, obrázky, drag and drop... a dokonce tak luxusní služby hraničící s DTP, jako přímé řízení kerningu nebo slitky:



Další kapitola       Přehled       Zpět


Copyright (c) Ondra Čada, Tom Honzák