Mobiltelefonapplikationer med Java ME: Lektion 6

Idag: Mera användargränssnitt med List och Form

Klicka på startknappen i den lilla mediespelaren ovan för att lyssna på lektionen. (Man kan behöva vänta en stund på att ljudfilen laddas ner.) Om mediespelaren inte syns, eller om det inte fungerar av något annat skäl, kan man klicka här för att ladda ner mp3-filen (ca 30 minuter, ca 14 megabyte). Beroende på hur webbläsaren är konfigurerad kan det kräva ett separat mp3-spelarprogram av något slag.

Tänk på att lektionerna ger en översikt och introduktion. Du måste läsa i kursboken och arbeta med övningarna för att tillgodogöra dig kursen.

Bild 1: Displayable och dess subklasser

Displayable och dess subklasser

Bild(er) 2: Listor

Klassen List.

Det finns enkelvalslistor (EXCLUSIVE), flervalslistor (MULTIPLE) och direktvalslistor (IMPLICIT).

En enkelvalslista i emulatorn     En flervalslista i emulatorn

"Bild" 3: Programkod för enkelvalslistan

Klassen ExclusiveListTest från filen ExclusiveListTest.java:

    1	import javax.microedition.midlet.*;
    2	import javax.microedition.lcdui.*;
    3	
    4	public class ExclusiveListTest extends MIDlet implements CommandListener {
    5	    private Display displayen;
    6	    private List listan;
    7	    private TextBox textrutan;
    8	    private Command exitkommandot, okkommandot;
    9	
   10	    public ExclusiveListTest() {
   11	        listan = new List("Välj ett av följande alternativ", Choice.EXCLUSIVE);
   12	        okkommandot = new Command("OK", Command.OK, 1);
   13	        exitkommandot = new Command("Avsluta", Command.EXIT, 0);
   14	        textrutan = new TextBox("Resultat", "Inget resultat", 100, 0);
   15	        listan.append("Tripp", null);
   16	        listan.append("Trapp", null);
   17	        listan.append("Trull", null);
   18	        listan.append("Stora Svampen", null);
   19	
   20	        listan.addCommand(okkommandot);
   21	        listan.addCommand(exitkommandot);
   22	        listan.setCommandListener(this);
   23	
   24	        textrutan.addCommand(exitkommandot);
   25	        textrutan.setCommandListener(this);
   26	    }
   27	
   28	    public void startApp() {
   29	        displayen = Display.getDisplay(this);
   30	        displayen.setCurrent(listan);
   31	    }
   32	
   33	    public void commandAction(Command kommandot, Displayable s) {
   34	        if (kommandot == exitkommandot) {
   35	            destroyApp(false);
   36	            notifyDestroyed();
   37	        }
   38	        else if (kommandot == okkommandot) {
   39	            int valet;
   40	            displayen.setCurrent(textrutan);
   41	            valet = listan.getSelectedIndex();
   42	            textrutan.setString("Du valde alternativ nummer " +
   43	                                valet +
   44	                                ", \"" +
   45	                                listan.getString(valet) + "\".\n");
   46	        }
   47	    }
   48	
   49	    public void destroyApp(boolean unconditional) { }
   50	
   51	    public void pauseApp() { }
   52	} // class ExclusiveListTest

Bild 4: Resultat av körningen

När vi valt i enkelvalslistan i emulatorn

"Bild" 5: Programkod för flervalslistan

Klassen MultipleListTest från filen MultipleListTest.java:

    1	import javax.microedition.midlet.*;
    2	import javax.microedition.lcdui.*;
    3	
    4	public class MultipleListTest extends MIDlet implements CommandListener {
    5	    private Display displayen;
    6	    private List listan;
    7	    private TextBox textrutan;
    8	    private Command exitkommandot, okkommandot;
    9	
   10	    public MultipleListTest() {
   11	        listan = new List("Välj några av följande alternativ", Choice.MULTIPLE);
   12	        okkommandot = new Command("OK", Command.OK, 1);
   13	        exitkommandot = new Command("Avsluta", Command.EXIT, 0);
   14	        textrutan = new TextBox("Resultat", null, 200, 0);
   15	        listan.append("Tripp", null);
   16	        listan.append("Trapp", null);
   17	        listan.append("Trull", null);
   18	        listan.append("Stora Svampen", null);
   19	
   20	        listan.addCommand(okkommandot);
   21	        listan.addCommand(exitkommandot);
   22	        listan.setCommandListener(this);
   23	
   24	        textrutan.addCommand(exitkommandot);
   25	        textrutan.setCommandListener(this);
   26	    }
   27	
   28	    public void startApp() {
   29	        displayen = Display.getDisplay(this);
   30	        displayen.setCurrent(listan);
   31	    }
   32	
   33	    public void commandAction(Command kommandot, Displayable s) {
   34	        if (kommandot == exitkommandot) {
   35	            destroyApp(false);
   36	            notifyDestroyed();
   37	        }
   38	        else if (kommandot == okkommandot) {
   39	            boolean[] valen = new boolean[listan.size()];
   40	            displayen.setCurrent(textrutan);
   41	            int antalet;
   42	            antalet = listan.getSelectedFlags(valen);
   43	            textrutan.setString("Du valde " + antalet + " alternativ.\n");
   44	
   45	            for (int i = 0; i < listan.size(); ++i) {
   46	                if (valen[i])
   47	                    textrutan.insert("Du valde alternativ nummer " +
   48	                                     i +
   49	                                     ", \"" +
   50	                                     listan.getString(i) + "\".\n",
   51	                                     textrutan.getString().length());
   52	            }
   53	        }
   54	    }
   55	
   56	    public void destroyApp(boolean unconditional) { }
   57	
   58	    public void pauseApp() { }
   59	} // class MultipleListTest

Bild 6: Resultat av körningen

När vi valt i flervalslistan i emulatorn

Bild(er) 7: Formulär

Ett formulär med flera Item-objekt i emulatorn     Samma formulär, efter lite inmatning och scrollning

Bild(er) 8: Små skärmar!

Skärmstorlekar:

Emulatorn DefaultColorPhone har en skärm som är 240 x 320 bildpunkter
DefaultColorPhone (240 x 320)
    Minsta tillåtna skärmstorleken i en MID är bara 96 x54 bildpunkter
(176 x 220)
    Minsta tillåtna skärmstorleken i en MID är bara 96 x54 bildpunkter
(96 x 54)

Bild 9: Och ganska stora skärmar

Emulatorn QwertyDevice har en skärm som är 636 x 235 bildpunkter.

Emulatorn QwertyDevice har en skärm som är 636 x 235 bildpunkter

Bild 10: Item och dess subklasser

Item och dess subklasser

"Bild" 11: Koden till formulärtestet

Klassen FormTest från filen FormTest.java:
(Men det finns ett fel i programmet. Se övningarna nedan!)

    1	import java.io.*;
    2	import javax.microedition.midlet.*;
    3	import javax.microedition.lcdui.*;
    4	
    5	public class FormTest extends MIDlet implements CommandListener {
    6	    private Display displayen;
    7	    private Form formuläret;
    8	    private Command exitkommandot, okkommandot;
    9	
   10	    public FormTest() {
   11	        formuläret = new Form("Några olika Item-objekt i ett formulär");
   12	
   13	        StringItem etiketten = new StringItem("Namn: ", "FormTest");
   14	        etiketten.setLayout(Item.LAYOUT_2);
   15	        formuläret.append(etiketten);
   16	
   17	        Spacer tomrummet = new Spacer(10, 50);
   18	        tomrummet.setLayout(Item.LAYOUT_2);
   19	        formuläret.append(tomrummet);
   20	
   21	        TextField textfältet = new TextField("Skriv nånting här:",
   22	                                             "", 30, 0);
   23	        textfältet.setLayout(Item.LAYOUT_2);
   24	        formuläret.append(textfältet);
   25	
   26	        Image bilden = null;
   27	        try {
   28	            bilden = Image.createImage("/pilbild.png");
   29	        }
   30	        catch (IOException e) {
   31	            System.out.println(e);
   32	        }
   33	        ImageItem bildmojängen = new ImageItem("Bilden", bilden,
   34	                                               Item.LAYOUT_2,
   35	                                               "Här fattas en bild");
   36	        bildmojängen.setLayout(Item.LAYOUT_2);
   37	        formuläret.append(bildmojängen);
   38	
   39	        DateField datumfältet = new DateField("Ange ett datum",
   40	                                              DateField.DATE);
   41	        datumfältet.setLayout(Item.LAYOUT_2);
   42	        formuläret.append(datumfältet);
   43	
   44	        Gauge mätaren = new Gauge("Ställ in", true, 10, 0);
   45	        mätaren.setLayout(Item.LAYOUT_2);
   46	        formuläret.append(mätaren);
   47	
   48	        ChoiceGroup valgruppen =
   49	            new ChoiceGroup("Välj några av följande alternativ",
   50	                            ChoiceGroup.MULTIPLE);
   51	        valgruppen.setLayout(Item.LAYOUT_2);
   52	        valgruppen.append("Tripp", null);
   53	        valgruppen.append("Trapp", null);
   54	        valgruppen.append("Trull", null);
   55	        valgruppen.append("Stora Svampen", null);
   56	        formuläret.append(valgruppen);
   57	
   58	        exitkommandot = new Command("Avsluta", Command.EXIT, 0);
   59	        formuläret.addCommand(exitkommandot);
   60	
   61	        okkommandot = new Command("OK", Command.OK, 1);
   62	        formuläret.addCommand(okkommandot);
   63	    }
   64	
   65	    public void startApp() {
   66	        displayen = Display.getDisplay(this);
   67	        displayen.setCurrent(formuläret);
   68	    }
   69	
   70	    public void commandAction(Command kommandot, Displayable s) {
   71	        if (kommandot == exitkommandot) {
   72	            destroyApp(false);
   73	            notifyDestroyed();
   74	        }
   75	        else if (kommandot == okkommandot) {
   76	
   77	        }
   78	    }
   79	
   80	    public void destroyApp(boolean unconditional) { }
   81	
   82	    public void pauseApp() { }
   83	} // class FormTest

