Image
27.6.2016 0 Comments

Programujeme v Jave /8.časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

Udalostný model JTree a komponenty na prácu s menu

V predošlej časti sme sa venovali dosť zložitým a užitočným komponentom JTable a JTree. Toto pokračovanie začneme tam, kde sme minule skončili, teda pri komponente JTree, pretože sa budeme venovať jeho udalostnému modelu. Po ňom sa budeme zaoberať tvorbou menu v našich appletoch.

Udalostný model JTree

V súvislosti s použitím komponentu JTree dochádza k viacerým udalostiam, ktorých obsluhu je potrebné často riadiť programovo. Tieto udalosti môžeme rozdeliť do dvoch kategórií – udalosti súvisiace so zmenami v dátovom modeli a udalosti súvisiace s interakciou užívateľa s vizuálnym komponentom JTree.

Na obsluhu udalostí prvého druhu, teda tých, ktoré súvisia so zmenami v dátovom modeli, slúži rozhranie TreeModelListener. Poslucháča implementujúceho toto rozhranie zaregistrujete pomocou metódy addTreeModelListener(), definovanej v triede TreeModel. Takýmto poslucháčom je zväčša samotný vizuálny komponent JTree, vďaka čomu dokáže reagovať na akékoľvek zmeny v dátovom modeli správnym vykreslením svojho obsahu.

Rozhranie TreeModelListener deklaruje štyri metódy:

treeNodesChanged() – táto metóda je volaná v prípade, ak sa uzol alebo množina súrodeneckých uzlov nejakým spôsobom zmenila, ale ich pozícia v strome zostala rovnaká, teda napr. ak sa zmenil ich textový opis,

treeNodesInserted() – ako už názov napovedá, metóda je volaná po pridaní uzlov do stromu,

treeNodesRemoved() – metóda volaná pri odstránení uzla v strome. Pokiaľ bol odstránený celý podstrom, metóda je volaná iba pre koreňový uzol odstráneného podstromu, nie pre každý odstránený uzol osobitne,

treeStructureChanged() – metóda je volaná pri zmene štruktúry stromu. Volanie prebehne iba raz pre koreňový uzol podstromu, ktorého štruktúra sa zmenila.

Každej z týchto metód je odovzdaný ako parameter objekt typu TreeModelEvent, pomocou ktorého môžete získať informácie o uzle, ktorého sa daná zmena týka. Na to vám poslúžia hlavne metódy getPath() a getChildIndices(), prípadne getChildren().

Pri obsluhe udalostí súvisiacich s komponentom JTree sa však budete viac venovať udalostiam súvisiacim s interakciou užívateľa s týmto komponentom. Na to nám poslúžia rozhrania TreeExpansionListener, TreeSelectionListener a TreeWillExpandListener. Každý z týchto typov poslucháčov môžete zaregistrovať príslušnými metódami addTreeExpansionListener(), addTreeSelectionListener() a addTreeWillExpandListener(), definovanými v triede JTree. Každé z týchto rozhraní slúži na obsluhu rôznych typov udalostí.

Rozhranie TreeExpansionListener

Toto rozhranie poskytuje metódy na obsluhu udalostí súvisiacich s rozbalením niektorej vetvy stromu. Poskytuje dve metódy – treeCollapsed() a treeExpanded(). Prvá z metód je volaná hneď po zbalení vetvy stromu, druhá po rozbalení vetvy. Každá z metód preberá ako parameter objekt typu TreeExpansionEvent, ktorý nám poskytuje metódu getPath() na identifikáciu uzla, ktorý bol zbalený alebo rozbalený.

Rozhranie TreeSelectionListener

