V predošlom článku sme si povedali niečo stručné ohľadom Echo2 s tým, že sme si naprogramovali základ nášho organizéra. Avšak zatiaľ toho naša aplikácie veľa nedokáže. S tým musíme niečo urobiť! Než si ukážeme nové komponenty, naučíme sa, ako môžeme externe nahrávať správy zo súboru. I keď je toto skôr všeobecný postup, je to niečo, čo využijete v každej reálnej aplikácii nielen pri použití Echo2.

Vytvorme si teraz nový balíček organizer.messages. Vytvorme v ňom triedu Messages a súbor s názvom napríklad Spravy.properties. Trieda Messages len poskytuje metódu, ktorá nahrá určitú správu z properties súboru. Tieto správy budeme nahrávať podľa ich kľúča. Predtým, než si ukážeme metódu, si zadefinujeme cestu ku nášmu properties súboru ako statický atribút:

private static final String MESSAGES_PATH = „organizer.messages.Spravy“;

Hlavná metóda triedy je statická metóda getMessage:

public static String getMessage(String key)
{
   try
   {
      Locale locale = AppInstance.getActive().getLocale();
      ResourceBundle resource = ResourceBundle.getBundle(MESSAGES_PATH, locale);
      return resource.getString(key);
   } catch (MissingResourceException e) {
      return „Správa nebola nenájdená!“;
   }
   }
}

V jednoduchosti povedané, získame si objekt Locale, ktorý vložíme spolu s cestou ku nášmu properties súboru ako parametre metódy getBundle. Následne vrátime nami hľadanú správu alebo chybovú správu, pokiaľ správa nebola nájdená.

Pridávame nové komponenty

Zo všetkého najprv si vysvetlíme jeden z najzákladnejších prvkov v rámci Echo2.

Trieda nextapp.echo2.app.SplitPane predstavuje kontajner, rozdeľujúci obrazovku na dve časti. Podstatné je vedieť, že do každej z tých častí môžete vložiť maximálne jeden komponent. Na vytvorenie jednoduchého SplitPane je potrebné zadať len jeho orientáciu a určiť vzdialenosť oddeľujúcej čiary.

SplitPane sp = new SplitPane(SplitPane.ORIENTATION_VERTICAL_TOP_BOTTOM,new Extent(20));

Orientácia

Ako prvý parameter sme predali orientáciu. V rámci triedy SplitPane je zadefinovaných hneď niekoľko statických atribútov, ktoré ovplyvňujú celkové jeho správanie. Nami zadaný parameter nič nezmení, keďže .ORIENTATION_VERTICAL_TOP_BOTTOM je jeho základné nastavenie. Je dôležité povedať, že „TOP_BOTTOM“ znamená, že prvý pridaný komponent do SplitPane sa umiestni na vrch a druhý na spodok.

Vzdialenosti

Druhým parametrom sme určili vzdialenosť oddeľovaciej čiary. Bod, od ktorého sa počíta vzdialenosť, závisí od orientácie SplitPane. Na definovanie jednotiek slúži trieda nextapp.echo2.app.Extent. Pri jej vytváraní musíme zadať aspoň nami požadovanú vzdialenosť. Druhý nepovinný parameter určuje jednotky, v ktorých sme veľkosť zadali. Nie každý komponent podporuje každý typ jednotky, preto je potrebné sa najprv pozrieť do dokumentácie ku príslušnej metóde.

Echo Extras

Ako už z názvu vyplýva, Echo Extras prináša niečo extra, konkrétne sa jedná o nové komponenty. Echo Extras by malo byť podľa oficiálne dokumentácie považované za beta produkt. Nás to však nezastaví, keďže na naše účely sa toto rozšírenie hodí výborne. Samozrejme nemôžeme ďalej pokračovať bez toho, aby sme si stiahli príslušné knižnice. Skrývajú sa pod \NextApp_Echo2_Extras\BinaryLibraries.

Čo si vyberiete z nášho menu?

Na vytvorenie menu použijeme komponent z balíka Echo Extras, a to konkrétne extapp.echo2.extras.app.MenuBarPane Celý nasledujúci kód vložíme do konštruktora triedy MainScreen:

MenuBarPane menu = new MenuBarPane();
menu.setModel(createMenuModel());
menu.addActionListener(menuListener);

Postup pri vytváraní je jednoduchý. Vytvoríme objekt, ktorému zadefinujeme model (metódu createMenuModel). My sme ešte pridali ActionListener, ktorého vytvoríme ako súkromný atribút triedy MainScreen:

public MenuModel createMenuModel()
{
   DefaultMenuModel model = new DefaultMenuModel();
   DefaultMenuModel subMenu1 = new DefaultMenuModel(„1“, Messages.getMessage(„Menu.Vytvor“));
   subMenu1.addItem(new DefaultOptionModel(„11“, Messages.getMessage(„Menu.Vytvor.NovyPrvok“), null));
   model.addItem(subMenu1);

   return model;
}

