UINF/PAZ1c 2013 – 10. prednáška

Vytváranie Swing aplikácií na zelenej lúke. Komponenty, reakcie na udalosti. Anonymné vnútorné triedy. Demonštrácia na projekte RSS čítačky.

RSS čítačka

Trieda pre biznis logiku

  • Využijeme knižnicu Rome, modul Rome-Fetcher.
  • Pridáme závislosť

    <dependency>
      <groupId>org.rometools</groupId>
      <artifactId>rome-fetcher</artifactId>
      <version>1.2</version>
    </dependency>
    
  • Vytvoríme servisnú triedu:

    package sk.upjs.ics.ereses;
    
    import com.sun.syndication.feed.synd.SyndEntry;
    import com.sun.syndication.io.FeedException;
    import java.io.IOException;
    import java.net.URL;
    import java.util.List;
    import org.rometools.fetcher.FetcherException;
    import org.rometools.fetcher.impl.HttpURLFeedFetcher;
    
    public class RssService {
        public List<SyndEntry> getEntries(URL adresa) {
            try {
                SyndFeed feed = new HttpURLFeedFetcher().retrieveFeed(adresa);
                return feed.getEntries();
    
            } catch (IOException e) {
                throw new RssException("Nemožno načítať RSS kanál kvôli I/O chybe. Je sieť dostupná?", e);
            } catch (FeedException e) {
                throw new RssException("Nesprávny formát RSS kanála. Syntaktická chyba?", e);
            } catch (FetcherException e) {
                throw new RssException("Chyba pri spracovani kanala. HTTP komunikácia zlyhala.", e);
            }
        }
    }
    
  • metóda vráti zoznam položiek com.sun.syndication.feed.synd.SyndEntry, ktoré v sebe nesú všetky základné veci (titulok, dátum, popis).

  • RssException je naša vlastná výnimka dediaca od RuntimeException.

Prázdne okno

public class MainForm extends JFrame {
    /* tu nič nie je */
}

Spustenie

public class Runner {
    public static void main(String[] args) {
        new MainForm().setVisible(true)
    }
}
  • Spustí sa prázdne sivé okno
  • S nulovými rozmermi
  • V ľavom hornom rohu monitora

Dodanie zoznamu

public class MainForm extends JFrame {
    private RssService rssService = new RssService();

    private JList lstPolozky;

    public MainForm() throws MalformedURLException {

        lstPolozky = new JList();

        URL url = new URL("http://rss.sme.sk/rss/rss.asp?id=frontpage");
        List<SyndEntry> entries = rssService.getEntries(url);
        lstPolozky.setListData(entries.toArray());
        add(lstPolozky);

        setBounds(0, 0, 640, 480);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }


    public static void main(String[] args) throws Exception {
        new MainForm().setVisible(true);
    }
}
  • komponenty zavádzajme ako inštančné premenné
  • cez setListData() vieme do JListu dodať pole objektov, ktoré sa majú zobraziž

Ďalšie nastavenia okna:

  • cez setBounds() nastavíme rozmery a polohu okna
  • cez setDefaultCloseOperation() povieme, že aplikácia sa má ukončiť po zatvorení posledného okna. Štandardné správanie len schová okno, aplikácia však ďalej pobeží. (To si nemusíme všimnúť!)

Prispôsobenie zobrazovania položiek

  • Položky teraz ukazujú čudesné veci — volanie metódy toString() na SyndEntry.
  • Prispôsobiť ich môžeme cez vlastný cell renderer:

    package sk.upjs.ics.ereses;
    
    import com.sun.syndication.feed.synd.SyndEntry;
    import java.awt.Component;
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.JList;
    
    public class SyndFeedListCellRender extends DefaultListCellRenderer {
    
        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            SyndEntry entry = (SyndEntry) value; 
            String title = entry.getTitle();
            return super.getListCellRendererComponent(list, title, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates.
        }
    
    }
    
  • použitie:

    lstPolozky.setCellRenderer(new SyndFeedListCellRender());       
    

Dodanie komponentu pre zobrazovanie textu položky

  • Dodajme ďalší komponent pre textu položky: teda samotný text článku prevzatý z RSS atribútu <description>
  • Použijeme textové pole JTextArea.
  • Na oddelenie zoznamu položiek a textového políčka využijeme oddeľovač JSplitPane
    • oddeľovač berie dva komponenty: jeden hore, druhý dole
  • zoznam a textové políčko už nemusíme pridávať do okna; urobí to za nás oddeľovač.
  • oddeľovač funguje v horizontálnom režime (štandardný; položky vedľa seba) alebo vertikálnom (položky pod sebou; JSplitPane.VERTICAL_SPLIT).

Výsledok:

public class MainForm extends JFrame {

    private RssService rssService = new RssService();

    private JList lstPolozky;
    private JSplitPane oddelovac;
    private JTextArea txtDescription;

    public MainForm() throws MalformedURLException {

        lstPolozky = new JList();

        URL url = new URL("http://rss.sme.sk/rss/rss.asp?id=frontpage");
        List<SyndEntry> entries = rssService.getEntries(url);
        lstPolozky.setListData(entries.toArray());
        lstPolozky.setCellRenderer(new SyndFeedListCellRender());

        txtDescription = new JTextArea();

        oddelovac = new JSplitPane(JSplitPane.VERTICAL_SPLIT, lstPolozky, txtDescription);
        add(oddelovac);

        setDefaultCloseOperation(EXIT_ON_CLOSE);

        pack();
    }

    /*...*/
}