Metódy tohto rozhrania slúžia na obsluhu udalostí súvisiacich so zmenou označených položiek v strome. Jedinou metódou deklarovanou v tomto rozhraní je valueChanged(), volaná pri každej zmene zoznamu vybraných položiek stromu. Na bližšiu identifikáciu zmien jej slúži objekt typu TreeSelectionEvent, ktorý jej je odovzdaný ako parameter. Jeho metódou getPaths() môžeme získať pole objektov typu TreePath, ktoré identifikujú cestu k uzlom, ktoré boli označené alebo odznačené. Pokiaľ chceme zistiť, či konkrétny uzol bol označený alebo odznačený, môžeme použiť metódu isAddedPath() v niekoľkých preťažených verziách (pozri dokumentáciu API). Pomocou nej dokážeme určiť, či uzol identifikovaný danou cestou bol pridaný alebo odobraný zo zoznamu označených uzlov.

Rozhranie TreeWillExpandListener

Toto rozhranie poskytuje metódy, ktoré umožňujú reagovať na udalosti rozbalenia a zbalenia uzlov tesne pred vykonaním danej akcie. Metóda treeWillCollapse() je volaná vždy pred zbalením uzla a, naopak, metóda treeWillExpand() je volaná vždy pred rozbalením uzla. Vďaka tomu môžete vykonať potrebné akcie na rozbalenie alebo zbalenie uzla stromu, prípadne rozbaleniu alebo zbaleniu uzla zabrániť. To je možné vyvolaním výnimky ExpandVetoException. Bližšiu identifikáciu uzla, ktorého sa udalosť týka, umožňuje objekt typu TreeExpansionEvent, odovzdávaný každej metóde rozhrania TreeWillExpandListener ako parameter. Na získanie cesty k uzlu, ktorého sa udalosť týka, použijete metódu getPath(), definovanú v tejto triede.

Ukážeme si jednoduchú implementáciu tohto rozhrania, ktoré umožňuje dovoliť a zakázať rozbalenie alebo zbalenie uzla:

public class EVTest implements TreeWillExpandListener {
 
  private boolean allowExpand = true;
  private boolean allowCollapse = true;
 
  public void treeWillExpand(TreeExpansionEvent tee) throws ExpandVetoException {
    if (!allowExpand) throw new ExpandVetoException(tee);
  }
  public void treeWillCollapse(TreeExpansionEvent tee) throws ExpandVetoException {
    if (!allowCollapse) throw new ExpandVetoException(tee);
  }
 
  public void setAllowExpand(boolean allowExpand) {
    this.allowExpand = allowExpand;
  }
 
  public void setAllowCollapse(boolean allowCollapse) {
    this.allowCollapse = allowCollapse;
  }
 
}

Táto trieda pomocou metód setAllowExpand() a setAllowCollapse() umožňuje nastaviť zákaz alebo povolenie rozbaľovania a zbaľovania uzlov v strome. Metódy definované rozhraním TreeWillExpandListener vyvolajú výnimku ExpandVetoException v prípade, že daná akcia nie je povolená (t. j. daný príznak je nastavený na false). Stačí už len vytvoriť inštanciu tejto triedy a zaregistrovať ju metódou addTreeWillExpandListener() komponentu JTree.

Menu

Menu je dôležitou súčasťou všetkých grafických aplikácií. Prostredníctvom neho môže užívateľ jednoducho zadávať príkazy a určovať ďalší beh aplikácie. V zásade rozlišujeme dva druhy menu – klasické menu (menu bar), ktoré má zväčša každá GUI aplikácia hneď pod titulkovým pruhom, a pop-up menu, ktoré je spravidla vyvolané pravým tlačidlom myši. Ukážeme si, ako vytvoriť oba druhy menu.

Klasické menu – JMenuBar

