|
|
|
|
La GUI (Graphics User Interface)
(I) |
|
|
|
|
|
O sigui, allò
que l'usuari veu a la pantalla de la màquina i que li serveix per
interactuar amb l'aplicació. |
|
|
|
|
|
Què volem fer? |
|
|
|
|
|
|
Ho hem previst a la planificació
de la pràctica anterior. Justament això: |
|
|
|
|
|
Fase
del disseny de la o les GUIs (Graphics
User Interface: Interfícies gràfiques d'usuari) |
GUI
: Una sola finestra (JFrame), amb |
Un MonVisible, fill de JPanel,
on es visualitzen els estats del món,
Un JPanel amb quatre
JButtons per a les accions de "Pas a pas",
"Engegar/parar el procés continu",
"Extermini" i "Sortir".
El JButton "Pas a pas"
ha de quedar inhabilitat quan estigui en marxa el procés
continu, i
El JButton "Engegar/parar
el procés continu" ha de canviar d'etiqueta
segons el procés continu estigui actiu o no.
|
|
|
|
|
|
|
 |
Toca, doncs, obrir
i crear un nou projecte: JocDeLaVida. Aquest projecte
el pots posar a qualsevol carpeta de la teva màquina. Inmediatament
ja pots crear-hi la classe Finestra, derivada
de javax.swing.JFrame: |
|
|
|
|
|
|
|
|
|
|
 |
import javax.swing.JFrame;
/**
* Escriviu aquí una descripcìó de la classe
Finestra
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Finestra extends JFrame {
}
|
|
|
|
|
|
|
Com que la classe Finestra
és filla de la classe javax.swing.JFrame,
la primera línia és imprescindible: calia importar
la classe javax.swing.JFrame! |
|
|
|
|
|
Ara pots compilar i crear un
objecte de la classe Finestra: l'objecte es crea
i no passa rés més... Cal configurar-la! |
|
|
|
|
|
Tot construïnt la finestra... |
|
|
|
|
|
|
Doncs això: has d'escriure-li
un mètode constructor. Aquest mètode ha de fer tres coses: |
|
|
|
|
|
- Determinar el títol, l'aspecte i les mides generals
de la finestra Finestra,
- Posar-hi els controls (botons, etc.) que hagi de contenir
i distribuir-los adequadament, i
- Fer-la visible i iniciar l'aplicació.
|
|
|
|
|
|
Si després, quan tot ja
funcioni, vols fer-hi millores, t'anirà bé que, des del començament,
el codi sigui el més clar possible. En conseqüència,
el mètode constructor ha de tenir aquest aspecte (no compilis ara,
que hi ha tres mètodes encara no implementats!): |
|
|
|
|
 |
/**
* Mètode constructor per a
objectes de la classe Finestra.
*/
public Finestra () { //
constructor
setConfiguracio();
setControls();
inicia();
}
|
|
|
|
|
|
|
de manera que cadascuna de les
coses que ha de fer estan segregades en mètodes a part. |
|
|
|
|
|
Naturalment, per tal que puguis
compilar, els tres mètodes han d'estar ja a la classe: |
|
|
|
|
 |
import
javax.swing.JFrame;
/**
* Escriviu aquí una descripcìó de la classe Finestra
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Finestra extends JFrame {
/**
* Mètode constructor per a objectes
de la classe Finestra.
*/
public Finestra () { //
constructor
setConfiguracio();
setControls();
inicia();
}
/**
* Mètode que fixa els paràmetres
generals d'aquesta Finestra.
*/
private void setConfiguracio () {
}
/**
* Mètode que crea i distribueix
els controls d'aquesta
* Finestra.
*/
private void setControls () {
}
/**
* Mètode que inicia l'aplicació.
*/
private void inicia () {
}
} |
|
|
|
|
|
|
Primer que tot: que funcioni! |
|
|
|
|
|
|
Per tal que puguis veure tot
allò que aniràs afegint, necessites veure efectivament la
finestra. Cal començar, doncs, pel mètode inicia(): |
|
|
|
|
 |
