© Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

6. Aivan vähän GUI:sta ja tapahtumaohjatusta ohjelmoinnista

(Muutettu viimeksi 8.2.2005)

Tämä luku sisältää lähinnä vain oppikirjan ja vanhan www-materiaalin luvun 6 joitakin vanhentuneita ohjelmaesimerkkejä nykyaikaistettuna Swing-versioiksi. Tarkoituksena ei ole vielä oppia itse tekemään graafisia käyttöliittymiä ("graphical user interface", GUI), tarkoituksena on vain saada ideatason käsitys, miten Javassa graafisia näkymiä luodaan ja miten ohjelmoidaan tapahtumiin reagointia.

Graafinen sovellus

(Vanhan luvun 6.5 esimerkkejä "Swingattuina")

Sovellus on main-metodilla käynnistettävä Java-ohjelma. Graafiseen käyttöliittymään (GUI) perustuvan sovelluksen päämetodi rakentaa käyttöliittymän näkymän.

Pieni esimerkki: (HoiGSovellus0.java)

import javax.swing.*;

public class HoiGSovellus0 extends JFrame {

  public HoiGSovellus0() { // konstruktori!
    JTextField hoi = new JTextField("Hoi maailma!");
    add(hoi); // lisätään kenttä luokan näkymään
  }

  public static void main(String args[]) {
    HoiGSovellus0 ikkuna = new HoiGSovellus0();
    ikkuna.setTitle("Hoi 0!");
    ikkuna.pack();
    ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ikkuna.setVisible(true);
  }
}

Graafista käyttöliittymää käyttävän sovelluksen luokka on luokan JFrame aliluokka. JFrame määrittelee ikkunan, jolla on reunat ja otsikkopalkki. Se tarjoaa yliluokkineen välineet mm. ikkunoiden käsittelyyn. Pääohjelma luo ilmentymän omasta luokastaan HoiGSovellus0. Pääohjelma myös asettaa sovelluksen ikkunaan otsikkorivin (setTitle), antaa luvan asettaa ikkunan komponentit oletuskokoonsa (pack) ja asettaa ikkunan näkyväksi (setVisible).

... ja ikkunassa tapahtuu ...

Graafisen käyttöliittymän tapahtumiin reagointi voidaan ohjelmoida useilla erilaisilla tavoilla. Seuraavassa esimerkissä asia hoidetaan hyvin yksinkertaisesti eikä lainkaan "olio-ohjelmointihenkisesti"!

Esimerkki: (HoiGSovellus2.java)
import javax.swing.*;
import java.awt.event.*;

public class HoiGSovellus2 extends JFrame
                           implements ActionListener {

  private JTextField hoi = new JTextField("Paina enter!");
  private int elkm = 0;

  public HoiGSovellus2() {
    add(hoi);
    hoi.addActionListener(this);
  }

  public void actionPerformed(ActionEvent tapahtuma) {
    Object aiheuttaja = tapahtuma.getSource();
    if (aiheuttaja == hoi) {
       ++elkm;
       hoi.setText(elkm+". enter");
    }
  }

  public static void main(String args[]) {
    HoiGSovellus2 ikkuna = new HoiGSovellus2();
    ikkuna.setTitle("Hoi 2!");
    ikkuna.pack();
    ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ikkuna.setVisible(true);
  }
}

Nappuloita

(Vanhan luvun 6.5 esimerkkejä "Swingattuina")

Laaditaan muutamia graafisen käyttöliittymän komponentteja (luokat JButton, JTextField, JTextArea) käyttäen sovellus, joka osaa reagoida nappuloiden painamiseen ja tekstikenttään kirjoittamiseen. Komponentteja on monia, monia muitakin: ks. Java-API:n pakkaus javax.swing.

Näihin luokkiin sekä esimerkkiin tutustuminen jätetään oman harrastuksen varaan: Suorita ohjelmaa, tutki luokkien kuvailuja, kokeile ohjelman muuttamista, ...

