|
|
|
|
|
|
|
El ratolí |
|
|
|
|
|
|
|
|
|
|
|
Molts anys abans que els ordinadors personals fossin, no només
comuns, sinó tan sols pensables, Douglas
Engelbart ja havia inventat uns quants dispositius d'accés
als sistemes informàtics, entre els quals l'ara ben comú
ratolí
(mouse). Engelbart va presentar-ne un primer prototipus a la Conferència
de Tardor de 1968 a San Francisco amb el títol de "X-Y
Position Indicator for a Display System". Després,
la incorporació de les interfícies
gràfiques d'usuari (GUI)
als sistemes Apple
Macintosh va popularitzar el dispositiu i, ben aviat, aparegueren
noves GUI
als sistemes MS-DOS
(Windows 3.x),
UNIX
(X-Windows)
i OS/2,
per les quals, l'ús del ratolí era ja imprescindible.
|
|
|
|
|
|
Java
tracta les accions que fa l'usuari amb el ratolí sobre components
gràfics com a esdeveniments. Alguns controls, els botons per
exemple, ja incorporen un mecanisme d'emisió d'esdeveniments adequat
a la seva funció, tal com ja hauràs vist a les pràctiques
anteriors d'aquest mòdul. Ara, però, es tracta d'aprendre
a controlar els esdeveniments de ratolí que no estan lligats a cap
funcionalitat concreta del control sobre el qual es produeixen: |
|
|
|
|
|
Esdeveniments
de ratolí |
|
|
|
|
|
Java
contempla les següents accions: |
|
|
|
|
|
- Clic
sobre un punt ("mouse clicked"): l'usuari prem i deixa
anar un botó del ratolí quan el cursor és sobre
un punt d'un cert component.
- Entrada
en un component ("mouse entered"): el cursor del ratolí
entra en un component.
- Sortida
d'un component ("mouse exited"): el cursor surt d'un
component.
- Pressionar
sobre un punt ("mouse pressed"): l'usuari prem un
botó del ratolí quan el cursor és sobre un punt
d'un cert component.
- Deixar
anar sobre un punt ("mouse released"): l'usuari deixa
anar un botó del ratolí (que mantenia apretat) quan el
cursor és sobre un punt d'un cert component.
- Arrossegar
("mouse dragged"): l'usuari, amb un botó del
mouse apretat, mou el cursor sobre un component.
- Moure
("mouse moved"): l'usuari, sense cap botó del
mouse apretat, mou el cursor sobre un component.
|
|
|
|
|
|
Per a cadascuna d'aquestes accions,
el component sobre les quals s'han produït emet un esdeveniment
(objecte!) java.awt.event.MouseEvent que ha
de ser escoltat pels listeners corresponents. Cada objecte MouseEvent
conté informació important, que es pot recuperar mitjançant
els mètodes corresponents: |
|
|
|
|
|
- public Object getSource() (de
la classe java.util.EventObject, de la qual
deriva la classe java.awt.event.MouseEvent)
que retorna l'objecte (Atenció: Object.
Segur que caldrà fer càsting per identificar-lo!)
sobre el qual s'ha produït l'esdeveniment.
- public int getX() (de la pròpia
classe MouseEvent) que retorna la coordenada
x del lloc del component on s'ha produït
l'esdeveniment.
- public int getY() que fa el
mateix que l'anterior, però per a la coordenada y.
- public long getWhen() (de la
classe java.awt.event.InputEvent, de la qual
deriva la classe MouseEvent) que retorna el
temps del sistema (milisegons) en el qual s'ha produït l'esdeveniment.
|
|
|
|
|
|
Aquestes informacions i, en general,
tot el que es refereix a esdeveniments de ratolí (MouseEvents)
són completament independents de l'aspecte concret que tingui el
cursor del ratolí a cada moment. Com canviar l'aspecte del cursor
ja ha estat estudiat a la pràctica 1
d'aquest mateix mòdul. |
|
|
|
|
|
Hi ha dues interfícies (interfaces)
per escoltar esdeveniments MouseEvent: |
|
|
|
|
|
- La interfície java.awt.event.MouseListener,
amb els mètodes
- public void mouseClicked(MouseEvent
e), que s'executa quan l'usuari fa l'acció "Click
sobre un punt",
- public void mousePressed(MouseEvent
e), que s'executa quan hi ha l'acció "Pressionar
sobre un punt",
- public void mouseReleased(MouseEvent
e), que s'executa quan hi ha l'acció "Deixar
anar sobre un punt",
- public void mouseEntered(MouseEvent
e), que s'executa quan hi ha l'acció
"Entrada en un component",
- i public void mouseExited(MouseEvent
e), que s'executa quan hi ha l'acció "Sortida
d'un component",
- i la interfície java.awt.event.MouseMotionListener,
amb els mètodes
- public void mouseDragged(MouseEvent
e), que s'executa quan hi ha l'acció d'"Arrossegar",
- public void mouseMoved(MouseEvent
e), que s'executa quan hi ha l'acció de "Moure"
|
|
|
|
|
|
Per tal que un component tingui listeners
que escoltin els esdeveniments MouseEvent que
pugui emetre, els mètodes corresponents (de la classe java.awt.Component)
són |
|
|
|
|
|
- public void addMouseListener(MouseListener
mL), i
- public void addMouseMotionListener(MouseMotionListener
mML)
|
|
|
|
|
 |
Ara ja pots experimentar. Crea el
projecte ratoli i la classe Ratoli,
de moment, amb aquest codi: |
|
|
|
|
 |
import javax.swing.JFrame;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Escriviu aquí una descripcìó de la
classe Ratoli
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Ratoli extends JFrame implements MouseListener,
MouseMotionListener {
/**
* Mètode constructor per
objectes de la classe Ratoli.
*/
public Ratoli () { //
constructor
setTitle("Proves
amb el ratolí");
Container cnt=getContentPane();
JPanelAmbNom panelNord=new
JPanelAmbNom("panel Nord");
panelNord.setPreferredSize(new
Dimension(300,50));
panelNord.setBackground(Color.BLUE);
panelNord.addMouseListener(this);
panelNord.addMouseMotionListener(this);
cnt.add(panelNord,BorderLayout.NORTH);
JPanelAmbNom
panelSud=new JPanelAmbNom("panel Sud");
panelSud.setPreferredSize(new
Dimension(300,50));
panelSud.setBackground(Color.RED);
panelSud.addMouseListener(this);
panelSud.addMouseMotionListener(this);
cnt.add(panelSud,BorderLayout.SOUTH);
JPanelAmbNom
panelEst=new JPanelAmbNom("panel Est");
panelEst.setPreferredSize(new
Dimension(50,300));
panelEst.setBackground(Color.YELLOW);
panelEst.addMouseListener(this);
panelEst.addMouseMotionListener(this);
cnt.add(panelEst,BorderLayout.EAST);
JPanelAmbNom
panelOest=new JPanelAmbNom("panel Oest");
panelOest.setPreferredSize(new
Dimension(50,300));
panelOest.setBackground(Color.GREEN);
panelOest.addMouseListener(this);
panelOest.addMouseMotionListener(this);
cnt.add(panelOest,BorderLayout.WEST);
JPanelAmbNom
panelCentre=new JPanelAmbNom("panel Centre");
panelCentre.setBackground(Color.WHITE);
panelCentre.addMouseListener(this);
panelCentre.addMouseMotionListener(this);
cnt.add(panelCentre,BorderLayout.CENTER);
pack();
show();
}
/**
* Mètode que s'executa quan
l'acció és "Click sobre un punt"
* @param e un MouseEvent
*/
public void mouseClicked (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Entrada en un
* component"
* @param e un MouseEvent
*/
public void mouseEntered (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Sortida d'un
* component"
* @param e un MouseEvent
*/
public void mouseExited (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Pressionar sobre
* un punt"
* @param e un MouseEvent
*/
public void mousePressed (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Deixar anar sobre
* un punt"
* @param e un MouseEvent
*/
public void mouseReleased (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Moure"
* @param e un MouseEvent
*/
public void mouseMoved (MouseEvent
e) {
}
}
/**
* La classe JPanelAmbNom no és més que la
classe JPanel a la
* qual se li ha afegit la variable nom, per tal de poder
iden-
* tificar cadascun dels panels.
*/
class JPanelAmbNom extends JPanel {
/**
* El nom que identifica cada objecte
JPanelAmbNom
*/
String nom;
/**
* Mètode constructor per a
objectes de la classe JPanelAmbNom.
* @param nom el nom identificador
d'aquest JPanelAmbNom
*/
JPanelAmbNom (String nom) { //
constructor
super();
this.nom=nom;
}
}
|
|
|
|
|
|
|
Com pots veure, es tracta d'una finestra
amb cinc objectes JPanel, cadascun a una de les
posicions que permet el layout BorderLayout.
En realitat, aquest objectes són de la classe JPanelAmbNom,
filla de la classe JPanel, a la qual se li ha
incorporat el camp String nom, per tal que els
poguem identificar després. El codi per a aquesta classe és
al mateix fitxer Ratoli.java, al final, després
del codi per a la classe Ratoli. |
|
|
|
|
 |
|
|
|
|
|
|
Algunes observacions sobre el codi: |
|
|
|
|
|
- Com que aquests objectes JPanelAmbNom
no contenen cap component, cal establir-ne les dimensions d'avançada
amb el mètode de la classe JComponent (mare
de JPanel)
public
void setPreferredSize(Dimension preferredSize) |
Si no, swing els faria de dimensió
0 x 0!
- Per tal que cadascun d'aquests objectes JPanelAmbNom
presenti un color diferent, cal cridar el mètode, també
de la classe JComponent,
public
void setBackground(Color colorFons) |
que determina el color del fons d'aquests components.
- Cal establir qui ha d'escoltar els esdeveniments
de ratolí que es produeïxin als objectes JPanelAmbNom.
Els mètodes (de la classe Component)
són:
public
void addMouseListener(MouseListener mL) |
i
public
void addMouseMotionListener(MouseMotionListener mML) |
com ja ha estat comentat abans.
- El listener d'esdeveniments, en els dos casos,
és l'objecte Ratoli, al qual se li
han implementat les dues interfícies: MouseListener
i MouseMotionListener.
- I, com sempre que s'implementen interfícies a
una classe, cal implementar tots els mètodes d'aquestes
interfícies, encara que els deixem buits de codi, com ara mateix
estan.
|
|
|
|
|
|
Naturalment, com que els mètodes
de les interfícies estan buits de codi, no fan res i sembla que cap
dels objectes JPanelAmbNom sigui sensible a les
accions del ratolí. És ara el moment d'omplir aquests mètodes: |
|
|
|
|
 |
<codi
anterior>
/**
* Mètode que s'executa quan
l'acció és "Click sobre un punt"
* @param e un MouseEvent
*/
public void mouseClicked (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"Clic sobre el "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Entrada en un
* component"
* @param e un MouseEvent
*/
public void mouseEntered (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"El ratolí ha entrat al "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Sortida d'un
* component"
* @param e un MouseEvent
*/
public void mouseExited (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"El ratolí ha sortit del "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Pressionar sobre
* un punt"
* @param e un MouseEvent
*/
public void mousePressed (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"Botó apretat sobre el "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Deixar anar sobre
* un punt"
* @param e un MouseEvent
*/
public void mouseReleased (MouseEvent
e) {
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"Botó deixat anar sobre el "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"Arrossegament sobre el "+
nom+"
a la posició "+
x+", "+y);
}
}
/**
* Mètode que s'executa quan
l'acció és "Moure"
* @param e un MouseEvent
*/
public void mouseMoved (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanelAmbNom?
if
(font instanceof JPanelAmbNom) {
//
Càsting per tal de poder-lo tractar com a
//
objecte JPanelAmbNom
JPanelAmbNom
panel=(JPanelAmbNom)font;
//
Quin és el seu nom identificador?
String
nom=panel.nom;
//
En quines coordenades s'ha produït l'esdeveni-
//
ment?
int
x=e.getX();
int
y=e.getY();
//
Imprimeix a la sortida standard del sistema
//
un missatge que expliqui tot això...
System.out.println("Esdeveniment:
"+
"Moviment sobre el "+
nom+"
a la posició "+
x+", "+y);
}
}
<codi següent>
|
|
|
|
|
|
 |
Ara ja pots jugar amb el ratolí:
fes clics sobre els panels, arrossega, mou, entra, surt... T'apareixerà,
a la finestra de terminal, un rapport detallat a temps real de tot
allò que facis: |
|
|
|
|
|
|
|
|
|
|
|
Dibuixar amb
el ratolí: rectangles |
|
|
|
|
|
|
Dominar els esdeveniments del ratolí
obre un munt de possibilitats, de les quals et convidem a explorar-ne una:
la de dibuixar sobre un objecte JPanel: |
|
|
|
|
 |
Muntaràs la classe Rectangles,
la qual consisteix amb un objecte JFrame, el contenidor
per defecte del qual se substitueix per un objecte JPanel,
que és on podràs dibuixar-hi rectangles. Així, doncs,
al projecte ratoli, afegeix-li la classe Rectangles,
amb aquest codi: |
|
|
|
|
 |
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Escriviu aquí una descripcìó de la
classe Rectangles
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Rectangles extends JFrame implements MouseListener,
MouseMotionListener {
/**
* Mètode constructor per
objectes de la classe Rectangles.
*/
public Rectangles () { //
constructor
setTitle("Dibuix
de rectangles");
//
L'objecte JPanel per dibuixar-hi
JPanel panel=new
JPanel();
//
Determinació dels listeners d'esdeveniments de ratolí
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
//
Cal determinar-ne les dimensions perquè, com que no
// conté
res, swing el faria de dimensions 0 x 0
panel.setPreferredSize(new
Dimension(300,200));
//
Substitució del contenidor per defecte del JFrame per
// aquest JPanel
setContentPane(panel);
pack();
show();
}
/**
* Mètode que s'executa quan
l'acció és "Click sobre un punt"
* @param e un MouseEvent
*/
public void mouseClicked (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Entrada en un
* component"
* @param e un MouseEvent
*/
public void mouseEntered (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Sortida d'un
* component"
* @param e un MouseEvent
*/
public void mouseExited (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Pressionar sobre
* un punt"
* @param e un MouseEvent
*/
public void mousePressed (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Deixar anar sobre
* un punt"
* @param e un MouseEvent
*/
public void mouseReleased (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent
e) {
}
/**
* Mètode que s'executa quan
l'acció és "Moure"
* @param e un MouseEvent
*/
public void mouseMoved (MouseEvent
e) {
}
}
|
|
|
|
|
|
|
Per dibuixar rectangles, faràs
servir el mètode
public
void drawRect(int x,int y,int ample,int alt) |
de la classe java.awt.Graphics (mira la pràctica
6 d'aquest mateix mòdul) . Les dades que es necessiten són
|
|
|
|
|
|
- Les coordenades del primer punt on es prem el
botó, que seran les coordenades del vèrtex superior esquerre
del rectangle. Com que aquest punt és constant per a cada rectangle,
cal desar-ne les coordenades en sengles camps de la classe: caldrà
afegir-li, doncs, els camps int puntIniciX
i int puntIniciY. La tasca del mètode
mousePressed() és, doncs, desar les
coordenades de l'esdeveniment en aquests camps.
puntIniciX=e.getX();
puntIniciY=e.getY(); |
- Les amplades i altures successives dels rectangles que
es dibuixen en arrossegar el ratolí. Una de les feines
que ha de fer el mètode mouseDragged()
és, precisament, fer aquests càlculs:
int
ample=e.getX()-puntIniciX;
int alt=e.getY()-puntIniciY; |
|
|
|
|
|
|
El mateix mètode
mouseDragged()pot encarregar-se d'esborrar i dibuixar
els rectangles:
Graphics g=panel.getGraphics();
panel.update(g);
g.setColor(Color.BLACK);
g.drawRect(puntIniciX,puntIniciY,ample,alt);
|
|
|
|
El codi de la classe Rectangles
queda: |
|
|
|
|
 |
import
javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Graphics;
/**
* Escriviu aquí una descripcìó de la
classe Rectangles
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Rectangles extends JFrame implements MouseListener,
MouseMotionListener {
/**
* Les coordenades del primer punt
on es prem el botó
*/
int puntIniciX,puntIniciY;
/**
* Mètode constructor per
objectes de la classe Rectangles.
*/
public Rectangles () { // constructor
setTitle("Dibuix
de rectangles");
//
L'objecte JPanel per dibuixar-hi
JPanel panel=new
JPanel();
// Determinació
dels listeners d'esdeveniments de ratolí
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
// Cal determinar-ne
les dimensions perquè, com que no
// conté
res, swing el faria de dimensions 0 x 0
panel.setPreferredSize(new
Dimension(300,200));
// Substitució
del contenidor per defecte del JFrame per
// aquest JPanel
setContentPane(panel);
pack();
show();
}
/**
* Mètode que s'executa quan
l'acció és "Click sobre un punt"
* @param e un MouseEvent
*/
public void mouseClicked (MouseEvent e)
{
//
Aquest mètode no es fa servir
}
/**
* Mètode que s'executa quan
l'acció és "Entrada en un
* component"
* @param e un MouseEvent
*/
public void mouseEntered (MouseEvent e)
{
//
Aquest mètode no es fa servir
}
/**
* Mètode que s'executa quan
l'acció és "Sortida d'un
* component"
* @param e un MouseEvent
*/
public void mouseExited (MouseEvent e)
{
//
Aquest mètode no es fa servir
}
/**
* Mètode que s'executa quan
l'acció és "Pressionar sobre
* un punt"
* @param e un MouseEvent
*/
public void mousePressed (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Desa-les als camps corresponents
puntIniciX=x;
puntIniciY=y;
}
}
/**
* Mètode que s'executa quan
l'acció és "Deixar anar sobre
* un punt"
* @param e un MouseEvent
*/
public void mouseReleased (MouseEvent
e) {
//
Aquest mètode no es fa servir
}
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent e)
{
//
Quina és la font de l'esdeveniment?
Object
font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Calcula les dimensions del rectangle
int
ample=x-puntIniciX;
int
alt=y-puntIniciY;
//
Identifica la font com a objecte JPanel
JPanel
panel=(JPanel)font;
//
L'objecte Graphics del panel
Graphics
g=panel.getGraphics();
//
Esborra els dibuixos del panel
panel.update(g);
//
Determina el color i pinta el rectangle
g.setColor(Color.BLACK);
g.drawRect(puntIniciX,puntIniciY,ample,alt);
}
}
/**
* Mètode que s'executa quan
l'acció és "Moure"
* @param e un MouseEvent
*/
public void mouseMoved (MouseEvent e)
{
//
Aquest mètode no es fa servir
}
}
|
|
|
|
|
|
|
i ja pots dibuixar tants rectangles
com et vingui de gust! |
|
|
|
|
 |
|
|
|
|
|
|
MouseAdapter
i MouseMotionAdapter |
|
|
|
|
|
|
Quan, com en el cas anterior, hi
ha mètodes d'una interfície que no es fan servir, pot resultar
feixuc haver d'escriurel's, tot i que no serveixin per a res. El SDK
de Java
preveu això i posa a la teva disposició dues classes, java.awt.event.MouseAdapter
i java.awt.event.MouseMotionAdapter, que no són
més que objectes amb les interfícies MouseListener
i MouseMotionListener respectivament implementades
i amb els mètodes buits. Només caldrà, doncs construir-los
i sobreescriure-hi (override) els mètodes que t'interessin i oblidar-te
dels altres. Aleshores, la classe principal ja no cal que implementi cap
de les interfícies MouseListener i MouseMotionListener
i, per tant, tampoc cal implementar-hi cap dels seus mètodes. Els
mètodes que sí interessen van a parar als corresponents objectes
MouseAdapter i MouseMotionAdapter.
|
|
|
|
|
 |
Per veure com funciona això,
crea la classe RectanglesAlt, que no és
més que la mateixa classe Rectangles, amb
aquestes modificacions: |
|
|
|
|
 |
import
javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
import java.awt.Graphics;
/**
* Escriviu aquí una descripcìó de la
classe RectanglesAlt
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class RectanglesAlt extends JFrame
{
/**
* Les coordenades del primer punt
on es prem el botó
*/
int puntIniciX,puntIniciY;
/**
* Mètode constructor per
objectes de la classe RectanglesAlt.
*/
public RectanglesAlt
() { // constructor
setTitle("Dibuix
de rectangles");
//
L'objecte JPanel per dibuixar-hi
JPanel panel=new
JPanel();
// Determinació
dels listeners d'esdeveniments de ratolí
//
Aquí es crea l'objecte MouseAdapter
panel.addMouseListener(new
MouseAdapter() {
//
Mètode mousePressed per a aquest
//
MouseAdapter
public
void mousePressed (MouseEvent e) {
//
Quina és la font de l'esdeveni-
//
ment?
Object
font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeve-
//
niment
int
x=e.getX();
int
y=e.getY();
//
Desa-les als camps corres-
//
ponents
puntIniciX=x;
puntIniciY=y;
}
}
}
);
//
Aquí es crea l'objecte MouseMotionAdapter
panel.addMouseMotionListener(new
MouseMotionAdapter() {
//
Mètode mouseDragged per a aquest
//
MouseAdapter
public
void mouseDragged (MouseEvent e) {
//
Quina és la font de l'esdeveni-
//
ment?
Object
font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeve-
//
niment
int
x=e.getX();
int
y=e.getY();
//
Calcula les dimensions
//
del rectangle
int
ample=x-puntIniciX;
int
alt=y-puntIniciY;
//
Identifica la font com
//
a objecte JPanel
JPanel
panel=(JPanel)font;
//
L'objecte Graphics del
//
panel
Graphics
g=
panel.getGraphics();
//
Esborra els dibuixos
//
del panel
panel.update(g);
//
Determina el color i
//
pinta el rectangle
g.setColor(Color.BLACK);
g.drawRect(puntIniciX,
puntIniciY,
ample,
alt);
}
}
}
);
// Cal
determinar-ne les dimensions perquè, com que no
// conté
res, swing el faria de dimensions 0 x 0
panel.setPreferredSize(new
Dimension(300,200));
// Substitució
del contenidor per defecte del JFrame per
// aquest JPanel
setContentPane(panel);
pack();
show();
}
}
|
|
|
|
|
|
|
i, despres de compilar i crear un
objecte RectanglesAlt, comprovaràs que
el comportament de l'objecte és el mateix d'abans... |
|
|
|
|
|
Quin botó? |
|
|
|
|
|
|
Potser no te n'has adonat, però,
per ara, tot funciona indistintament amb qualsevol dels botons del
ratolí. Però hi ha algunes maneres de distingir quin dels
botons ha estat el responsable de l'acció. La més popular
és apelar al mètode static de la
classe javax.swing.SwingUtilities, |
|
|
|
|
|
- public static boolean isLeftMouseButton(MouseEvent
e), que retorna true si el responsable
de l'esdeveniment és el botó esquerre del ratolí,
- public static boolean isMiddleMouseButton(MouseEvent
e), que retorna true si el responsable
és el botó central del ratolí,
- i public static boolean isRightMouseButton(MouseEvent
e), que retorna true si el responsable
és el botó de la dreta del ratolí.
|
|
|
|
|
 |
Una petita modificació al
mètode mouseDragged() de la classe Rectangles
et permetrà dibuixar rectangles plens amb el botó de l'esquerra
i rectangles sense interior amb el botó de la dreta: |
|
|
|
|
 |
<codi anterior>
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent e)
{
// Quina és
la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Calcula les dimensions del rectangle
int
ample=x-puntIniciX;
int
alt=y-puntIniciY;
//
Identifica la font com a objecte JPanel
JPanel
panel=(JPanel)font;
//
L'objecte Graphics del panel
Graphics
g=panel.getGraphics();
//
Esborra els dibuixos del panel
panel.update(g);
//
Determina el color i pinta el rectangle
g.setColor(Color.BLACK);
//
És el botó esquerre?
if
(SwingUtilities.isLeftMouseButton(e))
{
g.drawRect(puntIniciX,puntIniciY,ample,alt);
//
És el botó de la dreta?
}
else
if (SwingUtilities.isRightMouseButton(e)){
g.fillRect(puntIniciX,puntIniciY,ample,alt);
}
}
}
<codi següent>
|
|
|
|
|
|
|
No t'oblidis d'importar el
paquet javax.swing.SwingUtilities! |
|
|
|
|
 |
|
|
|
Amb
el botó de l'esquerra |
|
|
|
|
|
|
|
|
Amb
el botó de la dreta |
|
|
|
|
|
Línies |
|
|
|
|
|
|
La classe Rectangles
podem fer-la més interessant: en lloc de dibuixar rectangles, que
es dibuixin línies, tot seguint l'itinerari del cursor del ratolí.
Només cal, al mètode mouseDragged(),
substituir la crida al mètode drawRect()
per la crida al mètode |
|
|
|
|
|
public
void drawLine(int x1,int y1,int x2,y2) |
|
|
|
|
|
|
Els paràmetres x1
i y1 han de ser, respectivament, puntIniciX
i puntIniciY, els paràmetres x2
i y2 han de ser les coordenades del punt de l'esdeveniment
"arrossegar", és a dir, e.getX()
i e.getY(). A més, just després
del dibuix, els valors de x2 i y2
han de substituir els anteriors a i, en a puntIniciX
i puntIniciY, per preparar el dibuix del següent
fragment de línia. Cal, també, no esborrar els fragments anteriors
i, per tant, cal suprimir la crida al mètode update().
Finalment, el botó esquerre dibuixa en negre i el de la dreta en
vermell. El nou mètode mouseDragged() és: |
|
|
|
|
 |
<codi anterior>
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent e)
{
// Quina és
la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Identifica la font com a objecte JPanel
JPanel
panel=(JPanel)font;
//
L'objecte Graphics del panel
Graphics
g=panel.getGraphics();
//
Determina el botó i determina el color
//
És el botó esquerre?
if
(SwingUtilities.isLeftMouseButton(e)) {
g.setColor(Color.BLACK);
//
És el botó de la dreta?
}
else
if (SwingUtilities.isRightMouseButton(e)){
g.setColor(Color.RED);
}
//
Dibuixa la línia
g.drawLine(puntIniciX,puntIniciY,x,y);
// Determina el nou punt inicial
puntIniciX=x;
puntIniciY=y;
}
}
<codi següent>
|
|
|
|
|
|
|
Quan tornis a compilar i creis un
nou objecte Rectangles, podràs fer això: |
|
|
|
|
 |
|
|
|
|
|
|
i, si vols millorar l'aspecte de
les línies, només cal que facis servir la classe java.awt.Graphics2D
en lloc de la classe java.awt.Graphics, (mira
la pràctica
anterior) i els corresponents RenderingHints: |
|
|
|
|
 |
<codi anterior>
/**
* Mètode que s'executa quan
l'acció és "Arrossegar"
* @param e un MouseEvent
*/
public void mouseDragged (MouseEvent e)
{
// Quina és
la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Identifica la font com a objecte JPanel
JPanel
panel=(JPanel)font;
//
L'objecte Graphics del panel
Graphics
g=panel.getGraphics();
//
Objecte Graphics g convertit a objecte
//
Graphics2D
Graphics2D
g2D=(Graphics2D)g;
//
A partir d'ara, qui dibuixa és l'objecte g2D:
//
El RenderingHint per activar antialiasing
g2D.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//
Determina el botó i determina el color
//
És el botó esquerre?
if
(SwingUtilities.isLeftMouseButton(e)) {
g2D.setColor(Color.BLACK);
//
És el botó de la dreta?
}
else
if (SwingUtilities.isRightMouseButton(e)){
g2D.setColor(Color.RED);
}
//
Dibuixa la línia
g2D.drawLine(puntIniciX,puntIniciY,x,y);
// Determina el nou punt inicial
puntIniciX=x;
puntIniciY=y;
}
}
<codi següent>
|
|
|
|
|
|
|
No t'hauràs pas oblidat d'importar
les classes java.awt.Graphics2D i java.awt.RenderingHints,
oi? |
|
|
|
|
 |
|
|
|
|
|
|
Doble clic |
|
|
|
|
|
|
Hi ha una acció, que és
molt corrent en el maneig del ratolí, que és el doble
clic sobre un punt. Ara et mostrarem com implementar-lo: es tracta,
simplement de mesurar el temps entre dos execucions del mètode mousePressed()
i, si aquest temps és menor que un temps prefixat, es considerarà
un doble clic. Naturalment, necessites un camp de la classe, long
tempsAnteriorClic, que contingui el temps en el qual es va esdevenir
l'anterior clic. Ara cal actuar sobre el mètode mousePressed(): |
|
|
|
|
 |
<codi anterior>
public class RectanglesAlt extends
JFrame {
/**
* Les Les coordenades del primer
punt on es prem el botó
*/
int puntIniciX,puntIniciY;
/**
* El temps (instant) en el qual
es va esdevenir l'anterior
* clic
*/
long tempsAnteriorClic;
/**
* Mètode constructor per
objectes de la classe RectanglesAlt.
*/
public RectanglesAlt () { // constructor
<codi següent>
...
...
...
<codi anterior>
/**
* Mètode que s'executa quan
l'acció és "Pressionar sobre
* un punt"
* @param e un MouseEvent
*/
public void mousePressed (MouseEvent e)
{
// Quina és
la font de l'esdeveniment?
Object font=e.getSource();
//
És un objecte JPanel?
if
(font instanceof JPanel) {
//
Coordenades de l'esdeveniment
int
x=e.getX();
int
y=e.getY();
//
Temps de l'esdeveniment
long
temps=e.getWhen();
//
Desa-les als camps corresponents
puntIniciX=x;
puntIniciY=y;
//
Interval entre dos clicks
long
interval=temps-tempsAnteriorClic;
//
Cal fer això per garantir que interval > 0
if
(interval<0) {
interval=-interval;
}
//
És un doble click? és a dir, entre aquest click
//
i l'anterior hi ha hagut menys de 300 mili-
//
segons?
if
(interval<300L) {
//
Sí: és un doble clic. Ara pots fer
//
qualsevol cosa. Per exemple, esborrar
//
el panel...
JPanel
panel=(JPanel)font;
panel.repaint();
}
//
El temps d'aquest clic cal desar-lo per tal que
//
el següent pugui comparar...
tempsAnteriorClic=temps;
}
}
<codi següent>
|
|
|
|
|
|
|
El resultat és que, ara, a
la classe Rectangles, pots esborrar les línies
que hi hagi dibuixades amb un doble
clic de qualsevol dels botons del ratolí... |
|
|
|
|
|
Un exercici,
per acabar... |
|
|
|
|
 |
La última
versió de la classe Rectangles, la que
et permet dibuixar línies de dos colors segons el botó del
ratolí que facis servir, i que et permet esborrar els dibuixos amb
un doble clic, està construida implementant les interfícies
MouseListener i MouseMotionListener.
Es tracta que n'escriguis una nova versió, la classe RectanglesAlt,
que no implementi aquestes interfícies i que, en canvi, faci servir
objectes MouseAdapter i MouseMotionAdapter,
de la manera que ho hauràs fet aquí. |
|
|
|
|
|
No miréssis pas la solució,
eh? la qual està ben amagadeta aquí... |
|
|
|
|
|
|
 |