Java applety - interakcia s používateľom

Z Kiwiki
Skočit na navigaci Skočit na vyhledávání

V tejto časti bude ukázaný spôsob ako do apppletu pridať funkcionalitu, ktorá zabezpečí interakciu s používateľom. Náš applet bude reagovať na udalosti spôsobené stlačením klávesy, poklikaním alebo iba prechodom myši nad applet.

Udalosti vyvolané 'myšou'

Pre začlenenie funkčnosti interakcie s používateľom treba do appletu pridať odkaz na triedu, ktorá toto zabezpečuje. Implementovanie doplnkovej funkcionality programu (appletu) sa v Jave robí pomocou mechanizmu rozhraní. Pre prácu s myšou existujú 2 rozhrania:

  • MouseListener
  • MouseMotionListener

Pred samotným použitím udalostí treba definovať, ktoré použité komponenty budú schopné udalosti zachytiť. V našom prípade to bude objekt Applet.

MouseListener

Metódy triedy MouseListener sú nasledujúce:

Rozhranie MouseListener
Metóda Opis
mouseClicked(MouseEvent) Metóda sa zavolá po kliknutí
mouseEntered(MouseEvent) Metóda sa zavolá keď kurzor prejde nad komponent
mouseExited(MouseEvent) Metóda sa zavolá keď kurzor opustí oblasť komponentu
mousePressed(MouseEvent) Metóda sa zavolá keď sa stačí tlačidlo myši nad objektom
mouseReleased(MouseEvent) Metóda sa zavolá keď sa pustí tlačidlo myši, ktoré bolo pred tým stlačené (nad komponentom)
Vybrané metódy triedy MouseEvent
Metóda Opis
int getX()

int getY()

Point getPoint()

Vráti pozícu (x,y) na ktorej nastala udalosť. Pozícia je relatívna k oblasti komponentu, na ktotom udalosť vznikla.
int getButton() Vráti informáciu o tom, ktoré tlačidlo bolo stlačené. Ako návratová hodnota sú použité konštanty: NOBUTTON, BUTTON1, BUTTON2, alebo BUTTON3.

Ak chceme v našom applete použiť rozhranie MouseListener, musíme implementovať všetky jej metódy. V nasledujúcom kóde je prázdny applet, ktorý implementuje rozhranie MouseListener:

import java.applet.Applet;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.Graphics;

public class Udalost1 extends Applet implements MouseListener {

    public void init() {
         addMouseListener(this);
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void paint(Graphics g){        
    }
}

Zápis addMouseListener(this); v metóde init spôsobí, že applet bude reagovať na udalosti myši. Bez tohoto riadku by udalosti neboli zachytené.


Úloha 1.1: Do appletu implementujte funkcionalitu rozhrania MouseListener:

  • Keď sa stlačí tlačidlo myši, v danom mieste nakreslite obdĺžnik
  • Keď sa uvoľní tlačidlo myši, v danom mieste, kde sa tlačidlo pustilo nakreslite kruh
  • Keď sa klikne na applet, nakreslite plný kruh.


Analýza úlohy

Ako prvé treba povedať rozdiel medzi kliknutím a stlačením a pustením tlačítka myši:

  • Kliknutie je akcia, pri ktorej sa stlačí tlačidlo myši a následne sa pustí. Medzi týmito dvoma akciami sa nemôže myš pohnúť.
  • Ak sa medzi týmito akciami myš pohne, udalosť mouseClick nenastane.

Úlohou je nakresliť geometrický tvar (kruh, obdĺžnik) tam, kde sa klikne. Na to si vytvoríme premenné (x, y) v triede appletu. Aby sme rozlíšili, kedy je tlačidlo myši stlačené a kedy nie je stlačené, pridáme booleovskú premennú stlacene. Premenná bude nadobúdať hodnotu true vtedy, ak bude tlačidlo myši stlačené. V opačnom prípade bude mať hodnotu false. Pre zistenie, kedy sme na applet klikli použijeme pomocnú premennú kliknute. Tá bude mať hodnotu true len v tom prípade, ak nastala udalosť mouseClicked.

Samotné vykresľovanie sa sa bude diať iba v metóde paint, avšak nastavovanie premenných x, y bude v metódach, ktoré obsluhujú zachytené udalosti.

Riešenie:

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Udalost1 extends Applet implements MouseListener {

    public int x, y;
    boolean stlacene;
    boolean kliknute;

    public void init() {
        addMouseListener(this);
        this.x = 0;
        this.y = 0;
        this.stlacene = false;
        this.kliknute = false;
    }

    public void mouseClicked(MouseEvent e) {
        this.kliknute = true;
        repaint();
    }

    public void mousePressed(MouseEvent e) {
        this.x = e.getX();
        this.y = e.getY();
        this.stlacene = true;
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
        this.x = e.getX();
        this.y = e.getY();
        this.stlacene = false;
        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void paint(Graphics g) {

        if (this.kliknute) {
            g.fillOval(x, y, 10, 20);
           
        } else {
            if (this.stlacene) {
                g.drawRect(x, y, 20, 10);
            } else {
                g.drawOval(x, y, 20, 20);
            }
        }
         this.kliknute = false;
    }
}

Vysvetlenie programu:

Metóda paint

  • Ak sa zistí, že používateľ klikol, tak sa vykreslí plný kruh
  • V opačnom prípade zisťujeme, či sa jedná o stlačenie tlačidla myši, alebo o jeho pustenie.
    • Ak sa jedná o stlačenie (this.stlacene=true) vykreslí sa obdĺžnik.
    • V opačnom prípade sa vykreslí prázdny kruh.
  • Po vykreslení nastavíme premennú kliknute na false (očakávame ďalšie kliknutie)


Metóda mouseClicked

  • do premennej kliknutie triedy Udalost1 uložíme hodnotu true (ako informáciu o tom, že sme zachytili udalosť kliknutie)
  • Pomocou volania metódy repaint() vynútime prekreslenie appletu.


Metóda mousePressed/mouseReleased

  • Do premenných x, y uložíme pozíciu kde sme klikli
    • Táto pozícia je uložená v samotnej udalosti MouseEvent, ktorá je parametrom metód mousePressed a mouseReleased. V objekte e sú všetky potrebé informácie o tom, kde sme klikli, ktorým tlačidlom sme klikli, ...
  • prípad mousePressed - do premennej stlacene nastavíme hodnotu true
  • prípad mouseReleased- do premennej stlacene nastavíme hodnotu false
  • Pomocou volania metódy repaint() vynútime prekreslenie appletu.


Úloha 1.2: Zmodifikujte predchádzajúci príklad nasledovne: Pri kliknutí na applet nakreslite elipsu/obdĺžnik podľa nasledujúcich pravidiel

  • prvé stlačenie tlačidla myši bude určovať bod, z ktorého začneme kresliť
  • pri uvoľnení tlačidla myši zistíme druhý bod
    • Tieto dva body vymedzujú oblasť kde sa bude vykresľovať elipsa/obdĺžnik
      • Ak bude budeme stláčať ľavé tlačítko, nakreslíme obdĺžnik
      • Ak bude budeme stláčať pravé tlačítko, nakreslíme elipsu

Analýza:

Zadeklarujme si 2 body A a B. Použijeme na to triedu Point (z balíčka java.awt.Point). Hodnoty bodu A naplníme, keď stlačíme tlačidlo myši a hodnoty bodu B naplníme keď pustíme tlačidlo myši.

Riešenie:

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Udalost1 extends Applet implements MouseListener {

    boolean tlacidlo;
    Point A, B;

    public void init() {
        A = new Point();
        B = new Point();
        addMouseListener(this);
        this.tlacidlo = false;
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        this.A.x = e.getX();
        this.A.y = e.getY();
        if(e.getButton() == MouseEvent.BUTTON1)
            this.tlacidlo = true;
        else
            this.tlacidlo = false;
    }

    public void mouseReleased(MouseEvent e) {
        this.B.x = e.getX();
        this.B.y = e.getY();
        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void paint(Graphics g) {

        int sirka, vyska;
        sirka = this.B.x - this.A.x;
        vyska = this.B.y - this.A.y;
        if (this.tlacidlo) {
            g.drawRect(this.A.x, this.A.y, sirka, vyska);
        } else {
            g.drawOval(this.A.x, this.A.y, sirka, vyska);
        }
    }
}

Vysvetlenie: V metóde mousePressed treba určiť, ktoré tlačidlo bolo stlačené. Informáciu o stlačenom tlačidle je v objekte e (e.getButton()). Túto hodnotu porovnávame s konštantami definovanými v triede MouseEvent. Konštanty sú MouseEvent.BUTTON1, MouseEvent.BUTTON2 a MouseEvent.BUTTON3. Podľa toho, ktoré tlačidlo bolo stlačené nastavíme hodnotu premennej tlacidlo na true alebo false. Túto hodnotu si následne prečítame pri vykresľovaní (metóda paint). Všimnime si, že pri udalosti stlačenia tlačidla myši nepožiadame o prekreslenie. O prekreslenie požiadame až po uvoľnení tlačidla (mouseReleased)

MouseMotionListener

Metódy triedy MouseMotionListener sú nasledujúce:

Rozhranie MouseMotionListener
Metóda Opis
mouseDragged(MouseEvent e) Metóda sa zavolá po stlačení tlačidla myši a následom ťahaní.
mouseMoved(MouseEvent e) Metóda sa zavolá pri pohyby myši nad daným komponentom (bez stlačenia tlačidla)

Ak chceme v našom applete použiť rozhranie MouseMotionListener , musíme implementovať všetky jej metódy. V nasledujúcom kóde je prázdny applet, ktorý implementuje rozhranie MouseMotionListener :

import java.applet.Applet;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.Graphics;

public class Udalost1 extends Applet implements MouseMotionListener {

    public void init() {
         addMouseMotionListener (this);
    }

    public void mouseDragged(MouseEvent e) {
    }

    public void mouseMoved(MouseEvent e) {
    }

    public void paint(Graphics g){        
    }
}

Úloha 1.3: Budeme meniť farbu pozdia appletu. Pri pohybe myši v osi x budeme meniť farbu, pri ťahaní myši (v osi x) budeme meniť svetlosť.


Analýza riešenia: Pre zmenu farby použijeme farebný model HSB[1]. Zloždy HSB sú odtieň (Hue), saturácia (Saturation) a jas (Brightness). Aby boli farby čo najjasnejšie, bude hodnota jasu vždy na maximálnej hodnote. Hodnoty HSB sú v intervale 0 až 1.

Aby zmena farby nebola závislá na veľkosti appletu, prepočítame polohu kurzoru myši vzhľadom na šírku okna, na hodnotu (0,1):

[math]H=\frac{x}{sirka}[/math]

kde x je poloha myši vzhľadom na os x a H je hodnota odtieňa. Pre saturáciu bude platiť rovnaký vzťah. V prípade, že budeme myšou len pohybovať nad appletom, budeme meniť hodnotu jasu (H), v prípade že budeme myš ťahať, budeme meniť hodnotu saturácie (S). Jas bude nastavený vždy na maximálnu hodnotu (1).


Riešenie:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

public class farbaPozadia extends Applet implements MouseMotionListener {

    Color farba;
    int sirka;
    float s, h;

    public void init() {
        farba = new Color(Color.HSBtoRGB(0, 1, 1));
        addMouseMotionListener(this);
        this.sirka = this.getWidth();
    }

    public void mouseDragged(MouseEvent e) {
        this.s = (float) (this.sirka - e.getX()) / sirka;
        repaint();
    }

    public void mouseMoved(MouseEvent e) {
        this.h = (float) (this.sirka - e.getX()) / sirka;
        repaint();
    }

    public void paint(Graphics g) {
        farba = new Color(Color.HSBtoRGB(this.h, this.s, 1));
        this.setBackground(this.farba);
        this.sirka = this.getWidth();
    }
}


Úloha 1.4: Na applet vykreslite 'slnko' (žltý kruh). Pri ťahaní myšky smerom hore sa bude farba slnka jasnejšia, pri pohybe dolu bude farba slnka tmavšia. Stmavovanie a zosvetľovanie bude fungovať len vtedy, ak sa bude myš nachádzať nad slnkom. Pri ťahaní mimo slnka, applet nebude reagovať.


Analýza riešenia: V tejto úlohe potrebujeme implementovať obe rozhrania, pretože potrebujeme získať informáciu, kde používateľ klikol a ktorým smerom ťahá myš. Rrincíp je podobný minulému príkladu s niekoľkými rozdielmi:

  • pri ťahaní nebudeme prepočítavať hodnotu odtieňu vzhľadom na šírku appletu, alebo budeme prepočítavať jas vzhľadom na priemer kruhu.
  • zmenu jasu treba robiť len v prípade, ak sa kurzor myši nachádza nad slnkom.

Tu treba zistiť, či bod, v ktorom sa nachádza kurzor myši je v kruhu alebo mimo neho. Pre kruh, ktorý má stred v bode [math][X,Y][/math] platí rovnica:

[math]\sqrt{(x-X)^2+(y-Y)^2} = r[/math]

kde [x,y] je bod, v ktorom sa nachádza kurzor myši. Stačí teda zistiť či platí nerovnosť:

[math]\sqrt{(x-X)^2+(y-Y)^2} \lt r[/math]

Ak platí tak kurzor myši sa machádza vo vnútri kruhu a môžeme meniť jas.


Poznámky k riešniu:

  • Žltá farba má hodnotu odtieňa 1.666
  • Vzorec pre zistenie polohy kurzoru myši je implementovaný v metóde mousePressed
    • Pri výpočte vzorca uvažujeme stred kruhu v strede appletu, teda: [sirka/2, vyska/2]
  • Premenná stlacene má hodnotu true, len vtedy keď je tlačidlo myši stlačené
    • jas meníme len vtedy, ak je tlačidlo myši stlačené (myš ťaháme)

Riešnie:

package applet;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class slunce extends Applet implements MouseMotionListener, MouseListener {

    public int x, y;
    public int polomer;
    public Color farbaSlnka;
    private boolean stlacene;

    public void init() {
        // zlta farba
        farbaSlnka = new Color(Color.HSBtoRGB((float) 0.166666, (float) 0.1, (float) 1.0));

        this.setSize(300, 300);
        this.polomer = 100;
        this.stlacene = false;

        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void mouseDragged(MouseEvent e) {
        int aktY = e.getY();
        if (this.stlacene) {
            int rozdil = this.y - aktY;
            float r = (float) rozdil / (this.polomer * 2);
            if (r < 0) {
                r = 0;
            }
            this.farbaSlnka = new Color(Color.HSBtoRGB((float) 0.16666, r, (float) 1.0));
            repaint();
        }

    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        int aktY = e.getY();
        int aktX = e.getX();
        double rr = Math.pow(aktX - this.getWidth() / 2, 2) + (Math.pow(aktY - this.getHeight() / 2, 2));
        if (rr < Math.pow(this.polomer, 2)) {
            this.x = e.getX();
            this.y = e.getY();
            this.stlacene = true;
        }
    }

    public void mouseReleased(MouseEvent e) {
        this.stlacene = false;
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void paint(Graphics g) {
        g.setColor(this.farbaSlnka);
        g.fillOval(this.getWidth() / 2 - polomer, this.getHeight() / 2 - polomer, polomer * 2, polomer * 2);
    }
}

Udalosti vyvolané klávesnicou

Pre prácu s udalosťami klávesnice existuje rozhranie KeyListener [2]. Trieda KeyListener ke definovaná v balíčku java.awt.event.KeyListener.

Rozhranie KeyListener

Rozhranie KeyListener
Metóda Opis
keyPressed(KeyEvent e) Metóda sa zavolá po stlačení klávesy.
keyReleased(KeyEvent e) Metóda sa zavolá po uvoľnení klávesy.
keyTyped(KeyEvent e) Metóda sa zavolá po stlačení a následnom uvoľnení klávesy.

Trieda KeyEvent je definovaná v balíčku java.awt.event.KeyEvent [3].

Vybrané metódy triedy KeyEvent
Metóda Opis
Konštanty
  • VK_0 až VK_9 - znaky reprezentujúce číslice '0' až '9'
  • VK_ALPHANUMERIC - v3etky alfanumerick0 znaky
  • VK_AMPERSAND - '&'
  • VK_AT - '@'
  • VK_COLON - ':'
  • VK_DELETE
  • VK_DOLLAR - '$'
  • VK_ENTER - klávesa enter
  • VK_F1 až VK_F24 - funkčné klávesy
  • VK_RIGHT , VK_LEFT, VK_DOWN, VK_UP - smerové šípky (nie na nmerickej klávesnici)
char getKeyChar() Vráti ztlačenú klávesu ako znak
int getKeyCode() Vráti stlačenú klávesu ako kód
static String getKeyText(int keyCode) Vráti reťazecopisujúci kód znaku ako napr: 'HOME', 'F1' alebo 'A'


Úloha 1.5

Vytvorte applet, v ktorom sa bude vykreslovať text, ktorý budete zadávať na klávesnici. Po stlačení klávesu ENTER sa text zmaže a bude sa pokračovať so zadávaním od začiatku.


Analýza úlohy:

Vytvoríme si premennú text (typu String), do ktorej pri stlačení klávesu pridáme na koniec stlačený znak. Ak bude stlačený ENTER, tak z reťazca text odstránime všetky znaky. Pri vykreslovaní reťazca do appletu budemem tento vykreľovať na pozíciu [x,y]. Hodnoty týchto premenných sú definované v metóde init().


Riešenie:

public class Klavesy extends Applet implements KeyListener{

    String text;
    int x,y;

    public void init() {
        this.text="";
        this.x=10;
        this.y=50;
        addKeyListener(this);
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
       if(e.getKeyCode()==KeyEvent.VK_ENTER)
           this.text="";
       else
           this.text+=e.getKeyChar();
       repaint();
    }

    public void keyReleased(KeyEvent e) {      
    }

    public void paint(Graphics g){
        g.drawString(this.text, this.x, this.y);
    }
}


Úloha 1.6

Upravte predcházajúci príklad, aby sa text vykresľoval na miesto, kde sa klikne myšou.


Analýza

Do appletu pridáme rozhranie MouseListener. Po zachytení udalosti mousePressed nastavíme triedne premenné x, y na hodnotu súradnice, kde sme klikli


Riešenie:

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Klavesy extends Applet implements KeyListener, MouseListener{

    String text;
    int x,y;

    public void init() {
        this.text="";
        this.x=10;
        this.y=50;
        addKeyListener(this);
        addMouseListener(this);
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
       if(e.getKeyCode()==KeyEvent.VK_ENTER)
           this.text="";
       else
           this.text+=e.getKeyChar();
       repaint();
    }

    public void keyReleased(KeyEvent e) {      
    }

    public void paint(Graphics g){
        g.drawString(this.text, this.x, this.y);
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        this.x=e.getX();
        this.y=e.getY();
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
}

Zdroje a odkazy