3. diel - Dokončenie jednoduché kalkulačky pre MacOS vo Swift
V predchádzajúcej lekcii, Návrh jednoduchej kalkulačky pre MacOS , sme dokončili užívateľské rozhranie našej jednoduché kalkulačky a zostáva ho uviesť k životu. To znamená, že dnes začneme písať Swift kód. Ešte predtým ale musíme naše komponenty používateľského rozhrania "napojiť" na kód, aby sme k nim mohli pristupovať.
Budeme totiž potrebovať čítať zadané čísla, vybranú operáciu a
tiež reagovať na stlačenie tlačidla. No a samozrejme nesmieme zabudnúť na
náš Label, ktorý zobrazí výsledok.
Prepojenie UI s kódom
Prepojenie komponentov s kódom funguje na MacOS úplne rovnako ako na iOS, takže pre mnohých z vás určite pôjde iba o opakovanie.
Začneme otvorením Main.storyboard a prepneme na Assistant
editor, ktorý zobrazí dva otvorené súbory vedľa seba. Prepínač môžete
vidieť nižšie.

Naľavo by ste mali vidieť naše užívateľské rozhranie a vedľa súbor
ViewController.swift, ktorý bude obsluhovať práve naše
okno.
Za seba odporúčam označovať komponenty v Document Outline (to je ten zoznam komponentov naľavo od náhľadu používateľského rozhrania). Potom za držanie klávesy Ctrl ťaháme z komponenty do zdrojového súboru, ako je vidieť na animáciu nižšie:

Týmto vytvoríme tzv. @IBOutlet, čo je špeciálny premenná
odkazujúce na našu komponent. Pri spustení programu bude automaticky
inicializovaná a môžeme pomocou nej čítať obsah Text Field
komponenty a ďalej s ňou manipulovať.
Rovnakým štýlom prepojíme ešte Combo Box, druhý
Text Field a posledný Label pre zobrazenie
výsledku.
V zdrojovom kóde VC by ste mali mať tieto prepojené komponenty:
@IBOutlet var firstInput: NSTextField! @IBOutlet var secondInput: NSTextField! @IBOutlet var mathOperationComboBox: NSComboBox! @IBOutlet var resultsLabel: NSTextField!
Moc nepomáha, že v kóde nie sú komponenty
Text Field a Label rozlíšené podobne, ako tomu je u
iOS. Ich automatické nastavenie ale vybraním v časti s tvorbou UI zaistí,
že sa budú správať korektne.
Zostáva tlačidlo. S ním nebudeme pracovať ako s @IBOutlet,
ale zaujíma nás iba situácie, keď na neho používateľ klikne. Pre to
slúži špeciálne metódy označovanej ako @IBAction a ich
vytvorenie je dosť podobné @IBOutlet, stačí zmeniť typ pri
vytváraní, pozri opäť animácie nižšie:

A máme hotovú metódu, ktorá bude automaticky spustená pri každom kliknutí na tlačidlo. Práve tu budeme riešiť výpočet a zobrazovať výsledok.
@IBAction func calculateBtnClicked(_ sender: NSButton) {
}
Úpravy storyboard
Ešte, než sa pustíme do implementácie našej výpočtovej metódy,
uľahčíme si prácu pomocou jednoduchej úpravy v
Main.storyboard. Ako možno viete, náš rodný jazyk používa
čiarku na oddelenie desatinnej časti čísla, ale angličtina a programovacie
jazyky používajú bodku.
Takže jednoducho našim Text Field komponentom, respektíve ich
formátující časti, nastavíme, aby ignorovala lokalizáciu. To v preklade
znamená, že bude vždy očakávať bodky v desatinných číslach. Inak nám
nedovolí potvrdiť vstup, rovnako ako keby sme napísali písmeno.
V Document Outline je najskôr potrebné rozkliknúť Text Field
komponent a dostať sa až na Number Formatter, ako môžete
vidieť na screenshote nižšie:

Potom stačí v Attribute inšpektorovi odškrtnúť voľbu "Localizo Format".

