|
Fins ara (pràctiques 2, 3
i 4) coneixem i hem fet GUI's
que inclouen quatre tipus de controls:
- java.awt.Label
- java.awt.Button
- java.awt.Checkbox
- java.awt.CheckboxGroup
En aquesta pràctica n'introduirem quatre més:
- java.awt.List
- java.awt.TextArea
- java.awt.TextField
- java.awt.Choice
i, de passada, aprendrem una manera de fer que les nostres GUI's
siguin multilingües. Amb més
profunditat, això serà la manera de discutir els conceptes
de classe final i de mètodes
i variables static.
(Ja tocava, no?) |
|
|
|
Un editor de missatges: |
|
|
 |
La nostra aplicació será una finestra, la qual contindrá:
- Dues zones on
l'usuari podrà escriure els noms respectius del destinatari i
del remitent del missatge
- Dues llistes,
una per a encapçalaments i l'altra per a fórmules de comiat,
de les quals l'usuari podrà escollir les que li convinguin.
- Una zona dedicada
a què l'usuari hi escrigui el text del missatge. L'encapçalament
i el comiat s'hi escriuen automàticament a partir de les seleccions
fetes als controls anteriors.
- Un botó
de conformitat amb les seleccions.
- Un botó
per enviar el missatge.
|
|
L'aspecte en serà
aquest: |
|
|
|
|
|
|
- Les etiquetes "Nom
del destinatari" i "Nom
del remitent" són labels
amb justificació java.awt.Label.RIGHT,
per tal que estiguin el més enganxades possible als camps
de text respectius de la seva dreta. També ho és
l'espai a l'esquerra del botó "Enviar".
Es tracta d'un label sense text.
- Els botons "D'acord"
i "Enviar" són instàncies
de java.awt.Button.
- TextFields:
Els camps de text on ara hi ha escrit
"Julieta" i "Romeu"
són instàncies de la
classe java.awt.TextField.
La classe java.awt.TextField
representa una línia de text editable.
Els mètodes per manipular
el text són:
- public String getText(),
que retorna el text (cadena,
string) que hi hagi escrit al
TextField
- public void setText(String
t), que situa la cadena
(string) t
en el TextField.
La classe java.awt.TextField
és capaç d'emetre esdeveniments
java.awt.event.ActionEvent quan hom prem
la tecla "Retorn"
del teclat. Per tant, té,
com era d'esperar, un mètode
public void addActionListener(ActionListener l)per
poder afegir listeners que l'escoltin.
En aquest sentit, es comporta exactament com java.awt.Button,
que ja ha estat utilitzat per nosaltres..
- TextArea: La
zona de text destinada a ser escrita
per l'usuari són instàncies
de la classe java.awt.TextArea.
La classe java.awt.TextArea
representa una zona de text editable,
que pot tenir vàries línies.
El text no es justifica. i,
si la quantitat de text ho requereix, s'activen scrollbars
horitzontals i/o verticals. Els mètodes
per manipular el text són iguals que els de java.awt.TextField:
- public String getText(),
que retorna el text (cadena,
string) que hi hagi escrit al
TextField
- public void setText(String
t), que situa la cadena
(string) t
en el TextField.
Com que hi ha la possibilitat de canvis
de línia, podem incloure a les cadenes
de text el caràcter de control
"\n" amb garantia que tindrà
efecte.
- Llistes: Les
dues llistes d'ítems a seleccionar
per l'usuari que hi ha a l'esquerra de la zona
de text són instàncies
de la classe java.awt.List.
La classe java.awt.List
representa una llista d'ítems per
seleccionar, i segons com es construeixi,
admet selecció múltiple,
és a dir, de més d'un ítem
a la vegada. Si els textos o la quantitat d'items
ho requereixen, s'activen scrollbars
horitzontals i/o verticals. Els mètodes
principals per manipular els ítems
són:
- public void add(String
item), que afegeix un ítem
amb el text item al final de la llista.
- public String getSelectedItem(),
que retorna la cadena (string)
de text que hi hagi a l'ítem
seleccionat.
- public void select(int
index), que selecciona
l'ítem a la posició
index (la de dalt de tot és la
posició zero).
- public void removeAll(),
que elimina tots els ítems
i deixa la llista buida.
La classe java.awt.List
emet esdeveniments java.awt.event.ItemEvent
quan es canvia la selecció.
Té, per tant, un mètode
public void addItemListener(ItemListener l),
per poder afegir listeners que escoltin
aquests esdeveniments.
La classe java.awt.List,
a més, és capaç d'emetre
esdeveniments java.awt.event.ActionEvent
quan hom fa un doble click sobre
un dels seus ítems, que queda,
a més, seleccionat. Per això,
ha de tenir i té, un mètode
public void addActionListener(ActionListener l),
que permet afegir listeners que l'escoltin.
|
|
Amb aquests elements construirem l'aplicació
Missatgeria01 amb el funcionament següent:
- Als camps de text
superiors l'usuari hi posarà (si vol) els noms del destinatari
i del remitent del missatge. Els valors quedaran validats
en prèmer la tecla "Retorn"
o en prèmer el botó "D'acord".
- De les dues llistes
de l'esquerra, l'usuari seleccionarà
els tractaments de cortesia tant per la introducció com pel comiat.
Les seleccions es validen,
o bé per doble click sobre un
ítem, o bé mitjançant
el botó "D'acord"
- L'usuari confegeix el text del missatge a l'àrea
de text i, després, mitjançant el botó
"Enviar", l'"envia"
al destinatari. Aquí, "enviar el missatge" consistirà
en què aparegui escrit a la sortida
standard del sistema.
|
|
|
|
Creem, doncs, el projecte
Missatgeria01 amb aquest fitxer
Missatgeria01.java: |
|
|
|
/*
* @(#)Missatgeria01.java 1.0 02/09/28
*
* 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.missatgeria01;
import java.awt.*;
import java.awt.event.*;
class Missatgeria01 extends Frame {
public Missatgeria01() { //constructor
|
|
setBackground(Color.LIGHT_GRAY);
ElMeuPanel panel=new ElMeuPanel();
add(panel,BorderLayout.CENTER); |
|
addWindowListener(new
WindowAdapter() {
public
void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
public static void main(String args[]) {
System.out.println("Starting
Missatgeria01...");
Missatgeria01 mainFrame
= new Missatgeria01();
|
|
mainFrame.setSize(600,
300);
mainFrame.setTitle("Missatgeria"); |
|
mainFrame.setVisible(true);
}
}
|
|
class
ElMeuPanel extends Panel implements ActionListener {
Label labelNomDestinatari;
Label labelNomRemitent;
TextField fieldNomDestinatari;
TextField fieldNomRemitent;
Button ok;
Button enviar;
List listInici;
List listFinal;
TextArea text;
public ElMeuPanel() { //constructor
super();
setLayout(new BorderLayout());
Panel panelNord=new Panel();
panelNord.setLayout(new
BorderLayout());
Panel panelLabels=new
Panel();
panelLabels.setLayout(new
GridLayout(2,1));
labelNomDestinatari=new
Label("Nom del destinatari:",
Label.RIGHT);
labelNomRemitent=new Label("Nom
del remitent: ",
Label.RIGHT);
panelLabels.add(labelNomDestinatari);
panelLabels.add(labelNomRemitent);
panelNord.add(panelLabels,BorderLayout.WEST);
Panel panelNoms=new
Panel();
panelNoms.setLayout(new
GridLayout(2,1));
fieldNomDestinatari=new
TextField();
fieldNomDestinatari.addActionListener(this);
fieldNomRemitent=new TextField();
fieldNomRemitent.addActionListener(this);
panelNoms.add(fieldNomDestinatari);
panelNoms.add(fieldNomRemitent);
panelNord.add(panelNoms,BorderLayout.CENTER);
ok=new Button("D'acord");
ok.addActionListener(this);
panelNord.add(ok,BorderLayout.EAST);
add(panelNord,BorderLayout.NORTH);
text=new TextArea("");
add(text,BorderLayout.CENTER);
Panel panelCortesia=new
Panel();
panelCortesia.setLayout(new
GridLayout(2,1));
listInici=new List(9);
listInici.add("");
listInici.add("Apreciat
");
listInici.add("Apreciada
");
listInici.add("Benvolgut
");
listInici.add("Benvolguda
");
listInici.add("Estimat
");
listInici.add("Estimada
");
listInici.add("Caríssim
");
listInici.add("Caríssima
");
listInici.select(1);
listInici.addActionListener(this);
panelCortesia.add(listInici);
listFinal=new List(7);
listFinal.add("");
listFinal.add("Cordialment");
listFinal.add("Una
abraçada");
listFinal.add("Teu");
listFinal.add("Teva");
listFinal.add("Sempre
teu");
listFinal.add("Sempre
teva");
listFinal.select(1);
listFinal.addActionListener(this);
panelCortesia.add(listFinal);
add(panelCortesia,BorderLayout.WEST);
Panel panelSur=new Panel();
panelSur.setLayout(new
GridLayout(1,2));
panelSur.add(new Label(""));
enviar=new Button("Enviar");
enviar.addActionListener(this);
panelSur.add(enviar);
add(panelSur,BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent e) {
Object objAction=e.getSource();
if
(objAction instanceof TextField ||
objAction
instanceof List) {
preparaText();
}
else if (objAction instanceof Button) {
if(objAction==ok)
{
preparaText();
}
else if(objAction==enviar) {
enviaMissatge();
}
}
}
public void preparaText () {
text.setText(listInici.getSelectedItem()+
fieldNomDestinatari.getText()+
",\n\n<text de la nota>\n\n"+
listFinal.getSelectedItem()+
",\n "+
fieldNomRemitent.getText());
}
public void enviaMissatge() {
System.out.println(text.getText());
}
}
|
|
|
|
Observem: |
|
|
 |
- L'estructura de contenidors
(panels) niuats amb els seus layout
managers:
- mainFrame, instància
de java.awt.Frame
- panel, instància
de ElMeuPanel, classe
filla de java.awt.Panel
- panelNord, instància
de java.awt.Panel
- panelLabels, instància
de java.awt.Panel
- panelNoms, instància
de java.awt.Panel
- panelCortesia, instància
de java.awt.Panel
- panelSur, instància
de java.awt.Panel
Convindrà ara que ara fem un mapa d'aquesta estructura
dels contenidors i controls
que hi ha a cadascun d'aquests contenidors...
- Tots els controls,
excepte els labels i l'àrea
de text, veuen els esdeveniments
que emeten capturats per un únic
listener, que és la classe
ElMeuPanel. Això és així
perquè per a cadascun d'aquests controls
hem executat el mètode control.addActionListener(this).(Qüestió:
a què es refereix la clàusula
"this"?).
Com que s'emetran esdeveniments java.awt.ActionEvent,
la classe ElMeuPanel
ha d'implementar la interface
java.awt.event.ActionListener i, en conseqüència,
el mètode public
void actionPerformed(ActionEvent e).
- Quan es produeix l'esdeveniment,
llavors s'executa el mètode
public void actionPerformed(ActionEvent e)
i per determinar quines accions cal fer, és necessari saber quin
control n'és l'emissor. Aquí
n'hem fet una primera identificació
per tipus (la clàusula
"instanceof") i, després,
com que hi ha dos botons, els
hem distingit simplement per referència
als seus noms (l'operador relacional
"==").
- En lloc de descriure les accions a fer dintre del
mateix mètode public
void actionPerformed(ActionEvent e), és molt millor cridar
a d'altres mètodes especialitzats:
public void preparaText () per a la incorporació
de les opcions escollides per l'usuari i public void
enviaMissatge() per "enviar" efectivament el
missatge. Això fa guanyar intel·ligibilitat al codi i
permet facilitar-ne la modificació i millora.
|
|
|
|
Un altre control: la
classe java.awt.Choice: |
|
|
 |
La classe java.awt.Choice
representa un menú desplegable amb una
llista d'ítems per seleccionar. L'item
seleccionat apareix com a títol
del choice. Els mètodes
principals per manipular els ítems
són:
- public void add(String item),
que afegeix un ítem amb el text
item al final de la llista.
- public String getSelectedItem(),
que retorna la cadena (string)
de text que hi hagi a l'ítem seleccionat.
- public int getSelectedIndex(),
que retorna la posició (index)
de l'ítem seleccionat (la de
dalt de tot és la posició zero).
- public void select(int index),
que selecciona l'ítem
a la posició index
- public void removeAll(),
que elimina tots els ítems i
deixa el choice buit.
La classe java.awt.Choice
emet esdeveniments java.awt.event.ItemEvent
quan es canvia la selecció. Naturalment,
per poder afegir listeners que escoltin
aquests esdeveniments, té un mètode
public void addItemListener(ItemListener l). |
|
|
|
Per tal de fer funcionar
un choice, ara farem una petita variació
del nostre gestor de missatges. Afegirem un choice
a la dreta del botó "enviar"
que ens ha de permetre seleccionar l'idioma
en el qual se'ns presentaran els títols, les etiquetes i les opcions
entre català, castellà i anglès. Aquí el teniu
en l'"estat llengua anglesa": |
|
|
|
|
|
|
La funcionalitat ha de
consistir en què, quan seleccionem
un idioma determinat, inmediatament quedaran traduïts a aquesta nova
llengua tots els textos dels labels, botons,
lists i els del propi choice. |
|
|
|
Com hem fet abans,podríem
incloure els textos traduïbles en algun lloc del
fitxer Missatgeria01 (en aquest fitxer
els textos són a cadascuna de les definicions
dels controls, al mètode constructor
de la classe ElMeuPanel)
, però és molt més elegant i pràctic situar
tots aquests textos en un fitxer *.java
apart, i procurar que el funcionament dels mètodes
al fitxer principal sigui independent de
la quantitat d'idiomes i d'eleccions que hi hagi al fitxer
de textos. Això vol dir que per afegir noves opcions o nous
idiomes, només caldrà manipular aquest fitxer
de textos tot deixant intacte el fitxer
principal. |
|
|
|
Fem ara un nou
projecte, Missatgeria02, com a "Basic
Java Application" i, després de comprovar que, com sempre,
s'ha creat el fitxer Missatgeria02.java,
que és el fitxer principal, hem
d'afegir aquest fitxer, "Etiquetes.java",
al projecte que en serà el fitxer
de textos: |
|
|
|
public
final class Etiquetes {
public static int idiomaInicial=0;
public static String[] titolFrame={"Missatgeria",
"Mensajería",
"Messages"};
public static String[] nomTo={"Nom del destinatari:
",
"Nombre
del destinatario: ",
"To
"};
public static String[] nomFrom={"Nom del remitent:
",
"Nombre
del remitente: ",
"From
"};
public static String[][] hi={{" ","Apreciat
",
"Apreciada
","Benvolgut ",
"Benvolguda
","Estimat ",
"Estimada
","Caríssim ",
"Caríssima
"},
{"
","Apreciado ",
"Apreciada
","Querido ",
"Querida
","Estimado ",
"Estimada
","Carísimo ",
"Carísima
"},
{"
","Dear "}};
public static String[] espaiText={"text de
la nota",
"texto
de la nota",
"message
text"};
public static String[][] bye={{" ","Cordialment",
"Una
abraçada","Teu",
"Teva","Sempre
teu",
"Sempre
teva"},
{"
","Cordialmente",
"Un
abrazo","Tuyo",
"Tuya","Siempre
tuyo",
"Siempre
tuya"},
{"
","Greetings",
"Yours","My
best wishes"}};
public
static String[] ok={" D'acord "," Sí ","
Ok "};
public static String[][]
idiomes={{"Català","Castellà",
"Anglès"},
{"Catalán","Español",
"Inglés"},
{"Catalan","Spanish",
"English"}};
public static String[]
enviar={"Enviar","Enviar","Send"};
}
|
|
|
 |
Public, static, final,
arrays... |
|
|
|
Bé. Ha arribat el moment de repassar alguns conceptes...
- La classe Etiquetes
ha estat definida mitjançant les clàusules
"public" i "final".
Què vol dir això?
- La clàusula
public implica que allò
a què s'aplica (classes,
variables o mètodes)
és accessible pels mètodes
de qualsevol altre objecte de l'aplicació
en funcionament. Si no definim la classe
Etiquetes amb la clàusula
"public", el seu contingut resultaria
inaccessible per qualsevol dels mètodes
de les classes del fitxer
M4p5_02.java!
Respecte a la visibilitat/accessibilitat
de classes, variables
i mètodes, Java
ens ofereix tres possibilitats, expressades en les corresponents
tres clàusules:
- public: (classes,
variables i mètodes)
L'element corresponent és visible
i accessible des de qualsevol
altre element de l'aplicació.
- protected: (variables
i mètodes) L'element
definit així només és visible
i accessible des de la pròpia
classe i des de les classes
filles.
- private: (variables
i mètodes) L'element
definit així definit és visible
i accessible des de la pròpia
classe, però no des
de les classes filles.
Si no s'especifica cap d'aquestes tres cláusules,
llavors l'element només és visible
i accessible pels objectes
el codi dels quals és al mateix fitxer
*.java que el de l'element en qüestió.
Ara ja podeu veure que hem estat força generosos repartint
clàusules "public"
als mètodes de les classes
definides a M4p5_02.java, les quals són
totes supèrflues. Però és una bona pràctica
posar-les sempre que preveiem que algun objecte
voldrà accedir a
aquesta classe, variable
o mètode.
- Si una classe es
defineix com a "public", llavors
ha de ser la primera de les classes
definides en el fitxer *.java,
el qual ha de tenir exactament el mateix
nom que la classe. (Qüestió:
un fitxer *.java pot contenir més
d'una classe pública?)
- La clàusula
"static" s'aplica a variables
i mètodes. Significa que
aquests variable o mètode
de la classe mare
són accessibles i/o executables
sense necessitat que aquesta classe
hagi estat instanciada en un objecte.
Les variables static
venen a jugar el paper de les constants
de C (a Java
no hi ha precompilació i
per tant, no existeix la clàusula
#define) i els mètodes
static venen a ser les
funcions de llibreries de C
(a java tampoc hi ha la fitxers
de capçalera i, per tant, no hi ha la clàusula
#include).
Observeu que, a diferència de la crida
a mètodes no static,
en la qual es fa:
<nom de l'objecte>.elMetodeQue
Sigui( ... ) |
a la crida a mètodes
static es fa:
<nom de la classe>.elMetodeQue
Sigui( ... ) |
Ara ja podem entendre una mica perquè el mètode
main(String[] args); és, precisament,
static: quan l'aplicació comença
a executar-se, encara no s'ha construït
cap objecte. Com que el
primer mètode que crida
la Màquina Virtual és
main(String[] args); és clar que
aquest ha de ser static per força!
Observeu que main(String[] args); una
de les primeres coses que fa és construir
una instància de la seva
mateixa classe (mainFrame
en els nostres exemples) i, a partir d'aquí, tots els altres
mètodes es criden
com a pertanyents a l'objecte (mainFrame),
no pas a la classe (M2px_xx).
- A vegades convé que, d'una classe,no
en puguem derivar classes filles
(això n'augmenta l'eficiència). Llavors es defineix
mitjançant la clàusula
"final", la qual prohibeix que
poguem construir-ne classes filles.
Normalment, una classe final
no té mètodes constructors
i totes les variables i mètodes
accessibles són static.
El nostre fitxer de textos, que té
la única funcionalitat d'emmagatzemar els textos de la GUI
de l'aplicació, es defineix
doncs com a public (per tal que sigui accessible)
i final (per tal que no se'n puguin fer
instàncies ni fer-ne subclasses
o classes filles). El seu paper en
la nostra aplicació, comparat amb la construcció equivalent
de C, és el d'un fitxer
de capçalera amb definició de constants.
Totes les variables (constants
si fós C) són static.
- Com que per a cadascun dels
idiomes hi ha una possibilitat per a cada text, els textos s'enmagatzemen
en matrius (arrays).
No oblidem que, a Java, totes les variables es passen als mètodes
per referència i no per valor (no hi ha apuntadors!). En consequència,
al declarar les variables segons el tipus, cal especificar si ens referim
a un sol valor o a un array de valors:
- nom_de_tipus:
declarem un sol valor.
- nom_de_tipus[]:
declarem un array simple (lineal)
de valors. Els índexos
comencen per 0.
- nom_de_tipus[][]:
declarem un array rectangular de
valors, que no és més
que un array lineal d'arrays
lineals. Els respectius índexos
comencen per 0.
- nom_de_tipus[][][]:
declarem un array cúbic
de valors.
- etc.
Els valors continguts a nom_de_tipus[]
elMeuArray es criden mitjançant
elMeuArray[index], els valors
continguts a nom_de_tipus[][] elMeuArray es
criden mitjançant
elMeuArray[index_0][index_1], etc.
|
|
Ara ja ha de quedar clar
el codi del fitxer
Etiquetes.java. La variable
idiomaInicial és un enter
(int) posat inicialment a 0,
que representa els tres idiomes: 0 pel català,
1 pel castellà i 2
per l'anglès. idiomaInicial actuarà
com a índex dels arrays
de textos (fixeu-vos en l'ordenació a cada array!) |
|
|
|
I ja podem escriure el
fitxer principal (projecte
Missatgeria02) . Consisteix essencialment en el
mateix codi de Missatgeria01 amb les variacions
que expliquem al final. Només hem marcat amb color groc les parts
de codi que difereixen del de Missatgeria01: |
|
|
|
/*
* @(#)Missatgeria02.java 1.0 02/09/29
*
* 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.missatgeria02;
import java.awt.*;
import java.awt.event.*;
class Missatgeria02 extends Frame {
public Missatgeria02() {
//constructor
setBackground(Color.LIGHT_GRAY);
|
|
ElMeuPanel
panel=new ElMeuPanel(this); |
|
add(panel,BorderLayout.CENTER);
addWindowListener(new WindowAdapter()
{
public
void windowClosing(WindowEvent e) {
dispose();
System.exit(0);
}
});
}
public static void main(String args[]) {
System.out.println("Starting
Missatgeria02...");
Missatgeria02 mainFrame
= new Missatgeria02();
mainFrame.setSize(600,
300);
mainFrame.setVisible(true);
}
}
|
|
class
ElMeuPanel extends Panel implements ActionListener,
ItemListener
{
Missatgeria02 mainFrame; |
|
Label
labelNomDestinatari;
Label labelNomRemitent;
TextField fieldNomDestinatari;
TextField fieldNomRemitent;
Button ok;
Button enviar;
List listInici;
List listFinal;
TextArea text; |
|
int
numIdioma=Etiquetes.idiomaInicial;
Choice idioma;
public ElMeuPanel(Missatgeria02 f) {
//constructor
|
|
super(); |
|
mainFrame=f; |
|
setLayout(new
BorderLayout());
Panel panelNord=new Panel();
panelNord.setLayout(new
BorderLayout());
Panel panelLabels=new
Panel();
panelLabels.setLayout(new
GridLayout(2,1));
|
|
labelNomDestinatari=new
Label("",Label.RIGHT);
labelNomRemitent=new Label("",Label.RIGHT); |
|
panelLabels.add(labelNomDestinatari);
panelLabels.add(labelNomRemitent);
panelNord.add(panelLabels,BorderLayout.WEST);
Panel panelNoms=new
Panel();
panelNoms.setLayout(new
GridLayout(2,1));
fieldNomDestinatari=new
TextField();
fieldNomDestinatari.addActionListener(this);
fieldNomRemitent=new TextField();
fieldNomRemitent.addActionListener(this);
panelNoms.add(fieldNomDestinatari);
panelNoms.add(fieldNomRemitent);
panelNord.add(panelNoms,BorderLayout.CENTER);
|
|
ok=new
Button(); |
|
ok.addActionListener(this);
panelNord.add(ok,BorderLayout.EAST);
add(panelNord,BorderLayout.NORTH);
text=new TextArea("");
add(text,BorderLayout.CENTER);
Panel panelCortesia=new
Panel();
panelCortesia.setLayout(new
GridLayout(2,1));
|
|
listInici=new
List(); |
|
listInici.addActionListener(this);
panelCortesia.add(listInici);
|
|
listFinal=new
List(); |
|
listFinal.addActionListener(this);
panelCortesia.add(listFinal);
add(panelCortesia,BorderLayout.WEST);
Panel panelSur=new Panel();
panelSur.setLayout(new
GridLayout(1,2));
|
|
idioma=new
Choice();
idioma.addItemListener(this);
panelSur.add(idioma);
enviar=new Button(); |
|
enviar.addActionListener(this);
panelSur.add(enviar);
add(panelSur,BorderLayout.SOUTH);
|
|
canviaIdioma(); |
|
}
public void actionPerformed(ActionEvent e) {
Object objAction=e.getSource();
if
(objAction instanceof TextField ||
objAction
instanceof List) {
preparaText();
}
else if (objAction instanceof Button) {
if(objAction==ok)
{
preparaText();
}
else if(objAction==enviar) {
enviaMissatge();
}
}
}
|
|
public
void itemStateChanged(ItemEvent e) {
numIdioma=idioma.getSelectedIndex();
canviaIdioma();
}
public void canviaIdioma() {
mainFrame.setTitle(Etiquetes.titolFrame[numIdioma]);
labelNomDestinatari.setText(Etiquetes.nomTo[numIdioma]);
labelNomRemitent.setText(Etiquetes.nomFrom[numIdioma]);
ok.setLabel(Etiquetes.ok[numIdioma]);
listInici.removeAll();
int totalHis=Etiquetes.hi[numIdioma].length;
for
(int i=0;i<totalHis;i++) {
listInici.add(Etiquetes.hi[numIdioma][i]);
}
listInici.select(1);
listFinal.removeAll();
int totalByes=Etiquetes.bye[numIdioma].length;
for
(int i=0;i<totalByes;i++) {
listFinal.add(Etiquetes.bye[numIdioma][i]);
}
listFinal.select(1);
idioma.removeAll();
int totalIdiomes=Etiquetes.idiomes.length;
for
(int i=0;i<totalIdiomes;i++) {
idioma.add(Etiquetes.idiomes[numIdioma][i]);
}
idioma.select(numIdioma);
enviar.setLabel(Etiquetes.enviar[numIdioma]);
preparaText();
mainFrame.validate();
}
|
|
public
void preparaText () {
text.setText(listInici.getSelectedItem()+
fieldNomDestinatari.getText()+ |
|
",\n\n
< . . . "+
Etiquetes.espaiText[numIdioma]+
"
. . . >\n\n"+ |
|
listFinal.getSelectedItem()+
",\n
"+
fieldNomRemitent.getText());
}
public void enviaMissatge() {
System.out.println(text.getText());
}
} |
|
|
|
Observem i entenguem... |
|
|
 |
- Hem mantingut ElMeuPanel
com a únic listener de tots
els esdeveniments.
- La finestra mainFrame,
que conté el panel ElMeuPanel
té un títol que cal que,
al demanar canvi d'idioma, també canviï. Per tal que el
mètode per canviar l'idioma
(public void canviaIdioma()) de ElMeuPanel
(que és l'únic listener)
pugui referir-se al mainFrame
que el conté, cal que ElMeuPanel
"sàpiga" qui és aquest Missatgeria02.
Per tant, ElMeuPanel ha de tenir una variable
de classe (Missatgeria02 mainFrame)
que contingui la referència
al Missatgeria02 contenidor.
Aquesta referència li passa
el mètode constructor de ElMeuPanel
que ara, en lloc de no tenir paràmetres,
té un paràmetre Missatgeria02.
- La classe ElMeuPanel
ha de ser listener d'esdeveniments,
tant java.awt.event.ActionEvent com
java.awt.event.ItemEvent. Per tant ha de ser definida
tot implementant les dues
interfaces java.awt.event.ActionListener
i java.awt.event.ItemListener. Vegeu la sintaxi
de la implementació, a la qual,
a la clàusula implements
hi segueixen els noms de les interfaces
separades per ",".
- La variable
int numIdioma s'inicialitza
amb el valor que hi ha definit a Etiquetes.
- Els controls (labels,
camps de text, àrea
de text, lists i el choice
per a l'idioma) es construeixen sense
textos ni ítems d'opció.
Igualment, el títol del mainFrame
és buit. Es reserva la càrrega dels textos
i dels ítems
al mètode public
void canviaIdioma(), el qual actuarà tant al fer una nova
selecció al choice, com
en el moment inicial, abans de la presentació de la GUI
a la pantalla.
- Com que mainFrame és
ItemListener, ha d'implementar
el mètode public
void itemStateChanged(ItemEvent e). No cal identificar l'origen
dels esdeveniments i només cal
fixar el nou valor de numIdioma
a partir de la lectura del choice,
i cridar al mètode per canviar
l'idioma (public void canviaIdioma()).
- El mètode
public void canviaIdioma() consisteix en determinar
els textos dels controls a partir del
valor de l'índex numIdioma i
dels valors de les
variables static de la classe
Etiquetes:
- El títol
del mainFrame es fixa mitjançant
el mètode public
void setTitle(String title) (classe
java.awt.Frame).
- El text dels
labels es fixa mitjançant el mètode
public void setText(String text) (classe
java.awt.Label).
- El text dels
botons es fixa mitjançant el mètode
public void setLabel(String text) (classe
java.awt.Button).
- Els lists
i el choice tenen un tractament
una mica més complicat:
- Es comença per buidar-los
amb el mètode public
void removeAll() (classes
java.awt.List i java.awt.Choice)
- Ara cal saber el nombre
d'ítems que han de contenir cadascun d'ells. Això
ho fem mitjançant la variable
length que està associada a
qualsevol array. Observeu que
això fa que no sigui necessari tenir el mateix nombre
d'ítems per a cada idioma i que puguem modificar
el nombre d'ítems
al fitxer Etiquetes.java
sense comprometre el funcionament del programa.
- Finalment, només cal omplir els
list i el choice
mitjançant sengles estructures
de control for() { ... }, controlades
pel nombre d'ítems llegit
abans.
- I, finalment, després de posar el text
adequat a l'àrea de text,
una línia de codi molt,
molt important:
El mètode public
void validate() de la classe
java.awt.Container (i, per tant, de totes
les seves subclasses o classes
filles, com ara java.awt.Frame
i java.awt.Panel) té, com a efecte,
redisposar (to lay out) tots els
components d'un container
i, si algun o alguns d'aquests components
també és un container,
redisposar-ne els components) tot
adaptant-se a les noves condicions després d'un canvi. En
el nostre exemple, hi ha un label amb
el text "Nom del destinatari: " (llarg)
que, al passar a l'anglès es converteix en "To:
" (curt). Si ometem mainFrame.validate(),
llavors els textos canvien, però no les dimensions
dels controls que els contenen. Això no és
greu al passar del català a l'anglès (el label
queda massa gros), però sí si hem començat
en anglès i passem al català (el label
queda petit i el nou text no hi cap. Proveu-ho!
|
|
|
|
Déu n'hi dó,
oi? |
|
|
|
|
|
|
|
|
 |
|
|
|
|