001    /**
002    * @author Václav Mikolášek
003    * nicklaus@students.zcu.cz
004    */
005    
006    package animace.label;
007    
008    import animace.*;
009    import javax.swing.*;
010    import javax.imageio.*;
011    import java.awt.*;
012    import java.awt.image.*;
013    import java.awt.event.*;
014    import java.io.*;
015    import java.util.*;
016    
017    /**
018     * PictureLabel je potomkem třídy JLabel, umožňuje umísťovat
019     * objekty třídy MoveablePicture a stará se o to, aby byly vkresleny
020     * Viz metoda paintComponent. Pokud uživatel klikne na PictureLabel, je
021     * zajištěno obsluhou teto události, že kliknul-li na nějaký MoveablePicture,
022     * je mu tato událost distribuována (volaním processEvent(e)).
023     */
024     public class PictureLabel extends JLabel {
025            
026            private BufferedImage background;
027                                    
028            private ArrayList mPictures = new ArrayList();          // MoveablePicture List
029            private Iterator it;
030    
031            /**
032             * Vytvoří PictureLabel s obrázkem na pozadí
033             * @param background obrázek, který příjde na pozadí
034             */
035            public PictureLabel(BufferedImage background) {
036                    this.background = background;
037                    init();
038            }
039    
040            /**
041             * Vytvoří PictureLabel bez obrázku.
042             */
043            public PictureLabel() {
044                    this.background = null;
045                    init();
046            }
047            
048            /**
049             * Inicializační metoda nastaví opaque na true. Tím urychlíme vykreslování.
050             * Předpokládá se ovšem že obrázek na pozadí je neprůhledný. Pozor! Voláním
051             * setOpaque(true) nezpůsobíme neprůhlednost PictureLabelu, jen řekneme, že je neprůhledný
052             * a o to, aby doopravdy byl, se musíme postarat sami.  Protože dědíme od
053             * JLabelu, který je implictině průhledný : isOpaque() vrací false, je toto volání nezbytné.
054             */
055            public void init() {
056                    setOpaque(true); // DULEZITE !
057                    addMouseListener(new ClickListener());
058            }
059                    
060            /**
061             * Vykreslí obrázek na pozadí a potom volá metodu paint(Graphics g) nad všemi svými
062             * MoveablePictures a nad každým jeho PaintControlerem ještě volá objectPainted();
063             */
064            public void paintComponent(Graphics g) {
065                            
066                    if (background != null)
067                            g.drawImage(background,0,0,null);
068                    else {
069                            g.setColor(Color.white);
070                            g.fillRect(0,0,getWidth(),getHeight());
071                    }
072                    
073                    it = mPictures.iterator();
074                    while(it.hasNext()) {
075                            MoveablePicture mp = (MoveablePicture) it.next();
076                            mp.paint(g);
077                            mp.getPaintControl().objectPainted();
078                            
079                    }
080            }
081            
082            /**
083             * Touto metodou přidáváme pohyblivé obrázky na PictureLabel
084             */
085            public void addMoveablePicture(MoveablePicture mp){
086                    mPictures.add(mp);
087            }
088            
089            /**
090             * doMPLayout romzisti vsechny MoveablePictures do jakehosi grid layoutu
091             * Tady je to spise pomocna metoda.
092             */
093            public void doMPLayout() {
094                    int perRow      = 7;            // pocet MPictures na jedne radce
095                    int xGap        = 10;           // odsazeni na ose x
096                    int yGap        = 5;            // odsazeni na ose y
097                    Iterator it = mPictures.iterator();
098                    for(int i = 0; it.hasNext(); i++) {
099                            MoveablePicture mp = (MoveablePicture) it.next();
100                            mp.setLocation((i%perRow)*(mp.getWidth() + xGap) + (getPreferredSize().width - (perRow * (mp.getWidth() + xGap))) / 2, i / perRow * (mp.getHeight()+ yGap));
101                    }
102            }
103            
104            /**
105             * Vnitřní třída, která implementuje MouseListener (dědí od MouseAdapter)
106             * a zajišťuje, že kliknutí nad touto komponentou (JLabelem) bude posláno dál
107             * jestliže se uskutečnilo nad nějakým MoveablePicturem. Tím, že procházím
108             * seznam mPictures v opačném pořadí než jsou objekty vykreslovány, reším to, který  
109             * objekt leží nad kterým, takže se nemůže stát, že bude volána metoda processEvent
110             * nad objektem, který leží vespod.
111             */
112            public class ClickListener extends MouseAdapter {
113                    public void mouseClicked(MouseEvent e) {
114                            MoveablePicture mp;
115                            boolean oneHasBeenClicked = false;
116                            
117                            Point click = e.getPoint();
118                            ListIterator lit = mPictures.listIterator(mPictures.size());
119                            while(lit.hasPrevious()) {
120                                    mp = (MoveablePicture) lit.previous();
121                                    if (mp.contains(click)) {
122                                            mp.processEvent(e);
123                                            oneHasBeenClicked = true;
124                                            break;
125                                    }
126                            }
127                            
128                            /// jeslize se nekliklo na MoveablePicture, tak s kliknutim nalozte
129                            /// jak chcete
130                            if (!oneHasBeenClicked) {
131                                    //
132                                    // Tady muze byt obsluha, kterou chceme 
133                                    // provest primo nad PictureLabelem
134                                    //
135                            }
136                    }
137            }
138    }