Animerade bilder
Provkör klassen
Tema:
- Image
- MediaTracker
- Flertrådiga program
- Applet parametrar från HTML sidan
Trådar (Threads)
För att få en liten grund till vad trådar är kan du prova följande (om du har NT eller W2K):
- Starta Task Managern (t.ex gemom att ta Ctrl+Alt+Del)
- Välj "fliken" Processes
- Välj sedan i menyn View, Select Columns... där du kryssar för Thread Countoch klickar sedan på OK
- Bredda vid behov task Managerns fönster.
Du kommer i detta fönster att se att många program/processer har en Thread Count som
är större än 1. Detta betyder att dessa program består av flera "delprogram" som körs
pararellt. T.ex. Excel kan lägga igång en omkalkylering av kalkylarket medan en annan del av
programmet kör vidare med sitt. De olikia processerbna i ett program som kan pararellköras
kallas för Threads eller trådar
I VB ser vi aldrig dessa trådar, men i Java kan vi direkt
skapa fler trådar. Om vi t.ex. vill ha ett program som med jämna mellanrum visar en ny bild
måste vi skapa en separat tråd som sköter om dessa byten. I annat fall skulle hela
programmet vara upptaget med bildbytena, och skulle inte kunna göra någonting annat.
Asynkron laddning och MediaTrackern
Ett annat inneboende problem med Java (och indirekt Internet) är att saker och ting
inte sker s.k. synkront. Tänk dig t.ex. att du i ett VB program öppnar en fil. Programmet
kommer då att stanna till vid filöppningen, tills filen är helt läst. Sedan fortsätter
programmet.
I Internet sker motsvarande oftast asynkront. Detta betyder att när vi öppnar en fil
(t.ex. en bildfil), så kommer programmet att fortsätta även om inte filen är helt inläst.
Detta gör att vi efter att ha öppnat en bild inte kan vara helt säkra på att denna bild
är tillgänglig i vårt program. Den kan fortfarande hålla på och laddas...
På grund av ovastående orsaker är bildhanteringen inte så enkel i Java. Till vår hjälp har vi
dock en klass benämnd MediaTracker, som kan hålla en koll på bilderna och meddela när de är laddade.
Nedanstående program är en direkt variant på den exempelkod som finns för MediaTracker i Javas
hjälp.
För att köra programmet måste vi ha en katalog med namnet images som skall finnas
direkt under den katalog vi har vårt projekt i. Denna katalog skall innehålla en bild med namnet
background.gif, samt 5 st. bildfiler med namnen anim0.jpg, anim1.jpg, anim2.jpg, anim3.jpg samt anim4.jpg
På testsidan finns färdiga bilder du kan använda Klicka här
ImageBlaster.java
Skapa en fil med namnet ImageBlaster.java och sätt in följande kod:
import java.applet.Applet;
import java.awt.*;
public class ImageBlaster extends Applet
implements Runnable // för att få ett flertrådigt program
// har vi Runnable måste vi ha en start, stop och
// run funktion i vårt program (se nedan)
{
// MediaTrackern kan hålla reda på om alla bilder är laddade
MediaTracker tracker;
// bakgrundsbilden
Image bg;
// en array med 5 st Images
Image anim[] = new Image[5];
// nuvarande bild
int index;
// en separat tråd som skall sköta om animationen
Thread animator;
// hämta bilden för bakgrunden (id = 0)
// och de fem bilderna som skall animeras (id == 1)
// och lägg in dem i MediaTrackern så att vi vet
// när de är laddade
public void init()
{
// skapa en MediaTracker som skall meddela oss
// när bilderna är laddade
tracker = new MediaTracker(this);
// hämta bakgrundsbilden
// getDocumentbase() säger var Appletten finns
// bilderna antas finnas i en images katalog
// under den katalog som appletten finns i
// getDocumentBase fungerar inte för en Application
bg = getImage(getDocumentBase(),
"images/background.gif");
// eftersom bilden inte laddas ommeddelbart så
// säger vi åt vår MediaTracker att den skall meddela oss
// när den finns tillgänglig
tracker.addImage(bg, 0);
// hämta resten av bilderna som antas finnas i en images katalog
// ochhet anim0.gif, anim1.gif ... anim4.gif
for (int i = 0; i < 5; i++)
{
anim[i] = getImage(getDocumentBase(),
"images/anim"+i+".gif");
// säg åt MediaTrackern at den skall meddela oss när
// bilderna är tillgängliga
tracker.addImage(anim[i], 1);
}
}
// start behövs om man har implements Runnable
// dvs om man har ett flertrådigt program
public void start()
{
// skap en till tråd och sätt den i animator objektet
animator = new Thread(this);
// starta denna tråd
animator.start();
}
// stop behövs om man har implements Runnable
public void stop()
{
// stopp tråden
animator.stop();
// och döda den
animator = null;
}
// Kör animeringstråden
// men vänta först på att alla bilder är laddade
public void run()
{
// felhanteringen i Java fungerar med try - catch systemet
// som i C++
// vi försöker således vänta på att bakgrunden är laddad
// för att sedan vänta på att de övriga bilderna blivit
// laddade
try {
tracker.waitForID(0);
tracker.waitForID(1);
}
// någonting har gått fel - avbryt körningen
catch (InterruptedException e)
{
return;
}
// Kolla vilken tråd vi kör
// och sätt undan denna i en Thread
Thread me = Thread.currentThread();
// så länge som den körda tråden är animerings tråden
while (animator == me)
{
// försök stoppa tråden 100 millisekunder
try {
Thread.sleep(1000);
}
// om det inte gick så avbryter vi loopen
catch (InterruptedException e)
{
break;
}
// vi skall öka på index för vilken bild som skall visas
// för att undvika att någon annan del av programmet
// försöker göra någonting åt index variabeln så
// använder vi ordet synchronized, som betyder att
// denna kod måste bli färdig innan någon annan tråd eller
// del av programmet får röra index variabeln
synchronized (this)
{
index++;
if (index >= anim.length)
{
// om vi har den sista bilden så tar vi som nästa
// den första
index = 0;
}
}
// rita om Appletten
repaint();
}
}
// vid uppdatering så ritar vi om allt
public void update(Graphics g)
{
paint(g);
}
// Rita en röd bakgrund om bilderna inte kunde hämtas
// I annat fall så ritar vi dit bakgrundsbilden
public void paint(Graphics g)
{
// har någonting gått fel vid bildhämtningen?
if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0)
{
// röd färg över hela bakgrunden
g.setColor(Color.red);
g.fillRect(0, 0, getSize().width, getSize().height);
// och bort härifrån
return;
}
// kom vi hit borde vi ha en bakgrundsbild som vi
// då kan rita ut
g.drawImage(bg, 0, 0, this);
// har vi hunnit ladda alla andra bilder?
if (tracker.statusID(1, false) == MediaTracker.COMPLETE)
{
// om så är fallet så kan vi rita ut den som
// är aktuell. Om index är 1 kommer således
// anim1.gif att ritas
g.drawImage(anim[index], 10, 10, this);
}
}
}