Lekce 6 - Upomínač narozenin v Java Swing - Propojení vrstev
V minulém dílu seriálu, Upomínač narozenin v Java Swing - Logická vrstva, jsme dokončili základ logické vrstvy aplikace.
Dnes ji propojíme s formulářem a aplikaci tak zprovozníme.
Propojení prezentační a logické vrstvy
Nyní máme dokončenou tzv. prezentační část aplikace (formuláře) a logickou část (třídy). Tyto 2 vrstvy se v aplikaci striktně oddělují, jelikož jinak je kód velmi nepřehledný. Nikdy byste neměli provádět výpočty, zápisy do souborů, databáze a podobné věci přímo v kódu formuláře! Vždy si vytvoříme třídu, která poskytuje příslušné metody a tuto třídu z formuláře pouze používáme. Logika zůstane ve třídě. Třída by naopak vůbec neměla vědět o formuláři. Neměla by tedy např. zobrazovat chybové hlášky, ale pouze vyhazovat v případě chyby výjimky. Je potom na formuláři, aby uživateli chybu zobrazil. Právě formulář je ta část aplikace, která s uživatelem komunikuje. Žádná jiná to nedělá.
Pokud vás napadlo, že naše jednoduchá kalkulačka, kterou jsme vytvořili v prvních dílech seriálu, byla návrhově špatně, máte pravdu. Z důvodu jednoduchosti jsme napsali výpočty rovnou do obslužné metody tlačítka. Správně bychom měli mít nějakou třídu, která by výsledky počítala a tu bychom z formuláře pouze volali.
Ukážeme si tedy, jak se to dělá správně.
Propojení prezentace a logiky
Přejdeme do zdrojového kódu formuláře PrehledJFrame a třídě přidáme privátní atribut typu SpravceOsob, ve kterém rovnou vytvoříme instanci správce:
private SpravceOsob spravceOsob = new SpravceOsob();
Instance správce se vytvoří při vytvoření formuláře a formulář s ní dále bude komunikovat a tak provádět úkony, které si přeje uživatel.
V konstruktoru formuláře nastavíme dnesJLabel na aktuální datum a JListu nastavíme vlastnost model na model ze správce osob. Tím napojíme JList na DefaultListModel, odteď bude zobrazovat jeho obsah a pokud se do modelu něco přidá, projeví se to i v JListu. Pokud jsou v modelu nějaké osoby, nastavíme vybranou položku JListu na první index.
public PrehledJFrame() { initComponents(); dnesJLabel.setText(Datum.zformatuj(LocalDate.now())); osobyJList.setModel(spravceOsob.getModel()); if (!spravceOsob.getOsoby().isEmpty()) { osobyJList.setSelectedIndex(0); } }
Přidávání a mazání osob
Abychom něco konečně také viděli, přejdeme k přidávání osob. Nejprve přejdeme do kódu dialogu OsobaJDialog, kde si přidáme privátní atribut typu osoba, ke kterému vygenerujeme getter. Až budeme dialog později zobrazovat, právě odtud si načteme osobu, jejíž údaje uživatel zadal.
private Osoba osoba = null; public Osoba getOsoba() { return osoba; }
Nyní naklikneme tlačítko OK, kde se pokusíme vytvořit osobu na základě údajů, které uživatel zadal. Osobu uložíme do privátního atributu.
Pokud se něco nepovede, zobrazíme MessageDialog s chybou. Jistě jste se již setkali s konstrukcí try-catch, která umožňuje odchytit vyvolané výjimky a nějak na tyto chyby reagovat místo toho, abychom nechali aplikaci spadnout.
private void okJButtonActionPerformed(java.awt.event.ActionEvent evt) { try { LocalDate narozeniny = Datum.naparsuj(narozeninyJFormattedTextField.getText()); osoba = new Osoba(jmenoJTextField.getText(), narozeniny); dispose(); } catch (ParseException | IllegalArgumentException ex) { JOptionPane.showMessageDialog(null, "Chyba: " + ex.getMessage()); } }
Právě řádek:
osoba = new Osoba(jmenoJTextField.getText(), narozeniny);
Může vyvolat výjimku, jelikož výjimku přímo vyhazujeme v konstruktoru osoby v případě špatných údajů, můžete se tam podívat. Další výjimku může vyvolat i parsování datumu, i když k ní prakticky nedojde z důvodu použití JFormattedTextField. Kód, který výjimku vyvolává, umístíme do bloku try. V bloku catch poté výjimku odchytíme a zobrazíme její zprávu uživateli. Pokud vše proběhne hladce, program se do bloku catch ani nedostane. Výjimky většinou vyvoláváme v logických třídách a potom je chytáme ve formulářích. Výjimky jsou podrobněji popsané v článku Výjimky v Javě. Pomocí dispose() zavíráme aktuální formulář.
V tomto formuláři jsme skončili. Přesuneme se zpět do PrehledJFrame, tentokrát do grafické části a naklikneme tlačítka pridatJButton a odebratJButton.
private void pridatJButtonActionPerformed(java.awt.event.ActionEvent evt) { OsobaJDialog osobaJDialog = new OsobaJDialog(this, true); osobaJDialog.setLocationRelativeTo(null); osobaJDialog.setVisible(true); Osoba nova = osobaJDialog.getOsoba(); if (nova != null) { spravceOsob.pridej(nova); } }
V obslužné metodě tlačítka pridejJButton vytvoříme novou instanci dialogu OsobaJDialog, které v konstruktoru nastavíme rodičovský formulář na aktuální instanci PrehledJFrame (this) a v druhém parametru nastavíme dialog jako modální. Jakmile se dialog dále zobrazí pomocí setVisible(true), zablokuje zbytek aplikace, který se zaktivní až v případě, kdy se dialog zavře. Výsledkem je, že se s hlavním formulářem nedá pracovat dokud dialog nepotvrdíme či neukončíme. U dialogu se toto většinou dělá, již jen proto, aby si uživatel nemohl ten samý dialog vyvolat vícekrát. I když nám by v podstatě nevadilo, kdyby uživatel během zadávání nové osoby aplikaci používal a otevřel třeba další dialog k zadávání. Osobu z dialogu si načteme a pokud tam nějaká je (uživatel dialog potvrdil tlačítkem OK a neodkřížkoval ho), přidáme osobu do správce. Protože používáme ListModel, zobrazí se osoba ihned i v JListu na formuláři.
Obslužná metoda tlačítka odebratJButton bude vypadat takto:
private void odebratJButtonActionPerformed(java.awt.event.ActionEvent evt) { Osoba vybrana = (Osoba)osobyJList.getSelectedValue(); if (vybrana != null) { spravceOsob.odeber(vybrana); } }
JList
může být inicializován s Type
Parameter nastaveným jako`
String, který by pak vyvolal chybu. Pokud se jedná o váš případ, přejděte na kartu Design komponenty `OverviewJFrame
,
klikněte na JList
a vyhledejte kartu Code umístěnou na stejném
postranním panelu, kde jsou karty Properties a Events. Tam najdete možnost
Type Parameters
s hodnotou <String>
. Jednoduše
ji odeberte a vše bude fungovat.
Důležitá je podmínka, která zjišťuje, zda je v JListu vybraná nějaká položka. Jak vidíte, k vybrané položce se dostaneme přes vlastnost getSelectedValue. Položku následně přetypujeme na Osobu, jelikož je typu object (to aby byl JList univerzální). Tuto osobu předáme metodě odeber na správci, která dále vykoná fyzické odebrání z ListModelu.
Druhá možnost, jak zjistit, zda je v JListu
vybrána nějaká
položka, je použít na něm metodu isSelectionEmpty()
. Ta vrací
true
, pokud není vybrána žádná položka. Naše metoda
odebratJButtonActionPerformed()
by pak vypadala takto:
private void odebratJButtonActionPerformed(java.awt.event.ActionEvent evt) { if (!osobyJList.isSelectionEmpty()) { spravceOsob.odeber((Osoba)osobyJList.getSelectedValue()); } }
Aplikaci si nyní můžete vyzkoušet, již půjde přidávat a odebírat osoby. Přidané osoby se ihned objeví v JListu díky bindingům. JList vždy zobrazuje to, co vrací metoda toString() objektu. U osob tedy zobrazuje jejich jméno.

Příště, Upomínač narozenin v Java Swing - Dokončení logiky, doplníme logickou vrstvu aplikace o další metody a tím ji dokončíme.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 544x (19.47 kB)
Aplikace je včetně zdrojových kódů v jazyce Java