Scrollovanie v zozname

  • zoznam položiek sa natiahne na takú výšku, koľko zaberajú všetky položky dohromady
  • chceme zaviesť podporu pre scrollovanie
  • samotný zoznam JList nevie scrollovať
  • vieme ho však hodiť do scrollovacej plochy, ktorá bude scrollovať ním: JScrollPane
  • do oddeľovača potom nepošleme zoznam položiek, ale celú JScrollPane

    public class MainForm extends JFrame {

    private RssService rssService = new RssService();
    
    private JList lstPolozky;
    private JSplitPane oddelovac;
    private JTextArea txtDescription;
    private final JScrollPane lstPolozkyScrollPane;
    
    public MainForm() throws MalformedURLException {
    
        lstPolozky = new JList();
    
        URL url = new URL("http://rss.sme.sk/rss/rss.asp?id=frontpage");
        List<SyndEntry> entries = rssService.getEntries(url);
        lstPolozky.setListData(entries.toArray());
        lstPolozky.setCellRenderer(new SyndFeedListCellRender());
    
        txtDescription = new JTextArea();
    
        lstPolozkyScrollPane = new JScrollPane(lstPolozky);
    
        oddelovac = new JSplitPane(JSplitPane.VERTICAL_SPLIT, lstPolozkyScrollPane, txtDescription);
        add(oddelovac);
    
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    
        pack();
    }
    

Oživenie zoznamu

  • dodajme interakciu: výber položky v zozname JList zobrazí jej popis v textovom políčku
  • zoznam JList vie vyvolávať udalosť „zmenil sa výber“ (“list selection”)
    • vieme teda pridať poslucháča ListSelectionListener
    • poslucháč je ľubovoľná trieda implementujúca tento interfejs
    • pridáme ho cez metódu addListSelectionListener()
  • využime anonymné vnútorné triedy

    lstPolozky.addListSelectionListener(new ListSelectionListener() {
        public void valueChanged(ListSelectionEvent e) {
            if(e.getValueIsAdjusting()) {
                return;
            }
            SyndEntry polozka = (SyndEntry) lstPolozky.getSelectedValue();          
            txtDescription.setText(polozka.getDescription().getValue());
        }
    });
    
  • pri výbere položky môže nastať viacero udalostí po sebe. Z metódy getValueIsAdjusting() vieme zistiť, či ešte prebieha zmena výberu alebo už skončila

  • zo zoznamu vyberieme aktuálny objekt a pretypujeme ho
  • v treťom kroku nastavíme textové políčko na správnu hodnotu

Doladenie textového políčka

  • Ak chceme, aby textové políčko scrollovalo tiež, hodíme ho do JSplitPane
  • Nastavme mu tiež zalamovanie riadkov cez setLineWrap()
  • a nastavme zalamovanie na hraniciach slov (nie na písmenách) cez setWrapStyleWord()
  • nastavme tiež preferovanú veľkosť po štarte aplikácie

    txtDescription = new JTextArea();
    txtDescription.setLineWrap(true);
    txtDescription.setWrapStyleWord(true);
    txtDescription.setPreferredSize(new Dimension(200, 200));
    

Celý kód:

public class MainForm extends JFrame {

    private RssService rssService = new RssService();

    private JList lstPolozky;
    private JSplitPane oddelovac;
    private JTextArea txtDescription;
    private final JScrollPane lstPolozkyScrollPane;
    private final JScrollPane txtDescriptionScrollPane;

    public MainForm() throws MalformedURLException {

        lstPolozky = new JList();

        URL url = new URL("http://rss.sme.sk/rss/rss.asp?id=frontpage");
        List<SyndEntry> entries = rssService.getEntries(url);
        lstPolozky.setListData(entries.toArray());
        lstPolozky.setCellRenderer(new SyndFeedListCellRender());
        lstPolozky.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if(e.getValueIsAdjusting()) {
                    return;
                }
                SyndEntry polozka = (SyndEntry) lstPolozky.getSelectedValue();
                txtDescription.setText(polozka.getDescription().getValue());
            }
        });
        lstPolozkyScrollPane = new JScrollPane(lstPolozky);

        txtDescription = new JTextArea();
        txtDescription.setLineWrap(true);
        txtDescription.setWrapStyleWord(true);
        txtDescription.setPreferredSize(new Dimension(200, 200));

        txtDescriptionScrollPane = new JScrollPane(txtDescription);



        oddelovac = new JSplitPane(JSplitPane.VERTICAL_SPLIT, lstPolozkyScrollPane, txtDescriptionScrollPane);

        add(oddelovac);

        setDefaultCloseOperation(EXIT_ON_CLOSE);

        pack();
    }

    public static void main(String[] args) throws Exception {
        new MainForm().setVisible(true);
    }
}

Nastavenie výzoru

  • skúsme meniť výzor (look-and-feel)
  • metóda UIManager.getSystemLookAndFeelClassName() vráti názov triedy výzoru pre systémovo štandardný L&F. (Na Windowse aplikácia pripomína výzor Windowsu, na MacOSe Aqua…)

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        new MainForm().setVisible(true);
    }
    
  • alternatívne môžeme zaviesť niektorý zo zabudovaných výzorov:

    <dependency>
      <groupId>com.jgoodies</groupId>
      <artifactId>jgoodies-looks</artifactId>
      <version>2.5.2</version>
    </dependency>
    
  • následne:

    UIManager.setLookAndFeel(new com.jgoodies.looks.windows.WindowsLookAndFeel());
    

Referencie

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *