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 }