3.20. Pomocné funkce ve zdrojovém kódu
Návrh programu se nám výrazně zjednoduší, budeme-li již od začátku používat pomocné funkce pro obsluhu systémových volání. Jména pomocných funkcí vám doporučuji zvolit česká, aby se tyto funkce snadno odlišily od systémových volání. Prohlédněte si dva příklady v následujícím rámečku:
// Příklad 1 - přímé volání systémových funkcí ... if(CtlGetValue((ControlPtr)FrmGetObjectPtr(formular, FrmGetObjectIndex(formular, TlacitkoJedna)))) { promenna = 1; } ... // Příklad 2 - pomocné funkce Boolean JeStisknute(FormPtr formular, UInt16 id) { UInt16 index = FrmGetObjectIndex(formular, id); ControlPtr tlacitko = (ControlPtr)FrmGetObjectPtr(formular, index); return CtlGetValue(tlacitko); } ... if(JeStisknute(formular, TlacitkoJedna)) { promenna = 1; } ... |
Zdrojový text ve druhém příkladu je sice delší, použitím pomocné funkce však program získává na srozumitelnosti. Rychlost a velikost programu jsou díky kvalitní optimalizaci kompilátoru gcc ovlivněny jen minimálně.
Pomocné funkce, které jste již napsali, můžete mít uložené samostatně a při psaní nového programu je vložit do zdrojového textu. V dalších kapitolách si ukážeme, jak je možné vytvářet knihovnu pomocných funkcí.
Pomocné funkce pro překreslení a zjištění stavu tlačítka
Změníme-li text tlačítka, tak se změna projeví na displeji až při jeho opětovném vykreslení funkcí CtlDrawControl(). Před vykreslením musíme ale sami tlačítko vymazat funkcí CtlEraseControl(), jinak by nebyl nový text čitelný. Pomocná funkce, která tento úkol usnadní je následující:
static void PrekresliTlacitko(UInt16 prvekTlacitka) { ControlPtr tlacitko = (ControlPtr)Objekt(prvekTlacitka); CtlEraseControl(tlacitko); CtlDrawControl(tlacitko); } |
Zda je tlačítko nebo políčko k zaškrtnutí vybrané nebo ne, zjistíme pomocí funkce CtlGetValue(). I pro použití této funkce je výhodné napsat si funkci pomocnou, která zpřehlední zápis programu:
static Boolean JeVybrane(UInt16 prvekTlacitka) { ControlPtr tlacitko = (ControlPtr)Objekt(prvekTlacitka); return CtlGetValue(tlacitko); } |
Základem úspěšného použití pomocných funkcí ve vašich programech je několik zásad, které si pro přehlednost uvedeme v seznamu:
- Jména pomocných funkcí zvolit jednoduchá a přitom dostatečně výstižná.
- Nedávat funkcím jména, která by mohla být zaměněna se jmény funkcí PalmOS.
- Nepoužívat ve svých funkcích žádné globální proměnné.
- Používat pouze datové typy podporované PalmOS (Int16 místo int apod.).
- Zkontrolovat, zda funkce za určitých okolností (třeba předáme-li ji jako parametr příliš dlouhý řetězec) nemůže způsobit systémovou chybu a tyto případy ošetřit.
3.21. Vlastní výpočet
Při použití pomocných funkcí, které jsme si uvedli v předchozím odstavci, můžeme nyní napsat jednoduchou funkci, která spočte spodní a horní hodnotu pásma cílové výšky. Popsaná funkce poté text zobrazí ve dvou tlačítkách, která nepůjdou stisknout a budou pouze tvořit rámečky pro text (budou v souboru prostředků aplikace deklarována s atributem DISABLED).
V našem programu proto musíme nejprve deklarovat dvě řetězcové proměnné, ve kterých budou uloženy texty těchto dvou tlačítek. Tyto proměnné budou obsahovat výšku v centimetrech, která do nich bude ukládána přímo funkcí StrIToA(). Tyto proměnné doporučuji deklarovat s délkou maxStrIToALen (a to i když v nich nebude nikdy delší než trojmístné číslo). Ve funkci formuláře pak voláním funkce CtlSetLabel() nastavíme příslušná tlačítka tak, aby zobrazovala text v těchto proměnných.
Char gVysledekSpodni[maxStrIToALen] = ""; Char gVysledekHorni[maxStrIToALen] = ""; |
Tuto funkci pro výpočet budeme volat pokaždé, když se změní data ve formuláři. Uživatel může změnit hodnotu výšky jednoho z rodičů i pohlaví dítěte - tato změna se musí bezprostředně odrazit ve výsledných číslech. Ve funkci formuláře si tedy musíme ohlídat jak změnu kterékoliv číslice výšek rodičů, tak stisknutí některého z políček pro zaškrtnutí pohlaví. Příklad řešení funkce formuláře je v následujícím rámečku:
static Boolean UdalostHlavnihoFormulare(EventPtr udalost) { Boolean zpracovano = false; Boolean zmena = false; // Zavedeme pomocnou promennou, ktera bude mit hodnotu // |true| pokud zmenime data ve formulari switch(udalost->eType) { case frmOpenEvent: ... // Inicializujeme tlacitka, ve kterych zobrazujeme // vysledek CtlSetLabel((ControlPtr)Objekt(TlacitkoVyskaOd), gVysledekSpodni); CtlSetLabel((ControlPtr)Objekt(TlacitkoVyskaDo), gVysledekHorni); FrmDrawForm(FrmGetActiveForm()); // Na zacatku nastavime parametr |zmena| tak, aby se // zobrazila vypoctena data. zmena = true; zpracovano = true; break; case ctlSelectEvent: switch(udalost->data.ctlSelect.controlID) { ... // Sledujeme zpravy generovane policky k zaskrtnuti - // pokud zmenime pohlavi zmeni se totiz i vysledek ... case ZaskrtniChlapec: case ZaskrtniDivka: zmena = true; break; default: break; } break; case ctlRepeatEvent: switch(udalost->data.ctlRepeat.controlID) { case OpakujOtecPlus: zmena = UpravTlacitko(SkupinaOtec, 1); break; case OpakujOtecMinus: zmena = UpravTlacitko(SkupinaOtec, -1); break; case OpakujMatkaPlus: zmena = UpravTlacitko(SkupinaMatka, 1); break; case OpakujMatkaMinus: zmena = UpravTlacitko(SkupinaMatka, -1); break; } break; default: break; } // Byla-li zmeneno nektere z cisel nebo pohlavi, bude // vysledek prepocitan a znovu zobrazen if(zmena) { SpoctiANastavVysledek(); } return zpracovano; } |
Ve funkci SpoctiANastavVysledek() použijeme naše pomocné funkce JeVybrane() a PrekresliTlacitko(). Zdrojový text funkce, který byste ale již uměli napsat sami, je následující:
static void SpoctiANastavVysledek() { UInt16 vyskaMatky = (gMatka100cm[0] - '0') * 100 + (gMatka10cm[0] - '0') * 10 + gMatka1cm[0] - '0'; UInt16 vyskaOtce = (gOtec100cm[0] - '0') * 100 + (gOtec10cm[0] - '0') * 10 + gOtec1cm[0] - '0'; UInt16 stred = 0; // Kontrola spravnosti a vypocet if(vyskaMatky > 154 >> vyskaMatky < 178 >> vyskaOtce > 165 >> vyskaOtce < 193) { // Testujeme pohlavi podle ctverecku k zaskrtnuti if(JeVybrane(ZaskrtniChlapec)) { stred = (vyskaOtce + vyskaMatky + 13 + 1) / 2; } else if(JeVybrane(ZaskrtniDivka)) { stred = (vyskaOtce + vyskaMatky - 13 + 1) / 2; } } // Byl-li vypocet stredu spravny, uloz do globalnich // promennych, ktere obsahuji text tlacitek, ciselne // hodnoty; jinak tam budou otazniky. if(stred > 0) { StrIToA(gVysledekSpodni, stred - 10); StrIToA(gVysledekHorni, stred + 10); } else { StrCopy(gVysledekSpodni, "?"); StrCopy(gVysledekHorni, "?"); } // Po nastaveni prekreslime obe tlacitka // (promenne obsahujici text byly aktualizovany) PrekresliTlacitko(TlacitkoVyskaOd); PrekresliTlacitko(TlacitkoVyskaDo); } |
Zdrojový text příkladu si můžete stáhnout zde. Sami jistě přijdete na mnoho vylepšení. Můžete do programu například doplnit kontrolu vstupních hodnot výšky matky a otce tak, aby nebylo možné zadat nesmyslné číslo. Také se můžete zamyslet nad jinými způsoby vstupu číselných údajů. Co třeba udělat jednu skupinu přepínačů pro stovky a desítky centimetrů a druhou pro jednotky?
V příští a poslední části třetí kapitoly si povíme o způsobu, jak uložit stav našeho programu tak, aby měl uživatel při práci s ním dojem multitaskingu.