Trieda JMenuBar nám umožňuje jednoduché pridanie a použitie klasického menu v našich grafických aplikáciách a appletoch. Tento komponent predstavuje koreňový kontajner pre jednotlivé položky menu. Do tohto kontajnera môžete pridávať položky reprezentované objektmi typu JMenu. Tieto objekty samy takisto slúžia ako kontajnery, ale s tým rozdielom, že už sú viditeľné ako konkrétne položky pre užívateľa. Z tohto hľadiska môžeme položky menu rozdeliť na tie, ktorých výber má za následok vykonanie nejakej akcie (spustenie obslužnej rutiny, zaškrtnutie položky, výber inej položky atď.), a tie, ktorých výber má za následok zobrazenie ďalšieho podmenu. Položky prvého druhu sú reprezentované komponentom JMenuItem, položky druhého druhu zasa komponentom JMenu. Z toho vyplýva, že JMenuItem je už konkrétna položka, kliknutím na ktorú spustíte nejakú akciu, zatiaľ čo JMenu slúži iba na pridávanie komponentov JMenuItem. Keďže trieda JMenu je odvodená od JMenuItem, môžete do kontajnera JMenu pridávať ďalšie komponenty JMenu a tým vytvárať rôzne zložité menu hierarchie.

Je logické, že položky, ktoré sú viditeľné v menu pod titulkovým pruhom (sú v hierarchii najvyššie), sú typu JMenu, pretože ich výberom sa vždy zobrazí príslušné podmenu, nikdy nie je vykonávaná hneď nejaká akcia. Práve z tohto dôvodu je možné do kontajnera JMenuBar pridávať iba položky typu JMenu.

Vytvorenie inštancie JMenuBar je veľmi jednoduché – trieda disponuje jediným a bezparametrickým konštruktorom. Po vytvorení inštancie môžete pridávať do kontajnera položky JMenu pomocou metódy add(). Počet pridaných položiek JMenu môžete zistiť pomocou getMenuCount() a získať odkaz na konkrétnu položku JMenu pomocou metódy getMenu(), ktorej ako parameter odovzdáte index požadovanej položky (sú indexované od 0). Po vytvorení menu môžete toto menu priradiť appletu metódou setJMenuBar() triedy JApplet. Ako parameter jej odovzdáte odkaz na inštanciu JMenuBar, ktorá predstavuje menu, ktoré chcete použiť.

Vytvorenie inštancie JMenu je rovnako jednoduché, najčastejšie sa používa konštruktor preberajúci ako parameter reťazec, ktorý bude zobrazený ako text menu položky. Po vytvorení inštancie môžete pridávať do tohto kontajnera položky JMenuItem alebo ďalšie komponenty JMenu.

Inštanciu JMenuItem vytvoríte rovnako ako JMenu, teda špecifikujete ako parameter konštruktora reťazec, ktorý bude zobrazený ako textový opis položky. Takisto môžete špecifikovať ikonu, ktorá bude zobrazená ako položka menu vedľa textu (prípadne bez textu). Ukážeme si jednoduchý príklad, ako vytvoriť menu a pridať ho do appletu:

import javax.swing.*;
 
public class MenuTest extends JApplet {
 
  public void init() {
    JMenuBar menuBar = new JMenuBar();
    JMenu farby = new JMenu("Farby");
    JMenu ovocie = new JMenu("Ovocie");
    menuBar.add(farby);
    menuBar.add(ovocie);
 
    JMenu modra = new JMenu("Modrá");
    JMenuItem svetlomodra = new JMenuItem("Svetlomodrá");
    JMenuItem tmavomodra = new JMenuItem("Tmavomodrá");
    modra.add(svetlomodra);
    modra.add(tmavomodra);
    JMenuItem biela = new JMenuItem("Biela");
    JMenuItem zelena = new JMenuItem("Zelená");
    farby.add(modra);
    farby.add(biela);
    farby.add(zelena);
 
    JMenuItem jablko = new JMenuItem("Jablko");
    JMenuItem hruska = new JMenuItem("Hruška");
    ovocie.add(jablko);
    ovocie.add(hruska);
 
    this.setJMenuBar(menuBar);
  }
 
}

