Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Calcula Dora
Calcula Dora
Ejemplo: 2 Calculadora
La Geb de Joaqun
Programacin JAVA
INTERFAZ GRFICO DE USUARIO
APLICACIONES DE EJEMPLO
1 EJEMPLO: CALCULADORA
1 EJEMPLO: CALCULADORA
1.1 Definicin del ejemplo
1.2 Diseo del interfaz grfico de usuario
1.3 Implementacin del interfaz grfico de usuario
1.4 Diseo del tratamiento de eventos
1.5 Implementacin de las clases de tratamiento de eventos
1.6 Diseo del control
1.7 Implementacin del control
Imagen j030101
El comportamiento de la calculadora tambin ser sencillo. Su esquema bsico de
funcionamiento lo programaremos con el siguiente patrn:
Imagen j030102
Por ejemplo, podemos ir pulsando la secuencia: 8*4=, obteniendo el resultado 32;
posteriormente, ir pulsando la secuencia -2=, obteniendo 30 y as sucesivamente.
Los operandos podrn ser valores numricos (enteros o decimales) con signo, por ejemplo 8,
8.2, -3, -309.6, 108.42345. Un operando del tipo definido lo podemos modelizar de la
siguiente manera:
Imagen j030103
Por ltimo, deseamos que la calculadora cumpla las siguientes condiciones:
-) Diseada segn los principios bsicos de la programacin orientada a objetos.
-) Utilizacin amplia de las posibilidades de Java que han sido estudiadas.
-) Los botones pueden definirse de diversos colores.
-) Cuando nos situamos sobre un botn, ste debe cambiar de color y, al salir de l, recuperar
el color original. Este comportamiento se debe cumplir tanto al usar el teclado como al usar el
ratn.
-) Cuando pulsemos una opcin no vlida (por ejemplo, un dgito despus del signo igual, dos
operadores seguidos, etc.), nos muestre una indicacin de error en el rea de resultados y el
botn pulsado de color rojo.
Imagen j030104
Las clases GUICalculadorax necesitan tener acceso a los botones individuales que se definen
en las clases Digitos y Operadores; de esta manera, se podr asignar diferentes objetos de
tratamiento de eventos a los botones. Tambin resulta necesario que las clases Digitos y
Operadores proporcionen sus respectivos paneles con la estructura de botones. Finalmente,
para permitir que los botones de cada panel presenten el color deseado, se proporciona un
constructor que admite un parmetro de tipo Color.
La clase Resultados proporciona un campo de texto deshabilitado que har las veces de visor
de la calculadora. A continuacin, se muestra el diseo de las clases Digitos, Operadores y
Resultados:
Imagen j030105
Imagen j030101
Clase Digitos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import
import
import
import
java.awt.Button;
java.awt.Panel;
java.awt.GridLayout;
java.awt.Color;
}// End
class Digitos;
import
import
import
import
java.awt.Button;
java.awt.Panel;
java.awt.GridLayout;
java.awt.Color;
=
=
=
=
new
new
new
new
Button("+");
Button("-");
Button("*");
Button("/");
MiPanel.setLayout(LayoutBotones);
for (int i=0; i<NUM_OPERADORES; i++){
Operador[i].setBackground(ColorBotones);
MiPanel.add(Operador[i]);
}
}
Operadores(){this(Color.lightGray);}
public Panel DamePanel() {
return MiPanel;}
public Button[] DameBotones(){
return Operador;}
}// End class Operadores
Clase Resultados
1
2
3
4
5
6
7
8
9
10
import java.awt.*;
public class Resultados
{
private Panel MiPanel = new Panel();
private TextField Resultado = new TextField("",10);
Resultados(Color ColorEtiqueta){
FlowLayout LayoutResultado = new FlowLayout(FlowLayout.LEFT);
MiPanel.setLayout(LayoutResultado);
Resultado.setForeground(ColorEtiqueta);
MiPanel.add(Resultado);
Resultado.setEnabled(false);
}
Resultados(){this(Color.black);}
public Panel DamePanel(){
return MiPanel;}
public TextField DameCampo(){
return Resultado;}
}// End
class Resultados;
import java.awt.*;
public class GUICalculadora1{
GUICalculadora1(){
Frame MiMarco = new Frame();
Panel MiPanel = new Panel();
BorderLayout PuntosCardinales = new BorderLayout();
MiPanel.setLayout(PuntosCardinales);
Digitos InstanciaDigitos = new Digitos(Color.orange);
Operadores InstanciaOperadores =
new Operadores(Color.magenta);
Resultados InstanciaResultados = new Resultados();
13
14
15
16
MiMarco.add(MiPanel);
MiPanel.add(
InstanciaOperadores.DamePanel(), BorderLayout.EAST);
MiPanel.add(
InstanciaDigitos.DamePanel(), BorderLayout.CENTER);
MiPanel.add(
InstanciaResultados.DamePanel(), BorderLayout.NORTH);
17
18
19
20
21
22
23
24
25
MiMarco.setSize(150,150);
MiMarco.setTitle("Calculadora");
MiMarco.setVisible(true);
}
Clase Calculadora1
6
Utilizando las clases Digitos, Operadores y Resultados, podemos crear de forma muy sencilla
nuevas apariencias de calculadoras:
Clase GUICalculadora2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.awt.*;
public class GUICalculadora2{
GUICalculadora2(){
Frame MiMarco = new Frame();
Panel MiPanel = new Panel();
FlowLayout TodoSeguido = new FlowLayout(FlowLayout.CENTER);
MiPanel.setLayout(TodoSeguido);
Digitos PanelDigitos = new Digitos(Color.cyan);
Operadores PanelOperadores = new Operadores(Color.green);
Resultados PanelResultados = new Resultados(Color.red);
MiMarco.add(MiPanel);
MiPanel.add(PanelOperadores.DamePanel());
MiPanel.add(PanelDigitos.DamePanel());
MiPanel.add(PanelResultados.DamePanel());
MiMarco.setSize(250,150);
MiMarco.setTitle("Calculadora Dos");
MiMarco.setVisible(true);
}
}// end class GUICalculadora2
Clase PruebaCalculadora2
1
2
3
4
5
Imagen j030106
Imagen j030107
Imagen j030108
import java.awt.event.*;
public class ControlVentana extends WindowAdapter{
public void windowsClosing(WindowEvent EventoQueLlega){
System.exit(0);
}
}
La clase controlFoco se encarga de variar el color de los botones a medida que el usuario se
desplaza por ellos usando el teclado. El mtodo focusGained (lnea 12) pone los botones por
los que se pasa en color verde y el mtodo focusLost (lnea 17) los pone, al salir, del color
original (lnea 19).
Clase controlFoco
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.awt.event.*;
import java.awt.*;
public class ControlFoco implements FocusListener{
private Color ColorBoton;
ControlFoco(Color ColrBoton){
this.ColorBoton=ColorBoton;
}
public void focusGained(FocusEvent EventoQueLlega){
Button Boton = (Button) EventoQueLlega.getSource();
Boton.setBackground(Color.green);
}
public void focusLost(FocusEvent EventoQueLlega){
Button Boton = (Button) EventoQueLlega.getSource();
Boton.setBackground(ColorBoton);
}
}//end class ControlFoco
10
import java.awt.event.*;
import java.awt.*;
public class ControlRaton extends MouseAdapter{
private TextField Resultado;
private Color ColorBoton;
ControlRaton(TextField Resultado, Color ColorBoton){
this.Resultado = Resultado;
this.ColorBoton = ColorBoton;
}
public void mouseClicked(MouseEvent EventoQueLlega){
Button Boton = (Button) EventoQueLlega.getSource();
char Car = Boton.getLabel().charAt(0);
System.out.print(Car);
try{
Automata.CaracterIntroducido(Car);
}
catch(OpcionErronea e){
Resultado.setText(e.getMessage());
Boton.setBackground(Color.red);
}
}
public void mouseEntered(MouseEvent EventoQueLlega){
Button Boton = (Button) EventoQueLlega.getSource();
Boton.setBackground(Color.green);
}
Para finalizar este apartado, se presenta la clase GUICalculadora1 completa, con los
tratamientos de eventos asociados a los botones. En las lneas 20 a 22 se obtienen las
referencias de los botones y el campo de texto que componen la calculadora; para ello, se hace
uso de los mtodos DameBotones y DameCampo pertenecientes a las clases Digitos,
Operadores y Resultados. En la lnea 23 se instancia el autmata de control que veremos en el
prximo apartado.
En las lneas 25 a 35 se asocian instancias de las clases de tratamientos de eventos
ControlRaton y ControlFoco a todos los botones de la calculadora; finalmente, en la lnea 37
se asocia una instancia de la clase ControlVentana al marco principal de la aplicacin
(MiMarco).
Clase GUICalculadora1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.awt.*;
public class GUICalculadora1{
GUICalculadora1(){
Frame MiMarco = new Frame();
Panel MiPanel = new Panel();
BorderLayout PuntosCardinales = new BorderLayout();
MiPanel.setLayout(PuntosCardinales);
Digitos InstanciaDigitos = new Digitos(Color.orange);
Operadores InstanciaOperadores =
new Operadores(Color.magenta);
Resultados InstanciaResultados = new Resultados();
MiMarco.add(MiPanel);
MiPanel.add(
InstanciaOperadores.DamePanel(), BorderLayout.EAST);
MiPanel.add(
InstanciaDigitos.DamePanel(), BorderLayout.CENTER);
MiPanel.add(
InstanciaResultados.DamePanel(), BorderLayout.NORTH);
// Eventos
Button[] BotonesDigitos = InstanciaDigitos.DameBotones();
Button[] BotonesOperadores =
InstanciaOperadores.DameBotones();
TextField Resultado = InstanciaResultados.DameCampo();
Automata InstanciaAutomata = new Automata(Resultado);
for (int i=0; i<BotonesDigitos.length; i++){
BotonesDigitos[i].addMouseListener(
new ControlRaton(Resultado, Color.orange));
BotonesDigitos[i].addFocusListener(
new ControlFoco(Color.orange));
11
}
for (int i=0; i<BotonesOperadores.length; i++){
BotonesOperadores[i].addMouseListener(
new ControlRaton(Resultado, Color.orange));
BotonesOperadores[i].addFocusListener(
new ControlFoco(Color.orange));
}
MiMarco.addWindowListener(new ControlVentana());
MiMarco.setSize(150,150);
MiMarco.setTitle("Calculadora");
MiMarco.setVisible(true);
}
_
} // end class GUICalculadora1
Imagen j030109
El esquema completo de clases de la aplicacin nos queda de la siguiente manera:
12
Imagen j030110
Siguiendo el modelo grfico con el que formalizbamos el formato de un nmero, podemos
establecer el control completo de la calculadora. Recordemos que el esquema general es:
Imagen j030111
... y el de un nmero:
Imagen j030112
Combinando los dos grafos anteriores, podemos obtener con facilidad el autmata de estados
en el que nos vamos a basar para implementar el control de la calculadora. Las cajas
representan los diferentes estados en los que nos podemos encontrar y las flechas son las
transiciones permitidas desde cada uno de esos estados. Numerando los estados, en el grfico
siguiente, podemos expresar, por ejemplo, que en el estado 5 hemos recibido un nmero y un
operador y estamos a la espera de un dgito o del signo "-".
13
Imagen j030113
Siguiendo el esquema, nos resulta muy sencillo saber cmo vamos evolucionando segn el
usuario pulsa botones; tambin resulta inmediato conocer las pulsaciones permitidas en cada
situacin (por ejemplo, en el estado 7 solo podemos admitir como vlidas las pulsaciones en
los botones punto, igualo cualquier dgito).
Imagen j030114
Las propiedades que necesitaremos para almacenar el estado del autmata son Estado (indica
el valor numrico del estado en el que nos encontramos), Visor (contiene los ltimos
caracteres pulsados), Operador (operador seleccionado), Operando1 y Operando2 (valores a
partir de los que se calcula el resultado).
A modo de ejemplo, hemos definido estas propiedades como estticas, as como el mtodo
CaracterIntroducido que las utiliza: la aplicacin funciona correctamente y evitamos tener que
pasar la referencia de la instancia del autmata hasta la clase ControlRaton; sin embargo,
debemos tener en cuenta que si en una misma aplicacin deseamos crear ms de una
calculadora, el control no funcionara, puesto que todas las calculadoras de la aplicacin
compartiran las mismas propiedades de estado. Si cada calculadora se encontrase en una
aplicacin separada, s funcionara, puesto que cada calculadora se ejecutara sobre una JVM
diferente.
Evitar las propiedades estticas en nuestra aplicacin es muy sencillo, basta con pasar a la
clase ControlRaton la referencia del objeto Automata y, en su lnea 19, utilizar la referencia
en lugar del nombre de la clase.
El cdigo de la clase Automata sigue el diseo realizado: su mtodo Caracterlntroducido
consulta en primer lugar el estado en el que se encuentra el autmata (lnea 19) para realizar
un tratamiento u otro (marcado por el grafo de estados desarrollado en el apartado anterior);
se consulta el carcter que nos llega (lneas 22, 48, etc.), correspondiente al ltimo botn
pulsado por el usuario y se acta en consecuencia.
Por ejemplo, si estamos en el estado 1 (lnea 47) y nos llega un dgito (lneas 49 a 58),
pasamos al estado 2 (tal y como marca el grafo de estados) y actualizamos el visor de la
calculadora (lnea 60); si nos llega un carcter distinto a un dgito (lnea 62), nos encontramos
ante un error del usuario, por 10 que volvemos al estado O del autmata (lnea 63) y
levantamos la excepcin OpcionErronea (lnea 64).
Los dems estados se tratan de una manera anloga al explicado; en todos se levanta la misma
excepcin (OpcionErronea) cuando llega un carcter equivocado. Resultara muy sencillo y
til pasarle a la excepcin un texto indicando los caracteres permitidos en cada caso, por
ejemplo, en el estado 10: throw new OpcionErronea("+-*/,,), incorporando un constructor con
parmetro de tipo String a la excepcin OpcionErronea.
Los resultados se calculan cuando nos encontramos en el estado 9 (lnea 260) y nos llega el
carcter "=" (lnea 262): pasamos al estado 10 (lnea 263), obtenemos el segundo operando a
partir de los caracteres almacenados en el visor (lnea 264), calculamos el resultado (lnea
265), lo visualizamos (lnea 266) y asignamos el resultado como primer operando para la
siguiente operacin (lnea 267).
La clase OpcionErronea se ha mantenido lo ms sencilla posible; nicamente almacena el
texto "No valido" como indicacin de la causa de la excepcin, que siempre levantamos
cuando el usuario pulsa un botn inapropiado. El cdigo de esta clase se muestra al final del
apartado.
Clase OpcionErronea
1
15
OpcionErronea(){
super("No valido");
}
}
Clase Automata
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
16
import java.awt.TextField;
public class Automata {
private static
private static
private static
private static
private static
// hay un espacio
// para evitar un
byte Estado = 0;
TextField Visor;
double Operando1=0d;
double Operando2=0d;
char Operador= ' ';
entre las dos comillas sencillas
error de compilacion
case 1:
switch(Car){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=2;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 2:
switch(Car){
case '.':
Estado=1;
Visor.setText(Visor.getText()+Car);
break;
case '+':
case '-':
case '*':
case '/':
Estado=5;
Operador=Car;
Operando1=Double.parseDouble(Visor.getText());
Visor.setText("");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=2;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 3:
switch(Car){
case '0':
case '1':
case '2':
17
18
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=4;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 4:
switch(Car){
case '+':
case '-':
case '*':
case '/':
Estado=5;
Operador=Car;
Operando1=Double.parseDouble(Visor.getText());
Visor.setText("");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=4;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 5
switch(Car){
case '-':
Estado=6;
Visor.setText(Visor.getText()+Car);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=7;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 6:
switch(Car){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=7;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 7:
switch(Car){
case '.':
Estado=8;
Visor.setText(Visor.getText()+Car);
break;
case '=':
Estado=10;
Operando2=Double.parseDouble(Visor.getText());
double Resultado=ObtenerResultado();
Visor.setText(String.valueOf(Resultado));
Operando1=Resultado;
break;
case
case
case
case
'0':
'1':
'2':
'3':
19
20
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=7;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 8:
switch(Car){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=9;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 9:
switch(Car){
case '=':
Estado=10;
Operando2=Double.parseDouble(Visor.getText());
double Resultado=ObtenerResultado();
Visor.setText(String.valueOf(Resultado));
Operando1=Resultado;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Estado=9;
Visor.setText(Visor.getText()+Car);
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
case 10:
switch(Car){
case '+':
case '-':
case '*':
case '/':
Estado=5;
Operador=Car;
Visor.setText("");
break;
default:
Iniciar();
throw new OpcionErronea();
}
break;
}// End switch(Estado)
}// End Funcion CaracterIntroducido
21
Referencia Bibliogrfica
Java a travs de ejemplos
Jess Bobadilla Sancho / Adela Sancho Hernndez
RA-MA
ISBN.: 84-7897-549-7
22