/**
* Mètode que inicia l'aplicació.
*/
private void inicia () {
show();
}
|
|
|
|
|
|
|
Per ara, simplement, es tracta
de cridar el mètode show() de la classe
java.awt.Window, mare de javax.swing.JFrame
i, per tant de la nostra classe Finestra, el qual
s'ocupa de fer visible la finestra (representada per la classe Finestra).
Si consultes la documentació de la classe java.awt.Window,
veuràs que, si ja era visible, el mètode portarà la
finestra a primer pla. |
|
|
|
|
|
Si ara compiles i crees un objecte
de la classe Finestra, ara ja passen coses: |
|
|
|
|
|
No passa res? Sí, sí
que passa. A la part superior esquerra de la pantalla hi ha aparegut, discretament,
això sí, la nostra Finestra! |
|
|
|
|
|
|
|
|
|
|
|
Sí, sí: amb el
ratolí la pots fer més gran: |
|
|
|
|
|
|
|
|
|
|
|
i convencer-te que la finestra
existeix... |
|
|
|
|
|
La configuració general
de la finestra |
|
|
|
|
|
|
Inmediatament tens la tentació
de cridar el mètode setSize(int width, int height) per tal que la
Finestra aparegui una mica més gran i no
calgui buscar-la pels racons... El lloc adequat de la crida a aquest mètode
seria el mètode setConfiguracio() |
|
|
|
|
|
/**
* Mètode que fixa els paràmetres
generals d'aquesta Finestra.
*/
private void setConfiguracio () {
setSize(400,300);
// La Finestra tindrà
400 pixels d'ample
// i 300 pixels d'altura.
}
|
|
|
|
|
|
|
Prova-ho: Afegeix aquesta línia
al mètode setConfiguracio(),compila i crea
un objecte de la classe Finestra: |
|
|
|
|
|
|
|
|
|
|
|
Voilà! això ja
és tota una altra cosa! |
|
|
|
|
 |
Però, però,
però,... no, no i no! Has oblidat que Java
és multiplataforma i que allò que veus d'una certa
manera a la teva màquina, amb el teu sistema operatiu
i sistema de finestres pot veure's de manera força diferent a d'altres
màquines i a d'altres sistemes operatius. Deixa que Java
faci la feina i que adapti les dimensions de la Finestra
a les necessitats d'espai d'allò que conté. Mai, mai has de
començar amb les dimensions de la finestra principal, Java
s'ocuparà de fer-la prou gran (o prou petita) per tal que hi càpiga
tot. |
|
|
|
|
 |
Esborra, doncs, la línia
setSize(400,300), amb el benentès que,
fins que no posem coses a la Finestra, aquesta
tindrà unes dimensions mínimes. |
|
|
|
|
|
Preocupa't, per ara, només
del comportament i del títol: |
|
|
|
|
 |