Drobný problém je vyriešený a môžeme sa pustiť do implementácie
našej metódy na výpočet. Čo vlastne chceme robiť? V prvom rade potrebujeme
zistiť zadané čísla od užívateľa a potom podľa vybranej operácie v
komponente Combo Box vykonať výpočet.
Začneme získaním čísel z Text Field komponentov, vďaka
Number Formatter by mali byť vždy validný, ale pre istotu
využijeme guard a skúsime text z oboch komponentov previesť na
čísla. Keď sa to nepodarí, tak skrátka nič ďalšie robiť nebudeme:
guard let firstNumber = Float(firstInput.stringValue), let secondNumber = Float(secondInput.stringValue) else {return}
V tomto kroku už vieme, že máme k dispozícii dve čísla a môžeme
vykonať výpočet. Z Combo Box možno jednoducho získať index
zvoleného prvku, takže využijeme jednoduchý switch a rovno
výsledok nastavíme ako stringValue našej Label
komponente pre zobrazenie výsledku:
switch mathOperationComboBox.indexOfSelectedItem { case 0: resultsLabel.stringValue = "\(firstNumber + secondNumber)" case 1: resultsLabel.stringValue = "\(firstNumber - secondNumber)" case 2: resultsLabel.stringValue = "\(firstNumber / secondNumber)" case 3: resultsLabel.stringValue = "\(firstNumber * secondNumber)" default: resultsLabel.stringValue = "-" }
Teraz môžete aplikáciu zapnúť a bude počítať. Pre istotu si ukážeme kompletnú metódu pre tlačidlo:
@IBAction func calculateBtnClicked(_ sender: NSButton) { guard let firstNumber = Float(firstInput.stringValue), let secondNumber = Float(secondInput.stringValue) else {return} switch mathOperationComboBox.indexOfSelectedItem { case 0: resultsLabel.stringValue = "\(firstNumber + secondNumber)" case 1: resultsLabel.stringValue = "\(firstNumber - secondNumber)" case 2: resultsLabel.stringValue = "\(firstNumber / secondNumber)" case 3: resultsLabel.stringValue = "\(firstNumber * secondNumber)" default: resultsLabel.stringValue = "-" } }
Naša kalkulačka má jeden drobný problém, v Combo Box nie je
po zapnutí nič vybrané. To môžeme vyriešiť jedným riadkom kódu v
metóde viewDidLoad(), ktorá je zavolaná po spustení
aplikácie.
Tu jednoducho vyberieme treba prvú operáciu:
override func viewDidLoad() { super.viewDidLoad() mathOperationComboBox.selectItem(at: 0) }
Ak vám vadí, že sa aplikácia pri skúšaní nezavrie pri zatvorení okna,
existuje na to rýchla oprava. Otvorte si AppDelegate.swift a
pridajte túto metódu. Xcode vám ju prípadne napovie:
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true }
Jej názov jednoznačne vystihuje, o čo vlastne ide. Keď používateľ zavrie posledný okno (v našom prípade jedinej), dôjde tiež k vypnutiu aplikácie.
Dialóg
Možno vás napadlo, čo sa stane, keď sa používateľ pokúsi deliť
0 ? Aplikácia prekvapivo nespadne, ale zobrazí výsledok "inf"
ako infinity čiže nekonečno. Keby sme ako dátový typ používali
Int miesto Float, tak aplikácia spadne.
Ani jedno nie je ideálne, takže si ukážeme riešenia a rovno tiež, ako zobraziť informačný dialóg užívateľmi.
Pripravíme si metódu, ktorá zobrazí tento dialóg a informuje
užívateľa, že deliť 0 jednoducho nejde:
func showDivisionByZeroAlert() { let alert = NSAlert() alert.messageText = "Even this cool app cannot divide by 0!" alert.runModal() }
Zobrazenie základného dialógu je veľmi jednoduché. Stačí vytvoriť
inštanciu NSAlert a pridať text. Potom už len stačí dialóg
zobraziť. Bude vyzerať takto:

Zostáva teda vyriešiť situáciu, keď sa používateľ pokúsi deliť
0. Upravíme teda náš switch v metóde obsluhujúci
tlačidlo, konkrétne prípad, keď je vybrané delenie. Pred samotnej delenie
umiestnime podmienku, kde sa jednoducho spýtame, či náhodou nie je druhé
číslo 0. Ak áno, tak zobrazíme dialóg a ďalej
nepokračujeme:
case 2: if secondNumber == 0 { showDivisionByZeroAlert() return } resultsLabel.stringValue = "\(firstNumber / secondNumber)"
A to je celé! Máme prvý funkčný MacOS aplikáciu.

V budúcej lekcii, PRIPOMIENKOVÉ narodenín pre MacOS - Príprava UI , začneme už komplexnejšie projekt, na ktorom sa naučíme používať ďalšie ovládacie prvky.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 19x (38.85 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift
