Chapter 12
Grafiske brugergrænseflader i Java, del 1

Kurt Nørmark ©
Department of Computer Science, Aalborg University, Denmark


September 2001


Abstract
Previous lecture Next lecture
Index References Contents
Grafiske brugergrænseflader er et væsentligt emne, hvis man ønsker at skriver 'moderne' programmer. Desværre er dette aspekt af et program også et af de vanskeligste at lave. Der er store forskelle fra sprog til sprog, og ofte er det endvidere maskinafhængigt, hvordan man angriber programmering af brugergrænsefladen. Lad os i den forbindelse bemærke, at Java bidrager med en (i princippet) maskin-uafhængig teknik til programering af brugergrænseflader.

Her vil vil primært koncentrer os om de væsentligste generelle karakteristika ved objekt-orienteret programmering af brugergrænseflader. Sekundært vil vi se på, hvordan det kan ske i Java.


Introduktion til grafiske brugergrænseflader

Oversigt over Java's udvikling af brugergrænseflader
Slide Note Contents Index
References Speak
Vi giver her en kort oversigt over de versioner, som Java har gennemlevet hvad angår faciliteter til udvikling af grafiske brugergrænseflader

  • Java 1.0

    • Ingen separate listener objekter

    • Event håndteres af ganske få metoder som er tilknyttet et syn

      • Stort behov for eksplicit forgrening og test ved brug af if-then-else kæder

  • Java 1.1

    • Definerer AWT: Abstract Windowing Toolkit

    • Baserer sig på platformens brugergrænseflade faciliteter

  • Java 1.2

    • Introducerer nye biblioteketer til håndtering af af grafiske brugergrænseflader, kendt under navnet Swing

    • Indeholder ingen platformsafhængige aspekter

    • Følger grundliggende de samme principper som AWT

    • Flere og mere alsidige brugergrænseflade komponenter end i AWT

Litteratur om grafiske brugergrænseflader
Slide Note Contents Index
References Speak
Vi starter med en kort karakterisk af litteraturen, der beskriver hvordan man laver brugergrænseflader i et Java program

  • Litteratur:

    • Kapitlerne 16 og 17 i Barnes giver en fyldestgørende indføring til emnet

    • Kapitel 9 i lærebogen 'Java Software Solutions' af Lewis of Loftus (2ed) giver en introduktion til emnet

    • The Java Tutorial indeholder en mere uddybende og mere teknisk gennemgang af Java brugergrænseflader

      • AWT version (arkiv)

      • Swing version

        • Svarer i omfang til en bog på 950 sider

Hvis man læser første udgave af lærebogen 'Java Software Solutions' af Lewis of Loftus er det kapitel 10 som giver en introduktion til grafiske brugergrænseflader

Hvis man læser første udgave af lærebogen 'Java Software Solutions' af Lewis of Loftus er det kapitel 10 som giver en introduktion til grafiske brugergrænseflader

References


Applets

Introduktion til applets
Slide Note Contents Index
References Speak
Applets spiller ikke den store rolle på dette kursus. Vi vil dog i denne lektion præsentere nogle eksempler på brugergrænseflader via applets. (Det er naturligvis fristende at bruge denne mulighed for at kunne inkludere brugergrænsefladerne direkte i en Internet browser). Her ser vi først på nogle generelle egenskaber af Java applets

The concept applet: En applet er et Java program som kan afvikles i en 'Java enabeled' Internet browserEn stor del af den almene interesse for Java stammer fra applet ideen. Moderne Internet browsere indeholder en Java fortolker og et Java bibliotek. Derved bliver det muligt for browseren at udføre et Java program, som kan modtages fra en vilkårlig maskine på nettet.
The concept applikation: En applikation er en kontrast til en appletEn applikation er et Java program, som ikke er udviklet med henblik på afvikling i en browser. Langt de fleste programmer, som vi interesserer os for på dette kursus, er applikationer. I denne lektion vil vi dog vise et par applets, først og fremmest fordi vi hermed på en let måde kan inkludere en kørende brugergrænseflade i online versioner af noterne

  • Karakteristik af Applet og dets metoder

    • En applet er en brugergrænseflade komponent, som kan indeholde andre komponenter

    • Applet klassen indeholder metoderne init, start, stop og destroy, som kaldes ved bestemte begivenheder i en applets livsforløb

      • En applet programmør definerer disse metoder, men han/hun kalder dem typisk ikke

Vi vil senere studere de forskellige brugergrænseflade komponenter i Java, og vi vil ved denne lejlighed støde på Applets igen

References

Applets i denne lektion
Slide Note Contents Index
References Speak

Vi viser nogle få applet's i denne lektion - mest fordi det er bekvemt i et WWW baseret materiale

De fleste applets i materialet kan også anvendes som applikationer

En applet vises på en HTML side via en særlig applet tag

Program: En simpel HTML side som indeholder en applet. Længere fremme i denne lektion vil vi bl.a. studere denne applets.
<HTML>
   <HEAD>
      <TITLE>The Div Mod Applet</TITLE>
   </HEAD>
   <BODY>
      <H3>The Div Mod Applet:</H3>
      <APPLET CODE="DivModPresenter.class" WIDTH=200 HEIGHT=200>
      </APPLET>
   </BODY>
</HTML>

References


Arkitektur af et program med grafisk brugergrænseflade

Hvem kalder hvem?
Slide Note Contents Index
References Speak
Vi vil indledningsvist se på en vigtigt princip, som dukker op i flere sammenhænge når vi arbejder med grafiske brugergrænseflader i Java.

Don't call us - we call you

  • Traditionelt

    • Alle metoder, som vi definerer, kaldes eksplicit af 'vore egne metoder'

  • I forbindelse med brugergrænseflade programmering

    • Vi definerer ofte metoder, som kaldes ('implicit') fra systemets metoder

      • Start og stop metoderne i en Applet

      • Eventhåndterings metoder i 'Listener' objekter

      • Metoder som opdaterer den grafiske præsentation af en brugergrænseflade

