Hem E-böcker Specialeffekter och spelutveckling i Java Navigationsmenyer  

Specialeffekter och spelutveckling i Java(TM) - En "fontförstorarmeny" med menyvalsbeskrivningar (FontEnlargerMenu)

av Anibal Wainstein

6.2.2 En "fontförstorarmeny" med menyvalsbeskrivningar (FontEnlargerMenu)

När jag satt framför datorn och utvecklade den här appleten, så fick jag ideligen meddelandet "nullpointerexception" när jag skulle köra den. Det spelade ingen roll hur mycket jag bankade på tangentbordet eller monitorn. Det fungerade helt enkelt inte. Efter att ha avverkat två tangentbord, så såg jag att jag hade skrivit en av HTML-parametertaggarna som "PARAN" istället för "PARAM" och det gjorde att appleten inte kunde läsa parametern. Det var ett löjligt men nästan omöjligt fel att hitta. Detta visar att även den bäste kan råka ut för pinsamma fel. Dessutom visar det också att våld mot datorer lönar sig, för jag hittade ju felet efter att ha gett den en omgång, eller hur?
"fontförstorarmenyn" som vi skall göra nu är en horizontell meny med ett antal menyval (i form av texter), som ändrar storlek när besökaren flyttar muspekaren över dem. När muspekaren pekar på ett av menyvalen så visas också en kort beskrivning. Skapa en tom fil som heter "fontenlargermenu.java" och lägg till appletdeklarationen och de nödvändiga "import" deklarationerna. Vi börjar med att titta på variabeldeklarationerna:

//"maxitems" får hålla reda på hur
//många menyval som användaren har
//specifierat.
public int maxitems;

//Arrayerna "items", "descriptions" och
//"urls" kommer att användas för att
//lagra menyvalen, dess beskrivningar
//och adresserna.
public String items[],descriptions[],urls[];
public String target;

//Variablerna "normalfont" och
//"mouseoverfont" lagrar fonterna som
//kommer att användas när vi skriver
//ut menyvalen. Metricsvariablerna
//används för att mäta på dessa fonter.
//Variablerna "descriptionfont" och
//"descriptionmetrics" används för
//menyvalbeskrivningstexten.
public Font normalfont,mouseoverfont,descriptionfont;
public FontMetrics normalmetrics,mouseovermetrics;
public FontMetrics descriptionmetrics;

//Följande variabler har kopierats
//från ButtonMenu appleten. Vi behöver
//dem. Vi har också lagt till "textcolor"
//variabeln.
public Image bufferimage;
public Graphics bufferg;
public Color backgroundcolor,textcolor;
public Image backgroundimage=null;
public Dimension d;

//"currentitem" kommer att användas
//för att hålla reda på vilken
//menyval som precis har valts.
public int currentitem=0;

//Variabeln "displaydescription"
//indikerar om beskrivningstexten
//skall skrivas ut.
public boolean displaydescription=false;


Variabeln "maxitems" får som vanligt hålla reda på antalet menyval. Arrayerna "items", "descriptions" och "urls" används för att lagra menyvalstexten, dess beskrivningar och adresserna. Den här menyn kommer att använda två fonter för varje menyval, en heter "normalfont" och används för att rita ut texten när besökaren inte fifflar med appleten. När besökaren pekar på ett speciellt menyval så används fonten "mouseoverfont" för att rita texten istället. Vi skall ha ännu en font, "descriptionfont", och den används när vi skall rita ut beskrivningstexten. Dessa tre fonter har dessutom var sitt FontMetrics objekt. Nu när vi arbetar med texter så har vi också en färgvariabel för att lagra textfärgen, den heter "textcolor". Den sista variabeln som bör nämnas är "displaydescription", när den är sann så skall det visas en beskrivningstext för menyvalet som muspekaren pekar på. Metoden init() är ganska komplicerad:

public void init()
{
    //while-slingan söker igenom hur många
    //"item" parametrar det finns.
    maxitems=0;
    while (getParameter("item"+maxitems)!=null) maxitems++;

    items=new String[maxitems];
    descriptions=new String[maxitems];
    urls=new String[maxitems];

    //Parametrarna för varje menyval läses
    //in.
    for (int i=0; i<maxitems; i++)
{
items[i]=getParameter("item"+i);
descriptions[i]=getParameter("description"+i);
urls[i]=getParameter("url"+i);
} //Bakgrundsfärgen och textfärgen läses in. backgroundcolor=new Color(getIntegerParameter("backgroundcolor",16)); textcolor=new Color(getIntegerParameter("textcolor",16)); //Bakgrundsbilden läses in, det är bara att //kopiera och klistra in raderna från TextScroller3. MediaTracker tracker=new MediaTracker(this); String backimage=getParameter("backgroundimage"); if (backimage!=null && (backimage.toUpperCase().indexOf("JPG")>-1 || backimage.toUpperCase().indexOf("GIF")>-1)) { backgroundimage=getImage(getDocumentBase(),backimage); tracker.addImage(backgroundimage,0); try {tracker.waitForAll();} catch(InterruptedException e) {} } //Bufferten initieras... //Klistra in raderna //från textscroller3 exemplet. d=size(); bufferimage=createImage(d.width,d.height); bufferg=bufferimage.getGraphics(); //Följande rader har kopierats från //TextScroller3 appleten för att //ta reda på om appletanvändaren //vill ha fet eller kursiv stil //på menytexten. int fonttype=0; if (getParameter("italic")!=null && getParameter("italic").substring(0,1).equalsIgnoreCase("y")) fonttype+=Font.ITALIC; if (getParameter("bold")!=null && getParameter("bold").substring(0,1).equalsIgnoreCase("y")) fonttype+=Font.BOLD; //Skapa menyvalfonterna med de parametrar som har //specifierats. Observera att nu finns det två //fontsizeparametrar, "normalfontsize" och "mouseroverfontsize". normalfont=new Font(getParameter("font"),fonttype,getIntegerParameter("normalfontsize",10)); mouseoverfont=new Font(getParameter("font"),fonttype,getIntegerParameter("mouseoverfontsize",10)); //Initiera metricsvariablerna så att //de kan användas för att mäta fonterna. bufferg.setFont(normalfont); normalmetrics=bufferg.getFontMetrics(); bufferg.setFont(mouseoverfont); mouseovermetrics=bufferg.getFontMetrics(); //För descriptionfonten bestämmer vi //storleken och typen. descriptionfont=new Font("Helvetica",Font.PLAIN,12); bufferg.setFont(descriptionfont); descriptionmetrics=bufferg.getFontMetrics(); //Targetparametern laddas in... target=getParameter("target"); }

Till att börja med så initieras "maxitems". Här har vi bara klistrat in raderna från ButtonMenu och ändrat "normalimage" till "item". Nästa steg är att initiera arrayerna och läsa in färgerna och bilderna samt att initiera bufferten. Här kan du också klistra in många av raderna från TextScroller3 eller ButtonMenu. Efter ett tag när man har utvecklat många applets så finner man att man lätt kan återanvända många metoder och kodrader. Raderna för att ta fram fontstilen klistras också in. När det gäller fonterna så skall "normalfont" och "mouseoverfont" ha samma fontnamn och stil, men de skall ha varsin "fontsize" parameter. Då kan appletanvändaren specifiera olika fontstorlekar. Efter det så initieras "normalmetrics" och "mouseovermetrics" som är FontMetrics-objekten för de två fonterna. Fonten som används för beskrivningstexten får vara fast, fontnamnet blir "TimesRoman" med vanlig stil och storlek 12, den får användaren inte ändra på (det finns ingen anledning till det heller). Okej, innan vi fortsätter så hoppas jag att du kom ihåg att klistra in getIntegerParameter(), gotoURL() och update() från ButtonMenu appleten.
Metoden paint() ser ut som följer:

public void paint(Graphics g)
{
if (bufferg!=null)
{
if (backgroundimage!=null)
{
bufferg.drawImage(backgroundimage,0,0,this);
}
else
{
bufferg.setColor(backgroundcolor);
bufferg.fillRect(0,0,d.width,d.height);
}
//Slingan ser till att alla menyval
//ritas ut.
for (int i=0; i<maxitems; i++)
{
bufferg.setColor(textcolor); //If-satsen undersöker om besökaren //pekar på menyvalet. Beroende på om //han/hon gör det eller inte så //används "mouseovermetrics" eller //"normalmetrics" för att mäta på //fonten. if (currentitem==i) { //Följande rad används för att centrera //menytexten horizontellt. int dx=(d.width/maxitems-mouseovermetrics.stringWidth(items[i]))/2; //Följande rad används för att centrera //knappen vertikalt. int dy=(d.height-mouseovermetrics.getHeight())/2; //Besökaren pekar på den här meny- //valet så därför använder vi //mouseover fonten. bufferg.setFont(mouseoverfont); //Observera att eftersom menyn är en vertikal //meny så ser vi till att det finns ett //steg på (d.width/maxitems) innan nästa //menyval skrivs ut. bufferg.drawString(items[i],dx+i*d.width/maxitems,dy+mouseovermetrics.getAscent()); } else { //Besökaren pekar INTE på den här meny- //valet så därför använder vi //normal fonten. bufferg.setFont(normalfont); int dx=(d.width/maxitems-normalmetrics.stringWidth(items[i]))/2; int dy=(d.height-normalmetrics.getHeight())/2; bufferg.drawString(items[i],dx+i*d.width/maxitems,dy+normalmetrics.getAscent()); } } //Om "displaydescription" är satt, //så rita ut en beskrivningstext //för menyvalet besökaren pekar på. //Skriv ut texten längst ner //på appletfönstret. if (displaydescription) { bufferg.setColor(textcolor); bufferg.setFont(descriptionfont); bufferg.drawString(descriptions[currentitem] ,(d.width-descriptionmetrics.stringWidth(descriptions[currentitem]))/2 ,d.height-2); } g.drawImage(bufferimage,0,0,this); } }

Raderna som ritar ut bakgrundsbilden har jag klistrat in från ButtonMenu, men annars ser metoden helt annorlunda ut. For-slingan ritar ut alla menyval horizontellt. Där inne så undersöker vi först om "currentitem" pekar på ett menyval, om den gör det så använder den "mouseoverfont" för att rita ut texten. Varje text centreras med hjälp av variablerna "dx" och "dy". Vi kan lätt få reda på bredden och höjden på en text med FontMetrics-metoderna stringWidth() och getHeight(). Vi räknar ut "dx" och "dy" på liknande sätt som vi gjorde i ButtonMenu exemplet, fast vi använder istället bredden och höjden på varje menytext istället. Observera också att eftersom den här menyn är horizontell, så adderas termen i*d.width/maxitems till x-posisitionen för varje text och det leder till att texterna radas upp i x-led. Om besökaren inte pekar på ett menyval så används "normalfont" och "normalmetrics" för att rita ut texten istället. Slutligen så undersöks om "displaydescription" är sant så att beskrivningstexten skrivs ut. Den här texten centreras horizontellt i mitten av appletområdet och ritas längst ner på appleten med hjälp av termen (d.height-2). Metoden mouseMove() är inte så komplicerad:

public boolean mouseMove(Event e, int x, int y)
{
    //Här fungerar beräkningen av menyvalet
    //nästan exakt som i ButtonMenu, fast vi
    //använder "x" och "d.width" istället.
    currentitem=x/(d.width/maxitems);

    //"displaydescription" måste nu
    //sättas så att beskrivningen för det
    //valda menyvalet kommer upp.
    displaydescription=true;
    update(getGraphics());
    return true;
}


Det enda vi gör här är att beräkna "currentitem" och sätta "displaydescription" till sant. Variabeln "currentitem" kan sedan användas i paint() metoden ovan, för att undersöka om ett menyval har valts. Metoderna mouseExit() och mouseDown() ser ut som följande:

public boolean mouseExit(Event e, int x, int y)
{
    //"displaydescription" måste nu
    //sättas till falsk.
    displaydescription=false;

    //Om användaren lämnar appletområdet
    //så sätts "currentimage" till -1 så
    //att ingen text ser ut att vara förstorad.
    currentitem=-1;

    update(getGraphics());
    return true;
}

public boolean mouseDown(Event e, int x, int y)
{
    gotoURL(urls[currentitem],target);
    return true;
}

I mouseExit() så sätts "currentitem" till -1, dvs den pekar på ingenting. Variabeln "displaydescription" sätts till falskt, så att beskrivningstexten inte syns. Den enda som man behöver göra i mouseDown() är att anropa gotoURL() med adressen till det menyval som "currentitem" indikerar. Parametrarna för appleten skulle kunna se ut så här:

<APPLET CODE="fontenlargermenu.class" WIDTH=500 HEIGHT=50>
<PARAM name="backgroundcolor" value="000000">
<PARAM name="textcolor" value="00afff">
<PARAM name="backgroundimage" value="background3.jpg">
<PARAM name="font" value="TimesRoman">
<PARAM name="normalfontsize" value="16">
<PARAM name="mouseoverfontsize" value="20">
<PARAM name="italic" value="no">
<PARAM name="bold" value="yes">
<PARAM name="item0" value="Huvudsida">
<PARAM name="item1" value="Om Javahuset">
<PARAM name="item2" value="Kontakta oss">
<PARAM name="item3" value="Applets">
<PARAM name="description0" value="Kom till Javahusets huvudsida.">
<PARAM name="description1" value="Här är en beskrivning på vad vi gör.">
<PARAM name="description2" value="Skriv ett brev till oss.">
<PARAM name="description3" value="Titta på vår appletsamling">
<PARAM name="url0" value="http://www2.passagen.se/javahuset/">
<PARAM name="url1" value="http://www2.passagen.se/javahuset/omjavahuset.html">
<PARAM name="url2" value="http://www2.passagen.se/javahuset/kontaktaoss.html">
<PARAM name="url3" value="http://www2.passagen.se/javahuset/applets.html">
<PARAM name="target" value="">
</APPLET>

Skillnaden här, gentemot parametrarna i ButtonMenu, är att vi har lagt in font-parametrar också. Nu är det dags att titta på appleten, här är FontEnlargerMenu.

Vi har nu gått igenom alla de nödvändiga kunskaper som du måste ha för att kunna utveckla proffessionella applets. Men hittills har du bara ett blått bälte i appletprogrammering. Nästa kapitel kommer vi att gå igenom avancerad bildbehandling, som är en teknik som mycket få Java-programmerare kan, då kommer ditt bälte att bli svart som natten...

 


Nästa sida >>