Esimerkki (Nappuloita.java)

import javax.swing.*;
import java.awt.event.*;
import java.awt.FlowLayout;

public class Nappuloita extends JFrame
                        implements ActionListener {

  // muuttujia ikkunan komponenteille:

  private JButton nappula, tyhjaa, loppu;
  private JTextField tekstiKentta1, tekstiKentta2;
  private JTextArea tekstiAlue;

  public Nappuloita() {  // konstruktori

    setLayout(new FlowLayout()); // "kun rivi loppuu,
                                 //  uusi alkaa"
    // luodaan komponenttioliot:

    nappula = new JButton("nappula");
    tyhjaa  = new JButton("tyhjää");
    loppu   = new JButton("loppu");

    tekstiKentta1 = new JTextField(10);

    tekstiKentta2 = new JTextField(15);
    tekstiKentta2.setEditable(false);

    tekstiAlue = new JTextArea(5,14);

    // lisätään komponenttioliot ikkunaan:

    add(nappula);
    add(tyhjaa);
    add(loppu);
    add(tekstiKentta1);
    add(tekstiKentta2);
    add(tekstiAlue);

    // asetetaan kuuntelijat:

    nappula.addActionListener(this);
    tyhjaa.addActionListener(this);
    loppu.addActionListener(this);
    tekstiKentta1.addActionListener(this);
  }

  // tapahtumien käsittely:

  public void actionPerformed(ActionEvent tapahtuma) {

     Object aiheuttaja = tapahtuma.getSource();

     if (aiheuttaja == nappula) {
       tekstiKentta2.setText("Painoit nappulaa!");
       tekstiAlue.append("Painoit nappulaa!\n");
     }
     else if (aiheuttaja == tyhjaa) {
       tekstiKentta1.setText("");
       tekstiKentta2.setText("");
       tekstiAlue.setText("");
     }
     else if (aiheuttaja == loppu)
       System.exit(0); // lopetetaan

     else if (aiheuttaja == tekstiKentta1)
       tekstiAlue.append(tekstiKentta1.getText()+"\n");

  }

  public static void main(String args[]) {
      Nappuloita ikkuna = new Nappuloita();
      ikkuna.setSize(300, 200);
      ikkuna.setTitle("Nappuloita.java");
      ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      ikkuna.setVisible(true);
  }
} 

Paneeleja

Sovelluksen (ja sovelman) käyttöliittymäelementtien sijoittelua ikkunaan ohjataan ns. layout-määrittelyillä. "Layoutin" yksi suomennos on "asemointi".

Käytössä on mm. seuraavat asemointitavat:

  1. BorderLayout: elementtejä voi sijoitella alueen "ilmansuuntiin" ja keskelle:
         setLayout(new BorderLayout());
         add("North",  nappula1);
         add("South",  nappula2);
         add("East",   nappula3);
         add("West",   nappula4);
         add("Center", nappula5);
    

  2. CardLayout: elementit muodostavat "korttipakan", jonka päällimmäinen elementti on näkyvissä. Metodeilla voi vaihtaa päällimmäistä.

  3. FlowLayout: elementtejä näytetään "vasemmalta oikealle ja ylhäältä alaspäin" alueen koon mukaan. Kun alueen kokoa tai muotoa muutetaan, elementtien paikat voivat vaihtua.

  4. GridBagLayout: joustava ja samalla työläskäyttöinen asemointi.

  5. GridLayout: elementit sijoitetaan "riveihin ja sarakkeisiin":
         setLayout(new GridLayout(2,3)); // rivejä, sarakkeita
         add(nappula1);
         add(nappula2);
         add(nappula3);
         add(nappula4);
         add(nappula5);
         add(nappula6);
    
    

Sovelluksen ikkuna voidaan rakentaa "ali-ikkunoista", paneeleista, joilla jokaisella voi olla oma asemointitapansa. Ja koko ikkunalla omansa.

Ja toki paneeleilla voi olla omia alipaneeleitaan...