Model, syn og inputkontrol
Slide Note Contents Index
References Speak
Ideerne på denne side kan ledes tilbage til Smalltalk's model, view controller tankegang.

Vi ønsker at opdele et program i tre samarbejdende komponenter, som har færrest mulige indbyrdes bindinger mellem hinanden.

  • Model (Model)

    • Selve den indre programlogik løsrevet fra input og output aspekter

  • Syn (View)

    • Præsentationen af modellen

    • Output på skærmen

    • Der kan være flere syn på samme model

  • Inputkontrol (Controller)

    • Håndtering af input fra tastaturet og musen

    • Input forekommer ofte på et syn, og det påvirker for det meste modellen direkte og synet indirekte (feedback)

Image series: Cyklus i interationen mellem syn, inputkontrol og model.Cyklus i interationen mellem syn, inputkontrol og model.

Image no. 1. Brugeren påvirker et element af brugergrænsefladen (synet)
 

Image no. 2. Der oprettes et eventObjekt som repræsenterer hændelsen
 

Image no. 3. Hændelsen overføres til en metode i kontrol objektet, som abonnerer på hændelsen
 

Image no. 4. Metoden i kontrolobjektet aktiverer beregningen i modellen (her programObjektet)
 

Image no. 5. Programobjektet giver feedback tilbage til synet
 

Eksempel: Div mod calculator
Slide Note Contents Index
References Speak
Vi viser allerede nu et principielt og simpelt eksempel på model, view og control klasser. På denne måde bliver diskussionen konkret på et tidligt tidspunkt. Der vil være detaljer, som du ikke forstår på nuværende tidspunkt. Vi vender tilbage til detaljerne i løbet af lektionen. Det vigtigste er for nærværende organiseringen af et program med en grafisk brugergrænseflade i de nævnte tre dele: model, syn og inputkontrol

Applet. En simpel applet som beregner x div y og x mod y af de to tal x og y i inputfelterne
 

Program: Model klassen. Denne klasse foretager beregningen af kvotient og resten. Endvidere lagrer et objekt af klassen seneste input og output i instansvariable. Med blåt ser vi det sted, hvor vi registrerer hvilket objekt som viser resultatet af beregningen. Med rødt ser vi det sted, hvor synet bliver opdateret.
class DivModCalculator {

  private DivModPresenter viewObject;

  IntPair inputMemory, outputMemory;

  public DivModCalculator(DivModPresenter viewObject) {
    this.viewObject = viewObject;
    inputMemory = null; outputMemory = null;
  }
   
  private IntPair divMod(int x, int y){
    // require x > 0 && y > 0 ;

    int rest = x;
    int quotient = 0;
    
    while (rest >= y) {
      // invariant rest + quotient * y = x;
      rest = rest - y;
      quotient = quotient + 1;
    }
    return (new IntPair(quotient,rest));
    // ensure  rest + quotient * y = x && rest < y && rest >= 0 ;
  } // end div

  public void doCalculate(int input1, int input2){
    inputMemory = new IntPair(input1, input2);
    if (input1 > 0 && input2 > 0)
      outputMemory = divMod(input1, input2);
    else
      outputMemory = new IntPair(-1, -1);

    // update the view - in an easy but primitive way:
    viewObject.showResult(outputMemory);
  }
} // end DivModCalculator

Program: View klassen. Denne klasse udvider Applet, som tillader os at afvikle et Java program i en Internet Browser. Det er en instans af denne klasse som starter programudførelsen, når vi afvikler et Java program som er en Applet. Vi ser, at der instantieres et model og et inputkontrol objekt (med rødt). Dernæst laver vi de enkelte dele af den grafiske brugergrænseflade (vist med brunt). I init metoden associerer vi inputkontrol objektet 'listener' til de to inputfelter (vist med blåt ). Endelig ser vi, at vi tilføjer de fem grafiske elementer til brugergrænsefladen med add metoden (vist med lilla). Metoden main (nedtonet med gråt) gør det muligt at køre programmet som en applikation. I en applet bruges main ikke.
public class DivModPresenter extends Applet {

   private DivModCalculator modelObject;
   private DivModListener listener;

   private Label title;
   private TextField dividend, divisor;
   private Label quotient,rest;

   public DivModPresenter(){
     modelObject = new DivModCalculator (this);
     listener = new DivModListener (modelObject, this);

     title = new Label ("Div Mod Calculator");
     dividend = new TextField ("0",5);
     divisor = new TextField ("0",5);
     quotient = new Label ("Kvotient:");
     rest = new Label ("Rest:") ;
    }

   public void init() {
     dividend.addActionListener (listener);
     divisor.addActionListener (listener);

     setLayout(new GridLayout(6,1));

     add(title);
     add(divisor);  add(dividend); 
     add(quotient); add(rest); 

     resize (200,200);
   }

   // Extract and return the dividend from the view.
   public int getDividend(){
     String strResult = dividend.getText();
     return Integer.parseInt(strResult);
   }

   // Extract and return the divisor from the view.
   public int getDivisor(){
     String strResult = divisor.getText();
     return Integer.parseInt(strResult);
   }

   // Show the quotient and the rest as text labels in the view.
   public void showResult(IntPair quotientRest){
     quotient.setText("Kvotient: " + Integer.toString(quotientRest.firstInt,10));
     rest.setText("Rest: " + Integer.toString(quotientRest.secondInt,10));
   }

  public static void main(String[] args){
     Frame f = new Frame("Color adjuster");
     f.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
             System.exit(0);
           }
       });
     DivModPresenter presenter =  new DivModPresenter();
     presenter.init();
     f.add("Center", presenter);
     f.pack();
     f.setSize(new Dimension(500,500));
     f.setVisible(true);
 } // end main

} // end DivModPresenter