Ako model je nutné použiť triedu implementujúcu rozhranie nextapp.echo2.extras.app.menu.MenuModel. My si chceme šetriť čas, tak použijeme už pripravenú triedu z toho istého balíka, a to DefaultMenuModel.

Princíp vytvárania menu je jednoduchý. Najprv sme si vytvorili objekt model. Ten nám bude predstavovať základnú lištu v menu. Objekt subMenu1 je objektom tej istej triedy, avšak v tomto prípade sme mu ako parameter predali objekt typu ItemModel.

Tento ItemModel je len rozhranie. Z troch základných tried definujúcich toho rozhranie sme si vybrali DefaultOptionModel. Konštruktor preberá tri parametre, pričom prvý parameter je špeciálny identifikátor, ktorý budeme neskôr používať v listenerovi, a druhý parameter je názov hlavnej položky v menu.

Vytvárania podpoložiek je takisto jednoduché, stačí pomocou metódy addItem pridať objekt implementujúci OptionModel. Prvé dva parameter sú tie isté, rozdiel je v treťom. Tretí parameter je ikona pre našu položku. My ju zadáme „null“, keďže nám postačí len klasický text. Posledný riadok nám vráti nami vytvorený model.

Predtým, než sa pozrieme na naše menu, pridáme do súboru Spravy.properties

Menu.Vytvor = Vytvor
Menu.Vytvor.NovyPrvok = Nový Prvok

…a následne pridáme SplitPane do ContentPane:

sp.add(menu);
add(sp);

Neviem ako vám, ale mne sa teda naše menu veľmi nepáči. Sivá nie je moja obľúbená farba. Ako to len zmeníme?

Štýly a StyleSheet

V Echo2 môžeme štýly meniť buď priamo v kóde alebo v externom súbore. Pokiaľ chceme meniť štýly priamo v kóde, jednoducho vytvoríme triedu MutableStyle, ktorej nasetujeme potrebné vlastnosti. Následne tento objekt predáme komponentu, ktorý si žiadame zmeniť. (Pokiaľ chcete viac odkážem vás na tutoriál na stránke firmy NextApp.)

Zaujímavejšou možnosť bude pre nás definovanie štýlov v externom súbore:

  • Vytvoríme balíček organizer.styles, kde hneď aj pridáme súbor Style.xml.
  • Do triedy AppInstance vložíme statický atribút:

    public static final String PATH_TO_STYLE = „/organizer/styles/Style.xml“;

  • Konštruktor AppInstance obohatíme o:

    StyleSheet styleSheet = null;
    try
    {
       styleSheet = StyleSheetLoader.load(PATH_TO_STYLE,Thread.currentThread().getContextClassLoader());
    } catch (ComponentXmlException e) {
       e.printStackTrace();
    }
    setStyleSheet(styleSheet);

Hore uvedený kódom načítame a následne nasetujeme nami vytvorený štýl.

Súbor Style.xml

<?xml version=“1.0″ encoding=“UTF-8″?>
<stylesheet>
   <style name=“Menu“ type=“nextapp.echo2.extras.app.MenuBarPane“>
   <properties>
    <property name=“background“ value=“#3366cc“/>
    <property name=“foreground“ value=“#ffffff“/>
   </properties>
   </style>
</stylesheet>

V našom XML sa budeme stretávať s tagmi:

  • stylesheet – hlavný tag
  • style – obaľuje štýl určitého komponentu; obsahuje dva povinné atribúty:
    • name – názov štýlu; tento názov budeme volať z kódu
    • type – kompletný názov triedy komponentu
  • properties – obaľuje nastavenia pre štýl určitého komponentu
  • property – je vlastnosť určitého komponentu; obsahuje dva povinné atribúty:
    • name – názov vlastnosti (názov jednotlivých vlastností nájdeme v dokumentácii)
    • value – hodnota vlastnosti

Ako vidíte, my sme zmenili farbu pozadia a písma. Čo sa týka farieb, tie zadávame v hexadecimálnej hodnote. Teraz, keď máme zadefinovaný štýl, jednoducho ho priradíme:

menu.setStyleName(„Menu“);

Nezabudnite si redeploynúť aplikáciu a sami vyskúšať. Priraďovanie štýlov naozaj oceníte, pokiaľ budete mať niekoľko rovnako vyzerajúcich komponentov.

Okná, okná, okná

Tak máme menu, je vyfarbené pekne na modro a dokonca ho vieme aj rozkliknúť, avšak čo z toho? Bolo by dobré, keby sme pomocou tohto menu mohli niečo na obrazovku pridať.

Trieda nextapp.echo2.app.WindowPane predstavuje klasické okno. Pokiaľ si pamätáte, v predošlom článku sme si hovorili o ContentPane. Jednou z jeho vlastností je, že môže obsahovať len jeden komponent, až na jednu výnimku. Touto výnimkou je práve WindowPane, ktoré môžeme pridať len do ContentPane.