Esimerkki esittelee paneelien ja muutamien layout-asetusten käyttöä. Esimerkkiin perehtyminen jää oman harrastuksen varaan. (Paneeleja.java)

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;

import javax.swing.*;
import java.awt.event.*;

public class Paneeleja extends JFrame {

  private JButton b111 = new JButton("Nappula 111");
  private JTextField t112 = new JTextField("Kentta 112");
  private JLabel l121 = new JLabel("Teksti 121");
  private JButton b122 = new JButton("Nappula 122");

  private JButton b21 = new JButton("Nappula 21");
  private JTextField t22 = new JTextField("Kentta 22");
  private JButton b23 = new JButton("Nappula 23");

  private JButton b31 = new JButton("31");
  private JButton b32 = new JButton("32");
  private JButton b33 = new JButton("33");
  private JButton b34 = new JButton("34");
  private JButton b35 = new JButton("35");
  private JButton b36 = new JButton("36");
  private JButton b37 = new JButton("37");
  private JButton b38 = new JButton("38");

  private JButton b41 = new JButton("41");
  private JButton b42 = new JButton("42");

  public Paneeleja() {

    JPanel p11 = new JPanel(new BorderLayout());
    p11.add("North", b111);
    p11.add("South", t112);

    JPanel p12 = new JPanel(new BorderLayout());
    p12.add("North", l121);
    p12.add("South", b122);

    JPanel p1 = new JPanel(new FlowLayout());
    p1.add(p11); p1.add(p12);

    JPanel p2 = new JPanel(new FlowLayout());
    p2.add(b21); p2.add(t22); p2.add(b23);

    JPanel p3 = new JPanel(new GridLayout(2,4));
    p3.add(b31); p3.add(b32); p3.add(b33); p3.add(b34);
    p3.add(b35); p3.add(b36); p3.add(b37); p3.add(b38);

    JPanel pp1 = new JPanel(new BorderLayout());
    pp1.add("North", p1);
    pp1.add("Center", p2);
    pp1.add("South", p3);

    JPanel pp2 = new JPanel(new GridLayout(2,1));
    pp2.add(b41); pp2.add(b42);

    this.setLayout(new BorderLayout());
    this.add("Center", pp1);
    this.add("East", pp2);
  }

  public static void main(String args[]) {
    Paneeleja ikkuna = new Paneeleja();
    ikkuna.setTitle("Paneeleja");
    ikkuna.pack();
    ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    ikkuna.setVisible(true);
  }
}

Kirjoitusta ja piirustusta

(Vanhan luvun 6.2 esimerkkejä "Swingattuina") Sovelmat on muutettu sovelluksiksi.)

Näissä esimerkeissa piirustusalusta toteutetaan luokan JPanel aliluokkana. (Esimerkeissä aliluokka on kirjoitettu samaan käännösyksikköön varsinaisen ohjelman luokan kanssa.)

Oma piirustusalusta perii JPanel-luokalta mm. metodin protected void paintComponent(Graphics g). (JPanel on puolestaan itse perinyt tuon metodin omalta yliluokaltaan JComponent.) Ohjelman laatija korvaa (overrides) tämän perityn metodin sellaisella, joka piirtää komponenttiin halutun sisällön.

Järjestelmä kutsuu paintComponent(Graphics g)-metodia aina, kun näkymä pitää piirtää: ohjelman suorituksen alussa, kun näkymä on ollut peitettynä, kun se palautetaan kuvakkeesta ikkunaksi, ... Kutsuva järjestelmä antaa metodille parametrina Graphics-luokan ilmentymän, joka juuri on ohjelman ikkuna. (Kyseessä on itse asiassa Graphics-luokan jonkin aliluokan ilmentymä, koska Graphics on itse abstrakti!)

Luokassa Graphics on määritelty joukko metodeita sovelman ikkunassa näytettävän kuvan muodostamiseen ja käsittelyyn:

Ikkunan koordinaatit ilmaistaan kuvapisteinä (ns. pikseleinä) siten, että ikkunan vasemman yläkulman koordinaatit ovat (0,0), yläkulman alapuolinen pikseli on (0,1), yläkulman viereinen pikseli on (1,0), jne.

Huom: Piirrellä voidaan itse asiassa melkein minkä vain komponentin pinnalle! JComponent-luokalle luetellaan "tunnettuina aliluokkina" seuraavat: AbstractButton, BasicInternalFrameTitlePane, Box, Box.Filler, JColorChooser, JComboBox, JFileChooser, JInternalFrame, JInternalFrame.JDesktopIcon, JLabel, JLayeredPane, JList, JMenuBar, JOptionPane, JPanel, JPopupMenu, JProgressBar, JRootPane, JScrollBar, JScrollPane, JSeparator, JSlider, JSpinner, JSplitPane, JTabbedPane, JTable, JTableHeader, JTextComponent, JToolBar, JToolTip, JTree, JViewport. Näillä luokillakin on aliluokkia. Esimerkiksi AbstractButton-luokan JButton-aliluokan ilmentymät voivat joutua piirtelyn kohteeksi!

Tekstien kirjoittamista ikkunaan: (Kirjoittelua.java)

import javax.swing.*;
import java.awt.Graphics;

public class Kirjoittelua extends JFrame {

  public Kirjoittelua() {
    this.add(new KirjPaneeli());
  }

  public static void main(String[] args) {
        Kirjoittelua ikkuna = new Kirjoittelua();
        ikkuna.setTitle("Kirjoittelua");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(350, 350);
        ikkuna.setVisible(true);
    }
}

class KirjPaneeli extends JPanel {
  public void paintComponent(Graphics g) {
     for (int i=0; i<299; i+=10)
       g.drawString("Böö "+i, i, i);
  }
}

Luokasta Font löytyy monenlaisia kirjasintyyppejä. Esimerkki yhdestä kirjasintyypistä ja luokan Font käytöstä (Kaunokirjoittelua.java)

import javax.swing.*;
import java.awt.Graphics;
import java.awt.Font;

public class Kaunokirjoittelua extends JFrame {

  public Kaunokirjoittelua() {
    add(new KaunoPaneeli());
  }

  public static void main(String[] args) {
        Kaunokirjoittelua ikkuna = new Kaunokirjoittelua();
        ikkuna.setTitle("Kaunokirjoittelua");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(350, 350);
        ikkuna.setVisible(true);
    }
}

class KaunoPaneeli extends JPanel {
  public void paintComponent(Graphics g) {
    Font kirjasin = new Font("TimesRoman", Font.BOLD+Font.ITALIC, 14);
    g.setFont(kirjasin);
    for (int i=0; i<299; i+=10)
      g.drawString("Böö "+i, i, i);
  }
}

Laaditaan sitten pikku ohjelma, jolla voi tutkia, milloin ja miten usein paint-metodi suoritetaan. (Painttilaskuri.java)

import javax.swing.*;
import java.awt.Graphics;

public class Painttilaskuri extends JFrame {

  public Painttilaskuri() {
    add(new PainttiPaneeli());
  }

  public static void main(String[] args) {
        Painttilaskuri ikkuna = new Painttilaskuri();
        ikkuna.setTitle("Painttilaskuri");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(300, 100);
        ikkuna.setVisible(true);
  }
}

class PainttiPaneeli extends JPanel { 

  private int lkm=0;

  public void paintComponent(Graphics g) {
    g.drawString("Maalauskerta numero: "+lkm, 10,25);
    ++lkm;
  }
}

Graphics-luokassa on määritelty joukko piirtämisvälineitä. Metodit on määritelty abstrakteina. Graphicsin aliluokat siis itse asiassa toteuttavat nuo välineet omien vaatimustensa mukaisina.

Esimerkiksi janoja kuva-alalle piirretään metodilla