Program: Controller klassen. Denne klasse implementerer ActionListener interfacet (vist med grønt), som reagerer på 'Return' indtastet i inputfeltet. Når der via et af de to tekstfelter 'afsendes en tekststreng' ser vi at modelobjektets doCalculate metode bliver aktiveret på de to tal i inputfelterne (vist med rødt).
class DivModListener implements ActionListener{

  private DivModCalculator modelObject;
  private DivModPresenter viewObject;

  public DivModListener(DivModCalculator modelObject, DivModPresenter viewObject){
    this.modelObject = modelObject;
    this.viewObject = viewObject;
  }

  public void actionPerformed(ActionEvent action){
    modelObject.doCalculate(viewObject.getDivisor(), viewObject.getDividend());
  }

} // end DivModListener

Program: Det samlede Div Mod Calculator program.
/user/normark/courses/prog1/prog1-01/sources/noter/../../html/noter/applets/division/DivModPresenter.java

Image series: En typisk interaktion mellem view, model og controller.En typisk interaktion mellem view, model og controller.

Image no. 1. Der skabes et view, som i dette tilfælde er en applet
 

Image no. 2. I dette simple tilfælde skaber view'et model objektet og controller objektet
 

Image no. 3. View objektet opretter fem brugergrænseflade komponenter
 

Image no. 4. View objektet sender en besked til dividend om at registrere controller som 'action listener'
 

Image no. 5. View objektet sender en besked til divisor om at registrere controller som 'action listener'
 

Image no. 6. View objektet tilføje de fem brugergrænseflade komponenter til sig selv
 

Image no. 7. Brugeren opererer nu på brugergrænsefladen. Controlleren modtager en actionPerformed besked
 

Image no. 8. Controlleren sender getDivisor til view objektet, for at trække divisor ud af tekstfelterne
 

Image no. 9. View objektet udtrækker divisor teksten af divisor objektet. Teksten konverteres til et tal
 

Image no. 10. Controlleren sender getDividend til view objektet, for at trække dividend ud af tekstfelterne
 

Image no. 11. View objektet udtrækker dividend teksten af dividend objektet. Teksten konverteres til et tal
 

Image no. 12. Controlleren sender beskeden doCalculate til model objektet
 

Image no. 13. Model objektet foretager beregningen af kvotient og rest ved at sende beskeden divMod til sig selv
 

Image no. 14. Efter at have skabt objektet output sender model objektet beskeden showResult til view objektet
 

Image no. 15. View objektet sender beskeden setText til quotient for at vise kvotient resultatet
 

Image no. 16. View objektet sender beskeden setText til rest objektet for at vise rest resultatet
 

Exercise 12.1. En meget simpel calculatorIdeen med denne opgave er at udvide brugergrænsefladen af programmet, som beregner kvotienten og resten af to tal. Udvidelsen består i at tilføje en Liste komponent, hvor man kan angive et par af operationer, som skal udføres på de to tal i inputfelterne. I den oprindelige version vil applikationen udregne kvotient og rest af tallene. De nye operationer kan f.eks. være addition og subtraktion, multiplikation og division med videre, samt naturligvis de oprindelige (vær selv kreativ). Programmet skal beregne resultatet (de to operationer på de angivne input) når der tastes retur i inputfeltet eller når der udvælges et element i operationslisten.

Det er en pointe at gennemføre forandringerne af det oprindelige program så både model, syn og input kontrol objektet afspejler den generaliserede dialog. Eksempelvis skal rollerne af output (sum, differens, produkt ...) udskrives korrekt. Det vil være mest oplagt at gennemføre forandringerne inden for AWT. Næste gang vil en af opgaverne gå ud på at ændre løsningen på denne opgave til Swing. Afprøv gerne følgende variationer:

  • I stedet for en List anvendes en Choice.
  • Igangsæt beregningen når der trykkes på en knap (Button), som tilføjes brugergrænsefladen.
  • Eksperimenter med en anden layout manager.
Leg meget gerne med andre variationer af programmet.

Brug programmet fra noterne på denne fil som udgangspunkt for opgaveløsningen.

Exercise 12.2. Grafisk brugergrænseflade i projektetI de fleste projekter vil der være behov for en grafiske brugergrænseflade. I opfordres til at overveje hvilket behov I har i jeres projekt. Gennemfør nogle indledende eksperimenter, hvor I programmerer (dele af) en første version af brugergrænsefladen. Brug denne lejlighed til at få førstehånds erfaring med nogle af de brugergrænseflade Komponenter, som I ikke indtil nu har haft berøring med.

Overvej specielt den overordnede organisering af jeres program i model, view og control objekter.

References

Ansvarsfordeling i eksemplet
Slide Note Contents Index
References Speak
Her vil vi fremhæve ansvaret og ansvarsfordelingen mellem model, view og controller objekterne i eksemplet ovenfor

  • Ansvar og ansvarsfordeling

    • Model

      • Beregner kvotient og rest

      • Tager initiativ til at opdatere synet

      • Kender synet (for stort kendskab)

    • View

      • Opretter model og control objekterne (arbitrært)

      • Opretter GUI elementerne

      • Tilknytter input control objektet til relevante GUI elementer

      • Kender controller (udnyttes til abonnement på hændelser)

    • Control

      • Reagerer på bestemte input

      • Opdaterer modellen som følge af relevant input

      • Kender både model og view

Vi vil senere (i forbindelse med Observer mønstret) vende tilbage til vores observation om, at modellen har et for stort kendskab til synet

Det er kun i eksemplet at synet opretter model og control objekterne. Dette er på ingen måde naturligt, blot behændigt for at få startet det hele op

Control objektet har et naturligt behov for at kunne aflæse nogle egenskaber fra synet samt at kanalisere disse over i modellen med henblik på gennemførelse af nogle beregninger


Brugergrænseflade komponenter i AWT

