Codice commentato di MultiImage
Questa classe si occupa di preparare le immagini da visualizzare e di chiamare periodicamente il metodo di aggiornamento dei pixel delle istanze di ImageChanger. E' decisamente semplice e lineare, grazie al polimorfismo run-time di Java.
Indice
MultiImage.class
Clicca qui per il codice completo.
Impostiamo l'applet implementando Runnable in modo che si crei un Thread per il refresh dell'immagine. Implementiamo qualche costante, fra cui la più importante è NUM_CLASSES che permette al sistema di sapere fra quante istanze di ImageChanger può scegliere (a caso).
Le variabili sono abbastanza autoesplicative, però conviene notare paintImage che conterrà l'immagine creata run-time.
public class MultiImage extends Applet implements Runnable {
public final static String IMAGE_PARAM = "Immagine";
public final static String IMAGE_MASK_PARAM = "ImmagineMask";
public final static String WAIT_BETWEEN_FRAMES = "AttesaFraImmagini";
public final static Font FONT = new Font("TimesRoman", Font.BOLD, 16);
public final static int NUM_CLASSES = 10;
Image img[];
Image imgMask = null;
boolean imageDone = false;
Thread thread;
long waitBetweenFrames;
Image paintImage = null;
In init() per prima cosa cerchiamo di scoprire quante immagini sono state impostate come parametro. In questo modo l'applet può accettare un numero indefinito di immagini.
In seguito cerchiamo di vedere se l'utente ha impostato il parametro che indica il tempo di attesa fra le animazioni: se non l'ha fatto (o l'ha fatto in modo errato), impostiamo noi un valore di default.
Infine impostiamo un Thread parallelo che facciamo partire subito per iniziare a scaricare le immagini.
public void init() {
int count = -1;
String str = "";
while(str != null) {
count++;
str = getParameter(IMAGE_PARAM + count);
}
img = new Image[count];
str = getParameter(WAIT_BETWEEN_FRAMES);
if (str == null)
waitBetweenFrames = 3 * 1000;
else
try {
waitBetweenFrames = Integer.parseInt(str);
} catch(NumberFormatException e) {
waitBetweenFrames = 3 * 1000;
}
thread = new Thread(this, "MultiImage: Data-pump Thread");
Thread.currentThread().setPriority(Thread.NORM_PRIORITY+2);
Thread.currentThread().setName("MultiImage: Paint Thread");
thread.setPriority(Thread.NORM_PRIORITY+1);
thread.setName("MultiImage: Data-pump Thread");
thread.start();
}
In init() creiamo un'altro Thread per assicurarci che ce ne sia sempre uno attivo. Siccome il Thread controlla di essere quello memorizzato, uno in eccesso morirà automaticamente.
public void start() {
thread = new Thread(this);
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
stop() uccide semplicemente il Thread.
public void stop() {
thread = null;
}
In run() per prima cosa ci sinceriamo che le immagini siano state caricate. In caso negativo provvediamo.
public void run() {
if(img[0] == null) {
MediaTracker mt = new MediaTracker(this);
for(int i=0; i<mg.length; i++) {
img[i] = getImage(getCodeBase(), getParameter(IMAGE_PARAM + i) );
mt.addImage(img[i], 0);
}
imgMask = getImage(getCodeBase(), getParameter(IMAGE_MASK_PARAM) );
mt.addImage(imgMask, 0);
try {
mt.waitForAll();
} catch(InterruptedException e) { return; }
}
Adesso entriamo nel cuore dell'applet: il gestore delle animazioni. Per prima cosa istanziamo una oggetto discendente da ImageChanger passandogli le immagini da trattare ed, eventualmente, la maschera. Come si può notare gli effetti sono scelti a caso.
int curFrame = 0;
while(thread == Thread.currentThread()) {
int num = (int)(Math.random() * (NUM_CLASSES));
//System.out.println(num);
Image img_src = img[curFrame];
Image img_dest;
if(curFrame == img.length-1) {
img_dest = img[0];
curFrame = 0;
} else {
img_dest = img[curFrame+1];
curFrame++;
}
ImageChanger ic;
try {
switch(num) {
case 0 :
ic = new HorizontalBar(img_src, img_dest,
img_src.getHeight(null), this);
break;
case 1 :
ic = new RandomPixel(img_src, img_dest,
200, this);
break;
case 2 :
ic = new FadeOutIn(img_src, img_dest,
200, this);
break;
case 3 :
ic = new Moreus(img_src, img_dest,
200, this);
break;
case 4 :
ic = new SqrtPixel(img_src, img_dest,
200, this);
break;
case 5 :
ic = new BounceMask(img_src, img_dest,
imgMask, 600, this);
break;
case 6 :
ic = new BounceMaskOnlySrc(img_src, img_dest,
imgMask, 600, this);
break;
case 7 :
ic = new BounceMaskOnlyDest(img_src, img_dest,
imgMask, 600, this);
break;
case 8 :
ic = new BounceMaskFullColor(img_src, img_dest,
imgMask, 600, this);
break;
case 9 :
ic = new HorizontalBarBig(img_src, img_dest,
img_src.getHeight(null), this);
break;
default:
ic = new HorizontalBar(img_src, img_dest,
img_src.getHeight(null), this);
break;
}
} catch(DataException e) {
System.out.println("Errore " + e);
return;
}
System.out.println("ic == " + ic);
Adesso richiediamo all'istanza appena creata di restituirci un handle all'immagine che verrà modificata. In questo modo posso ridisegnare la finestra dopo essermi accertato che il metodo paint sia al corrente che l'immagine è pronta. In seguito chiamo step() (che aggiorna l'immagine) e chiedo il ridisegno specificando la dimensione da ridisegnare. Non facendo così il sistema non aggiorna correttamente lo schermo.
paintImage = ic.getImage();
imageDone = true;
repaint();
try { Thread.sleep(waitBetweenFrames); }
catch(InterruptedException e) { return; }
int last = 100;
while( (thread == Thread.currentThread()) && (last > 0)) {
last = ic.step();
repaint(0,0,paintImage.getWidth(null), paintImage.getHeight(null));
Thread.yield();
}
}
System.out.println("Thread exiting...");
}
Il metodo di disegno è semplice e si scompone in 2 parti a seconda che l'animazione sia pronta o meno.
public void update(Graphics g) { paint(g); }
public void paint(Graphics g) {
if (!imageDone) {
g.setColor(Color.black);
g.setFont(FONT);
g.fillRect(0,0, getSize().width, getSize().height);
g.setColor(Color.yellow);
g.drawString((img.length+1) +
" immagini in caricamento... attendere, prego :-)", 30,
getSize().height/2);
g.drawString("MindFlavor", getSize().width-100,
getSize().height - 10);
} else {
g.drawImage(paintImage, 0, 0, this);
}
}
Per vedere il codice commentato della classe astratta ImageChanger, seguite il collegamento.
Indice
|