Bild(er) 12: En mätare kopplad till en text via ett kommando

Ett formulär med en mätare och en text     Samma formulär, efter att man ändrat mätarställningen     Samma formulär, efter att man valt Uppdatera

"Bild" 13: Programkod för mätaren kopplad till en text

Klassen GaugeTest1 från filen GaugeTest1.java:

    1	import java.io.*;
    2	import javax.microedition.midlet.*;
    3	import javax.microedition.lcdui.*;
    4	
    5	public class GaugeTest1 extends MIDlet implements CommandListener {
    6	    private Display displayen;
    7	    private Form formuläret;
    8	    Gauge mätaren;
    9	    StringItem texten;
   10	    private Command uppdateringskommandot;
   11	    private Command exitkommandot;
   12	
   13	    public GaugeTest1() {
   14	        formuläret = new Form("En mätare och ett textfält, alternativ 1");
   15	
   16	        mätaren = new Gauge("Ställ in", true, 5, 3);
   17	        formuläret.append(mätaren);
   18	
   19	        texten = new StringItem("Värde: ", null);
   20	        formuläret.append(texten);
   21	
   22	        uppdateringskommandot = new Command("Uppdatera", Command.SCREEN, 1);
   23	        formuläret.addCommand(uppdateringskommandot);
   24	
   25	        exitkommandot = new Command("Avsluta", Command.EXIT, 0);
   26	        formuläret.addCommand(exitkommandot);
   27	
   28	        formuläret.setCommandListener(this);
   29	        commandAction(uppdateringskommandot, formuläret);
   30	    }
   31	
   32	    public void startApp() {
   33	        displayen = Display.getDisplay(this);
   34	        displayen.setCurrent(formuläret);
   35	    }
   36	
   37	    public void commandAction(Command kommandot, Displayable s) {
   38	        if (kommandot == exitkommandot) {
   39	            destroyApp(false);
   40	            notifyDestroyed();
   41	        }
   42	        else if (kommandot == uppdateringskommandot) {
   43	            texten.setText("" + mätaren.getValue());
   44	        }
   45	    }
   46	
   47	    public void destroyApp(boolean unconditional) { }
   48	
   49	    public void pauseApp() { }
   50	} // class GaugeTest1

Bild(er) 14: En mätare direktkopplad till en text

Ett formulär med en mätare och en text     Samma formulär, efter att man ändrat mätarställningen

"Bild" 15: Programkod för mätaren direktkopplad till en text

Klassen GaugeTest2 från filen GaugeTest2.java:

    1	import java.io.*;
    2	import javax.microedition.midlet.*;
    3	import javax.microedition.lcdui.*;
    4	
    5	public class GaugeTest2 extends MIDlet
    6	  implements CommandListener, ItemStateListener {
    7	    private Display displayen;
    8	    private Form formuläret;
    9	    Gauge mätaren;
   10	    StringItem texten;
   11	    private Command exitkommandot;
   12	
   13	    public GaugeTest2() {
   14	        formuläret = new Form("En mätare och ett textfält, alternativ 2");
   15	
   16	        mätaren = new Gauge("Ställ in", true, 5, 3);
   17	        formuläret.append(mätaren);
   18	
   19	        texten = new StringItem("Värde: ", null);
   20	        formuläret.append(texten);
   21	
   22	        exitkommandot = new Command("Avsluta", Command.EXIT, 0);
   23	        formuläret.addCommand(exitkommandot);
   24	
   25	        formuläret.setCommandListener(this);
   26	
   27	        formuläret.setItemStateListener(this);
   28	        itemStateChanged(mätaren);
   29	    }
   30	
   31	    public void startApp() {
   32	        displayen = Display.getDisplay(this);
   33	        displayen.setCurrent(formuläret);
   34	    }
   35	
   36	    public void commandAction(Command kommandot, Displayable s) {
   37	        if (kommandot == exitkommandot) {
   38	            destroyApp(false);
   39	            notifyDestroyed();
   40	        }
   41	    }
   42	
   43	    public void itemStateChanged(Item i) {
   44	        if (i == mätaren) {
   45	            texten.setText("" + mätaren.getValue());
   46	        }
   47	    }
   48	
   49	    public void destroyApp(boolean unconditional) { }
   50	
   51	    public void pauseApp() { }
   52	} // class GaugeTest2