Syn i Java: Komponenter
Slide Note Contents Index
References Speak
En præsentation af en model sker i Java gennem en komponent. En komponent er altså en bestanddel af synet i en brugergrænseflade. Komponenter er begrebsligt organiseret i et klassehierarki. Endvidere indgår komponentobjekterne i et et aggregeringshierarki, med dele og helheder. Det er meget vigtigt at skelne mellem disse to forskellige hierarkier. Vi ser eksempler på begge i det følgende.

En typisk Java brugergrænseflade komponeres af pre-definerede dele (komponenter).

Det er atypisk, at benytte tegne-primitiver til konstruktion af en brugergrænseflade

  • Roden i AWT komponenthierarkiet hedder Component

    • Klassen Component indeholder egenskaber som er fælles for alle AWT komponenter i Java

    • Klassen Component er abstrakt

    • Komponent hierarkiet afspejler den begrebslige opdelning af brugergrænseflade elementer i Java

    • Et klassehierarki med subklasser og superklasser.

  • En konkret brugergrænseflade udgøres af en aggregering af komponenter inden i hinanden

    • Ydre komponenter kaldes containere

    • Dette hierarki afspejler hvordan en bestemt brugergrænseflade er opbygget af dele og helheder

References

Komponent specialiseringshierarkiet i AWT
Slide Note Contents Index
References Speak
På denne side viser vi komponent begrebshierarkiet i Java. Dette hierarki viser, hvordan komponent klasserne i Java arver fra hinanden (specialisering)


Eksempel: Farveblander
Slide Note Contents Index
References Speak
Vi ser nu på et nyt og lidt mere kompliceret program med en grafisk brugergrænseflade. Her vil vi møde nogle af komponenterne fra hierarkiet ovenfor - men dog langt fra dem alle.

Applet. Et program som gør det muligt at blande en farve ud fra farvens RGB (røg, grøn, blå) sammensætning. Programmet viser også den hexadecimale streng, som anvendes til angivelse af farver i en Internetbrowser (i HTML)
 

Program: Det samlede farveblander program (kun view og kontrol klasser). Det skal bemærkes, at vi i dette eksempel kun opererer med kontrol og view klasser. Der er altså ikke nogen model klasse. Årsagen er, at der stort set ikke er nogen beregninger i dette program. Det er helt og holdent tale om et brugergrænseflade program.
/user/normark/courses/prog1/prog1-01/sources/noter/../../html/noter/applets/farver/ColorPresenter.java

På de næste sider vil vi se på udvalgte dele af farveblander programmet

Aggregering af komponenter i farveblanderen
Slide Note Contents Index
References Speak
En brugergrænseflade består af en række brugergrænseflade Komponenter (objekter), som indlejres i hinanden. Det er vigtigt ikke at sammenblande komponenternes specialiserings hierarki med aggregeringshierarkiet, som omtales på denne side

En brugergrænseflade er en aggregering af Component objekter

Aggregeringen af komponenter i farveblander brugergrænsefladen:

  • Applet
    • Label
    • Panel
      • Scrollbar
      • TextField
      • Label
    • Panel
      • Scrollbar
      • TextField
      • Label
    • Panel
      • Scrollbar
      • TextField
      • Label
    • Canvas
    • Label

Panels
Slide Note Contents Index
References Speak

Et Panel er en komponent Container som benyttes til at gruppere andre komponenter

Eksempler fra farveblander programmet

Program: Et specialiseret Panel, som indeholder andre komponenter. Vi ser at der tilføjes tre primitive brugergrænseflade komponenter (fremhævet med rødt). Dette er et bidrag til opbygningen af aggregeringshierarkiet af komponenter
class ColorPanel extends Panel {

  public ColorPanel (Label lab, TextField text, 
                     Scrollbar slider, ColorListener listener){

     GridBagConstraints c = new GridBagConstraints();
     GridBagLayout gridbag = new GridBagLayout();
     setLayout(gridbag);

     c.fill = GridBagConstraints.HORIZONTAL;

     add(lab); 

     c.gridwidth = GridBagConstraints.REMAINDER;
     gridbag.setConstraints(text, c);
     add(text);

     c.weightx = 1.0;
     c.gridwidth = 1;
     gridbag.setConstraints(slider, c);
     slider.setMaximum(255); 
     slider.setBlockIncrement(10);
     slider.setUnitIncrement(1);
     add(slider);

     text.addActionListener (listener);
     slider.addAdjustmentListener (listener);
  }
} // end class ColorPanel

Program: Instantiering og anvendelse af ColorPanel klassen i klassen ColorPresenter. Vi ser tre instantieringer og tilføjelsen af disse til applet'en. Dette er endnu et bridrag til opbygningen af aggregeringshierarkiet af komponenter
   private ColorPanel redGroup = 
     new ColorPanel(redLabel, redTextField, redSlider, listener);
   private ColorPanel greenGroup = 
     new ColorPanel(greenLabel, greenTextField, greenSlider, listener);
   private ColorPanel blueGroup =
     new ColorPanel(blueLabel, blueTextField, blueSlider, listener);

   /** Applet init */
   public void init() {

       setLayout(new GridLayout(6,1));

       add(title);
       add(redGroup); add(greenGroup); add(blueGroup); 
       add(colorBlop);    
       add(hexTextField);
    
       resize (400,250);
       adjust();
   } //end init

References

Scrollbars
Slide Note Contents Index
References Speak

Scrollbars kan knyttes til vinduer, men kan også bruges som selvstændige 'adjusters'

Eksempler fra farveblander programmet

Program: Sliders i ColorPanel klassen. Sliderens maksimum og 'incrementer' bliver sat til konkrete værdier (vist med rødt) hvorefter slideren bliver tilføjet til panelet (vist med blåt)
class ColorPanel extends Panel {