Vytvorme si balíček organizer.components, kde budeme vkladať všetky naše triedy, predstavujúce nejaký komponent. Do nášho nového balíčka si hneď aj pridajme triedu AddWindow, ktorá bude deďiť od triedy WindowPane. Konštruktor necháme jednoduchý:

super();
setWidth(new Extent(600));
setHeight(new Extent(400));
setStyleName(„Window“);
setModal(true);

Prvý riadok je snáď každému jasný. Ďalšie dva sú ľahko pochopiteľné, nastavujú šírku a výšku okna. Tých, čo čítali celý článok, neprekvapí ani nasledujúci riadok, ale čo znamená ten posledný?

Modálne okno znamená, že pokiaľ je otvorené, nie je možné na nič ostatné kliknúť. Dokiaľ ho nezavrieme, budeme sa musieť zaoberať len ním.

Aby okno bolo kompletné, doplníme súbor Style.xml o:

<style name=“Window“ type=“nextapp.echo2.app.WindowPane“>
   <properties>
      <property name=“titleBackground“ value=“#3366cc“/>
      <property name=“titleForeground“ value=“#ffffff“/>
      <property name=“background“ value=“#eeeeee“/>
      <property name=“resizable“ value=“false“/>
   </properties>
</style>

Ako vidíte, tag style som vyplnil podobne ako pri našom menu. Prvé dve vlastnosti sa týkajú farby lišty nášho okna, tretia určuje farbu samotného okna. Posledná vlastnosť zakáže zmenu veľkosti okna. Veľkosť okna sme definovali v kóde preto, lebo zatiaľ čo vzhľad okien v aplikáciách býva rovnaký, ich veľkosť už nie.

Teraz, keď máme vytvorené okno, je len potrebné ho nechať zobraziť pomocou menu. Pri vytváraní menu sme vytvorili aj ActionListener, pamätáte? Pridajme do neho tento kúsok kódu:

public void actionPerformed(ActionEvent ae)
{
   if(ae.getActionCommand().equals(„11“))
   {
      AppInstance.getActive().getDefaultWindow().getContent().add(new AddWindow());
   }
}

V (povinnej) metóde actionPerformed si zistíme ActionCommand použitého ActionEvent. Kontrolná otázka – viete, kedy sme si pridali actionCommand? Tí, čo hádali, že pri vytváraní menu, majú pravdu.

Hodnota 11 z kódu vyššie patrí prvej položke v menu s názvom Nový Prvok. Po kliknutí na túto položku získame príslušnú inštanciu ApplicationInstance (AppInstance .getActive()), následne získame objekt Window (getDefaultWindow()). Z tohto okna si vypýtame jeho obsah (getContent()), ktorý je v tomto prípade naša MainScreen. Ako posledné pridáme novú inštanciu triedy AddWindow.

Chcem vás upozorniť, že WindowPane je možné pridať len do ContentPane, čo je v našom prípade trieda MainScreen.

Súhrn

Vytváranie okna je to posledné, čo sme si v tomto článku ukázali. Keby sme si museli niečo z článku zapamätať, boli by to tieto veci:

  • Do jednotlivých častí SplitPane môžeme zadať len po jednom prvku typu Component. Poradie pridávaných prvkov záleží od jeho orientácie.
  • Predtým, než zadáme typ jednotiek pre Extent, musíme vedieť, či to podporuje daná metóda.
  • WindowPane môžeme pridať len do ContentPane.
  • Pre vytvorenie MenuBarPane mu musíme priradiť jeho model.
  • Štýly môžeme nastavovať v externom súbore alebo priamo v kóde.
  • Pokiaľ sa odkazujeme na objekt triedy ApplicationInstance, voláme statickú metódu AppInstance.getActive(), čo zabráni možným problémom s vláknami.

Malé cvičenie na záver

Po takých dvoch, troch dňoch od prečítania článku si pridáme niečo nové. Do menu pridajte novú hlavnú položku s názvom Zobraz. Nebudeme do nej zatiaľ nič vkladať.

Prečo čakať dva, tri dni? Pretože hneď po článku si toho človek pamätá relatívne dosť, ale to sa hneď vytratí. Ak trocha počkáme a potom to skúsime, zapamätáme si viac.

Tým, čo to s učením Echa myslia vážne, odporúčam si vyskúšať pridať nové štýly s novými vlastnosťami. Naučíte sa aspoň vyvarovať začiatočníckym chybám.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

3 Příspěvků v diskuzi

  1. Jen chci podpořit autora :) Konečně se začínají objevovat projekty (frameworky) odstinující vývojáře (ale i analytika) od nespočetného množství technologií. Seriál budu poctivě sledovat a rád Vaši snahu podpořím reklamou … :)

Odpovědět