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 }