  public ColorPanel (Label lab, TextField text, 
                     Scrollbar slider, ColorListener listener){

     GridBagConstraints c = new GridBagConstraints();
     GridBagLayout gridbag = new GridBagLayout();
     setLayout(gridbag);

     c.fill = GridBagConstraints.HORIZONTAL;

     add(lab); 

     c.gridwidth = GridBagConstraints.REMAINDER;
     gridbag.setConstraints(text, c);
     add(text);

     c.weightx = 1.0;
     c.gridwidth = 1;
     gridbag.setConstraints(slider, c);
     slider.setMaximum(255); 
     slider.setBlockIncrement(10);
     slider.setUnitIncrement(1);
     add(slider);

     text.addActionListener (listener);
     slider.addAdjustmentListener (listener);
  }
} // end class ColorPanel

Program: Instantieringen af Scrollbar objekter i ColorPresenter klassen.
   /** Construct individual components */
   private Label title = new Label ("Color adjuster", Label.CENTER);

   private Label redLabel = new Label ("Red:");
   private TextField redTextField = new TextField ("0",5);
   private Scrollbar redSlider = new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,255);

   private Label greenLabel = new Label ("Green:");
   private TextField greenTextField = new TextField ("0",5);
   private Scrollbar greenSlider = new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,255);

   private Label blueLabel = new Label ("Blue:");
   private TextField blueTextField = new TextField ("0",5);
   private Scrollbar blueSlider = new Scrollbar(Scrollbar.HORIZONTAL,0,1,0,255);
   
   private Label hexTextField = new Label ("#000000");
   private ColorBlop colorBlop = new ColorBlop(Color.white);

   private ColorListener listener = new ColorListener (this);

   private ColorPanel redGroup = 
     new ColorPanel(redLabel, redTextField, redSlider, listener);
   private ColorPanel greenGroup = 
     new ColorPanel(greenLabel, greenTextField, greenSlider, listener);
   private ColorPanel blueGroup =
     new ColorPanel(blueLabel, blueTextField, blueSlider, listener);

References

Canvas
Slide Note Contents Index
References Speak

Canvas er en komponent som tillader os eksplicit at tegne dele af en brugergrænseflade

Eksempel fra farveblander programmet

Program: Klassen ColorBlop er en specialisering af Canvas. Specialiseringen er meget simpel og ikke særlig illustrativ hvad angår mulighederne for at tegne egne dele af en brugergrænseflade. Det er paint metoden (vist med blåt) som tegner på selve canvasen
class ColorBlop extends Canvas {

  private Dimension size = new Dimension(100,100);
  private Color currentColorOfBlop;

  ColorBlop(Color c){
    currentColorOfBlop = c;
  }

  public void setColor (Color c){
    currentColorOfBlop = c;
  }

  public void paint (Graphics page) {
    page.setColor(currentColorOfBlop);
    page.fillRect(0,0,400,200);
  }

  public Dimension getMinimumSize() {
       return size;
  }

  public Dimension getPreferredSize() {
      return getMinimumSize();
  }
} // end class ColorBlop

References

Menu begreber
Slide Note Contents Index
References Speak
Menuer er, som bekendt, meget nyttige i mange sammenhænge i en grafisk brugergrænseflade. Vi ser her nærmere på selve menubegrebet. På næste side ser vi på menuer i AWT.

The concept menu: En menu er en brugergrænseflade komponent der tillader os at vælge én ud af flere muligheder, typisk med henblik på igangsætning af en bestemt handlingEn menu viser en række muligheder for os, ud fra hvilke man kan vælge en (eller måske flere) muligheder. Efter man har valgt et menupunkt vil det som regel afstedkomme igangsætning af en eller anden handling
The concept menu element: Et menu element er en bestanddel af en menu, som kan udvælgesEn menu består af såkaldte menu elementer

  • Forskellige former for tilknytning af menuer til brugergrænseflade elementer

    • 'Rullegardin menuer' knyttet til et vindue

    • 'Popup menuer' knyttet til et vilkårligt brugergrænseflade element

    • Faste menuer, der vises som en del af et vindue

  • Forskellige organiseringer af en menu

    • Lineære menuer

    • Lineære menuer med afsnitsinddeling

    • Hierarkiske menuer

      • En menu, hvor ét eller flere menu-elementer selv er menuer

    • Menuer med frit layout

Med en lineær menu mener vi en menu, hvor menu elementerne blot er ordnet lineært i forhold til hinanden

En afsnitsinddeling i en lineær menu (som en vandret streg) gør det muligt på en simpel måde at gruppere menu elementer

En hierarkisk menu kan siges at indeholder undermenuer. Vi har dog valgt at formulere det rekursivt ved at lade et menu element være en menu i sig selv. Det rekursive består naturligvis i, at en del af en menu (et menuelement) selv kan være en hel menu

I menuer med frit layout er det muligt at organisere menu items i et eller andet todimensionalt mønster

Menuer i AWT
Slide Note Contents Index
References Speak
Efter at have set på nogle generelle menu begreber vil vi nu studere Java's menu begreb, som er ganske veludviklet

I Java er en menu ikke en Component

Menuer håndteres vidt forskelligt på de forskellige platforme, hvor Java er implementeret. Dette siges at være årsagen til, at menuer ikke arver fra klassen Component

  • Oversigt over menu relaterede klasser i Java

    • Menubar

      • Rullegardinmenu som er knyttet til en Frame

    • MenuItem

      • Repræsenterer et menu element

    • Menu

      • Repræsenterer en enkelt menu

      • Er et (arver fra) MenuItem

    • PopupMenu

      • Repræsenterer en popup menu

