4.1.4 En konfigurerbar
och effektfull bildvisare (SlideShow)
Även om AppletAnimator II kan användas
för att visa bilder så är den inte särskilld
imponerande. Här ska vi nu göra en mer animerad
bildvisare som flyttar in en ny bild från ett slumpmässigt
område. Äntligen kommer vi i kontakt med slumptal.
Det finns en mycket användbar klass i Java som heter
Math. Denna består mest av statiska metoder så
du behöver inte göra ett Math-objekt för
att kunna använda dessa utan de kan anropas direkt.
En mycket viktig metod är random() metoden, som lämnar
ett slumpvärde mellan 0 och 0.999999999... i form av
ett flyttal (double). Genom att t.ex. multiplicera med tio
så skulle du kunna få slumptal mellan 0 och
9. Observera att när man talkonverterar
en double till integer så kommer talet att avrundas
ner. Se på följande rad:
int slumpvarde = (int)(Math.random()*2.0);
Variabeln "slumpvarde" kommer att
sättas till 0 eller 1. I bildvisaren kommer vi att
använda oss av slumptal för att bestämma
var en bild kommer ifrån. Vi kan faktiskt ta alla
variabler och metoder i AppletAnimatorII appleten och använda
dessa med bara en ändring i run() och paint() metoderna
samt lägga till följande globala applet variabler
precis under deklarationen av "currentimage" variabeln:
int nextimage = 0;
int nextimagexposition = 0;
int nextimageyposition = 0;
Dessa variabler bestämmer vilken bild som kommer
att animeras in i appletskärmen och vad dess nuvarande
position är. Paint() metoden kommer då att
se ut så här:
public synchronized void paint(Graphics g)
{
g.drawImage(images[currentimage],0,0,this);
//följande bild ritas ovanpå den gamla bilden
g.drawImage(images[nextimage]
,nextimagexposition,nextimageyposition,this);
}
Run() metoden blir dock lite mer komplicerad.
Vi måste nu för första gången få
reda på appletens dimensioner, ty den som kommer att
återanvända appleten kommer troligtvis att ändra
storlek. Det gör man med Applet metoden size(), som
lämnar ett Dimension objekt. Med detta kan vi sedan
få reda på appletens bredd och höjd med
objektets variabler "width" och "height".
public void run()
{
//vi tar reda på appletens dimension och
//sparar det i variabeln d. Vi kan nu komma
//åt appletens bredd och höjd genom att skriva
//d.width resp. d.height
Dimension d=size();
//displacement variablerna specifierar
//startkoordinaterna för bilden
int displacementx=0;
int displacementy=0;
//pathsize kommer att användas för att veta
//vilket avstånd som den nya bilden kommer
//att flyttas
int pathsize=0;
//currentimage initieras så att den börjar med
//den första bilden, följt av nästa bild som blir
//bild nummer två osv
currentimage=0;
nextimage=1;
while (true)
{
//Vi räknar ut startpositionerna för bilderna,
//dvs varifrån bilderna ska komma från.
int directionx=(int) (Math.random()*3.0)-1;
int directiony=(int) (Math.random()*3.0)-1;
//directionx och directiony kan komma
//att få tre värden: -1, 0 och 1.
//Det är inte kul om båda får värdet 0
//samtidigt, så därför så ändrar vi på
//directiony så att effekten blir lite
//roligare
if (directionx==0 && directiony==0) directiony=1;
//variabeln pathsize sätts till bredden eller
//höjden beroende på vilken som är lägst
if (d.width<d.height) pathsize=d.width;
else pathsize=d.height;
//följande rad är skydd mot problemet
//om användaren specifierar bara en enda
//bild
if (nextimage>maxitems-1) nextimage=0;
//följande slinga tar hand om att uppdatera
//skärmen under animeringen. Den kommer att
//flytta bilden det antal ggr som specifieras
//av pathsize, dvs kortsidan av appleten.
for (int i=0; i<=pathsize; i++)
{
//bildpositionerna flyttas med
//bråkdelen (i/pathsize).
nextimagexposition=displacementx
-directionx*(i*d.width)/pathsize;
nextimageyposition=displacementy
-directiony*(i*d.height)/pathsize;
update(getGraphics());
try {Thread.sleep(sleeptime);}
catch(InterruptedException e) {}
}
//när flyttningen är klar så sätts currentimage
//till den nya bilden
currentimage=nextimage;
//Vi ökar nextimage så att den
//pekar på nästa bild, samtidigt så ser vi till
//att nextimage inte överstiger arrayens index
//utan att den tvingas börja om från början
nextimage++;
if (nextimage>maxitems-1) nextimage=0;
}
Appleten börjar med att placera en bild utom synhåll
för åskådaren, dvs utanför appletskärmen.
Sakta så flyttar den in bilden mot centrum, en pixel
i taget. Ett problem som kan uppkomma här är
om appleten är en rektangel och inte en kvadrat.
Då måste appleten flytta bilden med olika
horisontella och vertikala steg. Därför hämtar
vi kortsidan på appletskärmen och for-slingan
får räkna upp till den här sidans pixelantal
(variabeln "pathsize"). Vi räknar upp ett
procentuellt värde på hur mycket bilden
skall röra sig (i/pathsize) och multiplicerar sedan
med d.width eller d.height för att få den totala
horisontella resp. vertikala sträckan som den har
rört sig.
Problemet här är att eftersom vi håller
på med integers så måste vi utföra
divisionen sist och därför skriver vi ((i*d.width)/pathsize)
istället. Annars så skulle (i/pathsize) alltid
ge värdet noll eftersom värdet på "pathsize"
är större än "i". Detta är
viktigt, dividerar man ett mindre heltal med ett
större så blir resultatet alltid noll.
Slutligen måste vi också multiplicera den
här termen med "directionx" eller "directiony"
så att bilden rör sig åt rätt håll.
Till slut så drar vi av den här termen från
"displacementx" resp. "displacementy"
som är bildens startkoordinater.

Bilden visar hur bildvisaren
fungerar. Den nya bilden "nextimage" kommer att
flytta sig över den gamla
bilden "currentimage".
Efter for-slingan så sätter vi
den nya bilden till "currentimage" och ökar
"nextimage". Om "nextimage" tidigare
har pekat på sista bilden så sätter vi
den till att peka på den första bilden istället
(index noll). Resultatet blir att bilderna kommer att rotera
runt. Den här raden måste kopieras till före
for-slingan också i händelse att användaren
av någon konstig anledning bara skulle vilja specifiera
en enda bild. Detta måste göras för att
slippa krascher. Nu kan du titta på resultatet genom
att klicka här.
Nu blev du ganska besviken, va? All den här
mödan bara för en flimrig applet! Problemet med
appleten är att när första bilden har ritats
ut i paint() metoden med drawImage() så uppdateras
appletskärmen omedelbart. Den visar därför
hela grundbilden innan den hinner rita över den med
nästa bild. Vi måste alltså hitta ett sätt
att förhindra att appletskärmen uppdateras mellan
de två drawImage() anropen. Det är här dubbelbuffringstekniken
kommer in och som vi kommer att diskutera i nästa delkapitel.