/**
* Mètode que fixa els paràmetres
generals d'aquesta Finestra.
*/
private void setConfiguracio () {
setTitle("El
Joc de la Vida..."); //
El títol
setResizable(true);
// La Finestra es podrà
fer més gran
// o més petita amb el ratolí
setDefaultCloseOperation(EXIT_ON_CLOSE); //
La finestra es
//
tancarà amb el
// botó "X" de
//
tancar.
}
|
|
|
|
|
|
|
Compila i crea un objecte Finestra,
el qual tornarà a ser una finestra molt petita. Fes-la més
gran amb el ratolí i en veuràs el títol. Comprova que,
amb el botó "X", es tanca. |
|
|
|
|
|
|
|
|
|
|
|
Omplim la finestra amb els
controls |
|
|
|
|
|
|
Ara ja pots omplir el mètode
setControls() i, en consequència, la finestra
Finestra. A la llista de la planificació
prèvia hi apareix un fill de JPanel
anomenat MonVisible, que és on es visualitzen,
a temps real, els successius estats del món. |
|
|
|
|
|
Hem de fer dues coses: |
|
|
|
|
|
- Crear, és a dir, escriure el codi de la classe
MonVisible, i
- Posar el JPanel MonVisible
a la Finestra.
|
|
|
|
|
|
Anem per parts: construir el MonVisible i posar-lo
al seu lloc és el que t'explicarem d'aquí al final de la
pràctica; els botons els reservem per la pràctica següent.
|
|
|
|
|
|
1.
Crear el MonVisible |
|
|
|
|
|
|
Comencem: al projecte JocDeLaVida,
crea la nova classe MonVisible: |
|
|
|
|
|
import javax.swing.JPanel;
/**
* La classe MonVisible representa el panell de visualització
d'allò
* que es va esdevenint en el "Joc de la Vida".
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class MonVisible extends JPanel {
}
|
|
|
|
|
|
|
Com que has de dibuixar-hi
(paint) els éssers, ha de ser un JPanel.
I, com que no actuarà com a contenidor (java.awt.Container)
d'altres components (java.awt.Component) has de
definir-ne explicitament les dimensions que volsque tingui, perquè
no hi haurà res a dintre que les determini: el dibuixos no
determinen dimensions! |
|
|
|
|
|
Amb
això, anirà bé, cara a possibles perfeccionaments,
que la classe Finestra concentri el comanament
de l'aplicació i, per tant, les dimensions d'aquest MonVisible.
Això implica afegir a la classe Finestra
un nou mètode, amb aquest contingut provisional: |
|
|
|
|
|
import javax.swing.JFrame;
import java.awt.Dimension;
/**
* Escriviu aquí una descripcìó de la classe
Finestra
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Finestra extends JFrame {
/**
* Mètode constructor per a
objectes de la classe Finestra.
*/
public Finestra () { // constructor
setConfiguracio();
setControls();
inicia();
}
/**
* Mètode que fixa les dimensions
del MonVisible.
* ATENCIÓ: CONTINGUT PROVISIONAL!
* @return les dimensions del
MonVisible
*/
public Dimension getDimensionsMonVisible
() {
return new Dimension(400,300);
}
/**
* Mètode que fixa els paràmetres
generals d'aquesta Finestra.
*/
private void setConfiguracio () {
setTitle("El
Joc de la Vida..."); // El títol
setResizable(true);
// La Finestra es podrà fer més gran
// o més petita amb el ratolí
setDefaultCloseOperation(EXIT_ON_CLOSE); //
La finestra es
//
tancarà amb el
// botó "X" de
//
tancar.
}
/**
* Mètode que crea i distribueix
els controls d'aquesta
* Finestra.
*/
private void setControls () {
}
/**
* Mètode que inicia l'aplicació.
*/
private void inicia () {
show();
}
}
|
|
|
|
|
|
|
a l'espera de disposar d'alguna
manera més adequada de calcular les dimensions del MonVisible.
Observa que, com que el mètode getDimensionsMonVisible()
retorna un objecte java.awt.Dimension, cal importar
aquesta classe. |
|
|
|
|
|
Tornem a la classe MonVisible:
per tal que els objectes d'aquesta classe puguin demanar el mètode
getDimensionsMonVisible(), ha d'haver-hi una
variable d'instància que contingui la Finestra.
El valor d'aquesta variable cal demanar-lo en el moment de construir els
objectes MonVisible. El mètode constructor
de la classe ha de ser alguna cosa com això: |
|
|
|
|
|
import javax.swing.JPanel;
/**
* La classe MonVisible representa el panell de visualització
d'allò
* que es va esdevenint en el "Joc de la Vida".
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class MonVisible extends JPanel {
/**
* La Finestra que conté aquest
MonVisible.
*/
protected Finestra finestra;
/**
* Mètode constructor per a
objectes de la classe MonVisible.
* @param finestra La Finestra que
conté aquest MonVisible
*/
public MonVisible(Finestra
finestra) { // constructor
this.finestra=finestra;
}
}
|
|
|
|
|
|
|
I, per fixar-ne les dimensions,
has de cridar el mètode public void setPreferredSize(Dimension
preferredSize) de la classe javax.swing.JComponent,
de la qual és filla javax.swing.JPanel: |
|
|
|
|
|
import javax.swing.JPanel;
import java.awt.Dimension;
/**
* La classe MonVisible representa el panell de visualització
d'allò
* que es va esdevenint en el "Joc de la Vida".
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class MonVisible extends JPanel {
/**
* La Finestra que conté aquest
MonVisible.
*/
protected Finestra finestra;
/**
* Mètode constructor per a
objectes de la classe MonVisible.
* @param finestra La Finestra que
conté aquest MonVisible
*/
public MonVisible(Finestra finestra) { //
constructor
this.finestra=finestra;
setPreferredSize(finestra.getDimensionsMonVisible());
}
}
|
|
|
|
|
|
|
2. Posar el MonVisible a la
Finestra |
|
|
|
|
|
|
Ara ja es pot afegir el component
MonVisible a la Finestra.
De fet, no s'afegeix a la Finestra sinó
al contenidor JRootPane que un JPanel
(i, en conseqüència, Finestra) per
defecte, ja conté. Aquest contenidor s'obté mitjançant
el mètode public Container getContentPane().
|
|
|
|
|
|
Recorda que aquest JRootPane
té, per defecte, com a layout, java.awt.BorderLayout,
cosa que cal tenir en compte a l'hora de posar-hi components. A més,
caldrà importar aquesta classe java.awt.BorderLayout! |
|
|
|
|
|
Ja es pot preveure que convé
que el MonVisible sigui accessible per d'altres
mètodes i classes. Per tant el posem com a variable d'instància
a la classe Finestra i el construïm i el
coloquem en el mètode setControls(); |
|
|
|
|
|
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.BorderLayout;
/**
* La classe Finestra és la classe arrel de l'aplicació
del Joc
* de la Vida.
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class Finestra extends JFrame {
/**
* L'objecte MonVisible que fa visibles
els éssers
* del món.
*/
protected MonVisible
monVisible;
/**
* Mètode getter per a la variable
monVisible
* @return el MonVisible d'aquesta
finestra
*/
public MonVisible
getMonVisible () {
return monVisible;
}
/**
* Mètode constructor per a
objectes de la classe Finestra.
*/
public Finestra () { // constructor
setConfiguracio();
setControls();
inicia();
}
/**
* Mètode que fixa les dimensions
del MonVisible.
* ATENCIÓ: CONTINGUT PROVISIONAL!
* @return les dimensions del
MonVisible
*/
public Dimension getDimensionsMonVisible
() {
return new Dimension(400,300);
}
/**
* Mètode que fixa els paràmetres
generals d'aquesta Finestra.
*/
private void setConfiguracio () {
setTitle("El
Joc de la Vida..."); // El títol
setResizable(true);
// La Finestra es podrà fer més gran
// o més petita amb el ratolí
setDefaultCloseOperation(EXIT_ON_CLOSE); //
La finestra es
//
tancarà amb el
// botó "X" de
//
tancar.
}
/**
* Mètode que crea i distribueix
els controls d'aquesta
* Finestra.
*/
private void setControls () {
monVisible=new
MonVisible(this); // Li passem
aquesta
//
Finestra com a parà-
//
metre
getContentPane().add(monVisible,
BorderLayout.CENTER); //
El posem a
//
la posició
//
CENTER
}
/**
* Mètode que inicia l'aplicació.
*/
private void inicia () {
pack();
// Adapta les dimensions d'aquesta
Finestra a allò
//
que es necessita, segons els components que
//
contingui.
show();
}
}
|
|
|
|
|
|
|
i encara calia una altra cosa:
fer que el JFrame Finestra
adapti les seves dimensions a les dels objectes que conté (per ara
només el MonVisible). Això ho fa
el mètode public void pack(), de la classe
java.awt.Window, de la qual JFrame
i, per tant, Finestra en són filles. Aquest
mètode, que cal cridar després d'haver incorporat tots els
controls, té el seu lloc natural al mètode inicia(); |
|
|
|
|
 |