Program: Uddrag af klassen MenuWindow fra The Java Tutorial. Det viste uddrag er en del af konstruktoren i klassen. Vi ser først erklæring af en lang række Menu relaterede instansvariable (med brunt). Dernæst instantieringen af MenuBar og dets tilknytning til denne frame med setMenuBar(mb) (med rødt) Sidst ser vi instantieringen af menu 1, tilføjelse af denne til menubaren mb, samt tilføjelse af to MenuItems til menu (med lilla)
        MenuBar mb;
        Menu m1, m2, m3, m4, m4_1, m5;
        MenuItem mi1_1, mi1_2, mi3_1, mi3_2, mi3_3, mi3_4,
                 mi4_1_1, mi5_1, mi5_2,
                 pmi1, pmi2, mi5_1_duplicate;
        CheckboxMenuItem mi2_1;

        //Build the menu bar.
        mb = new MenuBar();
        setMenuBar(mb);

        //Build first menu in the menu bar.
        //Specifying the second argument as true
        //makes this a tear-off menu.
        m1 = new Menu("Menu 1", true);
        mb.add(m1);
        mi1_1 = new MenuItem("Menu item 1_1");
        m1.add(mi1_1);
        mi1_2 = new MenuItem("Menu item 1_2");
        m1.add(mi1_2);

        // end menu 1

Program: Hele klassen MenuWindow fra The Java Tutorial hvoraf ovenstående er et uddrag.
/user/normark/courses/prog1/prog1-01/sources/java/noteEksempler/MenuWindow.java

References

Andre komponenter
Slide Note Contents Index
References Speak
Vi har ikke i denne lektion gjort et forsøg på at dække detaljerne i alle Java AWT brugergrænseflade komponenter. Her lister vi dem, vi ikke har dækket

Vi vil ikke her gå i detalje med alle slags brugergrænseflade komponenter.

Vi forsøger primært at dække nogle af de mere generelle principper bag programmering af brugergrænseflader

  • Andre nyttige brugergrænseflade komponenter

    • TextArea

    • List

    • Button

    • Choice

    • CheckBox

Det skal bemærkes, at menuer ikke er Komponenter, jf. specialiseringshierarkiet af Java komponenter, som vi har set på tidligere

Reference


Ansvarsfordeling mellem model, syn og inputkontrol

Ansvaret for opdatering af brugergrænsefladen
Slide Note Contents Index
References Speak
Vi vil her studere, hvordan opdateringen af brugergrænsefladen finder sted, når der er sket forandringer i den underliggende model. Vi skal i denne forbindelse have øjnene åbne for, at en model kan præsenteres i to eller flere syn.

Hvilken part har ansvar for at opdatere brugergrænsefladen?

Modellen eller brugergrænsefladen selv?

  • To forskellige alternativer:

    • Modellen er ansvarlig for opdatering af brugergrænsefladen

      • Modellen kalder direkte de procedurer, som tegner brugergrænsefladen

      • Tæt kobling mellem model og brugergrænseflade

    • Brugergrænsefladen er ansvarlig for at opdatere sig selv

      • Brugergrænsefladen får et signal (udefra) om, at modellen er ændret

      • Via signalet indhenter brugergrænsefladen selv information om forandringerne

      • Løs kobling mellem brugergrænsefladen og modellen

      • Observer design mønstret

Model ansvarlighed for opdatering af brugergrænsefladen udgør den naive løsning på problemet. Hvis der er flere samtidige syn på modellen belaster det den indre programlogik på en meget uheldig måde. Endvidere bliver der for stor viden om brugergrænsefladen i selve modellen, med deraf følgende vanskeligheder, hvis der skal laves forandringer i brugergrænsefladen på et eller andet tidspunkt

Det er måske at tage munden lidt fuld, når man siger at brugergrænsefladen opdaterer sig selv. Men vi ønsker at frigøre modellen for ansvaret for den direkte opdatering af brugergrænsefladen, herunder evt. multiple syn på modellen. Modellen skal have så lidt viden om de forskellige syn på modellen, som afspejles af brugergrænsefladen. Hermed bliver det meget lettere at ændre på brugergrænsefladen, når og hvis det bliver nødvendigt

Reference

Observer mønstret mellem model og view
Slide Note Contents Index
References Speak
Vi vender her tilbage til vores første eksempel. I stedet for at lade modellen opdatere synet direkte sender vi nu et update signal til synet, som så indhenter information om ændringen hos modellen. Baseret på denne information opdaterer synet sig selv

Applet. En simpel applet som beregner x div y og x mod y af de to tal x og y i inputfelterne. Denne brugergrænseflade er identisk med den tidligere viste. Dog er det uderliggende program lidt anderledes, idet det er baseret på observer mønstret
 

Program: Model klassen med tilkobling og notification af observer. Vi ser at nu er klassen en Observable (fremhævet med blåt). I konstruktoren kobler modelobjektet en observatør på sig selv (vist med rødt). Lige efter beregningen af kvotient og rest sender dette objekt beskederne setChanged og notifyObservers til sig selv. Dette afstedkommer, at der afsendes en update besked til alle de observers, som abonnerer på forandringer. (I de klasser vi viser her, kan vi ikke se det sted update bliver sendt. Det sker i notifyObservers, som jo er implementeret i Obervable, hvorfra modelklassen DivModCalculator arver). I dette eksempel er der kun ét objekt, som har gjort dette. Beskeden getResult bliver sendt af observeren for at finde ud af, hvad der egentlig er sket på model objektet
class DivModCalculator extends Observable{

  private DivModPresenterObs viewObject;

  IntPair inputMemory, outputMemory;

  public DivModCalculator(DivModPresenterObs viewObject) {
    this.viewObject = viewObject;
    addObserver(viewObject);
    inputMemory = null; outputMemory = null;
  }
   
  private IntPair divMod(int x, int y){
    // require x > 0 && y > 0 ;

    int rest = x;
    int quotient = 0;
    
    while (rest >= y) {
      // invariant rest + quotient * y = x ;
      rest = rest - y;
      quotient = quotient + 1;
    }
    return (new IntPair(quotient,rest));
    // ensure  rest + quotient * y = x && rest < y && rest >= 0 ;
  } // end div

  public void doCalculate(int input1, int input2){
    inputMemory = new IntPair(input1, input2);
    if (input1 > 0 && input2 > 0)
      outputMemory = divMod(input1, input2);
    else
      outputMemory = new IntPair(-1, -1);
    
    setChanged();       // now I am changed
    notifyObservers();  // ... and therefore I notifiy my observers
  }

