Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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.
Java - Interfaz Grfico De Usuario (AWT) Ejemplo: 2 Calculadora GUICalculadora2, etc. El esquema de clases, hasta el momento, nos queda de la siguiente manera:
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
Java - Interfaz Grfico De Usuario (AWT) Ejemplo: 2 Calculadora travs del mtodo DameBotones (lnea 35). El color de los botones se determina en la llamada al constructor con parmetro (lneas 12 y 25); el constructor vaco asigna el color gris claro (lnea 30). Los botones se sitan en una disposicin GridLayout de 4 x 3 (lneas 13 y 22); las tres primeras filas albergan los dgitos de 0 a 8 (lneas 14 a 16) y la tercera el dgito 9, el punto y el igual (lneas 19 a 21).
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;
public class Digitos { private Panel MiPanel = new Panel(); private final int NUM_DIGITOS=12; private Button[] Digito = new Button[NUM_DIGITOS]; Digitos(Color ColorBotones) { GridLayout LayoutBotones = new GridLayout(4,3); for (int fila=0; fila<3; fila++){ for (int col=0; col<3; col++){ Digito[fila*3+col] = new Button(String.valueOf(fila*3+col)); } } Digito[9] = new Button("9"); Digito[10] = new Button("."); Digito[11] = new Button("="); MiPanel.setLayout(LayoutBotones); for (int i=0; i<NUM_DIGITOS; i++){ Digito[i].setBackground(ColorBotones); MiPanel.add(Digito[i]); } } Digitos(){this(Color.lightGray);} public Panel DamePanel(){ return MiPanel;} public Button[] DameBotones(){ return Digito;}
Las clases Operadores y Resultados siguen el mismo esquema que Digitos: Clase Operadores
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 import import import import java.awt.Button; java.awt.Panel; java.awt.GridLayout; java.awt.Color;
public class Operadores { private Panel MiPanel = new Panel(); private final int NUM_OPERADORES=4; private Button[] Operador = new Button[NUM_OPERADORES]; Operadores(Color ColorBotones){ GridLayout LayoutBotones = new GridLayout(NUM_OPERADORES,1); Operador[0] Operador[1] Operador[2] Operador[3] = = = = 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);
La clase GUICalculadora1 implementa el interfaz de calculadora que se ha presentado en el primer apartado: "Definicin del ejemplo". Primero, se define un panel con disposicin BorderLayout (lneas 7 a 9); posteriormente, se crea una instancia de la clase Digitos, otra de la clase Operadores y una tercera de la clase Resultados (lneas 11 a 13). Finalmente, se obtienen los paneles de cada una de las instancias y se sitan en las posiciones este, centro y norte de nuestro panel (lneas 16 a 18). Clase GUICalculadora1 (Elemental)
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 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); MiMarco.setSize(150,150); MiMarco.setTitle("Calculadora"); MiMarco.setVisible(true); } } // end class GUICalculadora1
Clase Calculadora1
1 public class Calculadora1{
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 public class PruebaCalculadora2{ public static void main(String[] args){ GUICalculadora2 MiCalculadora = new GUICalculadora2(); } }
Imagen j030106
Imagen j030107
La clase de tratamiento de eventos de ratn (ControlRaton) contiene un constructor que permite indicar el color del fondo de los botones y el campo de texto que hace de visor de la calculadora. El primer parmetro sirve para que el mtodo mouseExited restituya el color de cada botn al salir de l (mouseEntered pone de color verde cada botn en el que se coloca el puntero del ratn). El segundo parmetro (TextField) permite que el mtodo mouseClicked site en el visor un mensaje de situacin errnea (circunstancia que conoce por la llegada de la excepcin OpcionErronea).
Imagen j030108
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);
El ltimo de los controladores de eventos utilizados en nuestro ejemplo es ControlRaton, de tipo MouseAdapter. Su constructor (lnea 9) permite indicar el color de los botones y el visor (de tipo TextField) que se est utilizando. Los mtodos mouseEntered (lnea 26) y mouseExited (lnea 31) realizan en esta clase la misma accin que focusGained y focusLost en la clase anterior; de esta forma, el color de los botones tambin vara al desplazamos con el ratn. El mtodo mouseClicked (lnea 14) obtiene el botn que gener el evento (lnea 15) y, posteriormente, extrae el primer carcter de su etiqueta (lnea 16). El carcter obtenido ("0", "1" ..., "9", "+", "-", "*", "/", ".", "=") se pasa a un mtodo de la clase Automata para que lo procese; esta clase se explica en el siguiente apartado; se puede producir una excepcin del tipo OpcionErronea si el botn seleccionado es inadecuado (lnea 21), en cuyo caso se coloca un mensaje de error sobre el visor (lnea 22) y se asigna el color rojo al botn que ha sido pulsado (lnea 23). Clase ControlRaton
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 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); }
10
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
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 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 public class OpcionErronea extends Exception{
15
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 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
Automata(TextField Visor) {this.Visor = Visor;} public static void CaracterIntroducido(char Car) throws OpcionErronea{ if (Visor.getText().equals("No valido")) Visor.setText(""); switch(Estado){ case 0: switch(Car){ case '-': Estado=1; 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=2; Visor.setText(Visor.getText()+Car); break; default: Iniciar(); throw new OpcionErronea(); } break;
16
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;
17
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':
18
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
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;
20
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
private static void Iniciar(){ Estado=0; Visor.setText(""); Operando1=0f; Operando2=0d; Operador=' '; } private static double ObtenerResultado(){ switch(Operador){ case '+': return Operando1+Operando2; case '-': return Operando1-Operando2; case '*': return Operando1*Operando2; case '/': return Operando1/Operando2; default: return 0d; }// end _switch(Operador) } }// end class Automata
21
Referencia Bibliogrfica
Java a travs de ejemplos Jess Bobadilla Sancho / Adela Sancho Hernndez RA-MA ISBN.: 84-7897-549-7
22