Objetivo interfas a codigo
-
Upload
robert-wolf -
Category
Documents
-
view
106 -
download
0
description
Transcript of Objetivo interfas a codigo
Objetivo: Introducir al estudiante en la programación de interfaces graficas de
usuario utilizando Java
A quien está
dirigido:
Estudiantes con conocimientos básicos de programación orientada a
objetos con Java, en particular deben de conocer los conceptos de:
Clases
Objetos
Herencia
Clases abstractas e interfaces
Competencia
esperada:
Al concluir el presente tutorial el estudiante debe de comprender que partes
de la API de Java puede utilizar para construir interfaces graficas de
usuario (GUIs), y la forma en que Java implementa el patrón observer.
Estilo: Guía paso a paso, el lector encontrará varias versiones del código, hacemos
esto para enfatizar lo que hace cada parte del código.
Interfaces graficas en Java
Para empezar la discución de como realizar interfaces graficas en Java, debemos
primero realizar algunas aclaraciones:
El concepto de "Interfaz de usuario" se refiere a los mecanismos para
construir ventanas, botones, menus, etc que permiten crear una interfaz
amigable para nuestros programas y no al concepto de "interface" que
existe en Java y que se refiere a una especie de clase abstracta pura.
Los mecanismos para crear "interfaces de usuario" en Java están pensados
para favorecer la creación de la lógica de negocio separada de la creación
de la interfaz de usuario. Sin embargo, no hay garantía de que esto suceda.
Es responsabilidad del programador cristalizar este objetivo. Para poder
lograrlo le sugerimos al lector estudiar el patron de diseño conocido como
MVC. Ligas a MVC: Spring Tutorial Patron
Para el manejo de eventos Java utiliza un modelo en el cual existe un
"ente" generador de eventos y otros "entes" interesados en dar respuesta a
los eventos. Cuando un evento se produce, el generador del evento avisa a
todos los "entes" que hayan manifestado su interes en el evento. Y cada
uno de los interesados responderá al evento utilizando su propia lógica.
Para mayor claridad construiremos un ejemplo completo poco a poco; sin
embargo debemos advertir que se asume que el lector está familiarizado con
conceptos como: clase, objeto, mensaje, constructora, referencias, imports,
herencia e interfaces.
Construiremos una calculadora de senos, cosenos y tangentes de ángulos.
Construcción de una ventana
1 import javax.swing.*;
2
3 public class Trigo extends JFrame{
4
5 }
En la primera línea simplemente importamos el paquete donde está definida la
clase JFrame. Un JFrame es la clase que representa al tipo "Ventana". En otras
palabras un "JFrame" es una ventana del sistema operativo. Como nuestra clase
hereda (extienda) a la clase JFrame, Trigo será por lo tanto también un JFrame es
decir una ventana.
Para comprobar esto añadiremos a nuestra clase un método "main", quedando
ahora de la siguiente forma:
1 import javax.swing.*;
2
3 public class Trigo extends JFrame{
4 public static void main(String[] arg){
5 Trigo miAplicacion = new Trigo();
6 miAplicacion.setBounds(10,10,200,200);
7 miAplicacion.pack();
8 miAplicacion.setVisible(true);
9 }
10 }
Todos los mensajes enviados al objeto "miAplicacion" son métodos heredados de
"JFrame". El primer método "setBounds" establece la posición inicial de la
ventana en la pantalla y sus dimensiones. El segundo, "pack", en este momento
no era realmente necesario ya que la ventana está vacia; pero quisimos incluirlo
para no tener que modificar el main más tarde. Este método optimiza la
disposición de los elementos dentro de la ventana. Y el último mensaje es
simplemente para ordenarle a la venta que se haga visible. Después de compilar y
ejecutar el código verá en pantalla algo como lo mostrado en la figura 1.
figura 1
Agregando un botón
La ventana (JFrame) sólo puede contener dos cosas: un menu, y un panel. Cada
uno de estos elementos con su espacio ya determinado. Por el momento no
utilzaremos el menú. Los botones y demás elementos a agregar no se colocan
directamente en la ventana, sino en un objeto interno, el "Panel". Este objeto
interno a su vez utiliza otro objeto interno conocido como LayoutManager, que
se encarga de controlar la disposción de los elementos dentro del panel.
Existen muchos LayoutManagers, cada uno con su propia lógica para la
dispocisión de los elementos, aqui ejemplificaremos el uso de un par de ellos.
Modificamos nuestra clase para agragar un botón quedando entonces como:
1 import javax.swing.*;
2 import java.awt.*;
3
4 public class Trigo extends JFrame{
5 private JButton b1;
6
7 public Trigo(){
8 b1 = new JButton("seno");
9 this.getContentPane().add(b1,BorderLayout.NORTH);
10 }
11 public static void main(String[] arg){
12 Trigo miAplicacion = new Trigo();
13 miAplicacion.setBounds(10,10,200,200);
14 miAplicacion.pack();
15 miAplicacion.setVisible(true);
16 }
17 }
Después de compilar y ejecutar el código tendremos algo como:
Figura 2
Ahora el tamaño de la ventana cambio y se adapto al único elemento que
contiene (el botón). El significado del código agregado es el siguiente:
En la línea 2 importamos el paquete donde se encuentra declarado la clase
"BorderLayout". Incluimos un "JButton" (un botón) como atributo de nuestra
clase "Trigo" y agregamos además una constructora, que es donde creamos el
objeto "b1" para después añadirlo al panel de la ventana con la instrucción de la
línea 9. Esta última instrucción merece la pena una explicación ya que la
utilizaremos bastante a través del ejemplo.
La parte que a continuación se muestra en azul se encarga de obtener una
referencia al panel de la ventana.
this.getContentPane().add(b1,BorderLayout.NORTH);
Mientras que la parte que se encuentra en rojo es la que le ordena al Panel que
agregue el botón, además de que le ordena que para añadirlo utilice un
"LayoutManager" de tipo "BorderLayout". Este tipo de "LayoutManager" divide
al panel en 5 regiones (Norte, Sur, Este, Oeste y Centro); donde cada región
puede contener sólo un elemento. En este caso añadimos el botón a la zona
"Norte" y para ordenarlo utilizamos la constante de clase "NORTH" definida en
la clase "BorderLayout".
De forma analoga incluiremos un campo de texto "JTextField" en la zona "Sur"
de nuestro panel.
1 import javax.swing.*;
2 import java.awt.*;
3
4 public class Trigo extends JFrame{
5 private JButton b1;
6 private JTextField campo1;
7
8 public Trigo(){
9 b1 = new JButton("seno");
10 campo1 = new JTextField();
11 this.getContentPane().add(b1,BorderLayout.NORTH);
12 this.getContentPane().add(campo1,BorderLayout.SOUTH);
13 }
14 public static void main(String[] arg){
15 Trigo miAplicacion = new Trigo();
16 miAplicacion.setBounds(10,10,200,200);
17 miAplicacion.pack();
18 miAplicacion.setVisible(true);
19 }
20 }
Figura 3
Para que observe bien la definición de zonas hechas en el panel por el
"BorderLayout" aumente la ventana y verá que el centro queda un espacio vacío
(la parte gris), ya que el botón se encuentra al Norte y el campo de Texto al Sur.
Figura 4
Añadiendo acciones al boton
Hasta ahora sólo hemos mostrado como agregar elementos a la ventana, ya
tenemos dos elementos un botón y un campo de texto. Sin embargo, el botón al
ser oprimido no produce ninguna acción. El botón es el ente que genera eventos
(es oprimido) pero no existe hasta el momento ningún objeto interesado en sus
eventos. Es decir que no existe ningún oyente de los eventos. Para registrar un
oyente el botón cuenta con el métodoaddActionListener. La firma del este
método es:
void addActionListener(ActionListener evento)
Esto significa que el elemento a registrarse como oyente de los eventos del botón
debe ser un "ActionListener". Para nuestro ejemplo, lo que deseamos es que la
ventana que contiene al botón "miAplicacion" sea la que se registre con el botón
como oyente de eventos. El problema con esto es que "miAplicacion" es de tipo
"Trigo" o bien de tipo "JFrame" pero no es un "ActionListener". Para que las
instancias de tipo "Trigo" también sean de tipo "ActionListener" tenemos que
hacer que la clase "Trigo" implemente la interfaz "ActionListener"; porque de
forma analoga a lo que sucede con la herencia (extends) cuando una clase
implementa una interfaz se establece una relación "es un" entre ellas. Para
anunciar que "Trigo" implementara la interfaz "ActionListener" modificamos la
definición de la clase de la siguiente forma:
public class Trigo extends JFrame implements ActionListener
El hecho de afirmar que la clase "Trigo" implementa la interfaz "ActionListener"
implica que ahora esta clase contiene todos los métodos definidos en la interfaz.
Cabe recordar que todos los métodos de una interfaz son abstractos por lo tanto o
sobre-escribimos los métodos agregandoles un cuerpo o bien tendremos que
declarar a nuestra clase "Trigo" como abstracta. Como en nuestro ejemplo no
deseamos que nuestra clase "Trigo" sea abstracta implementaremos todos los
métodos de la interfaz "ActionListener". Afortunadamente, esta interfaz sólo
define un método:
public void actionPerformed(ActionEvent e)
Este será el método que autómaticamente será ejecutado cuando el botón le avise
de su evento a la ventana. Para fines de este ejemplo deseamos que la acción a
realizar cuando se oprima el botón sea que en el campo de texto aparezca un
letrero en que se diga cuantas veces ha sido oprimido el botón. Por lo tanto
incluiremos una nueva variable (para contar el número de clicks sobre el botón,
linea 8), el método "actionPerformed" (de la linea 18 a la 21) y cambiaremos la
deficinición de la clase (linea 5). Ademas de registrar a la ventana como oyente
de los eventos del botón (linea 12). Quedando por lo tanto nuestra clase como:
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4
5 public class Trigo extends JFrame implements ActionListener{
6 private JButton b1;
7 private JTextField campo1;
8 private int numClicks = 0;
9
10 public Trigo(){
11 b1 = new JButton("seno");
12 b1.addActionListener(this);
13 campo1 = new JTextField();
14 this.getContentPane().add(b1,BorderLayout.NORTH);
15 this.getContentPane().add(campo1,BorderLayout.SOUTH);
16 }
17
18 public void actionPerformed(ActionEvent e){
19 numClicks++;
20 campo1.setText(numClicks+"");
21 }
22
23 public static void main(String[] arg){
24 Trigo miAplicacion = new Trigo();
25 miAplicacion.setBounds(10,10,200,200);
26 miAplicacion.pack();
27 miAplicacion.setVisible(true);
28 }
29 }
Prueba ahora dando clicks al botón.
Armando la calculadora
El ejemplo anterior sirve para mostrar los conceptos básicos, pero la promesa era
hacer una calculadora de funciones trigonometricas. El primer paso que
realizaremos será modificar un poco la interfaz, dejaremos el TextField como
medio de entrada para el ángulo del que deseamos saber el seno, y añadiremos
otro TextField para reportar el resultado del cálculo realizado. Tambien
incluiremos unas etiquetas para marcar la entrada y salida de nuestra calculadora.
Eliminaremos la variable que cuenta los clicks y para mostrar que los Paneles
pueden contener otros paneles utilizaremos un par de paneles para ir organizando
nuestra interfaz.
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4
5 public class Trigo extends JFrame implements ActionListener{
6 private JButton b1;
7 private JTextField campo1;
8 private JTextField campo2;
9 private JLabel etq1;
10 private JLabel etq2;
11 private Panel panelEntrada, panelSalida;
12 private JPanel panelDeLaVentana;
13
14 public Trigo(){
15 //Creamos el boton
16 b1 = new JButton("seno");
17
18 //Registramos a la ventana como oyente
19 b1.addActionListener(this);
20
21 //Creamos las etiquetas
22 etq1 = new JLabel("Angulo: ");
23 etq2 = new JLabel("Resultado: ");
24
25 //Creamos los campos de Texto
26 campo1 = new JTextField();
27 campo2 = new JTextField();
28
29 //Cambiamos la propiedades de los TextFields
30 campo2.setEditable(false);
31 campo2.setColumns(10);
32 campo2.setBackground(Color.lightGray);
33 campo1.setColumns(10);
34
35 //Creamos los paneles auxiliares
36 panelEntrada = new Panel();
37 panelSalida = new Panel();
38
39 //Obtenemos la referencia al panel principal
40 panelDeLaVentana = (JPanel)this.getContentPane();
41
42 //Agregamos los componentes del panel de entrada
43 panelEntrada.add(campo1,BoxLayout.X_AXIS);
44 panelEntrada.add(etq1,BoxLayout.X_AXIS);
45
46 //Agregamos los componentes del panel de salida
47 panelSalida.add(campo2,BoxLayout.X_AXIS);
48 panelSalida.add(etq2,BoxLayout.X_AXIS);
49
50 //Agregamos todo al panel Principal
51 panelDeLaVentana.add(panelEntrada,BorderLayout.NORTH);
52 panelDeLaVentana.add(b1,BorderLayout.CENTER);
53 panelDeLaVentana.add(panelSalida,BorderLayout.SOUTH);
54 }
55
56 public void actionPerformed(ActionEvent e){
57 }
58
59 public static void main(String[] arg){
60 Trigo miAplicacion = new Trigo();
61 miAplicacion.setBounds(10,10,200,200);
62 miAplicacion.pack();
63 miAplicacion.setVisible(true);
64 }
65 }
Ahora despues de compilar y ejecutar tendremos:
Figura 5
En la discusión anterior habiamos mencionado que un "BorderLayout" sólo te
permite poner una sola cosa en cada una de las regiones. Esta regla se sigue
cumpliendo, el "BorderLayout" del panel principal contiene una sola cosa en la
region Norte (linea 51); contiene el Panel llamado "panelEntrada", es este panel
el que a su vez contiene dos cosas una etiqueta y un campo de texto (lineas 43 y
44) utilizando su propia lógica para la disposición de los elementos, en este caso
utilizando un BoxLayout. Para la parte de la salida es algo similar, pero observe
además que la región del centro del panel principal "panelDeLaVentana" esta
ocupada por el botón.
De nueva cuenta una vez con la interfaz organizada procederemos a darle
funcionalidad al botón. Parte del trabajo ya está hecho:
La ventana ya es un "ActionListener" (implementa la interfaz
"ActionListener")
El botón ya registra a la venta como oyente de eventos (linea 19)
La clase "Trigo" ya tiene un método "actionPerformed", aunque vacío
Por lo tanto sólo nos falta esribir la lógica de ejecución para responder al evento
del botón. Lo que deseamos ahora ejecutar como respuesta al evento puede
resumirse en 3 sencillos pasos:
1. Leer el ángulo proporcionado en el "TextField" de entrada (campo1).
2. Calcular el seno del ángulo proporcionado
3. Escribir el resultado en el campo de texto correspondiente (campo2)
Al observar la API podemos darnos cuenta que entre el hecho de leer la entrada y
calcular el seno hay un paso adicional, porque el "TextField" reporta su
contenido como un "String" mientras que la función para calcular el seno,
definida en el paquete Math de Java, utiliza un "double" como entrada. Por lo
tanto, tendremos que convertir la cadena de caracteres en un double para después
calcular el seno. Para realizar esta conversión utilizaremos el método
"parseDouble" definido en la "Wrapper class" Double.
Double.parseDouble(String val)
Agregando estas modificaciones el código queda como:
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4
5 public class Trigo extends JFrame implements ActionListener{
6 private JButton b1;
7 private JTextField campo1;
8 private JTextField campo2;
9 private JLabel etq1;
10 private JLabel etq2;
11 private Panel panelEntrada, panelSalida;
12 private JPanel panelDeLaVentana;
13
14 public Trigo(){
15 //Creamos el boton
16 b1 = new JButton("seno");
17
18 //Registramos a la ventana como oyente
19 b1.addActionListener(this);
20
21 //Creamos las etiquetas
22 etq1 = new JLabel("Angulo: ");
23 etq2 = new JLabel("Resultado: ");
24
25 //Creamos los campos de Texto
26 campo1 = new JTextField();
27 campo2 = new JTextField();
28
29 //Cambiamos la propiedades de los TextFields
30 campo2.setEditable(false);
31 campo2.setColumns(10);
32 campo2.setBackground(Color.lightGray);
33 campo1.setColumns(10);
34
35 //Creamos los paneles auxiliares
36 panelEntrada = new Panel();
37 panelSalida = new Panel();
38
39 //Obtenemos la referencia al panel principal
40 panelDeLaVentana = (JPanel)this.getContentPane();
41
42 //Agregamos los componentes del panel de entrada
43 panelEntrada.add(campo1,BoxLayout.X_AXIS);
44 panelEntrada.add(etq1,BoxLayout.X_AXIS);
45
46 //Agregamos los componentes del panel de salida
47 panelSalida.add(campo2,BoxLayout.X_AXIS);
48 panelSalida.add(etq2,BoxLayout.X_AXIS);
49
50 //Agregamos todo al panel Principal
51 panelDeLaVentana.add(panelEntrada,BorderLayout.NORTH);
52 panelDeLaVentana.add(b1,BorderLayout.CENTER);
53 panelDeLaVentana.add(panelSalida,BorderLayout.SOUTH);
54 }
55
56 public void actionPerformed(ActionEvent e){
57 double angulo = Double.parseDouble(campo1.getText());
58 double resultado = Math.sin(angulo);
59 campo2.setText(resultado+"");
60 }
61
62 public static void main(String[] arg){
63 Trigo miAplicacion = new Trigo();
64 miAplicacion.setBounds(10,10,200,200);
65 miAplicacion.pack();
66 miAplicacion.setVisible(true);
67 }
68 }
Es hora de probar la calculadora, pero no hay que olvidar que de acuerdo a la
API, la función seno de la clase Math asume que el valor representa un ángulo en
radianes.