  public IntPair getResult(){
    return outputMemory;
  }

} // end DivModCalculator

Program: View klassen med ny update metode. Observatøren implementerer nu Interfacet Observer, som har én metode: update (vist med blåt). Metoden update (vist med lilla) trækker information tilbage fra modellen om forandringerne i dette objekt.
public class DivModPresenterObs extends Applet implements Observer{

   private DivModCalculator modelObject;
   private DivModListener listener;

   private Label title;
   private TextField dividend, divisor;
   private Label quotient,rest;

   public DivModPresenterObs(){
     modelObject = new DivModCalculator (this);
     listener = new DivModListener (modelObject, this);

     title = new Label ("Div Mod Calculator");
     dividend = new TextField ("0",5);
     divisor = new TextField ("0",5);
     quotient = new Label ("Kvotient:");
     rest = new Label ("Rest:") ;
    }

   public int getDividend(){
     String strResult = dividend.getText();
     return Integer.parseInt(strResult);
   }

   public int getDivisor(){
     String strResult = divisor.getText();
     return Integer.parseInt(strResult);
   }

   public void init() {
     dividend.addActionListener (listener);
     divisor.addActionListener (listener);

     setLayout(new GridLayout(6,1));

     add(title);
     add(divisor);  add(dividend); 
     add(quotient); add(rest); 

     resize (200,200);
   }

   public void update(Observable o, Object arg){
     // This view needs updating. Let us find out what happened in the model.
     IntPair divModObject = modelObject.getResult();
     quotient.setText("Kvotient: " + Integer.toString(divModObject.firstInt,10));
     rest.setText("Rest: " + Integer.toString(divModObject.secondInt,10));
   }

} // end DivModPresenterObs

Program: Controller klassen (uændret). Controlleren er ikke ændret som følge af indførelse af en observer.
class DivModListener implements ActionListener{

  private DivModCalculator modelObject;
  private DivModPresenterObs viewObject;

  public DivModListener(DivModCalculator modelObject, DivModPresenterObs viewObject){
    this.modelObject = modelObject;
    this.viewObject = viewObject;
  }

  public void actionPerformed(ActionEvent action){
    modelObject.doCalculate(viewObject.getDivisor(), viewObject.getDividend());
  }

} // end DivModListener

Image series: En typisk interaktion mellem view, model og controller - her med observer mønstret.En typisk interaktion mellem view, model og controller - her med observer mønstret. Vi har tidligere set på de samme billeder. De nye elementer, som involverer observer mønstret, er mærket ned 'Ny' i øverste venstre hjørne af billedet

Image no. 1. Der skabes et view, som i dette tilfælde er en applet
 

Image no. 2. I dette simple tilfælde skaber view'et model objektet og controller objektet
 

Image no. 3. Model objektet tilkobler et observer objekt
 

Image no. 4. View objektet opretter fem brugergrænseflade komponenter
 

Image no. 5. View objektet sender en besked til dividend om at registrerer controller som 'action listener'
 

Image no. 6. View objektet sender en besked til divisor om at registrerer controller som 'action listener'
 

Image no. 7. View objektet tilføje de fem brugergrænseflade komponenter til sig selv
 

Image no. 8. Brugeren opererer nu på brugergrænsefladen. Controlleren modtager en actionPerformed besked
 

Image no. 9. Controlleren sender getDivisor til view objektet, for at trække divisor ud af tekstfelterne
 

Image no. 10. View objektet udtrækker divisor teksten af divisor objektet. Teksten konverteres til et tal
 

Image no. 11. Controlleren sender getDividend til view objektet, for at trække dividend ud af tekstfelterne
 

Image no. 12. View objektet udtrækker dividend teksten af dividend objektet. Teksten konverteres til et tal
 

Image no. 13. Controlleren sender beskeden doCalculate til model objektet
 

Image no. 14. Model objektet foretager beregningen af kvotient og rest ved at sende beskeden divMod til sig selv
 

Image no. 15. Modelobjeket sender beskeden setChanged til sig selv
 

Image no. 16. Modelobjeket sender beskeden notifyObservers til sig selv
 

Image no. 17. notifyObservers sender update beskeden til de interesserede observers
 

Image no. 18. View objektet sender getResult beskeden til modellen
 

Image no. 19. View objektet sender beskeden setText til quotient for at vise kvotient resultatet
 

Image no. 20. View objektet sender beskeden setText til rest objektet for at vise rest resultatet
 

References

Ved brug af observer designmønstret bliver der en minimal binding mellem model og syn

Hvis der tilføjes flere eller anderledes syn skal model programmet ikke ændres overhovedet

Ansvaret for håndtering af events
Slide Note Contents Index
References Speak
Når brugeren interagerer med et program sker det gennem et syn. Herved skal modellen ændres, og der vil i de fleste tilfælde ske en opdatering af brugergrænsefladen. Vi vil nu koncentrere os om ansvarsfordelingen når det gælder fortolkning af brugerinput.

The concept event: Når brugeren interagerer med programmet frembringes en række events, som påvirker programmetEvents er i bred forstand de hændelser, som en programbruger foranlediger når han eller hun anvender programmet.

Hvilken part har ansvar for at lytte til og håndtere events?

Modellen, synene, eller en tredie part?

Modellen er ansvarlig for at lytte til og for at håndtere events.

De forskellige syn er ansvarlige for at håndtere events

Naturligt, idet events påvirker modellen

Naturlig, idet events er forekommer på et bestemt syn

Programmet organiseres omkring en stor løkke, som modtager og behandler alle events

Hvert syn håndterer sine egne events

Belaster modellen med en 'fremmedelement', som det helst havde været foruden

Belaster syn med et tungt ansvar, oven i alle de eksisterende ansvar