Ja pots compilar tot el paquet
i crear un objecte de la classe Finestra. Has d'obtenir quelcom semblant
a això: |
|
|
|
|
|
|
|
|
|
|
|
Una mica avorrida aquesta Finestra,
oi? Passa que el MonVisible hi és (en determina
les dimensions!) però no se'n veu res, perquè no hi has pintat
res. |
|
|
|
|
|
Bé, pinta-hi, com a mínim,
el fons! A la classe MonVisible afegeix-li (sobreescriu,
override) el mètode public void paint (Graphics
g): |
|
|
|
|
|
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Color;
/**
* La classe MonVisible representa el panell de visualització
d'allò
* que es va esdevenint en el "Joc de la Vida".
*
* @author (el vostre nom)
* @version (un número de versió o la data)
*/
public class MonVisible extends JPanel {
/**
* La Finestra que conté aquest
MonVisible.
*/
protected Finestra finestra;
/**
* Mètode constructor per a
objectes de la classe MonVisible.
* @param finestra La Finestra que
conté aquest MonVisible
*/
public MonVisible(Finestra finestra) { //
constructor
this.finestra=finestra;
setPreferredSize(finestra.getDimensionsMonVisible());
}
/**
* Mètode paint per a aquest
MonVisible.
* @param un objecte java.awt.Graphics
*/
public
void paint (Graphics g) {
Graphics2D
g2d=(Graphics2D)g; // La classe
Graphics2D di-
//
buixa molt millor que la
//
classe Graphics
//
Els RenderingHint(s) per millorar els gràfics
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.BLUE);
// Pinta blau...
int
ample=getSize().width; // Les
dimensions del MonVisible
int
alt=getSize().height;
g2d.fill3DRect(0,0,ample,alt,false);
// Pinta un rectangle
//
esfonsat de color
//
blau, que ocupa
//
tot el MonVisible
}
}
|
|
|
|
|
|
|
Torna a compilar i a crear un
objecte Finestra: |
|
|
|