Läsanvisningar

I den nya kursboken Kicking Butt with MIDP and MSA motsvaras den här lektionen av kapitel 8, More User Interface.

I den gamla kursboken Beginning J2ME motsvaras den här lektionen av kapitel 6, Lists and Forms. Kapitel 5 la grunderna om användargränssnitt i MIDP, och är därför ett särskilt viktigt kapitel. Kapitel 6 tar vid där kapitel 5 slutade, med fler användargränssnittskomponenter.

Här är några frågor som kan användas som instuderingsfrågor:

  1. Vad har man listor (alltså klassen List) till?
  2. Vad har man MULTIPLE-listor till?
  3. Vad har man EXCLUSIVE-listor till?
  4. Vad har man IMPLICIT-listor till?
  5. Skulle man kunna göra en lista som kombinerar MULTIPLE och IMPLICIT?
  6. Hur hanterar man ett val i en IMPLICIT-lista i Java-koden?
  7. Hur kan en MIDlet få tillgång till en bild som ska visas i ett användargränssnitt?
  8. I vilka olika sammanhang kan bilder visas i listor och formulär?
  9. På vilka sätt kan man i Java-koden ange vilka alternativ som ska finnas i en lista?
  10. Hur får man i Java-koden reda på vilka av alternativen som användaren har valt? Skiljer det sig mellan olika typer av listor?
  11. Vad är klassen Form?
  12. Vad är klassen Item?
  13. Varför behövs klassen Form? Skulle man inte kunna placera ut Item-objekten direkt på displayen?
  14. Hur många Item-objekt kan man ha i ett och samma formulär?
  15. Hur många Item-objekt bör man ha i ett och samma formulär?
  16. På vilka sätt kan man i Java-koden ange vilka Item-objekt som ska finnas i ett formulär?
  17. Ett Item kan, precis som en Displayable, ha kommandon. Vad kan man ha Item-kommandon till?
  18. Vad innebär Item.LAYOUT_2?
  19. Hur skulle man, med hjälp av metoden setLayout, placera ett Item i nedre högra hörnet av ett formulär?
  20. Hamnar det verkligen i nedre högra hörnet? (Provkör!)
  21. Vad används Item.HYPERLINK till?
  22. Vad används Item.BUTTON till?
  23. BUTTON som i knapp? Det måste väl vara en av de mest använda sakerna i MIDP?
  24. Vad är de viktigaste skillnaderna mellan StringItem och TextField?
  25. Klassen ImageItem har två olika konstruktorer. (Se API-dokumentationen för MIDP.) Vad skiljer dem åt?
  26. Hur skapar man ett DateField där man kan ange klockslag, men inte datum?
  27. Det finns flera olika sorters "mätare" (engelska: gauges), som alla representeras med klassen Gauge, men med olika inställningar. Vilka, och vad ska man använda dem till?
  28. Klassen ChoiceGroup har stora likheter med klassen List, men vilka skillnader finns det?
  29. Hur använder man gränssnittet ItemStateListener?
Om du vill skriva svar på instuderingsfrågorna, räcker det för de flesta frågorna med en eller några få meningar.

Programmeringsövningar

  1. Skapa en MIDlet som visar ett formulär med en Item av något slag.
  2. Lägg till en loop som skapar en väldig massa med Item-objekt och placerar på formuläret. Låt varje Item-objekt ha något kännetecken, till exempel ett nummer, så att man kan skilja dem åt. Prova att scrolla upp och ner! [Lösningsförslag]
  3. Skapa en MIDlet med två interaktiva Gauge-objekt, som är sammankopplade så att när man ändrar det ena så ändras också det andra, och tvärtom! [Lösningsförslag]
  4. Det finns ett fel i MIDleten FormTest ovan, som gör att den inte går att avsluta. Avsluta-kommandot fungerar helt enkelt inte. (Läraren, som provkörde det på sin riktiga telefon, fick be en kompis att ringa honom. Annars gick det inte att avsluta programmet, förutom genom att stänga av telefonen.) Vad är felet? Rätta felet, och verifiera genom att provköra i emulatorn! [Ledtråd]

Inlämningsuppgift 1 | Lektionslista | Nästa lektion


Thomas Padron-McCarthy (Thomas.Padron-McCarthy@oru.se), 29 augusti 2008