Ako vidíte, v príklade po vytvorení menu (komponentu JMenuBar) sme vytvorili dve hlavné položky, ktorými sú farby a ovocie. Do prvej položky sme pridali okrem dvoch položiek JMenuItem aj jednu položku JMenu, v ktorej sú vložené ďalšie dve položky JMenuItem, čím sme vytvorili podmenu. V položke ovocie sú vložené iba dve položky JMenuItem. Všimnite si, že položky sú v jednotlivých menu a podmenu zobrazované v poradí, v akom sme ich vkladali do jednotlivých kontajnerov. Po vytvorení všetkých položiek a vytvorení väzieb medzi nimi (vložení do konkrétnych kontajnerov) sme toto menu nastavili ako menu appletu pomocou metódy setJMenuBar().

Obsluha udalostí menu

Menu, ktoré sme si vytvorili, by nám bolo úplne nanič, keby sme nevedeli reagovať na výber jednotlivých položiek užívateľom. Jednotlivé položky menu umožňujú registráciu niekoľkých typov poslucháčov, ale nás bude najviac zaujímať možnosť reakcie na výber položky menu užívateľom (výberom rozumieme kliknutie na položku alebo stlačenie horúceho klávesu položky, prípadne označenie položky a stlačenie klávesu Enter). Keďže trieda JMenuItem je odvodená od triedy AbstractButton, môžeme registrovať poslucháčov typu ActionListener, čo je najjednoduchší a asi aj najčastejší spôsob, akým zachytávať udalosti výberu v menu. Ak si spomínate, rozhranie ActionListener deklaruje jedinú metódu actionPerformed(), ktorá je volaná pri žiadosti o vykonanie akcie združenej s tlačidlom (položky menu sú z tohto hľadiska teda v podstate takisto tlačidlami, aj keď trošku špecifickými). V nasledujúcom príklade si ukážeme jednoduchý spôsob, ako reagovať na udalosti vzniknuté v súvislosti s vybratím položky menu:

import javax.swing.*;
import java.awt.event.*;
 
public class MenuActionTest extends JApplet {
 
  private JLabel label = new JLabel();
 
  public void init() {
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("Menu");
    JMenuItem akcia1 = new JMenuItem("Akcia 1");
    JMenuItem akcia2 = new JMenuItem("Akcia 2");
 
    menu.add(akcia1);
    menu.add(akcia2);
    menuBar.add(menu);
 
    ActionListener al = new MyActionListener();
    akcia1.addActionListener(al);
    akcia2.addActionListener(al);
 
    this.setJMenuBar(menuBar);
    this.getContentPane().add(label);
  }
 
  class MyActionListener implements ActionListener {
 
    public void actionPerformed(ActionEvent ae) {
      label.setText(((AbstractButton) ae.getSource()).getText());
    }
 
  }
 
}

V tomto príklade sme vytvorili jednoduché menu s dvoma položkami – Akcia 1 a Akcia 2. Vytvorili sme vlastnú implementáciu rozhrania ActionListener, ktorej metóda actionPerformed() zistí text tlačidla, ktoré udalosť vyvolalo, a nastaví text textovej položky JLabel, ktorú sme pridali do kontajnera appletu. Inštanciu tejto triedy sme zaregistrovali ako poslucháča pri oboch položkách menu (jej implementácia nám dovoľuje použiť tú istú inštanciu).

Horúce klávesy

Horúce klávesy (angl. hotkeys) nám umožňujú vyberať položky menu pomocou stlačenia nejakého konkrétneho klávesu na klávesnici bez nutnosti kliknutia na túto položku. Definovať horúci kláves pre položku menu nám umožňuje metóda setAccelerator() triedy JMenuItem. Ako parameter preberá odkaz na inštanciu triedy KeyStroke, ktorá predstavuje akúsi abstrakciu stlačeného klávesu, prípadne kombináciu viacerých klávesov. Odkaz na inštanciu KeyStroke môžete získať niektorou z výrobných statických metód, definovaných v tejto triede. Ich názvy sú getKeyStroke() (v niekoľkých preťažených verziách) a getKeyStrokeForEvent().