drawLine(alkuX, alkuY, loppuX, loppuY)

Seuraava esimerkkiohjelma arpoo janan paikan (Arpaviiva.java)

import javax.swing.*;
import java.awt.Graphics;

public class Arpaviiva extends JFrame {

  public Arpaviiva() {
    add(new ArpaPaneeli());
  }

  public static void main(String[] args) {
        Arpaviiva ikkuna = new Arpaviiva();
        ikkuna.setTitle("Arpaviiva");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(350, 250);
        ikkuna.setVisible(true);
    }
}

class ArpaPaneeli extends JPanel {

  public void paintComponent(Graphics g) {

     System.out.println("maalataan");

     int alkux,alkuy, loppux, loppuy;

     alkux  = (int)(Math.random()*300);
     alkuy  = (int)(Math.random()*200);
     loppux = (int)(Math.random()*300);
     loppuy = (int)(Math.random()*200);

     g.drawRect(0,0,299,199);
     g.drawLine(alkux,alkuy,loppux,loppuy);
     g.drawString("("+alkux+","+alkuy+"),("+loppux+","+loppuy+")",1,12);
  }

}

Luokassa Color on värienkäsittelyvälineitä. Siellä on myös vakiot mm. seuraaville väreille: black, blue, cyan, darkGray, gray, green, lightGray, magenta, orange, pink, red, white ja yellow.

Muita värejä voi määritellä ns. RGB-lukukolmikkoina, jotka annetaan Color-konstruktorille. Valkoinen on Color(255,255,255), musta Color(0,0,0), puhdas punainen Color(255,0,0), ...

Esimerkki: Kokeillaan RGB-määriteltyjä värejä. Käydään läpi R- ja G-arvoja ja B-komponentti arvotaan joka maalauskerralla. (OmatVarit.java)

import javax.swing.*;
import java.awt.Graphics;
import java.awt.Color;

public class OmatVarit extends JFrame {

  public OmatVarit() {
    add(new VariPaneeli());
  }

  public static void main(String[] args) {
        OmatVarit ikkuna = new OmatVarit();
        ikkuna.setTitle("OmatVarit");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(285, 310);
        ikkuna.setVisible(true);
    }
}

class VariPaneeli extends JPanel {

  public void paintComponent(Graphics kuva) {

     kuva.drawRect(0,0, 277, 277);
     setBackground(Color.white);

     int r,g,b; // RGB värikolmikko

     b = (int)(Math.random()*256);

     for (r=0; r<256; r+=3) 
       for (g=0; g<256; g+=3) {
         Color vari = new Color(255-r,255-g,b);
         kuva.setColor(vari);
         kuva.fillRect(10+r,10+g, 3,3);
       }
  }
}

Nappuloita ja kuvia

Kuvia ja muita käyttöliittymäelementtejä voidaan toki yhdistellä.

Esimerkissä Maalaus.java luodaan pari käyttöliittymäelementtiä, asemoidaan niitä ja reagoidaan napin painallukseen:

public class Maalaus extends JFrame
                       implements ActionListener  {

  private JButton nappula = new JButton("Uusi maalaus!");
  private VariPaneeli kuva = new VariPaneeli();

  public Maalaus() {
    setLayout(new BorderLayout());
    add("Center", kuva);
    add("South", nappula);
    nappula.addActionListener(this);
    kuva.setOpaque(false); // estää "ylimääräisen" buttonin varjon
    nappula.setOpaque(false);
  }

  public void actionPerformed(ActionEvent tapahtuma) {
    Object aiheuttaja = tapahtuma.getSource();
    if (aiheuttaja == nappula) {
      kuva.repaint();
    }
  }

  public static void main(String[] args) {
        Maalaus ikkuna = new Maalaus();
        ikkuna.setTitle("Art_o");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(285, 330);
        ikkuna.setVisible(true);
    }
}

class VariPaneeli extends JPanel {

  public void paintComponent(Graphics kuva) {
  ...
  }
}
VariPaneeli-luokan toteuksella sitten onkin jo minun taiteellinen copyrightini... ;-)

Sattuu ja tapahtuu

Laaditaan väline, jolla voi kokeilla sovelluksen reagointeja rajapintaluokkien ComponentListener, MouseMotionListener, MouseListener, KeyListener ja FocusListener määrittelemiin tapahtumiin.

Koska luokka Reagointeja lupaa toteuttaa kaikki mainitut rajapintaluokat, sen on annettava toteutus niiden kaikille metodeille! Metodit vain tulostavat ilmoituksen itsestään siihen ikkunaan, josta sovellus on käynnistetty - tuttuun tapaan metodilla System.out.println(...)! (Reagointeja.java)

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Reagointeja
               extends JFrame
               implements ComponentListener, MouseMotionListener,
                          MouseListener, KeyListener, FocusListener {

   private TextArea alue =
     new TextArea ("\n    Reagoiva alue:\n\n" + 
                   "   Kokeile erilaisia\n" +
                   "   tapahtumia ja seuraa\n" +
                   "   systeemin ikkunaa!",
                   10, 20, TextArea.SCROLLBARS_NONE);

   private int laskuri = 0;
   private Label laskuriOtsikko = new Label("", Label.CENTER);

   public Reagointeja() {

      alue.setEditable(false);

      add ("Center", alue);
      add ("South", laskuriOtsikko);

      addComponentListener(this);

      alue.addFocusListener(this);
      alue.addKeyListener(this);
      alue.addMouseListener(this);
      alue.addMouseMotionListener(this);
   }

   private void kirjaaTapahtuma(AWTEvent tapahtuma) {
      laskuri++;
      laskuriOtsikko.setText("Tapahtumia: " + laskuri + " kpl");
      System.out.println(tapahtuma.toString().substring(15));
      // ei tulosteta kaikille yhteistä alkua "java.awt.event."!
   }

   public void componentMoved(ComponentEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void componentHidden(ComponentEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void componentResized(ComponentEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   } 
   public void componentShown(ComponentEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseDragged(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseMoved(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mousePressed(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseReleased(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseEntered(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseExited(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void mouseClicked(MouseEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void keyPressed(KeyEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void keyReleased(KeyEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void keyTyped(KeyEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void focusGained(FocusEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }
   public void focusLost(FocusEvent tapahtuma) {
      kirjaaTapahtuma(tapahtuma);
   }

   public static void main(String args[]) {
        Reagointeja ikkuna = new Reagointeja();
        ikkuna.setTitle("Tapahtuu ...");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.setSize(200, 200);
        ikkuna.setVisible(true);
    }
}

Ja tässä tulee todellinen hyötyohjelma! (HiiriTuliJaMeni.java)

import javax.swing.*;
import java.awt.event.*;
import java.awt.font.*;  // vain fonttia varten
import java.awt.*;       //        "

public class HiiriTuliJaMeni extends JFrame
                                implements MouseListener {

  private JTextArea alue = new JTextArea (1, 11);
  private int puremia = 0;

  public HiiriTuliJaMeni() {

    alue.setEditable(false);
    add ("Center", alue);

    alue.setFont(new Font("Serif", Font.BOLD, 20));
    alue.setText(" Hiirtä ei ole näkynyt.");

    alue.addMouseListener(this);  // luokka ITSE toteuttaa
                                  // kuuntelijan
  }

  public void mouseEntered(MouseEvent tapahtuma) {
    alue.setText("      Hiiri tuli!");
  }
   public void mouseExited(MouseEvent tapahtuma) {
    alue.setText("      Hiiri meni!");
  }

  public void mouseClicked(MouseEvent tapahtuma) {
    ++puremia;
    alue.setText(" Hiiri puri! ("+puremia+". kerta)"); 
  }

  // KAIKKI luvatut metodit on toteutettava (edes tyhjinä):

  public void mousePressed(MouseEvent tapahtuma)  { }
  public void mouseReleased(MouseEvent tapahtuma) { }


 public static void main(String[] args) {
        HiiriTuliJaMeni ikkuna = new HiiriTuliJaMeni();
        ikkuna.setTitle("Hiirielämää");
        ikkuna.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ikkuna.pack();
        ikkuna.setVisible(true);
    }
}

Sovelmista

Sovelmat toteuteaan hyvin samaan tapaan kuin graafiset sovellukset. Konstruktorin korvaa init()-metodi, jota kutsuen www-selain luo sovelman graafisen näkymän. Pääohjelmaa ei tarvita - selain hoitaa sen tehtävät. Sovelman elinkaareen liittyy muutama muukin metodi, joilla voi esimerkiksi käynnistää tai keskeyttää animoinnin yms.

Graafisen sovelluksen muuntaminen sovelmaksi on käytännössä (lähes) täysin mekaanista. Tälle kurssille sovelmista mahtuu kuitenkin vain pieni esimerkki. Kurssin vanhan materiaalin sovelmista kertovat osat saattavat olla vieläkin hyödyllisiä.

Edellä nähtiin esimerkkinä graafisesta sovelluksesta (application) luokka Maalaus.java. Sovelmaksi (applet) tuon ohjelman voi muuttaa yksinkertaisesti kopioimalla konstruktorin algoritmi init()-metodin algoritmiksi. Pääohjelma poistetaan: (BMaalaus.java)

import javax.swing.*;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;

public class BMaalaus extends JApplet
                       implements ActionListener  {

  private JButton nappula = new JButton("Uusi maalaus!");
  private BVariPaneeli kuva = new BVariPaneeli();

  public void init() {
    setLayout(new BorderLayout());
    add("Center", kuva);
    add("South", nappula);
    nappula.addActionListener(this);
    kuva.setOpaque(false); // estää "ylimääräisen" buttonin varjon
    nappula.setOpaque(false);
  }

  public void actionPerformed(ActionEvent tapahtuma) {
    Object aiheuttaja = tapahtuma.getSource();
    if (aiheuttaja == nappula) {
      kuva.repaint();
    }
  }

/* Pääohjelma on poistettu. */

}

class BVariPaneeli extends JPanel {

  public void paintComponent(Graphics kuva) {
    ...
  }
}

Www-sivut toteutetaan ns. html-kielellä, jonka perusidea on määritellä näytettävien sivujen looginen rakenne ns. "tägeillä" (tag), jotka ilmaisevat esimerkiksi kappalerajaa, otsikkoa, sisennettyä luetteloa, yms. (html-kielestä: ks. esimerkiksi Jukka Korpelan Web-julkaisemisen opas).

Java-sovelma liitetään www-sivulle tägillä "<APPLET CODE..." Tällä sivulla näkyvä sovelma on liitetty sivuun kirjoittamalla tämän sivun html-tiedostoon rivit:

<APPLET CODE="BMaalaus.class" WIDTH=258 HEIGHT=280>
Selain ei ymmärrä Javaa!
</APPLET>
Samaan tapaan kuin kaikelle maailmalle annetaan html-tiedoston lukuoikeus, myös sovelman toteuttaville class-tiedostoille on nimenomaan tämä lukuoikeus annettava. Suoritusoikeutta ei tarvita, koska sovelmat suoritetaan käyttäjän oman koneen selaimen Java-tulkilla! Tässä esimerkissä tiedoston BMaalaus.class lisäksi lukuoikeus on pitänyt antaa apuluokalle BVariPaneeli.class. (Sovelmaversiossa on muutettu myös hieman sovelluksen piirtoalaa BVariPaneeli-luokassa.)

Selain ei ymmärrä Javaa!


Ja "viritelty versio kansainväliseen käyttöön" ...


Takaisin pääsisällysluetteloon.


Java and all Java-based marks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. University of Helsinki is independent of Sun Microsystems, Inc.