Sovelman liittäminen WWW-sivulle
Sovelma sijoitetaan sivulle html-kielen <APPLET> ja </APPLET>-tunnisteilla. Aloitustunnisteeseen kirjoitetaan sovelman tietoja, esimerkiksi sovelman koodin sisältävän class-tiedoston nimi:
<APPLET CODE="HoiSovelma.class"
WIDTH=250 HEIGHT=70>
Tämä teksti tulostetaan, jos selain ei ymmärrä Javaa.
</APPLET>
<APPLET>-tunnisteeseen voidaan koodiviitteen lisäksi liittää muitakin määreitä, esimerkisi
tieto sovelmalle varattavasta tilasta
tieto siitä, mistä WWW-osoitteesta sovelman class-tiedosto haetaan (CODEBASE = codebaseURL)
<APPLET>- ja </APPLET>-tunnisteiden väliin voidaan kirjoittaa virheilmoitusteksti, joka tulostuu, jos selaaja ei ymmärrä sovelmia. Samaan kohtaan voidaan myös lisätä <PARAM>-tunnisteita, joilla sovelmalle voi antaa WWW-sivulta parametreja:
<APPLET CODE="JokinSovelma.class"
CODEBASE = "http://www.hut.fi/~liisaj/"
WIDTH=310 HEIGHT=80>
<PARAM name="Teksti"
value="Tämä tulee WWW-sivulta!">
Selain ei ymmärrä Javaa!
</APPLET>
Sovelmassa WWW-sivulla annetun parametrin arvo voidaan lukea metodilla getParameter(String paramNimi):
import java.awt.*;
import java.applet.Applet;
public class JokinSovelma extends Applet {
String tulostusTeksti;
public void init() {
tulostusTeksti = getParameter("Teksti");
}
public void paint(Graphics g) {
g.setFont(new Font("Helvetica", Font.PLAIN, 22));
g.drawString(tulostusTeksti, 10, 50);
}
}
Esimerkki: piirto-ohjelma
Seuraava esimerkki on yksinkertainen piirto-ohjelma, jossa käyttäjä voi piirtää hiirellä sovelman ikkunaan.
Sovelma reagoi hiiren raahaamisen aiheuttamiin tapahtumiin: aina tapahtuman sattuessa piirretään pieni ympyrä siihen kohtaan, josta tapahtuma aiheutui. (Kuviosta pyritään saamaan yhtenäisempi sillä, että pisteen sijasta piirretään pieni ympyrä.)
Paint-metodissa on piirrettävä aina koko kuvio eikä vain sen viimeksi piirrettyä osaa. Muuten kuvion alkuosa häviäisi, jos sovelman ikkuna olisi välillä peitettynä tai kuvakkeena. (Parempi vaihtoehto käsitellä tilanne annetaan myöhemmässä esimerkissä.)
Kun hiirtä on raahattu, pitää kutsua repaint-metodia, jotta kuvaa päivittettäisiin. Repaint-metodi kutsuu automaattisesti update-metodia, joka puolestaan kutsuu paint-metodia.
Update-metodin oletusversio tyhjentää ikkunan ennen kuin se kutsuu paint-metodia. Tällöin jatkuva kuvaruudun päivitys saa aikaan kuvaruudun vilkkumisen. Vilkkuminen voidaan estää kirjoittamalla update-metodi uudelleen, jolloin sovelman update-metodi korvaa oletusmetodin. Sovelman update-metodissa ei nyt tyhjennetä ikkunaa, vaan ainoastaan kutsutaan paint-metodia:
public void update(Graphics g) {
paint(g);
}
// Yksinkertainen sovelma, jossa käyttäjä voi piirtää hiirellä
// sovelman ikkunaan. Ohjelma on otettu (muokattuna) kirjasta
// Peltomäki, Malmirae: Java-ohjelmoinnin peruskirja (Teknolit)
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
public class Piirra extends Applet {
private Vector xKoord; // Vektoreihin talletetaan piirrettävät pisteet
private Vector yKoord;
private LiikkeenSeuraaja seuraaja;
public void init() {
xKoord = new Vector();
yKoord = new Vector();
seuraaja = new LiikkeenSeuraaja(this);
addMouseMotionListener(seuraaja);
setBackground(Color.white);
}
public void paint(Graphics g) {
int i, x, y;
for (i = 1; i < xKoord.size(); i++) {
x = ((Integer) xKoord.elementAt(i)).intValue();
y = ((Integer) yKoord.elementAt(i)).intValue();
g.fillOval(x, y, 4, 4);
}
}
// Korvataan Component-luokan update-metodi, jotta kuvaruutu ei
// vilkkuisi piirrettäessä.
public void update(Graphics g) {
paint(g);
}
public void asetaKoordinaatit(int x, int y) {
xKoord.addElement(new Integer(x));
yKoord.addElement(new Integer(y));
}
}
class LiikkeenSeuraaja extends MouseMotionAdapter {
private Piirra sovelma;
public LiikkeenSeuraaja(Piirra piirtosovelma) {
sovelma = piirtosovelma;
}
public void mouseDragged(MouseEvent tapahtuma) {
int x, y;
x = tapahtuma.getX();
y = tapahtuma.getY();
sovelma.asetaKoordinaatit(x,y);
sovelma.repaint();
}
}
Esimerkki: parempi piirtosovelma
Seuraava esimerkkisovelma käyttää apuna puskurikuvaa: muistissa pidetään toista kuvaa, johon piirretään täsmälleen samat asiat kuin sovelluksen ikkunassa näkyvään kuvaan.
Jos koko kuva pitää piirtää uudelleen, paint-metodissa kopioidaan puskurikuvaan piirretty kuva sovelluksen ikkunaan.
Normaalisti varsinainen piirtäminen tehdään hiiritapahtuman käsittelijässä: kutsutaan metodia piirraViiva, joka piirtää viivan aikaisemmasta pisteestä nykyiseen pisteeseen sekä sovelluksen ikkunaan että puskurissa olevaan kuvaan.
Puskurikuvan tyyppi on Image.
Sovelmassa voi lisäksi tyhjentää kuvaruudun painamalla hiiren oikeaa näppäintä kuvaruudun alueella.
Sovelman ikkunalla on punainen kehys. Kehystä ei näytetä oikein, jos ikkunan kokoa muutetaan.
Osa piirtämisestä tehdään metodeissa, joissa piirtämiseen liittyvää Graphics-luokan oliota ei ole valmiina käytössä. Silloin se luodaan ensin metodilla getGraphics().
/* Tämä sovelman avulla käyttäjä voi piirtää hiirellä ikkunaan.
Ikkunan voi tyhjentää hiiren oikealla näppäimellä. Sovellus
ei reagoi oikein ikkunan koon muutoksiin. Piirtämisen apuna
käytetään puskurikuvaa, joka kopioidaan tarvittaessa kuvaruudulle.
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
public class Piirra3 extends Applet implements MouseListener,
MouseMotionListener {
Image puskurikuva;
Graphics puskuri; // puskurikuvan grafiikkaolio
boolean pohjassa = false;
int vanhaX;
int vanhaY;
public void init() {
setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(this);
teePuskurikuva();
}
// korvataan peritty update-metodi vilkkumisen estämiseksi.
public void update(Graphics g) {
paint(g);
}
// paint-metodia kutsutaan vain silloin, kun kuva piirretään kokonaan
// uudestaan
public void paint(Graphics g) {
g.drawImage(puskurikuva, 0, 0, this); // kopioi puskurikuva ikkunaan
}
// alusta puskurikuva
void teePuskurikuva() {
puskurikuva = createImage(getSize().width, getSize().height);
puskuri = puskurikuva.getGraphics();
tyhjaaKuva();
}
void tyhjaaKuva() {
puskuri.setColor(Color.white);
puskuri.fillRect(0,0,getSize().width, getSize().height);
puskuri.setColor(Color.red);
puskuri.drawRect(0,0,getSize().width-1, getSize().height-1);
puskuri.setColor(Color.black);
}
// metodi piirtää samanlaisen viivan sekä ikkunaan että puskurikuvaan
void piirraViiva(int x1, int y1, int x2, int y2) {
Graphics g;
puskuri.drawLine(x1,y1,x2,y2);
g = getGraphics(); // luo ikkunaan liittyvä grafiikkaolio
g.drawLine(x1,y1,x2,y2);
g.dispose();
}
public void mousePressed(MouseEvent tapahtuma) {
if (tapahtuma.isMetaDown()) { // onko painettu oikeanpuoleista näppäintä
tyhjaaKuva();
repaint();
}
else {
pohjassa = true;
vanhaX = tapahtuma.getX();
vanhaY = tapahtuma.getY();
}
}
public void mouseDragged(MouseEvent tapahtuma) {
int uusiX, uusiY;
if (pohjassa) {
uusiX = tapahtuma.getX();
uusiY = tapahtuma.getY();
piirraViiva(vanhaX, vanhaY, uusiX, uusiY);
vanhaX = uusiX;
vanhaY = uusiY;
}
}
public void mouseReleased(MouseEvent tapahtuma) {
int uusiX, uusiY;
if (pohjassa) { // piirrä viivan viimeinen osa
uusiX = tapahtuma.getX();
uusiY = tapahtuma.getY();
piirraViiva(vanhaX, vanhaY, uusiX, uusiY);
pohjassa = false;
}
}
public void mouseClicked(MouseEvent tapahtuma) {}
public void mouseEntered(MouseEvent tapahtuma) {}
public void mouseExited(MouseEvent tapahtuma) {}
public void mouseMoved(MouseEvent tapahtuma) {}
}
Valikoiden tekeminen
Kuvaruudun ylälaidassa oleva valikkopalkki on luokan MenuBar olio. Valikkopalkki lisätään sovelluksen ikkunaan metodilla setMenuBar(MenuBar valikkopalkki).
Yksittäiset valikot ovat luokan Menu olioita. Luokan konstruktorille annetaan parametrina valikon otsikko. Valikko liitetään valikkopalkkiin add-operaatiolla, esimerkiksi
valikkopalkki.add(variValikko);
Valikoiden yksinkertaiset valinnat, valikkoalkiot, ovat luokan MenuItem olioita. Luokan konstruktorille annetaan parametrina valinnan teksti. Alkio liitetään valikkoon
add-metodilla, esimerkiksi
variValikko.add(variTaulukko[i]);
missä variTaulukko[i] on MenuItem-olio.
Valikkoalkioiden tekstit kannattaa määritellä
String-taulukoissa. Tällöin valikoiden luominen on helpompaa. Samaan valikkoon tulevat valikkoalkiot kannattaa järjestää MenuItem[]-taulukkoon.
Jotta ohjelman toimintaa voisi ohjata valikoiden avulla, pitää kuhunkin valikkoalkioon liittää ActionListener-tyyppinen tapahtumankuuntelija. Valikkoalkion valitseminen saa aikaan ActionEvent-tyyppisen tapahtuman.
Seuraavan esimerkkiohjelman ikkunassa on piirtokangas ja valikkopalkki. Piirtokankaalle tulevan kuvan väriä, kokoa ja muotoa voi vaihdella valikon avulla.
// Esimerkkiohjelma valikoiden käytöstä
import java.awt.*;
import java.awt.event.*;
public class Valikoita extends Frame
implements ActionListener {
private Nelioalusta paperi;
String varit[] = {"Punainen", "Sininen", "Keltainen", "Vihreä"};
String ympyrat[] = {"Pieni", "Keskikokoinen", "Suuri"};
String neliot[] = {"Pieni", "Keskikokoinen", "Suuri"};
private MenuBar valikkopalkki;
private Menu variValikko, ympyraValikko, nelioValikko;
private MenuItem[] variTaulukko, ympyraTaulukko, nelioTaulukko;
public Valikoita() {
paperi = new Nelioalusta();
paperi.setBackground(Color.white);
paperi.setSize(400,400);
valikkopalkki = new MenuBar();
valikkopalkki.setFont(new Font("TimesRoman", Font.PLAIN, 22));
variValikko = new Menu("Värit");
ympyraValikko = new Menu("Ympyrä");
nelioValikko = new Menu("Neliö");
variTaulukko = new MenuItem[varit.length];
ympyraTaulukko = new MenuItem[ympyrat.length];
nelioTaulukko = new MenuItem[neliot.length];
// luodaan varivalikko ja asetetaan kuuntelijat
for (int i = 0; i < varit.length; i++) {
variTaulukko[i] = new MenuItem(varit[i]);
variValikko.add(variTaulukko[i]);
variTaulukko[i].addActionListener(this);
}
// luodaan ympyravalikko ja asetetaan kuuntelijat
for (int i = 0; i < ympyrat.length; i++) {
ympyraTaulukko[i] = new MenuItem(ympyrat[i]);
ympyraValikko.add(ympyraTaulukko[i]);
ympyraTaulukko[i].addActionListener(this);
}
// luodaan neliovalikko ja asetetaan kuuntelijat
for (int i = 0; i < neliot.length; i++) {
nelioTaulukko[i] = new MenuItem(neliot[i]);
nelioValikko.add(nelioTaulukko[i]);
nelioTaulukko[i].addActionListener(this);
}
// lisataan luodut valikot valikkopalkkiin
valikkopalkki.add(variValikko);
valikkopalkki.add(ympyraValikko);
valikkopalkki.add(nelioValikko);
// lisataan valikkopalkki ja piirtoalusta ikkunaan
setMenuBar(valikkopalkki);
add(paperi);
addWindowListener(new HoiteleIkkunanSulkeminen());
}
public void actionPerformed(ActionEvent tapahtuma) {
Object aiheuttaja = tapahtuma.getSource();
// tutkitaan, tuliko tapahtuma varivalikosta
for (int i = 0; i < variTaulukko.length; i++)
if (aiheuttaja == variTaulukko[i])
paperi.vaihdaVari(i);
// tutkitaan, tuliko tapahtuma ympyravalikosta
for (int i = 0; i < ympyraTaulukko.length; i++)
if (aiheuttaja == ympyraTaulukko[i])
paperi.vaihdaKokoJaKuvio(Nelioalusta.YMPYRA, i);
// tutkitaan, tuliko tapahtuma neliovalikosta
for (int i = 0; i < nelioTaulukko.length; i++)
if (aiheuttaja == nelioTaulukko[i])
paperi.vaihdaKokoJaKuvio(Nelioalusta.NELIO, i);
}
public static void main(String args[]) {
Valikoita ikkuna = new Valikoita();
ikkuna.setTitle("Valikkokokeilu");
ikkuna.pack();
ikkuna.setVisible(true);
}
}
class Nelioalusta extends Canvas {
final public static int YMPYRA = 0;
final public static int NELIO = 1;
final private static int PUNAINEN = 0;
final private static int SININEN = 1;
final private static int KELTAINEN = 2;
final private static int VIHREA = 3;
final private static int PIENI = 0;
final private static int KESKIKOKOINEN = 1;
final private static int SUURI = 2;
private int tekstivari = PUNAINEN;
private int muoto = YMPYRA;
private int koko = PIENI;
// piirtaa ikkunan muuttujien tekstivari, muoto ja koko ohjaamalla
// tavalla
public void paint(Graphics g) {
if (tekstivari == PUNAINEN)
g.setColor(Color.red);
else if (tekstivari == SININEN)
g.setColor(Color.blue);
else if (tekstivari == KELTAINEN)
g.setColor(Color.yellow);
else if (tekstivari == VIHREA)
g.setColor(Color.green);
if (muoto == YMPYRA) {
if (koko == PIENI)
g.drawOval(50, 50, 50, 50);
else if (koko == KESKIKOKOINEN)
g.drawOval(50, 50, 150, 150);
else if (koko == SUURI)
g.drawOval(50, 50, 300, 300);
}
else if (muoto == NELIO) {
if (koko == PIENI)
g.drawRect(50, 50, 50, 50);
else if (koko == KESKIKOKOINEN)
g.drawRect(50, 50, 150, 150);
else if (koko == SUURI)
g.drawRect(50, 50, 300, 300);
}
}
public void vaihdaVari(int uusiVari) {
tekstivari = uusiVari;
repaint(); // piirretään ikkuna uudelleen
}
public void vaihdaKokoJaKuvio(int uusiKuvio, int uusiKoko) {
muoto = uusiKuvio;
koko = uusiKoko;
repaint(); // piirretään ikkuna uudelleen
}
}