Det kan være fordelagtigt at udfaktorisere ansvaret for event håndtering til et nyt objekt, inputkontrol objektet, som er associeret til modelobjektet med henblik på opdatering af modellen

Inputkontrol objektet er associeret til modelobjektet med henblik på opdatering af modellen. Men som vi så i eksemplet tidligere i denne lektion har inputkontrol objektet også kendskab til view objektet med henblik på udtræk af informationer fra brugergrænsefladen. Endvidere abonnererer inputkontrol objektet på hændelser fra komponenter af view objektet, således at metoder i inputkontrol objektet bliver aktiveret når brugeren arbejder på synet

Ansvaret for placering af komponenter i et syn
Slide Note Contents Index
References Speak
Hvis man arbejder med en brugergrænseflade, som består af flere komponenter, skal man tage stilling til, hvordan disse komponenter skal placeres i forhold til hinanden i det todimensionale plan. Vi vil her se, hvordan Java løser dette problem på en elegant måde. Løsningen består i at uddelegere ansvaret for placering af komponenter til en såkaldt layout manager.

Hvilken part har ansvar for layout af komponenterne i en brugergrænseflade?

Synet selv eller en tredie part?

  • Den indbyrdes placering af komponenter i en Container forvaltes i Java af en såkaldt layout manager

  • Layout manageren løser placeringsopgaven på tværs af platforme, og når en container ændrer størrelse

Det er muligt at konstruere sin egen layout manager

Man kan også sætte layout manageren ud af spillet og dermed opnå absolut positionering

References

Oversigt over layout managers i AWT
Slide Note Contents Index
References Speak
På denne side karakteriseres de enkelte Layout Manager's i Java

  • Forskellige layout managers i Java AWT

    • BorderLayout: Placerer komponenter i nord, syd, øst, vest og center

    • FlowLayout: Placerer komponter rækkevis

      • Fylder én række op før den næste startes

    • GridLayout: Placerer komponenter i et fast antal rækker og søjler

    • CardLayout: Specielt layout som gør det muligt at en række brugergrænseflader deles om det samme vindue

    • GridBagLayout: En variant af GridLayout, som tillader komponenter at tilknyttet forskellige 'constraints'

      • Kompleks og uigennemskuelig

Det er ofte nyttigt at indlejre komponenenter (Panels) i hinanden, som tilknytter hver sin type af layout managers

Box layout i Swing
Slide Note Contents Index
References Speak

Swing tilbyder en ny layout manager, som kaldes BoxLayout

  • BoxLayout:

    • En generalisering af FlowLayout i AWT

    • Muliggør både rækker og søjler

    • Understøtter forskellige alignments

    • Understøtter Fillers (glue)

BoxLayout anvendt i passende indlejrede paneler vil ofte kunne erstatte den komplicerede GridBagLayout

Reference

Eksempler på layouts i Java AWT
Slide Note Contents Index
References Speak
Vi viser her en række eksempler på layouts. Eksemplerne er dels fra Lewis and Loftus (lærebogen) og dels fra farveblander eksemplet ovenfor

Reference

Layout eksempler fra farveblander programmet:

Program: Det overordnede layout er et GridLayout (init i klassen ColorPresenter).
   /** Applet init */
   public void init() {

       setLayout(new GridLayout(6,1));

       add(title);
       add(redGroup); add(greenGroup); add(blueGroup); 
       add(colorBlop);    
       add(hexTextField);
    
       resize (400,250);
       adjust();
   } //end init

Program: Layoutet i et 'ColorPanel' er et GridBagLayout.
class ColorPanel extends Panel {

  public ColorPanel (Label lab, TextField text, 
                     Scrollbar slider, ColorListener listener){

     GridBagConstraints c = new GridBagConstraints();
     GridBagLayout gridbag = new GridBagLayout();
     setLayout(gridbag);

     c.fill = GridBagConstraints.HORIZONTAL;

     add(lab); 

     c.gridwidth = GridBagConstraints.REMAINDER;
     gridbag.setConstraints(text, c);
     add(text);

     c.weightx = 1.0;
     c.gridwidth = 1;
     gridbag.setConstraints(slider, c);
     slider.setMaximum(255); 
     slider.setBlockIncrement(10);
     slider.setUnitIncrement(1);
     add(slider);

     text.addActionListener (listener);
     slider.addAdjustmentListener (listener);
  }
} // end class ColorPanel

References


Collected references
Contents Index
The Java Tutorial om brugergrænseflader (Swing)
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
The Java Tutorial om brugergrænseflader (AWT)
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Writing Applets
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Klassen Applet i pakken java.Applet
The reference from above goes to Java API pageThe references above goes to material on the Internet
Farveblander eksemplet
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
DivMod eksemplet
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Ovenstående HTML side
The references above goes to material on the Internet
Interfacet ActionListener
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Applet i pakken java.Applet
The reference from above goes to Java API pageThe references above goes to material on the Internet
Composite design pattern
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Klassen Component i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Panel i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Farveblander eksemplet
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Klassificeringen af komponenter (tidligere side i denne lektion)
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Klassen Scrollbar i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Canvas i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen PopupMenu i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen MenuBar i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen MenuItem i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Menu i pakken java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Menuer i The Java Tutorial
The references above goes to material on the Internet
Komponent specialiseringshierarkiet
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Observer design mønstret
The reference above goes to a lecture note pageThe reference above points to an succeding page in the lecture notes
Interfacet Observer
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Observable
The reference from above goes to Java API pageThe references above goes to material on the Internet
Doing without layout managers
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Creating a custom layout manager
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Laying out components
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
How to use BoxLayout
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Klassen GridBagLayout i java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen CardLayout i java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen GridLayout i java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen FlowLayout i java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen BorderLayout i java.awt
The reference from above goes to Java API pageThe references above goes to material on the Internet

 

Chapter 12: Grafiske brugergrænseflader i Java, del 1
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: March 31, 2008, 12:09:34