PRACTICA UN EJERCICIO PARA UILIZAR LA INTERFASE GRAFICA JAVA construye las interfaces gráficas del usuario mediante AWT. Para crear una interfaz gráfica de usuario hace falta un contenedor que es la ventana donde se situarán los componentes (como botones, cajas de texto, etiquetas, entre otros) y donde se realizarán los dibujos. Lo podemos relacionar con los formularios, los componentes como tal y el modelo de eventos, que son las respuestas a las acciones como presionar un botón o hacer un click de ratón. Cuando el usuario realiza una determinada acción, se produce el evento correspondiente que el SO transmite al AWT, este crea un objeto de una determinada clase de evento derivada de AWTEvent y el evento es trasmitido a un determinado método (procedimiento o función de la clase) para que lo gestione. El componente u objeto que recibe el evento debe indicar previamente que objeto se va a hacer cargo de gestionar el evento. El modelo de eventos de JAVA Está basado en que los objetos sobre los que se producen los eventos o event sources registran los objetos que los gestionarán (event listener), para lo cual los event listener habrán de
disponer de los métodos adecuados. Esos métodos se llamarán automáticamente cuando se produzca el evento, la forma de garantizar que los event listener disponen de los métodos apropidos para gestionar los eventos es obligarles a implementar una determinada interface Listener, estas interfaces se corresponden con los tipo oris de eventos que se pueden producir. Proceso para crear una aplicación interactiva orientada a eventos con interfase gráfica de usuario.
Determinar los componentes que van a constituir la interfase de usuario, como botones, cajas de texto, menús, etc. Crear una clase para la aplicaci;on que contenga la función main().
Crear una clase Ventana, sub clase de Frame, que corresponda al evento WindowClosing().
La función main() deberá crear un objeto de la clase ventana para colocar los componentes y mostrarla por pantalla con el tamaño y la posición adecuados. Añadir al objeto Ventana todos los componentes y menús que deba contener. Se puede hacer un constructor de la Ventana o en el propio método main().
Definir los objetos listener (aquellos que respondan a eventos cuyas clases implementarán las distintas interfases Listener ) para cada uno de los eventos que deban estar soportados. En aplicaciones pequeñas, el propio objeto ventana se puede ocupar de responder a los eventos de sus componentes. En programas mas grandes se puede crear uno o mas objetos de clases especiales para ocuparse de los eventos.
Finalmente, se deben implementar los métodos de las interfases listener que se vayan a hacer cargo de la gestión de los eventos.
Como ejemplo vamos a realizar un programa en JAVA que sirva de juego para, en una ventana contenedora de botones amarillos y rojos, al clickear sobre uno de ellos aparezca el color del botón seleccionado. En NetBeans vamos a abrir un proyecto identificándolo con el nombre Juego y lo vamos a colocar en el escritorio. A la carpeta SRC le vamos a añadir dos clases adicionales a la principal. Una clase se va a llamar Botonera y la otra OyenteAcciones.
Vamos a importar las siguientes librerías Javax.swing.*
Java.awt.* Java.awt.event.*
La clase Botonera la vamos a llenar de botones amarillos y rojos. Esta clase va a heredar los atributos y métodos de la clase JPanel (por lo que hay que colocar que la clase Botonera extends JPanel. Podemos entonces declarar Public Botonera (int tamaño) { para colocar JButton [][] botones: y así crear una matriz de botones, se instancia botones con new JButton [tamaño][tamaño]. Se crea un oyente de acciones para los eventos con la otra clase que creamos en el proyecto, OyenteAcciones oyente = new OyenteAcciones(this):. Con un doble ciclo se crean los objetos botones For (int i=0;i<botones.length;i++){
For (int j=0;j<botones[i].length;i++){ Dentro del doble ciclo codificamos
botones[i][j]=new JButton(); botones[i][j].setPreferredSize(newDimension(50,50)); if ((i+j+1)%2==0) { botones[i][j].setBackground(Color.BLACK); }
De esta manera coloreamos los botones en negro de manera intercalada con el color por defecto, que sería el blanco.
Fuera del doble ciclo codificamos setLayout(new GridLayout (tamano,tamano)); En java, cuando hacemos ventanas, la clase que decide cómo se reparten los botones (Y demás controles) dentro de la ventana se llama Layout. Esta clase es la que decide en qué posición van los botones y demás componentes, si van alineados, en forma de matriz, cuáles se hacen grandes al agrandar la ventana, etc. Otra cosa importante que decide el Layout es qué tamaño es el ideal para la ventana en función de los componentes que lleva dentro. Con un layout adecuado, el método pack() de la ventana hará que coja el tamaño necesario para que se vea todo lo que tiene dentro. Este pone los componentes en forma de matriz (cuadrícula), estirándolos para que tengan todos el mismo tamaño. El GridLayout es adecuado para hacer tableros, calculadoras en que todos los botones son iguales, etc.
// Creación de los botones JButton boton[] = new JButton[9]; for (int i=0;i<9;i++) boton[i] = new JButton(Integer.toString(i)); // Colocación en el contenedor contenedor.setLayout (new
GridLayout (3,3)); // 3 filas y 3 columnas for (int i=0;i<9;i++) contenedor.add (boton[i]); // Añade los botones de 1 en 1.
Terminamos la clase con private Dimension newDimension(int i, int i0) { return null; } Aquí creamos una Dimension cuya anchura y altura son las que se especifican en los argumentos. En la clase OyenteAcciones implementamos un oidor, ya que tenemos el evento que va a activar a una caja de mensajes para indicar el color del botón. public class OyenteAcciones implements ActionListener { private JPanel panel; public OyenteAcciones(JPanel panel){ this.panel=panel; } public void actionPerformed(ActionEvent evento) {
JButton boton=(JButton) evento.getSource(); String color="BLANCO"; if (boton.getBackground()==Color.BLACK) color="NEGRO"; JOptionPane.showMessageDialog(panel, "Se ha pulsado un boton de color "+ color, "Boton Pulsado", JOptionPane.INFORMATION_MESSAGE); } } Por último, en el main java creamos la botonera y ps colocamos en la ventana contenedora public static void main(String[] args) { JFrame ventana=new JFrame("BOTONERA"); Botonera botonera = new Botonera(18);
ventana.add(botonera); ventana.pack(); ventana.setVisible(true); } -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐
Contenedores y gestión de los layout
En la lección anterior hemos visto como introducir en nuestras aplicaciones y en nuestros apliques unas etiquetas y unos botones. Para hacerlo hemos utilizado unos contenedores y unos layout sin saber cómo funcionaban. En este lección analizeremos sus funcionamientos y cómo aprovecharlos para mejorar nuestras interfaces. Empezamos con describir la clase Container del paquete java.awt. Es una extensión de la clase Component de la que proceden todos los componentes GUI y, en realidad, éste mismo es un componente GUI.
Un Container es un contenedor para los objetos GUI y, por lo tanto, también para los demás container. Se utiliza junto a un Layout Manager y permite que abarquen más de un GUI (y Contenedores), permitiendo que aparezcan varios objetos en nuestras interfaces. Vemos qué contiene la clase. Container() , es el único constructor de la clase. Unos métodos: Component add(Component comp), añade el componente al final del contenedor. Component add(Component comp, int index), añade el componente en la posición indicada por el contenedor. void add(Component comp, Object constraints) e void add(Component comp, Object constraints, int index) , como antes, lo único es que especifica unas constantes para el componente que se ha introducido. Component add(String name, Component comp), añade al contenedor el componente y le da un nombre.
void addContainerListener(ContainerListener l), ajusta el ContainerListener que escuchará los sucesos que han ocurrido en el contenedor. void doLayout(), provoca la disposición de los componentes en el contenedor. Component findComponentAt(int x, int y), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica). Component findComponentAt(Point p) , devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica). float getAlignmentX(), devuelve el ajuste de líneas a lo largo del eje X del contenedor. float getAlignmentY(), devuelve el ajuste de líneas a lo largo del eje Y del contenedor. Component getComponent(int n), devuelve el enésimo componente introducido en el contenedor. Component getComponentAt(int x, int y), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica). Component getComponentAt(Point p), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica). int getComponentCount() , da el número de componentes introducidos en el contenedor.
Component[] getComponents(), da todos los componentes introducidos en el contenedor. Insets getInsets(), da un objeto Insets para el contenedor. Este objeto representa el tamaño (gráfico= del contenedor. LayoutManager getLayout(), devuelve el LayuotManager asociado al contenedor. EventListener[] getListeners(Class listenerType), devuelve todos los oyentes de sucesos al contenedor. Dimension getMaximumSize(), devuelve el tamaño máximo que puede tener el contenedor. Dimension getMinimumSize(), devuelve el tamaño mínimo que puede tener el contenedor. Dimension getPreferredSize(), devuelve el tamaño preferido por el contenedor. void list(PrintStream out, int indent), imprime el listado de los componentes introducidos en el contenedor, sobre un stream de output. void list(PrintWriter out, int indent), imprime en una impresora los componentes introducidos en el contenedor. void paint(Graphics g), dibuja el contenedor. La paint es una función muy importante. Veremos cómo definirla para dibujar en una ventana. void paintComponents(Graphics g). dibuja todos los componentes del contenedor. void print(Graphics g), imprime el contenedor (el aspecto gráfico).
void printComponents(Graphics g), imprime todos los componentes introducidos en el contenedor (sus aspectos gráficos). void remove(Component comp), elimina el componente especificado por el contenedor. void remove(int index), aparta el componente que se encuentra en la posición especificada en el contenedor. void removeAll(), aparta todos los componentes introducidos en el contenedor. void removeContainerListener(ContainerListener l), elimina el oyente de sucesos para containers de este container. void setFont(Font f), ajusta las Font utilizadas por el texto en el contenedor. void setLayout(LayoutManager mgr), asocia al contenedor un gestor de layout. void update(Graphics g), vuelve a dibujar el contenedor. void validate(), anula el contenedor y sus componentes. Introduciendo componentes en el contenedor, como en el ejemplo sucesivo, nos damos cuenta de que sólo el último será visualizado. Esto ocurre porque no hemos dado gestor de Layout. En el caso de applet, en cambio, el LayoutManager de default es el FlowLayout.
import java.awt.*; public class Contenedor extends Frame { Label l1=new Label("Etiqueta1"); Label l2=new Label("Etiqueta2"); Label l3=new Label("Etiqueta3"); Label l4=new Label("Etiqueta4"); Label l5=new Label("Etiqueta5"); public Contenedor() { // uso add, porque el Frame es una extensión de Window, que a su // vez amplía Container. add(l1); add(l2); add(l3); add(l4); add(l5); doLayout(); pack(); show(); } public static void main(String [] arg) {
new Contenedor(); } } Por lo tanto, vemos cómo introducir un gestor de Layout en el contenedor. El método de la clase container que lo permite es void setLayout(LayoutManager mgr). No nos queda que ver cómo es el objeto de tipo LayoutManager. LayoutManager es una interfaz. De las clases que la implementan analizaremos GridLayout, FlowLayout. Hay otra interfaz llamada LayoutManager2, que amplía ésta y que tiene otras clases que la implementan. De éstas veremos: CardLayout, BorderLayout, GridBagLayout, BoxLayout, OverlayLayout. Por lo tanto, en el método setLayout (…) podemos utilizar como parámetro un objeto de estas clases. Llegados a este punto, tenemos que comprender qué diferencia hay entre los layout manager. El FlowLayout deja colocar los componentes de un contenedor de la izquierda hacia la derecha
en una sóla línea.
Para utilizar el LayoutManager FlowLayout del ejemplo precedente basta con invocar el método setLayout con parámetro new FlowLayout(), y después los componentes se introducen automáticamente, de la add de la derecha hacia la izquierda en la misma línea. import java.awt.*; public class ContEFL extends Frame { Label l1=new Label("Etiqueta1"); Label l2=new Label("Etiqueta2"); Label l3=new Label("Etiqueta3"); Label l4=new Label("Etiqueta4"); Label l5=new Label("Etiqueta5"); public ContEFL()
{ // uso add, porque el Frame es una extensión de Window, que a su // vez amplía Container. setLayout(new FlowLayout()); add(l1); add(l2); add(l3); add(l4); add(l5); pack(); show(); } public static void main(String [] arg) { new ContEFL(); } } La ventana que sale es:
El GridLayout permite colocar los componentes en un contenedor como si se dispusieran en una plantilla.
Todos los componentes tendrán el mismo tamaño. La clase tiene tres constructores, uno sin parámetros que crea una planilla con 1 línea, prácticamente un FlowLayout, y otros dos que permiten especificar el tamaño de la planilla. El ejemplo anterior cambia de esta forma: import java.awt.*;
public class ContEGL extends Frame { Label l1=new Label("Etiqueta1"); Label l2=new Label("Etiqueta2"); Label l3=new Label("Etiqueta3"); Label l4=new Label("Etiqueta4"); Label l5=new Label("Etiqueta5"); public ContEGL() { // uso add, poruqe el Frame es una extensión de Window, que a su // vez amplía Container. setLayout(new GridLayout(2,3)); add(l1); add(l2); add(l3); add(l4); add(l5); pack(); show(); }
public static void main(String [] arg) { new ContEGL(); } } La ventana es la siguiente:
El LayoutManager CardLayout permite visualizar los componentes diferentes en plazos de tiempo diferentes, es decir, que visualiza sólo un componente a la vez. Sin embargo el componete visualizado se puede cambiar. Hay aquí un ejemplo del uso de CardLayout import java.awt.*; import java.awt.event.*; public class ContECL extends Frame {
Label l1=new Label("Etiqueta1"); Label l2=new Label("Etiqueta2"); Label l3=new Label("Etiqueta3"); Label l4=new Label("Etiqueta4"); Label l5=new Label("Etiqueta5"); Panel p=new Panel(new GridLayout(2,1)); CardLayout CL=new CardLayout(14,14); Panel p1=new Panel(CL); Panel NPB=new Panel(new FlowLayout()); public ContECL() { p.add(NPB); p.add(p1); Button N=new Button("Próximo"); Button P=new Button("Anterior"); NPB.add(P); NPB.add(N); P.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e)
{ CL.previous(p1); } } ); N.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { CL.next(p1); } } ); p1.add("uno",l1); p1.add("dos",l2); p1.add("tres",l3); p1.add("cuatro",l4); p1.add("cinco",l5); add(p); pack(); show(); } public static void main(String [] arg) {
new ContECL(); } } El resultado de los ejemplos son las siguientes ventanas:
Muestran como las cinco etiquetas aparecen en la misma posición en plazos de tiempo diferentes. Notad que en el ejemplo no se han utilizado los demás gestores de Layout para que se puedan introducir los botones Próximo y Anterior. BorderLayout es uno de los gestores de Layout más utilizados. Permite introducir en un contenedor cinco componentes, uno al Norte, uno al Sur, uno al Este, uno al Oeste y otro al Centro. El tamaño del contenedor lo establecerá el componente central. Las cinco posiciones están indicadas por los contenedores de la clase: BorderLayout.NORTH BorderLayout.SOUTH
BorderLayout.EAST BorderLayout.WEST BorderLayout.CENTER hay aquí un ejemplo del uso de BorderLayout. He cambiado los colores de fondo de las etiquetas para que se vea el componente entero. import java.awt.*; public class ContEBL extends Frame { Label l1=new Label("Etiqueta al Norte",Label.CENTER); Label l2=new Label("Etiqueta al Sur",Label.CENTER); Label l3=new Label("Etiqueta al Este",Label.CENTER); Label l4=new Label("Etiqueta al Oeste",Label.CENTER); Label l5=new Label("Etiqueta al Centro",Label.CENTER); public ContEBL() { // uso add porque el Frame es una extensión de Window, que a su // vez amplía Container.
l1.setBackground(Color.pink); l2.setBackground(Color.lightGray); l3.setBackground(Color.green); l4.setBackground(Color.yellow); l5.setBackground(Color.orange); setLayout(new BorderLayout()); add(l1,BorderLayout.NORTH); add(l2,BorderLayout.SOUTH); add(l3,BorderLayout.EAST); add(l4,BorderLayout.WEST); add(l5,BorderLayout.CENTER); pack(); show(); } public static void main(String [] arg) { new ContEBL(); } }
El resultado es:
Hay también otros gestores de Layout, que no analizaremos, y que, sin embargo, podéis estudiar junto a éstos en la documentación oficial de las Java Development Kit.