Jednou z možností, ako získať inštanciu KeyStroke, je použiť metódu getKeyStroke(), ktorá ako parameter preberá objekt typu Character alebo kód klávesu a masku modifikátorov. Modifikátormi tu chápeme stav stlačenia funkčných klávesov, ako sú napr. Ctrl alebo Alt. Pre nastavenie tejto masky sú v triede InputEvent preddefinované konštanty (napr. pre kláves Ctrl konštanta CTRL_MASK alebo pre Alt ALT_MASK). Objekt typu Character vytvoríme jednoducho pomocou konštruktora preberajúceho ako parameter znak, ktorý má reprezentovať. Kód klávesu môžeme získať ako konštantu definovanú v triede KeyEvent (napr. pre klávesu A je to konštanta VK_A). Použitie horúcich klávesov si ukážeme na nasledujúcom príklade:

 
import javax.swing.*;
import java.awt.event.*;
 
public class MenuHkTest extends JApplet {
 
  public void init() {
    JMenuBar menuBar = new JMenuBar();
    JMenu subor = new JMenu("Súbor");
    JMenuItem otvor = new JMenuItem("Otvor");
    JMenuItem zatvor = new JMenuItem("Zatvor");
 
    otvor.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK));
    zatvor.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK | InputEvent.ALT_MASK));
 
    subor.add(otvor);
    subor.add(zatvor);
    menuBar.add(subor);
 
    this.setJMenuBar(menuBar);
  }
 
}

Ako vidíte, v menu máme dve položky: Otvor, ktorú je možné aktivovať kombináciou klávesov Ctrl + F2, a Zatvor, ktorú je možné aktivovať kombináciou klávesov Ctrl + Alt + Z. Tento príklad nám ukázal, ako je možné vytvoriť horúce klávesy (akcelerátory) k jednotlivým položkám menu. Prostredníctvom nich je možné tieto položky kedykoľvek vyvolať, dokonca aj vtedy, keď menu nie je aktívne. Na to, aby ste si mohli funkčnosť týchto akcelerátorov vyskúšať, musíte jednotlivým položkám priradiť nejakú akciu pomocou poslucháča ActionListener – to už nechám na vás, fantázii sa medze nekladú. Ešte vám odporúčam bližšie sa oboznámiť s triedou KeyEvent, pretože ju často budete využívať v prípadoch, kde budete potrebovať reagovať na povely užívateľa, zadávané z klávesnice. Jej použitie sa teda neobmedzuje len na akceleráciu položiek menu.

Záver

V tejto časti sme sa oboznámili s udalostným modelom komponentu JTree a začali sme sa venovať ďalšej zaujímavosti pri tvorbe GUI aplikácií – menu. Naučili ste sa menu vytvoriť a priradiť jednotlivým položkám konkrétne akcie a horúce klávesy. V nasledujúcom pokračovaní si ukážeme ďalšie druhy položiek, ktoré môžu byť pridané do menu, a takisto sa naučíme vytvárať a používať pop-up menu. Dovtedy dovidenia.

 

 

 

Autor: Andrej Chu

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

ITPro

Linux súkromne i pracovne v2.0 (14. časť): Small Business Server

09.11.2016 14:57

Pojem Small Business Server (malý firemný server) začala používať spoločnosť Microsoft ešte v roku 2000 na označenie servera, ktorý ­dokázal plniť úlohy niekoľkých samostatných serverov. Aplikačná vrs ...

ITPro

Industry 4.0: Fikcia alebo už realita?

09.11.2016 14:52

Štvrtá priemyselná revolúcia je pomenovanie rozsiahlych zmien prudko vstupujúcich do súčasného priemyslu. Nositeľom týchto zmien je digitalizácia výroby a optimalizácia všetkých podnikových procesov v ...

ITPro

Vývoj aplikácií UWP pre Xbox One II.

09.11.2016 14:47

V predošlej časti sme ukázali postup, ako si ­vytvoriť vývojársky účet a aktivovať vývojársky režim na hernej konzole Xbox One, aby ste mohli testovať svoje aplikácie. Výhodou hernej konzoly Xbox je v ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá