|
|||||||||||||||||
![]() |
|||||||||||||||||
Pràctica |
![]() |
Exercicis
|
|||||||||||||||
Captura d'esdeveniments | ||||||||||||||||||||||||||||||||||||||||||||||
Quan ja hem après una mica a disposar elements en un contenidor (pràctica 2) ,fent servir algun dels layout managers disponibles, ara és el moment de donar funcionalitat a aquests elements.Amb aquesta pràctica aprendrem a fer anar uns controls senzills: els botons i a més,amb això pretenem:
|
||||||||||||||||||||||||||||||||||||||||||||||
Controls que controlen ( capturant esdeveniments) | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
En aquest context, un control és un element visual (un element de la GUI) mitjançant el qual l'usuari d'una aplicació dóna o rep alguna informació a la aplicació. Si el control és per donar informació a la aplicació i no nomès per rebre'n (com és el cas dels labels de la pràctica anterior) la acció de l'usuari sobre el control fa que aquest emeti un esdeveniment i que, els qui estaven escoltant-lo (els listeners del control) s'assabentin de l'acció i obrin en conseqüència. Així, l'esquema general de funcionament d'un control és aquest:
|
|||||||||||||||||||||||||||||||||||||||||||||
Què cal tenir en compte de manera ineludible? | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Cal recordar dues coses:
|
|||||||||||||||||||||||||||||||||||||||||||||
Primer pas: donar a un objecte la condició de "listener" | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Això s'aconsegueix mitjançant la interfície (interface) corresponent. Cada mena d'esdeveniment té la corresponent interfície per a construir listeners d'aquest esdeveniment. Aquí n'hi ha algunes de les més usuals; les classes que emeten els esdeveniments són del paquet java.awt, els esdeveniments i les interfícies són del paquet java.awt.event: | |||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
El mecanisme és el següent: quan definim la classe els fills de la qual han de ser listeners d'una determinada mena d'esdeveniment cal, a més de la clàusula extends (si és que aquesta classe la derivem d'alguna altra, cosa que és el cas més usual), fer servir la clàusula implements per a la interface. Així:
El resultat d'això és que, a) ara la classe definida així no només hereta els mètodes de la classe mare, sinó que, també hereta els mètodes de la interfície corresponent, i b) aquesta classe ja serà identificada
per Java com a listener
d'aquesta mena d'esdeveniments. En certa
forma, els objectes derivats d'aquesta
classe tenen ara una doble identitat:
son, a la vegada, instàncies de
la classe mare i de l'interfície.
Per aquells que conegueu C++, això
és el màxim que Java permet
pel que fa a herència múltiple.
|
||||||||||||||||||||||||||||||||||||||||||||||
Segon pas: establir la llista de "listeners" d'un cert control | ||||||||||||||||||||||||||||||||||||||||||||||
El control tindrà un mètode per afegir-li listeners. Per exemple,en el cas dels botons, el mètode és public void addActionListener(ActionListener l). Només cal fer-lo servir... | ||||||||||||||||||||||||||||||||||||||||||||||
Un primer exemple: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Farem una petita finestra com aquesta: | |||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||
amb un botó a la part inferior i un label a la superior. Es tracta que, quan es prem el botó, el label es torni vermell: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||
Farem, doncs un frame de 200 x 100, amb GridLayout de dues files i una columna com a layout manager. | ||||||||||||||||||||||||||||||||||||||||||||||
quan el premem,el botó, en prémer-lo, emetrà una instància de java.awt.eventActionEvent (això no cal programar-ho, és una de les funcionalitats que ja porta la classe java.awt.Button). Haurem de definir algú que escolti al botó: serà el propi frame, el qual ha de ser definit ara com
Per tant, caldrà que, inexcusablement, la classe Botons01 implementi l'unic mètode de la interface java.awt.event.Action Listener, que és public void actionPerformed(ActionEvent e) en el qual hi posarem les instruccions necessàries per tal que el label canviï de color. D'altra banda, tot just després de definir el botó, haurem
d'incorporar el frame a la llista dels
qui l'escolten. Això ho farem amb la línia
|
||||||||||||||||||||||||||||||||||||||||||||||
així creem el projecte Botons01 com a "Basic Java Application" i altre cop després de comentar la línia package myprojects.Botons01;, modifiqueu el codi que JCreator ha posat en el fitxer Botons01.java. Les parts a modificar estan en color groc clar: | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
Observació molt important: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Com que el label es crida des de dos mètodes diferents (un quan el construim, a main, i una altra quan el canviem de color, a actionPerformed) cal que sigui una variable de classe i, per tant, accessible a tots els seus mètodes. Això ho fem mitjançant la declaració del principi de la classe:
|
|||||||||||||||||||||||||||||||||||||||||||||
A Java, com a C i C++ i la majoria de llenguatges estructurats, la vida d'una variable és la de la rutina o funció (aquí mètode) en la qual ha estat declarada. En canvi, com ja haureu observat, a diferència de C, no cal que la declaració de les variables es faci al principi del mètode. | ||||||||||||||||||||||||||||||||||||||||||||||
Fem-ho una mica més interessant; | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Podem fer que el nostre label canviï de color si fem alguns canvis al mètode actionPerformed: | |||||||||||||||||||||||||||||||||||||||||||||
public void actionPerformed(ActionEvent e) { | ||||||||||||||||||||||||||||||||||||||||||||||
//
label.setBackground(Color.red); // Eliminem aquesta línia Color color=label.getBackground(); // De quin color és el label ara mateix? int r=color.getRed(); // Quin n'és el valor de vermell? int g=color.getGreen(); // Quin n'és el valor de verd? int b=color.getBlue(); // Quin n'és el valor de blau? color=new Color((r+100)%256, // Canvis en els valors de vermell, (g+200)%256, // verd i blau, mirant de no passar (b+300)%256);// de 255 label.setBackground(color); // Nou color pel label |
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
i, de passada, explorem una mica més els mètodes de la classe java.awt.Color i fem ús de l'operador %... | ||||||||||||||||||||||||||||||||||||||||||||||
Una mica més sofisticat... | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Si hi ha més d'un control que envia esdeveniments al mateix listener, és clar que cal dotar al listener de la capacitat de distingir quin dels controls és l'emissor de l'esdeveniment per tal de decidir què ha de fer. Encara que per a determinats tipus de controls hom pot acudir a d'altres mètodes, l'esquema general de resolució de la qüestió és acudir al mètode public Object getSource() de la classe java.util.EventObject,
que és la classe mare de totes
les classes d'esdeveniments,
que l'hereden. Aquest mètode
ens permet conèixer quin objecte
concret ha estat l'emissor del esdeveniment
i, a partir d'aquesta informació, decidir què fa l'objecte
listener. |
|||||||||||||||||||||||||||||||||||||||||||||
Vegem-ho en el següent exemple: | ||||||||||||||||||||||||||||||||||||||||||||||
Un segon exemple: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Construirem un frame com aquest: | |||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||
Crearem un panel per a contenir-ho tot en el qual el layout manager serà el java.awt.GridLayout amb dues files i una columna. A la fila (casella) de dalt hi haurà un label de color Color.LIGHT_GRAY per al fons. A la fila (casella) de baix hi haurà un altre panel amb, també, java.awt.GridLayout com a layout manager, però d'una fila i tres columnes, el qual rebrà tres botons. El panel que ho conté tot l'afegirem a la posició "center" del layout (java.awt.BorderLayout) del frame. Com que a les altres quatre posicions, "north", "south", "east" i "west" no hi haurà res, allò que posem a "center" omplirà tot l'espai disponible al frame. | ||||||||||||||||||||||||||||||||||||||||||||||
La funcionalitat serà aquesta: quan premem qualsevol dels tres botons, el text del label canviarà i ens informarà de quin botó és el que hem apretat. | ||||||||||||||||||||||||||||||||||||||||||||||
Els objectes emissors d'esdeveniments seran els botons i, com és d'esperar, emetran instàncies de java.awt.event.ActionEvent (que caldrà distingir segons el botó que els origina!) i l'objecte listener serà el panel que ho conté tot. | ||||||||||||||||||||||||||||||||||||||||||||||
Creem, doncs, el projecte Botons02 com a "Basic Java Application" (comenteu la línia package myprojects.Botons02;!) i modifiqueu el codi creat per JCreator. Les parts a modificar estan en color groc clar: | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
A més, en lloc de fer servir directament les classes java.awt.Panel i java.awt.Button directament, ara necessitem derivar-ne, respectivament, les classes ElMeuPanel (codi en fons taronja) i ElMeuBoto (codi en fons rosa). Per què?
|
||||||||||||||||||||||||||||||||||||||||||||||
Conversió (casting) ... | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Bé, al mètode public void actionPerformed(ActionEvent e) de la classe listener ElMeuPanel la línia | |||||||||||||||||||||||||||||||||||||||||||||
Object botoObj=e.getSource(); | ||||||||||||||||||||||||||||||||||||||||||||||
posa a la variable botoObj
l'objecte emissor de l'esdeveniment
e. Per tant, ElMeuPanel
ja "sap" quin és l'objecte
emissor. Què cal fer ara?
|
||||||||||||||||||||||||||||||||||||||||||||||
Ara una mica més senzill: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
La classe java.awt.Button porta, però, una variable no pública, String actionCommand, que permet emmagatzemar una cadena (string) per a identificació. Per defecte, el valor n'és null. Si volem fixar el valor d'aquesta variable hi ha el mètode setter public void setActionCommand(String command) i per recuperar-lo hi ha el mètode getter public String getActionCommand() el qual, si ActionCommand és null, retorna l'etiqueta (label) del botó. Això ens pot estalviar de definir una classe derivada de java.awt.Button, tal com fèiem abans: |
|||||||||||||||||||||||||||||||||||||||||||||
Tot identificant botons: | ||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Creem el projecte Botons03 com abans. El codi a modificar, però que coincideix amb el del exemple anterior, és en groc, mentre que el codi en fons taronja correspon a les noves idees introduïdes aquí. | |||||||||||||||||||||||||||||||||||||||||||||
/* * @(#)Botons03.java 1.0 02/09/21 * * You can modify the template of this file in the * directory ..\JCreator\Templates\Template_1\Project_Name.java * * You can also create your own project template by making a new * folder in the directory ..\JCreator\Template\. Use the other * templates as examples. * */ |
||||||||||||||||||||||||||||||||||||||||||||||
//package
myprojects.Botons03; |
||||||||||||||||||||||||||||||||||||||||||||||
import
java.awt.*; import java.awt.event.*; class Botons03 extends Frame { public static void main(String
args[]) { |
||||||||||||||||||||||||||||||||||||||||||||||
mainFrame.setSize(400,
100); mainFrame.setTitle("Tres botons i un label"); mainFrame.add(new ElMeuPanel(),BorderLayout.CENTER); |
||||||||||||||||||||||||||||||||||||||||||||||
mainFrame.setVisible(true); |
||||||||||||||||||||||||||||||||||||||||||||||
class ElMeuPanel extends Panel implements ActionListener { |
||||||||||||||||||||||||||||||||||||||||||||||
Button
boto_A=new Button("Botó 'A'"); boto_A.setActionCommand("A"); |
||||||||||||||||||||||||||||||||||||||||||||||
boto_A.addActionListener(this); panel.add(boto_A); |
||||||||||||||||||||||||||||||||||||||||||||||
Button
boto_B=new Button("Botó 'B'"); boto_B.setActionCommand("B"); |
||||||||||||||||||||||||||||||||||||||||||||||
boto_B.addActionListener(this); panel.add(boto_B); |
||||||||||||||||||||||||||||||||||||||||||||||
Button
boto_C=new Button("Botó 'C'"); boto_C.setActionCommand("C"); |
||||||||||||||||||||||||||||||||||||||||||||||
boto_C.addActionListener(this); panel.add(boto_C); add(panel); } public void actionPerformed(ActionEvent
e) { |
||||||||||||||||||||||||||||||||||||||||||||||
if
(botoObj instanceof Button) { Button botoMeu=(Button)botoObj; String idBoto=botoMeu.getActionCommand(); label.setText("Has apretat el botó '"+idBoto+"'"); |
||||||||||||||||||||||||||||||||||||||||||||||
} } } |
||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Després d'executar boto_X.setActionCommand("X");, la variable ActionCommand de cadascun dels botons conté, respectivament, les cadenes "A", "B" o "C" (de la mateixa manera que, en l'exemple anterior la variable identificador contenia els nombres enters 0, 1 o 2). La cadena que ha d'aparèixer al label s'obté per concatenació de les cadenes "Has apretat el botó '", idBoto i "'", mitjançant l'ús de l'operador binari "+". | |||||||||||||||||||||||||||||||||||||||||||||
![]() |
||||||||||||||||||||||||||||||||||||||||||||||