190
LA BIBLIA DE JAVA = http://es.slideshare.net/jeanHisoka/labibliadejava2 MANUAL DE JAVA 320 PAGS. http://www.jorgesanchez.net/programacion/manuales/Java.pdf http://pedrobeltrancanessa-biblioteca.weebly.com/uploads/1/2/4/0/12405072/ java_swing.pdf transformar imagenes con java System.out.println(Math.rint(0.891)); for (var i = 0; i < myVar.length; i+3) { //every three } / Métodos de acceso (get) public int getNum() { return num; } public double getSaldo() { return saldo; } public String getNombre() { return nombre; } public double devuelve() // Sin parametros { . . . return . . . ;} public void asigna( double x ) // Un parametro, x de tipo double { . . . } publ ic int elMayor(int a, int b) // Dos parametros, a y b de tipo int { . . . } public static double sumatorio ( double [] v ) // Un parametro, v, array real { . . . } public boolean caducado ( F echa fechaLimite 1

Documentación Java

Embed Size (px)

DESCRIPTION

comprende varios artículos sobre diversos problemas que se presentan sobretodo con manejo de imágenes.

Citation preview

Page 1: Documentación Java

LA BIBLIA DE JAVA = http://es.slideshare.net/jeanHisoka/labibliadejava2 MANUAL DE JAVA 320 PAGS. http://www.jorgesanchez.net/programacion/manuales/Java.pdfhttp://pedrobeltrancanessa-biblioteca.weebly.com/uploads/1/2/4/0/12405072/java_swing.pdf

transformar imagenes con javaSystem.out.println(Math.rint(0.891));for (var i = 0; i < myVar.length; i+3) { //every three}/ Métodos de acceso (get) public int getNum() { return num; }

public double getSaldo() { return saldo; }

public String getNombre() { return nombre; }

public double devuelve() // Sin parametros{ . . .return . . . ;}public void asigna(double x) // Un parametro, x de tipo double{ . . . }public int elMayor(int a, int b) // Dos parametros, a y b de tipo int{ . . . }public static double sumatorio (double [] v) // Un parametro, v, array real{ . . . }public boolean caducado (Fecha fechaLimite)// Un parámetrode la clase Fechahttp://ocw.upm.es/lenguajes-y-sistemas-informaticos/programacion-en-java-i/Contenidos/LecturaObligatoria/15-parametrosoargumentos.pdf http://elvex.ugr.es/decsai/java/pdf/6A-Arrays.pdf

1

Page 2: Documentación Java

Arreglos: DECLARACION del arreglo = private float coordenadas []; ó private float coordenadas[] []; (para 2 dimensiones); CREACION: float coordenadas [] = new float [7]; (7 es el tamaño del arreglo);float coordenadas[] [] = new float [10][10]; (tamaño 10x10)

ESTRUCTURA DE LOS METODOS: declaración de parámetros en el ENCABEZADO:public double devuelve() // Sin parámetros tipo Get{ . . . return . . . ;}public void asigna(double x) // Un parametro, x de tipo double { . . . } (tipo Set)public int elMayor(int a, int b) // Dos parametros, a y b de tipo

int{ . . . } public static double sumatorio (double [] v) // Un parametro, v, array real{ . . . } public boolean caducado (Fecha fechaLimite) // Un parámetro

de la clase FechaUSO DE LA PALABRA THIS

Tu ejemplo no está completo, le faltan las variables de la clase, debería ser algo así:

String name; String favoriteFood;

public User(String name, String favoriteFood) { this.name = name; this.favoriteFood = favoriteFood; }

Fíjate que las variables del constructor se llaman exactamente igual que las de la clase, ¿cómo diferenciarlas?, con "this" que hace referencia a la variable de la clase (las de hasta arriba en este caso). Por eso this.name = name asigna el valor pasado como parámetro al constructor a la variable de clase.

Como cultura general, las variables de clase se llaman atributos.

2

Page 3: Documentación Java

Tutoriales de la universidad de Princeton = EXCELENTE ttp://introcs.cs.princeton.edu/java/stdlib/Picture.java.html ;

Compilation: javac Picture.java * Execution: java Picture imagename * * Data type for manipulating individual pixels of an image. The original * image can be read from a file in jpg, gif, or png format, or the * user can create a blank image of a given size. Includes methods for * displaying the image in a window on the screen or saving to a file. * * % java Picture mandrill.jpg * * Remarks * ------- * - pixel (x, y) is column x and row y, where (0, 0) is upper left * * - see also GrayPicture.java for a grayscale version * *************************************************************************/

import java.awt.Color;import java.awt.FileDialog;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyEvent;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import java.net.URL;import javax.imageio.ImageIO;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax.swing.KeyStroke;

/** * This class provides methods for manipulating individual pixels of * an image. The original image can be read from a <tt>.jpg</tt>, <tt>.gif</tt>, * or <tt>.png</tt> file or the user can create a blank image of a given size. * This class includes methods for displaying the image in a window on * the screen or saving it to a file. * <p> * Pixel (<em>x</em>, <em>y</em>) is column <em>x</em> and row <em>y</em>. * By default, the origin (0, 0) is upper left, which is a common convention * in image processing. * The method <tt>setOriginLowerLeft()</tt> change the origin to the lower left.

3

Page 4: Documentación Java

* <p> * For additional documentation, see * <a href="http://introcs.cs.princeton.edu/31datatype">Section 3.1</a> of * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> * by Robert Sedgewick and Kevin Wayne. * * @author Robert Sedgewick * @author Kevin Wayne */public final class Picture implements ActionListener { private BufferedImage image; // the rasterized image private JFrame frame; // on-screen view private String filename; // name of file private boolean isOriginUpperLeft = true; // location of origin private final int width, height; // width and height

/** * Initializes a blank <tt>width</tt>-by-<tt>height</tt> picture, with <tt>width</tt> columns * and <tt>height</tt> rows, where each pixel is black. */ public Picture(int width, int height) { if (width < 0) throw new IllegalArgumentException("width must be nonnegative"); if (height < 0) throw new IllegalArgumentException("height must be nonnegative"); this.width = width; this.height = height; image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // set to TYPE_INT_ARGB to support transparency filename = width + "-by-" + height; }

/** * Initializes a new picture that is a deep copy of <tt>picture</tt>. */ public Picture(Picture picture) { width = picture.width(); height = picture.height(); image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); filename = picture.filename; for (int col = 0; col < width(); col++) for (int row = 0; row < height(); row++) image.setRGB(col, row, picture.get(col, row).getRGB()); }

/** * Initializes a picture by reading in a .png, .gif, or .jpg from * the given filename or URL name. */ public Picture(String filename) { this.filename = filename; try { // try to read from file in working directory File file = new File(filename); if (file.isFile()) { image = ImageIO.read(file);

4

Page 5: Documentación Java

}

// now try to read from file in same directory as this .class file else { URL url = getClass().getResource(filename); if (url == null) { url = new URL(filename); } image = ImageIO.read(url); } width = image.getWidth(null); height = image.getHeight(null); } catch (IOException e) { // e.printStackTrace(); throw new RuntimeException("Could not open file: " + filename); } }

/** * Initializes a picture by reading in a .png, .gif, or .jpg from a File. */ public Picture(File file) { try { image = ImageIO.read(file); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Could not open file: " + file); } if (image == null) { throw new RuntimeException("Invalid image file: " + file); } width = image.getWidth(null); height = image.getHeight(null); filename = file.getName(); }

/** * Returns a JLabel containing this picture, for embedding in a JPanel, * JFrame or other GUI widget. * @return the <tt>JLabel</tt> */ public JLabel getJLabel() { if (image == null) { return null; } // no image available ImageIcon icon = new ImageIcon(image); return new JLabel(icon); }

/** * Sets the origin to be the upper left pixel. This is the default. */ public void setOriginUpperLeft() { isOriginUpperLeft = true; }

/** * Sets the origin to be the lower left pixel. */ public void setOriginLowerLeft() { isOriginUpperLeft = false;

5

Page 6: Documentación Java

}

/** * Displays the picture in a window on the screen. */ public void show() {

// create the GUI for viewing the image if needed if (frame == null) { frame = new JFrame();

JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("File"); menuBar.add(menu); JMenuItem menuItem1 = new JMenuItem(" Save... "); menuItem1.addActionListener(this); menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); menu.add(menuItem1); frame.setJMenuBar(menuBar);

frame.setContentPane(getJLabel()); // f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setTitle(filename); frame.setResizable(false); frame.pack(); frame.setVisible(true); }

// draw frame.repaint(); }

/** * Returns the height of the picture. * @return the height of the picture (in pixels) */ public int height() { return height; }

/** * Returns the width of the picture. * @return the width of the picture (in pixels) */ public int width() { return width; }

/** * Returns the color of pixel (<tt>col</tt>, <tt>row</tt>). * @return the color of pixel (<tt>col</tt>, <tt>row</tt>)

6

Page 7: Documentación Java

* @throws IndexOutOfBoundsException unless both 0 &le; <tt>col</tt> &lt; <tt>width</tt> * and 0 &le; <tt>row</tt> &lt; <tt>height</tt> */ public Color get(int col, int row) { if (col < 0 || col >= width()) throw new IndexOutOfBoundsException("col must be between 0 and " + (width()-1)); if (row < 0 || row >= height()) throw new IndexOutOfBoundsException("row must be between 0 and " + (height()-1)); if (isOriginUpperLeft) return new Color(image.getRGB(col, row)); else return new Color(image.getRGB(col, height - row - 1)); }

/** * Sets the color of pixel (<tt>col</tt>, <tt>row</tt>) to given color. * @throws IndexOutOfBoundsException unless both 0 &le; <tt>col</tt> &lt; <tt>width</tt> * and 0 &le; <tt>row</tt> &lt; <tt>height</tt> * @throws NullPointerException if <tt>color</tt> is <tt>null</tt> */ public void set(int col, int row, Color color) { if (col < 0 || col >= width()) throw new IndexOutOfBoundsException("col must be between 0 and " + (width()-1)); if (row < 0 || row >= height()) throw new IndexOutOfBoundsException("row must be between 0 and " + (height()-1)); if (color == null) throw new NullPointerException("can't set Color to null"); if (isOriginUpperLeft) image.setRGB(col, row, color.getRGB()); else image.setRGB(col, height - row - 1, color.getRGB()); }

/** * Is this Picture equal to obj? * @return <tt>true</tt> if this picture is the same dimension as <tt>obj</tt> * and if all pixels have the same color */ public boolean equals(Object obj) { if (obj == this) return true; if (obj == null) return false; if (obj.getClass() != this.getClass()) return false; Picture that = (Picture) obj; if (this.width() != that.width()) return false; if (this.height() != that.height()) return false; for (int col = 0; col < width(); col++) for (int row = 0; row < height(); row++) if (!this.get(col, row).equals(that.get(col, row))) return false; return true; }

/** * Saves the picture to a file in a standard image format. * The filetype must be .png or .jpg. */ public void save(String name) { save(new File(name));

7

Page 8: Documentación Java

}

/** * Saves the picture to a file in a standard image format. */ public void save(File file) { this.filename = file.getName(); if (frame != null) { frame.setTitle(filename); } String suffix = filename.substring(filename.lastIndexOf('.') + 1); suffix = suffix.toLowerCase(); if (suffix.equals("jpg") || suffix.equals("png")) { try { ImageIO.write(image, suffix, file); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("Error: filename must end in .jpg or .png"); } }

/** * Opens a save dialog box when the user selects "Save As" from the menu. */ public void actionPerformed(ActionEvent e) { FileDialog chooser = new FileDialog(frame, "Use a .png or .jpg extension", FileDialog.SAVE); chooser.setVisible(true); if (chooser.getFile() != null) { save(chooser.getDirectory() + File.separator + chooser.getFile()); } }

/** * Tests this <tt>Picture</tt> data type. Reads a picture specified by the command-line argument, * and shows it in a window on the screen. */ public static void main(String[] args) { Picture picture = new Picture(args[0]); System.out.printf("%d-by-%d\n", picture.width(), picture.height()); picture.show(); }

}

http://introcs.cs.princeton.edu/31datatype/ Java: abrir imagen, leer píxeles y pasar a escala de grises. Procesamiento digital de imágenes I.

http://algoimagen.blogspot.com/2013/08/java-abrir-imagen-leer-pixeles-y-pasar.html Cargar una imagen de archivo en el disco duro al JFrame de Netscape = http://ordenador.wingwit.com/Programacion/java-programming/89469.html#.VGUkBGfzjSh

métodos para transformar objetos de tipo BufferedImage, Image, ImageIcon e Icon entre ellos. (funcionó) = http://algoimagen.blogspot.com/2013/09/java-convertir-objetos.html

Dibujo de Polígonos

8

Page 9: Documentación Java

http://jugandoconjava.co/tutoriales/jFrames/dibujandoJFrame/dibujandoJFrame.html Curso programación java = http://recursosformacion.com/wordpress/2013/05/java-para-

programadores-5-3los-metodos-graphics-y-paint/ Trabajar con varios JFrame = https://www.youtube.com/watch?v=Ha6YBbK65XI

// Para leer un pixel determinado(x,y) de la imagenint color = image.getRGB(x,y);

// o para escribir el pixel en lugar determinado, asignándole el colorimage.setRGB(x,y,color);

A continuación vamos a crear un filtro que convierta una imagen en color a escala de grises. Para obtener la escala de grises debemos obtener de cada punto una tonalidad idéntica para asociarla a los tres colores primarios. En nuestro caso para obtener valor único vamos a realizar la media de las tres tonalidades de la imagen origen. Aquí tenéis el algoritmo.En el anterior algoritmo crea una imagen de las mismas dimensiones que la imagen original. A continuación recorre las imágenes y obtiene la media de tonos de cada punto almacenando esta media en todos los tonos de la segunda imagen.http://www.genbetadev.com/java-j2ee/tratamiento-de-imagenes-i-escala-de-grises

http://www.aprenderaprogramar.com/foros/index.php?topic=1514.0 = FORO DE APRENDER A PROGRAMAR

http://aprenderaprogramar.com/index.php?option=com_content&view=category&id=68&Itemid=188

http://es.wikihow.com/llamar-a-un-m%C3%A9todo-en-Java

tratamiento imágenes en JScroll Panehttp://atobeto-eremita.blogspot.com/search/label/Procesamiento%20de%20im%C3%A1geneshttp://atobeto-eremita.blogspot.com/2009/09/tratamiento-de-imagenes-en-java-parte-1.html

http://programacion.net/articulo/swing_y_jfc_java_foundation_classes_94/21Este programa establece el cliente cuando crea el panel desplazable.

// where the member variables are declaredprivate ScrollablePicture picture;...

// where the GUI is created picture = new ScrollablePicture( ... ); JScrollPane pictureScrollPane = new JScrollPane(picture);

Se puede cambiar dinámicamente el cliente del panel desplazable llamado al método setViewportView.

ScrollablePicture implementa el interface Scrollable principalmente para afectar a los incrementos de unidad y de bloque.Configurar el ScrollPane

Método PropósitoJScrollPane()

9

Page 10: Documentación Java

JScrollPane(Component)

JScrollPane(int, int)

JScrollPane(Component, int, int)Crea un ScrollPanel El parámetro Component, cuando existe, selecciona el cliente. Los dos parámetros

int, cuando existen, seleccionan los vigilantes de seguridad de las barras de desplazamiento vertical y horizontal (respectivamente).void setViewportView(Component) Selecciona el cliente del ScrollPane.

Implementar el Interface Scrollable

Método Propósitoint getScrollableUnitIncrement(Rectangle, int, int)

void getScrollableBlockIncrement(Rectangle, int, int)Obtiene el incremento de unidad o de bloque en pixels. El parámetro Rectangle son los límites del área

visible actualmente. El primer parámetro int es SwingConstants.HORIZONTAL o SwingConstants.VERTICAL dependiendo de la barra que haya pulsado el usuario. El segundo parámetro int indica la dirección del desplazamiento. Un valor menor que 0 indica arriba o izquierda. Una valor mayor que 0 indica abajo o derecha.Dimension getPreferredScrollableViewportSize() Obtiene el tamaño preferido del JViewport. Esto permite al cliente influenciar en el tamaño del componente en el que va ser mostrado. Si este tamaño no es importante devuelve getPreferredSize.boolean getScrollableTracksViewportWidth()

boolean getScrollableTracksViewportHeight()Obtiene su el ScrollPane debería forzar al cliente a tener la misma anchura o altura que el JViewport.

Devolver true por alguno de esto métodos efectivamente desactiva el desplazamiento horizontal o vertival (respectivamente).

_________________________________________

JPanel con JScrollPaneEn uno de mis proyectos he tenido el inconveniente de cargar datos en un jpanel (por lo visto algo muy fuera de lo normal, ya que no había solución clara) teniéndolo dentro de un jscrollpane no se llegaba a visualizarse mas que lo que abarcaba el tamaño del panel, vamos que el scroll no aparecía y por mas que refrescaba con getGraphics(); no había manera.Descubrí por ahí el siguiente método de los JPanel setPreferredSize(); una bendición ya que es la solución a mis problemas. Aquí os dejo como quedaría el código:

JPanel panel = new JPanel(); JScrollPane scroll = new JScrollPane(); scroll .setBounds(132, 155, 502, 311); scroll .setViewportView(panel); scroll .getViewport().setView(panel); panel.setLayout(null);

10

Page 11: Documentación Java

Creamos el jpanel creamos el jscrollpane definimos un tamaño al scroll y metemos en el scroll el panel. Por último el proceso de carga de datos usamos incluiremos:

panel.setPreferredSize(new Dimension(480,600);

Vamos variando los valores X, Y dependiendo de cuanto necesitamos para mostrar. El código de arriba variara ya que se supone el el jscrollpane estará en un jFrame, jDialog...

NOTA: parecerá una tontería pero buscar en internet a ver si hay algo referenciando a esta solución, por que a mí me a costado. Espero que para la próxima el siguiente que lo necesite lo encuentre antes de perder los nervios ;)

_________________________________Manos a la obra

Nuevamente nos basaremos en el esquema MVC (Modelo, Vista, Controlador) para la construcción del software, comenzando con la parte de la vista para nuestra ventana y nuestros paneles de opciones.

Componentes de la interfaz de usuario:

JSlider. Utilizaremos este componente para crear una pequeña paleta de intensidad de colores y otra de intensidad del brillo, de forma que podamos modificar con los tonos de rojo, verde y azul de las imágenes, así como el brillo que estas proyectan.JPanel. Utilizaremos este componente primero, para crear todos los paneles en los que se cargarán los componentes, y además crearemos una clase llamada PanelDeImagen que extenderá a la clase JPanel, para que funcione como un lienzo sobre el cual dibujaremos las imágenes que carguemos y editemos en la aplicación.JScrollPane. Ya que el tamaño de las imágenes puede varias respecto del tamaño de la ventana de nuestra aplicación, utilizaremos un panel de tipo JScrollPane, el cual tiene la característica de hacer aparecer barras de desplazamiento en sus bordes cuando su contenido excede a su tamaño en pantalla, de forma que podemos cargar imágenes más grandes que nuestra ventana sin problemas.JMenuBar, JMenu y JMenuItem. Estos componentes nos permitirán crear una barra de menú en el panel superior de nuestra aplicación, el cual contendrá las opciones relacionadas con los archivos, como son abrir un archivo de imagen, guardar la imagen editada, salir de la aplicación. También permitirán activar los paneles que contendrán las opciones para la edición de nuestras imágenes.JFileChooser. Este componente adicional, nos auxiliará para hacer más sencilla la selección y el guardado de archivos de imágenes, ya que con los objetos de esta clase podemos llamar una ventana de selección de archivos, que nos permitirá elegir los archivos que editaremos en nuestra aplicación de forma visual.

La Vista

El código para implementar la vista de la aplicación aparecerá a continuación, separando cada una de las clases en un apartado.

Código para la implementación de la ventana de la aplicación:

EditorImg.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;

11

Page 12: Documentación Java

/** * Descripción: Esta clase implementa un editor básico de imágenes .jpg y .gif, * utilizando componentes Swing y una serie de clases para el manejo y procesamiento de imagenes digitales. * @author Beto González * @version 1.0 * @category Multimedia */

public class EditorImg extends JFrame{ static final long serialVersionUID=10000; PanelSwing panel;// TODO Auto-generated method stub public static void main(String[] args) { EditorImg editor = new EditorImg();editor.setBounds(120, 120, 800, 600);editor.setVisible(true);editor.setDefaultCloseOperation(DISPOSE_ON_CLOSE);editor.addWindowListener(new WindowAdapter() {

public void WindowCloser(WindowEvent e) { System.exit(0); } }); } /** * @Desc Constructor de la clase */EditorImg() { super("Editor básico de imagenes");Container contentPane = getContentPane();panel = new PanelSwing(this);contentPane.add(panel); }}

Código para implementar el lienzo sobre el que se dibujará la imagen:

PanelDeImagen.java

import java.awt.Color;import java.awt.Dimension;import java.awt.Graphics;import java.awt.Image;import javax.swing.JPanel;import javax.swing.JScrollPane;/** * @Desc Clase que extiende a la clase JPanel que se utiliza para crear un panel que permita visualizar imágenes en su interior * @author Beto González * */public class PanelDeImagen extends JPanel{ static final long serialVersionUID=10000; Image img; Dimension tamaño; JScrollPane base;/** * @Desc Constructor de la clase */PanelDeImagen() { setBackground(Color.white); } /** * @Desc Método a través del cual la clase recibe el objeto de la imagen que será visualizada en su interior * @param i */ public void estableceImagen(Image i) { img = i; }/** * @Desc Método a través del cual la clase obtiene la referencia hacia el panel en el cual se encuentra contenido. * @param i */ public void estableceBase(JScrollPane contenedor) { base = contenedor; } /** * @Desc Método extendido que es llamado cada ves que un objeto de esta clase llama al método repaint(). A este le agregamos * una funcionalidad adicional que le permite redimencionar el panel que contiene la imagen de acuerdo a las dimensiones de * ésta */ public void paintComponent(Graphics g) { super.paintComponent(g); if (img != null) {

if(base != null) { setSize(new Dimension(base.getWidth()-10,base.getHeight()-10)); setPreferredSize(new Dimension(base.getWidth()-10,base.getHeight()-10)); }

12

Page 13: Documentación Java

tamaño = new Dimension(getWidth(),getHeight()); int x = tamaño.width - img.getWidth(this); while (x < 0) { tamaño.setSize(tamaño.width+1, tamaño.height); x = tamaño.width - img.getWidth(this); } if(x > 0) x = (int) x/2; int y = tamaño.height - img.getHeight(this); while (y < 0) { tamaño.setSize(tamaño.width, tamaño.height+1); y = tamaño.height - img.getHeight(this); } if(y > 0) y = (int) y/2; if(!getSize().equals(tamaño)) { setSize(tamaño); setPreferredSize(tamaño); } g.drawImage(img, x, y, this); } }}

La funcionalidad de los objetos de la clase PanelDeImagen consistirá en que recibirán una imagen por medio del método estableceImagen() y la dibujarán en su panel al llamar al método repaint() que heredaron de la clase JPanel. Ya que en esta implementación el panel de las imagenes estará contenida dentro de un objeto JScrollPane, es que además contamos con el método estableceBase(), con el cual podemos guardar una referencia a este panel. Además, debido a que las dimensiones de las imagenes cargada por la aplicación pueden, es que extendimos al método paintComponent(), el cuál además de encargarse de dibujar la imagen dentro del panel, modificará las dimensiones de este y del panel JScrollPane que lo contenga, de forma que se adapten al tamaño de las imágenes y estas puedan ser visualizadas en su totalidad en pantalla.

La siguiente clase implementa la totalidad de los componentes de la interfaz gráfica de la aplicación:

PanelSwing.java

import java.awt.*;import javax.swing.*;import javax.swing.event.ChangeEvent;import javax.swing.event.ChangeListener;/** * @Desc Clase utilizada para crear los componentes de la interfaz gráfica de la aplicación * @author Beto González * */

public class PanelSwing extends JPanel { static final long serialVersionUID = 10000; String nombreArchivo, ruta; JMenuBar barraMenu; JMenu menuArchivo, menuEdicion; JMenuItem abrir, guardar, salir, brillo, color, escala; JScrollPane panelDespl; JPanel panelBajo, panelBrillo, panelColor, panelVacio; int altura = 80; Image imagen; Image imgAux; EditorImg editor; PanelDeImagen lienzo; JSlider jslBrillo, jslRojo, jslVerde, jslAzul; JLabel lblRojo, lblVerde, lblAzul; CardLayout esqueInf; /** * @Desc Constructor de la clase * @param editor */

13

Page 14: Documentación Java

PanelSwing(EditorImg editor) { this.editor = editor; this.setLayout(new BorderLayout()); barraMenu = new JMenuBar(); FlowLayout f = new FlowLayout(); f.setAlignment(FlowLayout.LEFT); barraMenu.setLayout(f); menuArchivo = new JMenu("Archivo"); menuEdicion = new JMenu("Edición"); abrir = menuArchivo.add("Abrir"); guardar = menuArchivo.add("Guardar"); guardar.setEnabled(false); menuArchivo.addSeparator(); salir = menuArchivo.add("Salir"); brillo = menuEdicion.add("Ajustar Brillo"); color = menuEdicion.add("Ajustar Colores"); escala = menuEdicion.add("Escala de Grises"); brillo.setEnabled(false); color.setEnabled(false); escala.setEnabled(false); barraMenu.add(menuArchivo); barraMenu.add(menuEdicion); this.add("North",barraMenu); //Agregamos la barra de menu creapanelCentral(); //Creamos el panel en el que se mostrara la imagen seleccionada creapanelBajo(); //Creamos el panel en el que se mostraran los controles para manipular la imagen } /** * @Desc Método que crea el contenido del panel central de la ventana */

private void creapanelCentral() { lienzo = new PanelDeImagen(); panelDespl = new JScrollPane(lienzo); lienzo.estableceBase(panelDespl); add("Center",panelDespl); } /** * @Desc Método que crea el contenido del panel inferior de la ventana */ private void creapanelBajo() { panelBajo = new JPanel(); esqueInf = new CardLayout(); panelBajo.setLayout(esqueInf); panelBajo.setPreferredSize(new Dimension(this.getWidth(),altura)); jslBrillo = new JSlider(SwingConstants.HORIZONTAL,0,100,0); jslBrillo.setPaintTicks(true); jslBrillo.setPaintLabels(true); jslBrillo.setMajorTickSpacing(10); jslBrillo.setMinorTickSpacing(5); panelColor = new JPanel(); panelVacio = new JPanel(); panelBrillo = new JPanel(new BorderLayout());

14

Page 15: Documentación Java

panelBrillo.add("Center", new JLabel("Puedes ajustar el brillo de la imagen",JLabel.CENTER)); panelBrillo.add("South",jslBrillo); panelBajo.add("carta1", panelVacio); panelBajo.add("carta2", panelBrillo); creaPaletas(); esqueInf.show(panelBajo, "carta1"); this.add("South",panelBajo); } /** * @Desc Método que crea el contenido del panel inferior de la ventana */ private void creaPaletas() { GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints constrain = new GridBagConstraints(); panelColor.setLayout(gridbag); lblRojo = new JLabel("Rojo"); lblVerde = new JLabel("Verde"); lblAzul = new JLabel("Azul"); constrain.gridx = 0; constrain.gridy = 0; constrain.gridheight = 1; constrain.gridwidth = 2; gridbag.setConstraints(lblRojo, constrain); panelColor.add(lblRojo); constrain.gridx = 2; constrain.gridy = 0; gridbag.setConstraints(lblVerde, constrain); panelColor.add(lblVerde); constrain.gridx = 4; constrain.gridy = 0; gridbag.setConstraints(lblAzul, constrain); panelColor.add(lblAzul); jslRojo = new JSlider(SwingConstants.HORIZONTAL,0,50,0); jslVerde = new JSlider(SwingConstants.HORIZONTAL,0,50,0); jslAzul = new JSlider(SwingConstants.HORIZONTAL,0,50,0); constrain.gridx = 0; constrain.gridy = 1; constrain.gridheight = 1; constrain.gridwidth = 2; gridbag.setConstraints(jslRojo, constrain); panelColor.add(jslRojo); constrain.gridx = 2; constrain.gridy = 1; gridbag.setConstraints(jslVerde, constrain); panelColor.add(jslVerde); constrain.gridx = 4; constrain.gridy = 1; gridbag.setConstraints(jslAzul, constrain); panelColor.add(jslAzul); panelBajo.add("carta3", panelColor); }}

Hasta este punto hemos completado la parte de la Vista de la aplicación, y nos quedan pendientes el Controlador y el Modelo. Sin embargo, para poder apreciar realmente la funcionalidad de las clases anteriores es necesario probarlas, echando a correr el programa, de forma que podamos visualizarlas y obtener un resultado como el siguiente:

15

Page 16: Documentación Java

En esta captura, podemos apreciar los tres paneles principales de la aplicación, el menú de opciones en la parte superior, el panel central que contiene los paneles de los componentes de las clases JScrollPane y PanelDeImagen, y finalmente el panel inferior, en el cual se desplegarán los componentes visuales para la edición de las imagenes, una vez que el Controlador y el Modelo estén trabajando.

Ahora terminaremos con el código que quedó pendiente en el artículo anterior, que consiste en la programación del Controlador y el Modelo de nuestra aplicación.

El Controlador tendrá la obligación de manejar los eventos que ocurran en la interfaz de usuario, de modo que recibirá las acciones del usuario en el menú de opciones y las paletas de edición, los cuales ya creamos en el artículo anterior.

Por otro lado, el Modelo tendrá responsabilidades a más bajo nivel, encargándose de implementar la carga, la edición y el guardado de las imágenes. Separando las diferentes funcionalidades en dos capas de nivel distinto, como si de las capas de Negocio y Acceso a datos se tratara.

El Controlador

El Controlador de la aplicación consistirá en una única clase que implementará las interfaces ActionListener y ChangeListener, para implementar en control de eventos del menú y de las barras JSlider respectivamente.

El código es el siguiente:

Controlador.java

import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JMenuItem;import javax.swing.JSlider;import javax.swing.event.ChangeEvent;import javax.swing.event.ChangeListener;import javax.swing.JPanel;/** * @Desc Clase que implementa la gestión de evento en la interfaz de usuario * @author Beto González * */public class Controlador implements ActionListener, ChangeListener{ ManejadorDeImagenes manejador; PanelSwing panel; public Controlador(PanelSwing panel) { this.panel = panel; manejador = new ManejadorDeImagenes(); } /** * @Desc Método que capturará los eventos ocurridos en el menú principal del sistema */ public void actionPerformed(ActionEvent ie) { JMenuItem i = (JMenuItem)ie.getSource(); if(i.getText() == "Abrir"){ boolean estado = manejador.cargaArchivoDeImagen(panel, panel.lienzo); if(estado) { panel.guardar.setEnabled(true); panel.brillo.setEnabled(true); panel.color.setEnabled(true); panel.escala.setEnabled(true); panel.esqueInf.show(panel.panelBajo, "carta1"); } }

16

Page 17: Documentación Java

else if(i.getText() == "Guardar") manejador.guardaArchivoDeImagen(panel); else if(i.getText() == "Salir") System.exit(0); else if(i.getText() == "Ajustar Brillo") { manejador.restableceImagen(panel.lienzo); panel.jslBrillo.setValue(0); panel.esqueInf.show(panel.panelBajo, "carta2"); } else if(i.getText() == "Ajustar Colores") { manejador.restableceImagen(panel.lienzo); panel.esqueInf.show(panel.panelBajo, "carta3"); } else if(i.getText() == "Escala de Grises") { panel.esqueInf.show(panel.panelBajo, "carta1"); manejador.muestraEscalaDeGrises(panel.lienzo); } } /** * @Desc Método que captarará los eventos ocurridos en los componentes JSlider de la interfaz de usuario */ public void stateChanged(ChangeEvent e) { JSlider slider = (JSlider) e.getSource(); if(slider == panel.jslBrillo) manejador.muestraBrillo(panel.lienzo, slider.getValue()); else if(slider == panel.jslRojo) { manejador.muestraColores(panel.lienzo, slider.getValue(), panel.jslVerde.getValue(), panel.jslAzul.getValue()); } else if(slider == panel.jslVerde) manejador.muestraColores(panel.lienzo, panel.jslRojo.getValue(), slider.getValue(), panel.jslAzul.getValue()); else if(slider == panel.jslAzul) manejador.muestraColores(panel.lienzo, panel.jslRojo.getValue(), panel.jslVerde.getValue(), slider.getValue()); }}

Como podemos ver, en la implementación del método actionPerformed() lleva a cabo las acciones relacionadas con el menú de opciones, tanto para las acciones de la opción "Archivo" (Abrir, Guardar y Salir) como para la "Edición" (Ajustar Brillo, Ajustar Colores, Escala de Grises). Las opciones de edición solo se activarán una vez que un archivo de imagen haya sido cargado por el editor, para lo cual se apoyará en un objeto de la clase ManejadorDeImagenes, la cual veremos más adelante.

En la implementación del método stateChanged(), se reciben las acciones ocurridas en los controles de tipo JSlider, de forma que podremos capturar el valor del brillo o los colores que el usuario capture en la interface, y llamará a alguno de los métodos del objeto de la clase ManejadorDeImagenes para aplicar estos cambios a las imagenes cargadas.

El Modelo

Como ya explicamos antes, el modelo consistirá estará separado en dos capas, que en la programación veremos expresado como dos clases diferentes. La primera ManejadorDeImagenes, que equivaldrá a la capa de negocio

17

Page 18: Documentación Java

en las aplicaciones de manejo de datos. Esta clase será un intermediario entre el Controlador y la Vista de la aplicación con el nivel de Acceso a datos, que en este caso consiste en la apertura, modificación y salvado de las imágenes. Estas operaciones de bajo nivel serán llevadas a cabo por la clase ProcesadorDeImagenes, la cual estará completamente abstraída del resto de la aplicación, ya que en ella ocurrirán las operaciones a nivel de pixeles sobre las imágenes, y además poseerá métodos para cargar una imagen desde el archivo y salvar las imágenes resultantes del procesamiento hacia un archivo nuevo.

El código de la primera de estas clases aparece a continuación:

ManejadorDeImagenes.java

import java.awt.*;import javax.swing.JFileChooser;import javax.swing.JOptionPane;import javax.swing.JPanel;/** * @Desc Clase del nivel de la capa de negocios, que implementa las operaciones que son llamadas desde el Controlador de la aplicación * para poder cargar las imagenes, alamacenarlas y modificaralas, apoyandose en un objeto la clase de más bajo nivel, es decir ProcesadorDeImagenes * @author Beto González * */public class ManejadorDeImagenes { ProcesadorDeImagenes procesador; boolean editado = false; // Constructor de la clase public ManejadorDeImagenes() { procesador = new ProcesadorDeImagenes(); } /** * @Desc Método que lleva a cabo la carga de un archivo de imagen * @param contenedor * @param lienzo * @return */ public boolean cargaArchivoDeImagen(JPanel contenedor, PanelDeImagen lienzo) { String nombreArchivo = ""; boolean estado = true; if(editado) { new MsgError("Confirmacion","Aqui debemos pedir confirmación",200,180); int resultado = JOptionPane.showConfirmDialog((Component)null, "¿Deseas guardar los cambios en este documento?","Confirmación",JOptionPane.YES_NO_OPTION); if(resultado==JOptionPane.YES_OPTION) guardaArchivoDeImagen(contenedor); } JFileChooser selector = new JFileChooser(); selector.addChoosableFileFilter(new FiltrodeArchivo("gif","Archivos Gif")); String lista[] = {"jpeg","jpg"}; selector.addChoosableFileFilter(new FiltrodeArchivo(lista,"Archivos JPEG")); selector.setDialogTitle("Abrir archivo de imagen"); selector.setDialogType(JFileChooser.OPEN_DIALOG); int resultado = selector.showOpenDialog(null); if(resultado == JFileChooser.APPROVE_OPTION) { nombreArchivo = selector.getSelectedFile().getName(); String ruta = selector.getSelectedFile().getPath(); Image imagen = procesador.cargaImagen(ruta, nombreArchivo); lienzo.estableceImagen(imagen); lienzo.repaint(); editado = false; } else estado = false; return estado; } /** * @Desc Método que lleva a cabo la operación de salvar el archivo de imagen cargado * @param contenedor * @return */ public boolean guardaArchivoDeImagen(JPanel contenedor) {

18

Page 19: Documentación Java

boolean estado = true; JFileChooser selector = new JFileChooser(); selector.addChoosableFileFilter(new FiltrodeArchivo("gif","Archivos Gif")); String lista[] = {"jpeg","jpg"}; selector.addChoosableFileFilter(new FiltrodeArchivo(lista,"Archivos JPEG")); selector.setDialogTitle("Guardar archivo de imagen"); selector.setDialogType(JFileChooser.SAVE_DIALOG); int resultado = selector.showSaveDialog(contenedor); if(resultado == JFileChooser.APPROVE_OPTION) { //guardar archivo en la ruta especificada String nombreArchivo = selector.getSelectedFile().getName(); String ruta = selector.getSelectedFile().getPath(); estado = procesador.guardaImagen(ruta, nombreArchivo); if(!estado) JOptionPane.showMessageDialog((Component)null,"Error del sistema : "+procesador.devuelveMensajeDeError(),"Error de Imagen",JOptionPane.OK_OPTION); editado = false; } else estado = false; return estado; } /** * @Desc Método que lleva a cabo la transformación de la imagen cargada a una imagen de escala de grises y la despliega en pantalla * @param lienzo */ public void muestraEscalaDeGrises(PanelDeImagen lienzo) { procesador.escalaDeGrises(); lienzo.estableceImagen(procesador.devuelveImagenModificada()); lienzo.repaint(); }

/** * @Desc Método que lleva a cabo la modificación del brillo de la imagen cargada y despliega la imagen resultante en pantalla * @param lienzo * @param valor */ public void muestraBrillo(PanelDeImagen lienzo, int valor) { procesador.modificaBrillo(valor);

lienzo.estableceImagen(procesador.devuelveImagenModificada()); lienzo.repaint(); editado = true; } /** * @Desc @Desc Método que lleva a cabo la modificación de los colores de la imagen cargada y despliega la imagen resultante en pantalla * @param lienzo * @param rojo * @param verde * @param azul */ public void muestraColores(PanelDeImagen lienzo, int rojo, int verde, int azul) { procesador.modificaColor(rojo,verde,azul); lienzo.estableceImagen(procesador.devuelveImagenModificada()); lienzo.repaint(); editado = true; } /** * @Desc Método que coloca en la pantalla la imagen original que se cargó con el método cargarArchivoDeImagen * @param lienzo */ public void restableceImagen(PanelDeImagen lienzo) { lienzo.estableceImagen(procesador.devuelveImagenBase()); lienzo.repaint(); editado = false;

19

Page 20: Documentación Java

}}

Como vemos en los métodos cargaArchivoDeImagen() y guardaArchivoDeImagen(), la funcionalidad para elegir los archivos que serán cargados y guardados se facilita con el uso de la clase JFileChooser, la cual permite llamar a una ventana de selección de archivos, con la cual resulta más agradable esta tarea.

También podemos apreciar que se utiliza un objeto de la clase FiltroDeArchivo, para establecer el filtro que tendrá el objeto selector de la clase JFileChooser. De esta forma nos aseguramos que solo puedan ser seleccionadas imágenes de tipo JPEG y GIF. El código de esta clase auxiliar aparece a continuación:

FiltroDeArchivo.java

import java.io.*;/** * @Desc Clase que permite crear un filtro de archivos para utilizarlo con un selector de archivos * @author Beto González * */public class FiltrodeArchivo extends javax.swing.filechooser.FileFilter { String descrip = ""; String listTipos[]; FiltrodeArchivo(String tipo, String descripcion) { listTipos = new String[1]; listTipos[0] = tipo; descrip = descripcion; } FiltrodeArchivo(String listTipos[], String descripcion) { this.listTipos = listTipos; descrip = descripcion; } public boolean accept(File fileobj){ boolean extIgual = false; String extension = ""; int ind=0; if(fileobj.getPath().lastIndexOf(".") > 0) { extension = fileobj.getPath().substring(fileobj.getPath().lastIndexOf(".")+1).toLowerCase(); } if(extension!="") { while(ind<listTipos.length && !extIgual) { extIgual = extension.equals(listTipos[ind].toLowerCase()); ind++; } return extIgual; } else return fileobj.isDirectory(); } public String getDescription() { if (descrip != "") return descrip.concat(concatTipos()); else return ""; } private String concatTipos() { StringBuffer tipos = new StringBuffer(" (*."+listTipos[0]); for(int i=1;i<listTipos.length;i++) tipos.append(",*."+listTipos[i]); tipos.append(")"); return tipos.toString(); }}

20

Page 21: Documentación Java

Tanto estos dos métodos como el resto serán llamados desde el Controlador de la aplicación para cada acción que el usuario vaya realizando en la interfaz gráfica. De modo que el método muestraEscalaDeGrises() será llamado cuando el usuario seleccione la opcion "Escala de Grises" en el menú principal. Mientas que el método muestraBrillo() es llamado cuando el usuario realice un cambio en el brillo de la imagen, utilizando la barra JSlider jslBrillo para ajustar el brillo. Algo similar ocurrirá con el método muestraColores(), que se llamará cuando alguna de las barras JSlider de colores (jslRojo, jslVerde, jslAzul) sea utilizada. Estos métodos además llevan a cabo la actualización en la pantalla de las imágenes una vez que son modificadas. En el caso de que el usuario aumente el brillo o modifique los colores, la acción ocurrirá tan rápido que no podrá darse cuenta de todo el trabajo que la PC llevó a cabo para cambiar la apariencia de la imagen capturada.

El método restableceImagen() se utiliza para volver a colocar en la pantalla la imagen original que fue cargada, lo cual es simplemente una forma de asegurarnos que las tres acciones de edición (aumentar brillo, modificar colores y convertir a escala de grises) siempre ocurran sobre la misma imagen que fue cargada.

El código de la clase ProcesadorDeImagenes a la que nos hemos referido aparece a continuación:

ProcesadorDeImagenes.java

import java.awt.Canvas;import java.awt.image.*;import java.awt.Image;import java.awt.Toolkit;import java.io.IOException;import java.io.File;import java.awt.Graphics;import java.awt.image.BufferedImage;import javax.imageio.ImageIO;/** * @Desc Clase que implementa el procesamiento básico de imágenes digitales * @author Beto González * */public class ProcesadorDeImagenes extends Canvas { Image imagenBase; Image imagenModificada; String mensajeDeError = ""; String tipoDeImagen = ""; /** * @Desc Método que permite agregar una imagen al procesador que es recibida como parámetro * @param imagen */ public void estableceImagen(Image imagen) { imagenBase = imagen; imagenModificada = null; tipoDeImagen = (String)imagenBase.getProperty("type", this); } /** * @Desc Método que permite agregar una imagen al procesador directamente desde un archivo de imagen * @param imagen */ public Image cargaImagen(String ruta, String nombreDeArchivo) { imagenBase = Toolkit.getDefaultToolkit().getImage(ruta); imagenModificada = null; String[] partes = null; partes = nombreDeArchivo.split("\\."); int tope = partes.length; if(tope > 1) tipoDeImagen = partes[tope - 1]; return imagenBase; }

/** * @Desc Método que modifica el brillo de la imagen base contenida a partir del valor de intesidad recibido * @param intensidad * @return Verdadero si todo salió bien, falso en caso de error */ public boolean modificaBrillo(int intensidad) {

21

Page 22: Documentación Java

boolean estado = true; int p, rojo, verde, azul; int a = imagenBase.getWidth(this); //Ancho int h = imagenBase.getHeight(this); //Alto int totalDePixeles = a * h; int pixeles[] = new int[totalDePixeles]; //Arreglo de pixeles PixelGrabber pg = new PixelGrabber(imagenBase,0,0,a,h,pixeles,0,a); try { pg.grabPixels(); for(int i = 0; i < totalDePixeles; i++) { p = pixeles[i]; //Valor de un pixel rojo = (0xff & (p>>16)) + intensidad; //Desplaza el entero p 16 bits a la derecha y aplica la operacion AND a los primeros 8 bits verde = (0xff & (p>>8)) + intensidad; //Desplaza el entero p 8 bits a la derecha y aplica la operacion AND a los siguientes 8 bits azul = (0xff & p) + intensidad; //Aplica la operacion AND a los siguientes 8 bits if(rojo>255) rojo=255; if(verde>255) verde=255; if(azul>255) azul=255; if(rojo<0) rojo=0; if(verde<0) verde=0; if(azul<0) azul=0; pixeles[i]=(0xff000000|rojo<<16|verde<<8|azul); } imagenModificada = createImage(new MemoryImageSource(a,h,pixeles,0,a)); }catch(InterruptedException e) { JOptionPane.showMessageDialog((Component)null,"Error del sistema : "+e.getMessage(),"Error de Imagen",JOptionPane.OK_OPTION); estado = false; this.mensajeDeError = e.getMessage(); } return estado; }

/** * @Desc Método que convierte la imagen base contenida en una imagen a escala de grises * @return Verdadero si todo salió bien, falso en caso de error */ public boolean escalaDeGrises() { boolean estado = true; int p, promedio, rojo, verde, azul; int a = imagenBase.getWidth(this); //Ancho int h = imagenBase.getHeight(this); //Alto int totalDePixeles = a * h; int pixeles[] = new int[totalDePixeles]; //Arreglo de pixeles

22

Page 23: Documentación Java

PixelGrabber pg = new PixelGrabber(imagenBase,0,0,a,h,pixeles,0,a); try { pg.grabPixels(); for(int i = 0; i < totalDePixeles; i++) { p = pixeles[i]; //Valor de un pixel rojo = (0xff & (p>>16)); //Desplaza el entero p 16 bits a la derecha y aplica la operacion AND a los primeros 8 bits verde = (0xff & (p>>8)); //Desplaza el entero p 8 bits a la derecha y aplica la operacion AND a los siguientes 8 bits azul = (0xff & p) ; //Aplica la operacion AND a los siguientes 8 bits promedio = (int) ((rojo+verde+azul)/3); pixeles[i]=(0xff000000|promedio<<16|promedio<<8|promedio); } imagenModificada = createImage(new MemoryImageSource(a,h,pixeles,0,a)); }catch(InterruptedException e) { //JOptionPane.showMessageDialog((Component)null,"Error del sistema : "+e.getMessage(),"Error de Imagen",JOptionPane.OK_OPTION); estado = false; this.mensajeDeError = e.getMessage(); } return estado; } /** * @Desc Método que modifica los colores de la imagen base contenida a partir de los valores de intensidad de los colores rojo, verde y amarillo recibidos * @param iRojo * @param iVerde * @param iAzul * @return Verdadero si todo salió bien, falso en caso de error */ public boolean modificaColor(int iRojo, int iVerde, int iAzul) { boolean estado = true; int p, rojo=0, verde=0, azul=0; int a = imagenBase.getWidth(this); //Ancho int h = imagenBase.getHeight(this); //Alto int totalDePixeles = a * h; int pixeles[] = new int[totalDePixeles]; //Arreglo de pixeles PixelGrabber pg = new PixelGrabber(imagenBase,0,0,a,h,pixeles,0,a); try { pg.grabPixels(); for(int i = 0;i<(a*h);i++) { p = pixeles[i]; //Valor de un pixel rojo = (0xff & (p>>16)) + iRojo; verde = (0xff & (p>>8)) + iVerde; azul = (0xff & p) + iAzul; if(rojo>255) rojo=255; if(verde>255) verde=255;

23

Page 24: Documentación Java

if(azul>255) azul=255; if(rojo<0) rojo=0; if(verde<0) verde=0; if(azul<0) azul=0; pixeles[i]=(0xff000000|rojo<<16|verde<<8|azul); } imagenModificada = createImage(new MemoryImageSource(a,h,pixeles,0,a)); }catch(InterruptedException e) { estado = false; this.mensajeDeError = e.getMessage(); } return estado; } /** * @Desc Método que almacena la imagen contenida en una archivo de imagen, de acuerdo a la información del archivo que recibe como parámetro * @param ruta * @param nombreDeArchivo * @param tipoDeImagen * @return */ public boolean guardaImagen(String ruta, String nombreDeArchivo, String tipoDeImagen) { boolean estado = true; BufferedImage imagen = creaBufferedImage((imagenModificada != null) ? imagenModificada : imagenBase); try { ImageIO.write(imagen, tipoDeImagen, new File(ruta)); } catch (IOException e) { estado = false; this.mensajeDeError = e.getMessage(); } return estado; } /** * @Desc Versión por defecto del método guardaImagen * @param ruta * @param nombreDeArchivo * @return */ public boolean guardaImagen(String ruta, String nombreDeArchivo) { String[] partes = null; partes = nombreDeArchivo.split("\\.");

int tope = partes.length; if(tope > 1) tipoDeImagen = partes[tope - 1]; return guardaImagen(ruta, nombreDeArchivo, tipoDeImagen); } /** * @Desc Método que devuelve la imagen modificada por el procesador en un objeto de la clase Image * @return */ public Image devuelveImagenModificada() { return imagenModificada; } /** * @Desc Método que devuelve la imagen base dentro de un objeto de la clase Image * @return */ public Image devuelveImagenBase() { return imagenBase; } /** * @Desc Método que retora el último mensaje de error producido por los métodos de la clase * @return */ public String devuelveMensajeDeError() { return mensajeDeError; }

24

Page 25: Documentación Java

/** * @Desc Versión por defecto del método creaBufferedImage * @param imageIn * @return El objeto BufferedImage */ public BufferedImage creaBufferedImage(Image imagenDeEntrada) { return creaBufferedImage(imagenDeEntrada, BufferedImage.TYPE_INT_RGB); } /** * @Desc Método para convertir un objeto Image a un objeto BufferedImage * @param imageIn * @param imageType * @return El objeto BufferedImage */ public BufferedImage creaBufferedImage(Image imagenDeEntrada, int imageType) { BufferedImage bufferedImageDeSalida = new BufferedImage(imagenDeEntrada.getWidth(this),imagenDeEntrada.getHeight(this), imageType); Graphics g = bufferedImageDeSalida.getGraphics(); g.drawImage(imagenDeEntrada, 0, 0, null); return bufferedImageDeSalida; }}

Como ya mencionamos esta clase trabajo al nivel más bajo de la aplicación directamente con los pixeles de las imagenes. Para lograr esto utiliza dos objetos de las clase Image (imagenBase e imagenModificada), para almacenar tanto las imágenes que son leídas tanto como la imagen que resulta del procesamiento (respectivamente). Los métodos estableceImagen() y cargarImagen() le permiten tener una imagen sobre la cual llevar a cabo el procesamiento que ocurre en los otros métodos.

Los métodos modificaBrillo(), escalaDeGrises() y modificaColores() llevan a cabo los cambios en los pixeles de la imagen, aplicando una serie de operaciones a cada uno de sus valores de intensidad de color, almacenando los valores de los pixeles dentro de un arreglo de número enteros y recorriéndolo dentro de un ciclo for. De esta forma, cada uno de los pixeles es tratado como un número entero, para el cual los valores de la intensidad del color estarán contenidos en sus primeros tres grupos de 8 bits. Es decir, los primero 8 bits menos significativos del entero representarán la intensidad del azul, los siguientes 8 bits los del verde y los 8 bits que le siguen los del rojo. Es por esto que en el código vemos que se lleva a cabo un desplazamiento a nivel de bits del valor de un pixel, para junto con la operación AND obtener los 8 bits del valor de cada uno de los tres colores del pixel:

p = pixeles[i]; //Valor de un pixelrojo = (0xff & (p>>16)) + intensidad; //Desplaza el entero p 16 bits a la derecha y aplica la operacion AND a los primeros 8 bits verde = (0xff & (p>>8)) + intensidad; //Desplaza el entero p 8 bits a la derecha y aplica la operacion AND a los siguientes 8 bitsazul = (0xff & p) + intensidad; //Aplica la operacion AND a los siguientes 8 bits

El código anterior es el que encontramos en el método modificaBrillo(), y lo que vemos que se hace es justamente sumarle una misma cantidad a cada uno de los valores de color del pixel para de esta forma obtener un pixel más iluminado, para después almacenar este pixel obtenido dentro del arreglo de pixeles.

25

Page 26: Documentación Java

En los otros dos métodos se sigue una lógica parecida, con la única diferencia de que para modificaColores, se aumentará la intensidad de los colores de los pixeles con un valor distinto para cada color, mientras que en escalaDeGrises se promediará el valor de los tres colores de cada pixel y se almacenará el mismo resultado dentro de los tres valores de color del pixel, para de esta forma obtener el equivalente en escala de grises del color original.

Implementación final

Ahora bien, visto el código del Controlador y el Modelo de la aplicación, solo nos queda juntarlo todo con la Vista para echar a correr el programa final. Para hacer eso, tendremos que modificar el código de la clase EditorImg que realizamos en el artículo anterior, agregando las líneas que se remarcan en el siguiente código:

EditorImg.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;/** * Descripción: Esta clase implementa un editor básico de imagenes .jpg y .gif, * utilizando componentes Swing y clases de la libreria image. * @author Alberto González Espinoza * @version 1.0 * @category Multimedia */public class EditorImg extends JFrame{ static final long serialVersionUID=10000; PanelSwing panel; Controlador controlador; public static void main(String[] args) { // TODO Auto-generated method stub EditorImg editor = new EditorImg(); editor.setBounds(120, 120, 800, 600); editor.setVisible(true); editor.setDefaultCloseOperation(DISPOSE_ON_CLOSE); editor.addWindowListener(new WindowAdapter() { public void WindowCloser(WindowEvent e) { System.exit(0); } }); } /** * @Desc Constructor de la clase */ EditorImg() { super("Editor básico de imagenes"); Container contentPane = getContentPane(); panel = new PanelSwing(this); controlador = new Controlador(panel); panel.abrir.addActionListener(controlador); panel.guardar.addActionListener(controlador); panel.salir.addActionListener(controlador); panel.brillo.addActionListener(controlador); panel.escala.addActionListener(controlador); panel.color.addActionListener(controlador); panel.jslBrillo.addChangeListener(controlador); panel.jslRojo.addChangeListener(controlador); panel.jslVerde.addChangeListener(controlador); panel.jslAzul.addChangeListener(controlador); contentPane.add(panel); }}

26

Page 27: Documentación Java

Y como vemos, lo que se hace es simplemente agregar el Controlador a la aplicación, instanciando un objeto de la clase Controlador, y asignando la gestión de eventos del menú principal y de los componentes JSlider a este objeto.

Una vez listo el paso anterior, podemos probar correr el programa y deberemos ver la misma pantalla que en el artículo anterior, con la diferencia de que ahora ya podremos cargar, editar y modificar las imágenes.

Por ejemplo, así es como se visualiza el cargado de las imágenes:

Aquí vemos una imagen ya cargada:

Si modificamos los colores:

O el brillo:

Y aquí como se ve en escala de grises:

Al final solo tenemos que salvar la imagen para concluir con el proceso de edición.

Bien, el código está totalmente a su disposición y es obviamente propenso a mejoras :D, ya que las funciones de procesamiento que aquí implementamos son algunas de las que se consideran básicas, pero con estos principios es posible incursionar en conceptos más avanzados de procesamiento de imágenes, en particular le veo mucho potencial a la clase ProcesadorDeImagenes para seguirla desarrollando e incluir un amplio abanico de operaciones de procesamiento de imágenes digitales, y que gracias a la abstracción de su diseño, pueda ser llevada a otras aplicaciones de forma transparente.

________________________________

http://www.javamexico.org/foros/comunidad/imagen_con_jfilechooser

que tal amigos alguna sugerencia para mi problema.... la idea es mostrar una imagenque selecciono con un jfilechosser el porblema es que no lo hace , si pongo la imagen fuera del boton si lo hae laguna sugerencia,import java.awt.event.*;import java.awt.*;import javax.swing.*;import java.io.FileFilter;import java.io.*;public class Interfaz{ private JFrame frame; JPanel panel,dos; private JScrollPane scrollpane; private JButton pic; private JButton audio; private JButton salir;

public Interfaz() {

27

Page 28: Documentación Java

frame = new JFrame("JAVA MULTIMEDIA "); frame.setVisible(true); panel=new JPanel(); panel.setLayout(null); panel.setVisible(true); frame.add(panel); //--------------------> contenido del marco <-------------------- pic=new JButton("Imagen"); pic.setBounds(10,50,100,30); panel.add(pic); //-------------------> fin boton pic <--------------------------- audio=new JButton("Audio"); audio.setBounds(10,130,100,30); panel.add(audio); //-------------------> fin boton audio <--------------------------- salir=new JButton("Salir"); salir.setBounds(10,200,100,30); panel.add(salir); /* ImageIcon imagen = new ImageIcon("Dirk-Nowitzki1.jpg"); JLabel etiqueta = new JLabel(imagen); etiqueta.setBounds(20,30,60,36); panel.add(etiqueta);*/ frame.setBounds(200,300,600,360); frame.setResizable(false); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); pic.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JFileChooser selector=new JFileChooser(); selector.setFileFilter(new FiltroJava()); int estado=selector.showOpenDialog(null); File archivoelegido=selector.getSelectedFile();String ruta=archivoelegido.getPath(); if(archivoelegido.exists()) System.out.println("bien"); else System.out.println("no bien"); if(estado==JFileChooser.APPROVE_OPTION); { ImageIcon imagen = new ImageIcon("ruta"); JLabel etiqueta = new JLabel(imagen); etiqueta.setBounds(20,30,60,36);

panel.add(etiqueta); }

} });//boton

28

Page 29: Documentación Java

salir.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); }//constructor

}//clase<\code>

otro

import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.File;

import javax.swing.BorderFactory;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFileChooser;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane;

import javax.swing.JPanel;import javax.swing.UIManager;import javax.swing.filechooser.FileNameExtensionFilter;

public class Imagen implements ActionListener{ private JFrame frame; private JLabel labelImagen; private JButton boton; private JPanel panelComponentes, panelImagen; private JFileChooser fileChooser; public static void main(String arg[]) { //Bloque try-catch para atrapar los errores try { //Look and Feel para la aplicacion dependiendo del sistema operativo UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { e.printStackTrace();

29

Page 30: Documentación Java

} //Inicia la aplicacion new Imagen(); } //Construtor de la clase public Imagen() { //Creando frame principal y obteniendo un Contenedor y un manejador BorderLayout frame = new JFrame("Abrir imagenes"); frame.getContentPane().setLayout( new BorderLayout() ); /**Creacion de componentes*/ //Label labelImagen = new JLabel(); //Boton boton = new JButton("Abrir archivo"); //Seteando la propiedad actionCommand boton.setActionCommand("abre"); //Creando paneles y añadiendolos al frame principal panelComponentes = new JPanel(); panelComponentes.setLayout( new BorderLayout() ); panelComponentes.add(boton, BorderLayout.CENTER); panelComponentes.setBorder( BorderFactory.createTitledBorder ("Abre la imagen...") ); frame.add(panelComponentes, BorderLayout.NORTH); panelImagen = new JPanel(); panelImagen.setLayout( new BorderLayout() ); panelImagen.setBorder( BorderFactory.createTitledBorder ("Visualizacion de la imagen") ); panelImagen.add( labelImagen, BorderLayout.CENTER); frame.add( panelImagen ,BorderLayout.CENTER ); //Estableciendo visibilidad, tamaño y cierrre de la aplicacion frame.setVisible(true); frame.setBounds(500,200, 400, 600); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Agregando un escuchador al boton boton.addActionListener(this); //Creando FileChooser fileChooser = new JFileChooser(); //Añadiendole un filtro FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & PNG", "jpg", "png"); fileChooser.setFileFilter(filter); } //Metodo de accion para el boton public void actionPerformed(ActionEvent e)

30

Page 31: Documentación Java

{ if("abre".equals( e.getActionCommand() ) ) { //Valor que tomara el fileChooser int regresaValor = fileChooser.showOpenDialog(null); //Accion del fileChooser if(regresaValor == JFileChooser.APPROVE_OPTION) { //Crear propiedades para ser utilizadas por fileChooser File archivoElegido = fileChooser.getSelectedFile(); //Obteniendo la direccion del archivo String direccion = archivoElegido.getPath(); //Bloque try-catch para errores try { //Obtiene la direccion del archivo y lo instancia en icon ImageIcon icon = new ImageIcon( direccion ); //Setea el labelImagen con el archivo obtenido labelImagen.setIcon( icon ); } catch(Exception es) { JOptionPane.showMessageDialog(null, "Upss!! error abriendo la imagen "+ es); } } } } }

Trabajo con JFrame = http://jdeveloper.wikispaces.com/ (cómo hacer)______________________Calcular valores de los elementos de un arreglo = https://www.youtube.com/watch?v=N3autujqEc4

Como Insertar una Imagen a un JLabel desde URL

En este post indicaremos como insertar una imagen como icono en un JLabel. Ademas se insertara un scroll para que la imagen aparezca independiente del tamaño.La imagen a insertar sera tipo .jpg; se pueden utilizar imagenes con extensiones .png, jpg, gif.

En codigo descrito a continuacion establece un JFrame, sobre el cual se insertara un JLable, donde finalmente se pegara una imagen obtenida a traves de una URL.JFrame>>JLabel>>imagenNuestro primer paso es declarar la URL:URL url = new URL("http://www.info-centro-24.com/documents/admin/uploads/classifieds/img-45- 30867-original.jpg");

Seguido de esto se guardara la URL sobre una variable tipo Imagen.

31

Page 32: Documentación Java

Image image = ImageIO.read(url);A continuacion se crea el JLabel donde se pegara la variable "image" tipo Imagen, estableciendola como ImageIcon();JLabel label = new JLabel(new ImageIcon(image));

Nuestro ultimo paso es crear el Scroll y agregarlo al JLabel.JScrollPane scroll = new JScrollPane(label);add(scroll);

No olvidarse que en nuestro main tendremos que establecer el JFrame como visible, establecer un tamano para el mismo, de la siguiente manera:ImagenURL imagen = new ImagenURL();imagen.setSize(400, 400);imagen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);imagen.setVisible(true);imagen.setLocationRelativeTo(null);

La salida de nuestro programa quedara de la siguiente manera:El codigo se presenta a continuacion:Data hosted with ♥ by Pastebin.com - Download Raw - See Original

package imagenurl; import java.awt.Image; import java.io.IOException; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; /** * * @author Rafa */ public class ImagenURL extends JFrame{ public ImagenURL() throws IOException { super("ImagenURL"); //establece nombre a JFrame URL url = new URL("http://www.info-centro-24.com/documents/admin/uploads/" + "classifieds/img-45-30867-original.jpg"); Image image = ImageIO.read(url); //Creal el JLabel y ingresa la imagen sobre el. JLabel label = new JLabel(new ImageIcon(image));

32

Page 33: Documentación Java

//Establece las barras de desplazamiento de la imagen JScrollPane scroll = new JScrollPane(label); add(scroll); } public static void main(String[] args) throws IOException { ImagenURL imagen = new ImagenURL(); imagen.setSize(400, 400); imagen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); imagen.setVisible(true); imagen.setLocationRelativeTo(null); } }Podemos descargarnos el proyecto, click en la siguiente imagen:

http://es.slideshare.net/Votrepoete/tema-14-imgenes-en-java-por-gio = EXCELENTE Y COMPLETO =

Tema 14 imágenes en java por gio

1. ITSON Manuel Domitsu Kono

Imágenes en JavaUna imagen es un arreglo bidimensional de colores. Cada elemento de un arreglo se llama pixel. Una imagen es diferente de una superficie de dibujo. Los pixeles de una imagen no coinciden necesariamente con un pixel en la superficie de dibujo. Una imagen tiene ancho y un alto, medido en pixeles y un sistema de coordenadas que es independiente de la superficie de dibujo. En Java 2D, una imagen se representa por las clases Image y BufferedImage, figura 14.1.

33

Page 34: Documentación Java

La clase abstracta Image representa una imagen como un arreglo rectangular de pixeles. La clase BufferedImage le permite a la aplicación trabajar directamente con los datos de la imagen (por ejemplo obteniendo o estableciendo el color de un pixel). Esta clase administra directamente la imagen en memoria y provee métodos para almacenar, interpretar y obtener datos de los pixeles.

Figura 14.1 Clases que Representan una Imagen

2. 548 Imágenes en Java Un objeto de tipo BufferedImage es esencialmente un objeto del tipo Image con un buffer de datos accesible, por lo que la hace más eficiente para trabajar que con un objeto del tipo Image. Un objeto de tipo BufferedImage tiene un modelo de color, un objeto del tipo ColorModel y un entramado de los datos de la imagen, un objeto del tipo Raster, figura 14.2.

Figura 14.2

Un objeto de Tipo Buffered ImageEl objeto de tipo ColorModel provee una interpretación de los pixeles de la imagen dentro del espacio de color. Un espacio de color es esencialmente una colección de todos los colores que pueden representarse en un dispositivo particular. Los monitores, por ejemplo, por lo general definen su espacio de color usando el color de espacio GB. Una impresora, por otro lado puede usar el espacio de color CMYK. Las imágenes pueden usar una de varias subclases de ColorModel en las bibliotecas de la API de java 2D: • ComponentColorModel, en la que un pixel se representa por varios valores discretos, tipicamente bytes, cada uno representando una componente del color, como el componente rojo en la representación RGB. • DirectColorModel, en la que todos los componentes de un color están empaquetados juntos en bits separados del mismo valor de un pixel. • IndexColorModel, en la que cada pixel es un valor representado como un índice en una paleta de colores. El objeto de tipo Raster almacena los datos reales de los pixeles para una imagen en un arreglo rectangular accesado por las coordenadas x, y. Está formado de dos partes: • Un buffer de datos, que contiene los datos crudos de la imagen. • Un modelo de muestreo, que describe como los datos están organizados en el buffer. El entramado, realiza las siguientes tareas: • Representa las coordenadas rectangulares de la imagen. • Mantiene la imagen en memoria.• Provee de mecanismos para crear múltiples subimágenes a partir de un solo buffer de los datos de la imagen. • Provee de métodos para accesar a los pixeles específicos de una imagen.3. La clase BufferedImage una serie de constantes para los diferentes tipos de imágenes (modelos de colores). La tabla 14.1 describe los diferentes tipos de imágenes. Tabla 14.1 Tipos de Imagen de la clase BufferedImage.

Tipo DescripciónTYPE_3BYTE_BGR Representa una imagen con componentes RGB de 8 bits, con los colores azul, verde y

rojo almacenados en 3 bytes.TYPE_4BYTE_ABGR Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde

y rojo almacenados en 3 bytes y un byte para el valor de alfa. Los datos de los colores no están premultiplicados con el valor de alfa.

TYPE_4BYTE_ABGR_PRE Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo almacenados en 3 bytes y un byte para el valor de alfa. Los datos de los colores están premultiplicados con el valor de alfa.

TYPE_BYTE_BINARY Representa una imagen con pixeles opacos de 1, 2 o 4 bits empaquetados. Los

34

Page 35: Documentación Java

valores de los pixeles representan indices a una tabla de colores.TYPE_BYTE_GRAY Representa una imagen con pixeles en tonos de grises. El valor del pixel es un tono

de gris (0 a 255).

TYPE_BYTE_INDEXED Representa una imagen con pixeles opacos de 1 byte. Los valores de los pixeles representan indices a una tabla de colores de 256 valores, 216 colores y el resto de tonos de grises. TYPE_CUSTOM Tipo de imagen no reconocido. Debe ser una imagen con formato especial. TYPE_INT_ARGB Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores no están premultiplicados con el valor de alfa. TYPE_INT_ARGB_PRE Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores están premultiplicados con el valor de alfa. TYPE_INT_BGR Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo empacados en enteros. No hay valor de alfa. TYPE_INT_RGB Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y empacados en enteros. No hay valor de alfa. TYPE_USHORT_555_RGB Representa una imagen con componentes RGB de 5-5-5 bits para los colores azul, verde y rojo. No hay valor de alfa. TYPE_USHORT_565_RGB Representa una imagen con componentes RGB de 5-6-5 bits para los colores azul, verde y rojo. No hay valor de alfa. TYPE_USHORT_GRAY Representa una imagen con pixeles en tonos de grises. TYPE_INT_ARGB Representa una imagen con componentes RGBA de 8 bits, con los colores azul, verde y rojo y el valor de alfa empacados en enteros. Los datos de los colores no están premultiplicados con el valor de alfa. La tabla 14.2 muestra algunos de los métodos de la clase BufferedImage.

Tabla 14.3 Métodos de la clase BufferedImage. public BufferedImage(int width, int height, int imageType)

Construye una imagen del tipo BufferedImage de alguno de los tipos de imagenes predefinidos. public int getWidth() public int getHeight()

Regresan el ancho y la altura de la imagen del tipo BufferedImage, respectivamente. public Graphics2D createGraphics()

Crea un objeto del tipo Graphics2D que puede usarse para dibujar sobre esta imagen. public BufferedImage getSubimage(int x, int y, int w, int h)

Regresa una subimagen de esta imagen especificada por la región rectangular. La imagen regresada comparte el mismo arreglo de datos que la imagen original.

Dibujado de ImágenesAl igual que con las gráficas, podemos dibujar una figura sobre cualquier componente de swing que sea desplegable. La clase Graphics2D dispone del método drawImage() cuya sintaxis se muestra en la tabla 14.4.

Tabla 14.4 Método para dibujar una Imagen BufferedImage.

public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)//Despliega una imagen del tipo BufferedImage, que es filtrada con un filtro descrito por el objeto op, en las coordenadas (x, y).

El siguiente código muestra un método que permite dibujar una imagen .../** * Esta clase contiene métodos para cargar, guardar y procesar imágenes* * @author mdomitsu */

public class Control { ... // Imagen a ser desplegadaprivate BufferedImage dbi; ...

35

Page 36: Documentación Java

/** * Este metodo despliega la imagen del atributo dbi del tipo BufferedImage sobre el panel lienzo * @param lienzo Panel sobre el que se despliega la imagen */

public void despliegaimagen(JPanel lienzo) { // Si no hay una imagen para desplegarif (dbi == null) {JOptionPane.showMessageDialog(lienzo, "No hay una imagen para desplegar"); return; }

// Obtiene el tamaño de la imagenint altoImagen = dbi.getHeight();int anchoImagen = dbi.getWidth();

// Establece el tamaño del panel al tamaño de la imagenlienzo.setPreferredSize(new Dimension(altoImagen, anchoImagen));lienzo.revalidate();Graphics g = lienzo.getGraphics();Graphics2D g2 = (Graphics2D) g;

// Dibuja la imagen sobre el panelg2.drawImage(dbi, null, 1, 1); } ... }

La figura 14.3 muestra una imagen desplegada por el método anterior.

36

Page 37: Documentación Java

Figura 14.3 Despliegue de una Imagen

37

Page 38: Documentación Java

Creación de ImágenesPodemos crear una nueva imagen (una imagen con todos los pixeles en cero) para posteriormente dibujar sobre ella. Para ello se sigue el siguiente procedimiento:1. Crear un objeto del tipo BufferedImage.2. Obtener del objeto del tipo BufferedImage, un objeto del tipo Graphics2D, para dibujar sobre la imagen.3. Dibujar sobre la imagen usando los métodos del objeto del tipo Graphics2D.

// El siguiente código muestra un método que permite crear una imagen nueva.

public class Control {

... // Imagen originalprivate BufferedImage obi;

/** * Este método crea un objeto de tipo BufferedImage del tamaño del panel del parametro @param lienzo Panel que establece el tamaño de la imagen.public void nuevaImagen(JPanel lienzo) {

// Obtiene el tamaño del panelint altoImagen = lienzo.getHeight();int anchoImagen = lienzo.getWidth();

// Crea una imagen del tamaño del panelobi = new BufferedImage(anchoImagen, altoImagen, BufferedImage.TYPE_INT_RGB);Graphics2D g2 = obi.createGraphics();

// Establece el color de fondog2.setBackground(Color.white);g2.clearRect(0, 0, anchoImagen, altoImagen);

// Hace que la referencia dbi apunte a obidbi = obi; } ... }

El siguiente código dibuja sobre una imagen (nueva o existente):

/** * Este método dibuja una figura sobre la imagen obi * @param frame Ventana sobre la que se despliega el * mensaje de error */public void dibujaEnImagen(JFrame frame) {

// Si no hay una imagen para dibujarif (obi == null) { JOptionPane.showMessageDialog(frame, "No hay una imagen para dibujar");return; }

// Obtiene el contexto de graficación de la imagenGraphics2D g2 = obi.createGraphics();

// Establece el color de una trayectoriag2.setPaint(Color.black);

38

Page 39: Documentación Java

// crea una trayectoriaPath2D trayectoria = new Path2D.Double(Path2D.WIND_EVEN_ODD);trayectoria.moveTo(50, 50); trayectoria.lineTo(70, 44);trayectoria.curveTo(100, 10, 140, 80, 160, 80);trayectoria.lineTo(190, 40); trayectoria.lineTo(200, 56);trayectoria.quadTo(100, 150, 70, 60);trayectoria.closePath();

// Dibuja la trayectoria sobre la imagenobi g2.draw(trayectoria);

// Hace que la referencia dbi apunte a obidbi = obi; }

Las figuras 14.4 y 14.5 muestran una figura sobre una nueva imagen y sobre una imagen existente, dibujada por el método anterior, respectivamente.

39

Page 40: Documentación Java

40

Page 41: Documentación Java

Figura 14.6 Clase ImageIO La tabla 14.5 muestra los métodos de la clase ImageIO. Tabla 14.5

41

Page 42: Documentación Java

Tabla 14.5 Métodos de la Clase ImageIO. cont.

public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) throws IOExceptionEscribe la imagen del parámetro im con el formato dado por formatName al archivo, usando el objeto del tipo ImageOutputStream.

public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) throws IOException Escribe la imagen del parámetro im con el formato dado por formatName al archivo, usando el objeto del tipo OutputStream.

Como ejemplo de entrada / salida de imágenes se tiene un programa con una interfaz de usuario gráfica. El programa permitirá leer y guardar imágenes así como procesar esas imágenes. La opción para leer una imagen de un archivo se muestra en la figura 14.7. Al seleccionar esa opción se despliega un cuadro de diálogo para seleccionar el nombre del archivo con la imagen a leer, figuras 14.8 y 14.9. Figura 14.7

Figura 14.8 Figura 14.9 El código que permite leer una imagen de un archivo es el siguiente:

/** * Este metodo lee una imagen bmp, gif, jpg, png y la * guarda en el atributo dbi del tipo BufferedImage* @param frame Ventana sobre la que se despliega el cuadro * de dialogo JFileChooser */public void leeImagen(JFrame frame) { JFileChooser fc = new JFileChooser();

// Elimina el filtro *.* fc.setAcceptAllFileFilterUsed(false);

// Crea el filtro para las extenciones validasFileNameExtensionFilter extFiltro = new FileNameExtensionFilter( "Images", "bmp", "gif", "jpg", "png");

// Establece el filtro para las extenciones validasfc.setFileFilter(extFiltro);

// Despliega el cuadro de dialogo para seleccionar la imagen a// abrirint returnVal = fc.showOpenDialog(frame);

// Si se selecciono una imagenif (returnVal == JFileChooser.APPROVE_OPTION) {

// Obtiene el objeto File de la imagen seleccionadafile = fc.getSelectedFile(); try {

// lee la imagen y la guarda en el atributo obi // del tipo BufferedImageobi = ImageIO.read(file);

// Hace que la referencia dbi apunte a obidbi = obi; } catch (IOException e) { JOptionPane.showMessageDialog(frame, "Error al cargar imagen"); return; } } } La opción para guardar una imagen de un archivo se muestra en la figura 14.7. Al seleccionar esa opción se despliega un cuadro de diálogo para seleccionar el nombre del archivo en el que se guardará la imagen, figuras 14.10.

42

Page 43: Documentación Java

El código que permite guardar una imagen a un archivo es el siguiente:

/** * Este metodo guarda la imagen bmp, gif, jpg, png del * atributo bi del tipo BufferedImage en un archivo* @param frame Ventana sobre la que se despliega el cuadro * de dialogo JFileChooser */public void GuardaImagenComo(JFrame frame) {File fileSel = null; JFileChooser fc = new JFileChooser();

// Elimina el filtro *.*fc.setAcceptAllFileFilterUsed(false);

// Agrega varios filtros de imágenesfc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen BMP", "bmp"));fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen GIF", "gif"));fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen JPG", "jpg"));fc.addChoosableFileFilter( new FileNameExtensionFilter("Imagen PNG", "png"));

//Establece el nombre inicial de la imagenfc.setSelectedFile(file);

// Despliega cuadro de dialogo para obtener el nombre // del archivo en el que se va a guardar la imagenint returnVal = fc.showSaveDialog(frame);if (returnVal == JFileChooser.APPROVE_OPTION) {String nombreExt = null;

// Obtiene el nombre del archivo seleccionadofileSel = fc.getSelectedFile();

// Obtiene el nombre del filtro seleccionadoFileNameExtensionFilter extFiltro = (FileNameExtensionFilter) fc.getFileFilter();

// Obtiene la extension del nombre del filtro seleccionadoString ext = extFiltro.getExtensions()[0]; String path = fileSel.getPath();

// Obtiene la extension del nombre del archivo seleccionadonombreExt = getExtension(fileSel);

// Si el nombre seleccionado no corresponde a uno de imagenif(nombreExt != null && !esImageExtension(nombreExt)) { JOptionPane.showMessageDialog(frame, "No es un archivo de imagen");return; }

// Si no hay extension del nombre del archivo seleccionadoif (nombreExt == null) {

// Agregale la extension del nombre del filtro seleccionadopath += "." + ext; fileSel = new File(path);nombreExt = ext; } try {

// Guarda la imagen

43

Page 44: Documentación Java

ImageIO.write(bi, nombreExt, fileSel); }catch (IOException e) { JOptionPane.showMessageDialog(frame, "Error al guardar la imagen"); } } }

/** * Este metodo despliega la imagen del atributo bi* del tipo BufferedImage sobre el panel lienzo * @param lienzo Panel sobre el que se despliega la imagen*/public void despliegaimagen(JPanel lienzo) {

// Obtiene el tamaño de la imagenint altoImagen = bi.getHeight(); int anchoImagen = bi.getWidth();lienzo.setPreferredSize(new Dimension(altoImagen, anchoImagen));lienzo.revalidate(); Graphics g = lienzo.getGraphics();Graphics2D g2 = (Graphics2D) g; g2.drawImage(bi, null, 1, 1); }

/** * Este metodo estatico borra el contenido del panel de su parametro* un conjunto de lineas * @param lienzo Panel a borrar */public void borra(JPanel lienzo) {

// Obtiene un objeto de tipo Graphics del panelLienzoGraphics g = lienzo.getGraphics();

// Al invocar al metodo paint se borra su contenidolienzo.paint(g); }

/** * Este metodo estatico obtiene la extension de un archivo * @paramfile Objeto de tipo File de la que se obtiene * la extension * @return Extension de un archivo */ public static String getExtension(File file) { String ext = null;

// Obtiene el nombre del archivoString s = file.getName();

// busca el separador de la extensionint pos = s.lastIndexOf('.');

// Si hay un punto en el nombre y hay una // extension despues del puntoif (pos > 0 && pos < s.length() - 1) { ext = s.substring(pos + 1).toLowerCase();}return ext; }

/** * Este medodo determina si la extension del nombre de archivo * corresponte a una imagen * @param ext Extension del nombre de archivo *@return true si si la extension del nombre de archivo * corresponde a una imagen, false en caso contrario */public boolean esImageExtension(String ext) { String[] imagenesExt = {"bmp", "gif", "jpg", "png"};for(int i = 0; i < imagenesExt.length;i++) {if(ext.equals(imagenesExt[i])) return true; }return false; } }

44

Page 45: Documentación Java

Procesamiento de Imágenes

El procesamiento de imágenes describe la forma de manipular matemáticamente las imágenes. Procesar una imagen consiste en calcular una nueva coordenada para cada pixel de una imagen. Ese nuevo color puede depender del color actual del pixel, del color de los pixeles vecinos, de otros parámetros o una combinación de los anteriores. El API 2D de Java nos permite una forma sencilla de procesar imágenes basada en la clase BufferedImage y un conjunto de operaciones representadas en la interfaz BufferedImageOp. Las clases que implementan esta interfaz saben como procesar una imagen del tipo BufferedImage, llamada imagen fuente para producir una nueva imagen llamada imagen destino. Este proceso se muestra en la figura 14.11. Figura 14.11.

Con la API 2D de Java, el procesamiento de imágenes es un procedimiento de dos pasos:1. Instancíe la clase que represente la operación a realizar.2. Invoque a su método filter() con la imagen como parámetro.

La interfaz BufferedImageOp, las clases que implementan los métodos de la interfaz y las clases que las soportan se muestran en la figura 14.12. Figura 14.11. Las operaciones que realizan las clases que implementan la interfaz BufferedImageOp se muestran en la tabla 14.6. Tabla 14.6. Operaciones de Procesamiento de Imágenes Clase Operación ConvolveOp Convolución: Suavizado, intensificado, detección de orillas. LookupOp Tabla de búsquedas: Posterizar, binarizar. ColorConvertOp Conversión de colores: Convertir a tonos de grises. RescaleOp Reescalar colores: Aclarar, oscurecer. AffineTransformOp Transformar: Escalar, rotar.

45

Page 46: Documentación Java

package cargarimagen; import java.awt.Color;import java.awt.image.BufferedImage;import java.io.File;import javax.imageio.ImageIO;import javax.swing.JFileChooser;import javax.swing.filechooser.FileNameExtensionFilter; /** * * @author Luis */public class ProcesamientoImagen { //Imagen actual que se ha cargado private BufferedImage imageActual; //Método que devuelve una imagen abierta desde archivo //Retorna un objeto BufferedImagen public BufferedImage abrirImagen(){ //Creamos la variable que será devuelta (la creamos como null) BufferedImage bmp=null; //Creamos un nuevo cuadro de diálogo para seleccionar imagen JFileChooser selector=new JFileChooser(); //Le damos un título selector.setDialogTitle("Seleccione una imagen"); //Filtramos los tipos de archivos FileNameExtensionFilter filtroImagen = new FileNameExtensionFilter("JPG & GIF & BMP", "jpg", "gif", "bmp"); selector.setFileFilter(filtroImagen); //Abrimos el cuadro de diálog int flag=selector.showOpenDialog(null); //Comprobamos que pulse en aceptar if(flag==JFileChooser.APPROVE_OPTION){ try { //Devuelve el fichero seleccionado File imagenSeleccionada=selector.getSelectedFile(); //Asignamos a la variable bmp la imagen leida bmp = ImageIO.read(imagenSeleccionada); } catch (Exception e) { }

46

Page 47: Documentación Java

} //Asignamos la imagen cargada a la propiedad imageActual imageActual=bmp; //Retornamos el valor return bmp; } public BufferedImage escalaGrises(){ //Variables que almacenarán los píxeles int mediaPixel,colorSRGB; Color colorAux; //Recorremos la imagen píxel a píxel for( int i = 0; i < imageActual.getWidth(); i++ ){ for( int j = 0; j < imageActual.getHeight(); j++ ){ //Almacenamos el color del píxel colorAux=new Color(this.imageActual.getRGB(i, j)); //Calculamos la media de los tres canales (rojo, verde, azul) mediaPixel=(int)((colorAux.getRed()+colorAux.getGreen()+colorAux.getBlue())/3); //Cambiamos a formato sRGB colorSRGB=(mediaPixel << 16) | (mediaPixel << 8) | mediaPixel; //Asignamos el nuevo valor al BufferedImage imageActual.setRGB(i, j,colorSRGB); } } //Retornamos la imagen return imageActual; }}

Simplemente lo que hace esta clase es abrir una imagen (devolviendo una variable del tipo BufferedImage) y pasar esa imagen a escala de grises (también devolviendo un BufferedImage). Ahora lo que tenemos que hacer es, en nuestro formulario, hacer doble clic sobre el botón de abrir imagen y pasar a escala de grises para gestionar el evento de clic. Una vez realizado esto, incluimos el siguiente código:

//Código para cargar imagen private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { //Transformamos el BifferedImagen a ImageIcon para poder mostrarlo en el jLabel1 jLabel1.setIcon(new ImageIcon(ObjProcesamiento.abrirImagen())); } //Código para pasar a escala de grises private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { //Transformamos el BifferedImagen a ImageIcon para poder mostrarlo en el jLabel1 jLabel1.setIcon(new ImageIcon(ObjProcesamiento.escalaGrises())); }

47

Page 48: Documentación Java

La función paint nos va a proporcionar el objeto g de la clase Graphics que denominamos contexto gráfico del componente (applet). Desde dicho objeto llamaremos a las funciones miembro de la clase Graphics. Establecer un color

El color negro es el color por defecto del contexto gráfico. Para establecer otro color, como veremos en la página siguiente, se utiliza la función setColor, y se le pasa un color predefinido o definido por el usuario.

g.setColor(Color.cyan);

Dibujar una línea

Para dibujar una línea recta se llama a la función drawLine, le pasamos el punto inicial y el punto final. Para dibujar una línea diagonal desde el origen (0, 0) o esquina superior izquierda, hasta la esquina inferior derecha, obtenemos las dimensiones del applet mediante la función getSize, que devuelve un objeto de la clase Dimension. El miembro width nos sproporciona la anchura y el miembro height la altura.

g.drawLine(0, 0, getSize().width-1, getSize().height-1);

Dibujar un rectángulo

Un rectángulo viene definido por un origen (esquina superior izquierda), su anchura y altura. La siguiente sentencia dibuja un rectángulo cuyo origen es el punto 50, 150, que tiene una anchura de 50, y una altura de 60. La función drawRect dibuja el contorno del color seleccionado, y fillRect dibuja el rectángulo pintando su interior del color seleccionado, en este caso de color rojo.

48

Page 49: Documentación Java

g.setColor(Color.red);g.fillRect(50, 150, 50, 60);

Dibujar un arco

Los elipses (oval), arcos (arc), se dibujan en el interior del rectángulo circundante. Una elipse de dibuja mediante drawOval o fillOval, con los mismos parámetros que el rectángulo. Un arco requiere dos parámetros más el ángulo inical y el ángulo final. Las sentencias que vienen a continuación, dibujan un arco en el interior del rectángulo cuyo origen es el punto 10, 10, cuya anchura es 150, y cuya altura es 100. El ángulo inicial es 0 y el ángulo final es 270, expresado en grados.

g.setColor(Color.cyan); g.fillArc(10, 10, 150, 100, 0, 270); g.setColor(Color.black); g.drawArc(10, 10, 150, 100, 0, 270);

Dibujar un polígono

Para dibujar un polígono, se requieren un array de puntos. Un polígono y una polilínea son parecidos, el primero es una figura cerrada mientas que una polilínea es un conjunto de segmentos. Para formar un polígono a partir de una pililínea se une el punto inicial y el punto final. El polígono precisa de un array de abscisas x, un array de ordenadas y, y la dimensión del array.

int[] x={100, 150, 170, 190, 200}; int[] y={120, 280, 200, 250, 60}; g.setColor(Color.blue); g.drawPolygon(x, y, x.length);

Alternativamente, se puede usar un objeto de la clase Polygon, al cual se le añaden puntos mediante la función miembro addPoint.

Polygon poligono=new Polygon(); poligono.addPoint(100, 120); poligono.addPoint(150, 280); poligono.addPoint(170, 200); poligono.addPoint(190, 250); poligono.addPoint(200, 60);

Para dibujar el polígono con su interior pintado del color seleccionado se llama a la función fillPolygon y se le pasa el objeto poligono de la clase Polygon.

g.setColor(Color.yellow); g.fillPolygon(poligono);

Veremos en el applet un polígono cuyo contorno está dibujado en azul y su interior en amarillo. ------------------------

49

Page 50: Documentación Java

BufferedImage es una subclase de Image en Java, que describe una determinada imagen rasterizada en base a modelo de color.

Podemos leer una imagen desde el disco duro y guardarla en un tipo BufferedImage con la siguiente sentencia:

BufferedImage bi = ImageIO.read (“C:/ruta_del_fichero/imagen.bmp”);

Igualmente podríamos guardar una imagen desde un tipo BufferedImage a un fichero en disco duro de la siguiente forma (por ejemplo, en formato bmp):

ImageIO.write((RenderedImage)bi, “bmp”, new File(“C:/ruta_del_fichero/imagen.bmp”));

JPEGImageDecoder decoder =JPEGCodec.createJPEGDecoder(in);BufferedImageimage=decoder.decodeAsBufferedImage();g2.drawImage(image, 0, 20,this);in.close();}catch(IOExceptione) {e.printStackTrace();}catch(ImageFormatExceptione){e.printStackTrace();}}publicstaticvoidmain(Stringargs[]) {Imagenes v = newImagenes();v.setDefaultCloseOperation(EXIT_ON_CLOSE);v.setSize(375,300);v.setVisible(true);nes v = newImagenes();v.setDefaultCloseOperation(EXIT_ON_CLOSE);v.setSize(375,300);v.setVisible(true)

50

Page 51: Documentación Java

http://www.aprenderaprogramar.com/index.php?option=com_content&view=category&id=68&Itemid=188VISUALIZAR CLASES Y CREAR OBJETOS JAVA CON BLUEJ. INVOCAR MÉTODOS.

Vamos a crear varias clases y objetos en nuestro entorno de desarrollo. Para ello repetiremos el proceso que seguimos con la clase Ejemplo pero escribiendo el siguiente código:

/* Ejemplo - aprenderaprogramar.com */public class Taxi { public static void main (String[ ] arg) { System.out.println ("Soy un taxi"); } //Cierre del main} //Cierre de la clase

En otra clase escribiremos:

/* Ejemplo - aprenderaprogramar.com */public class Tranvia { public static void main (String[ ] arg) { System.out.println ("Soy un tranvía"); } //Cierre del main} //Cierre de la clase

La clase Ejemplo que teníamos en nuestra ventana de BlueJ la eliminaremos pulsando sobre ella y con botón derecho elegimos “Remove” (también podemos hacerlo a través del menú Edit -> Remove). Ahora tenemos dos clases y dos iconos de clase: Taxi y Tranvia. Para crear objetos taxi pinchamos sobre el icono Taxi y con botón derecho elegimos new Taxi(). Nos aparece una ventana que nos pide el nombre del objeto y escribimos BFG_7452 (usamos guión bajo porque no se admite guión medio). Repetimos varias veces el proceso y vamos creando distintos objetos taxi. Cada vez que creamos un taxi nos aparece en la parte inferior izquierda un rectángulo rojo con un texto como BFG_7452: Taxi. Este rectángulo representa un objeto taxi. El espacio en la parte inferior izquierda de la pantalla donde se van mostrando los objetos creados de esta manera se denomina “Banco de objetos” (Object Bench).

Hemos creado varios objetos taxi. Fíjate que cuando solo tenemos definida la clase no existen objetos: los objetos hay que crearlos para que existan.

¿Qué pueden hacer nuestros objetos taxis? Pues prácticamente nada, porque todavía no hemos escrito código que nos permita hacer algo. Vamos simplemente a pedir a cada taxi que nos diga el espacio de memoria que ocupa: para ello pulsamos sobre el icono de un objeto taxi (por ejemplo MDE_8127) y con botón derecho seleccionamos Inherited from Object -> String toString(). Se nos mostrará algo parecido a lo que mostramos en la siguiente imagen:

Nos aparece: returned “Taxi@105bd58” (no tiene por qué coincidir con estos dígitos). Prueba a hacer lo mismo con otros objetos Taxi. Verás que cada objeto devuelve una cadena Taxi@.......... distinta. Esto significa que cada objeto ocupa un espacio de memoria distinto y a ese espacio de memoria se le denomina de esa manera un poco extraña. Hacer esto ha sido posible porque al crear objetos en Java por defecto se dispone de algunos métodos comunes a cualquier objeto. Nosotros en realidad todavía no hemos definido métodos propios para los objetos tipo Taxi.

51

Page 52: Documentación Java

En un programa, cada objeto de tipo Taxi podría informar de su posición, de su tipo de motor, etc. o ser llamado para que tome determinada posición (coordenadas), o para modificar el tipo de motor que tiene establecido, entre muchas otras cosas.

Prueba a crear objetos tranvía y a consultar el identificador de su espacio de memoria. Prueba también a borrar objetos del banco de objetos. Para ello pulsa sobre su icono y con el botón derecho del ratón elige la opción “Remove”.

Por último, vamos a indicar un convenio que sigue la mayoría de los programadores: a las diferentes clases les pondremos nombres que comiencen por mayúscula como “Taxi”. Por el contrario, a los objetos les pondremos nombres que comiencen por minúscula. En nuestro caso podríamos haber nombrado a los objetos como taxi_BFG_7452 para respetar el convenio. Seguir esta norma no es obligada, pero hacerlo es recomendable para mantener un buen estilo de programación. Las empresas suelen mantener un manual de estilo que sirve de guía para que todos los programadores que trabajen en un proyecto sigan unas normas comunes.

DECLARACIÓN E INICIALIZACIÓN DE VARIABLES EN JAVA.

Vamos a ver ejemplos de uso de tipos de datos en Java. Para ello nos valdremos primeramente de algunos tipos primitivos usados habitualmente como son int (entero), String (cadena de caracteres), boolean (valor booleano verdadero o falso), float (decimal simple), etc. Aquí mostramos ejemplos de uso de tipos de datos en Java:/* Ejemplo - aprenderaprogramar.com */public class Ejemplo2 {private int precio; // Las instrucciones y declaraciones finalizan con ;private int importe_acumulado;private String profesor;private String aula;private int capacidad;private boolean funciona;private boolean esVisible;private float diametro;private float peso;private short edad;private long masa;private char letra1;} //Cierre de la clase

Hemos declarado variables de tipo primitivo u objeto usando la sintaxis private tipoElegido nombreVariable;

La palabra clave private es un indicador de en qué ámbito del programa va a estar disponible la variable. Supón que el programa es un edificio con gente trabajando y que hay elementos en el edificio, por ejemplo una impresora, que pueden tener un uso: individual para una persona, colectivo para un grupo de personas, colectivo para todas las personas de una planta, colectivo para todas las personas de un departamento aunque estén en varias plantas, o colectivo para todo el edificio. Pues bien, las variables en Java van a quedar disponibles para su uso en ciertas partes del programa según especifiquemos con las palabras clave public, private, protected, package, etc. Lo veremos más adelante, ahora simplemente nos interesa ver cómo declarar variables y usaremos de forma preferente la palabra clave private.

52

Page 53: Documentación Java

El hecho de declarar una variable implica que se reserva un espacio de memoria para ella, pero no que ese espacio de memoria esté ocupado aunque pueda tener un contenido por defecto. Ten en cuenta que en Java no puedes aplicar algunas normas que rigen en otros lenguajes, como que al declarar una variable entera ésta contendrá por defecto el valor cero. En Java esta situación puede dar lugar a errores de compilación: una variable entera no debemos suponer que contenga nada. Para que contenga algo debemos asignarle un contenido. Veamos ejemplos de asignación de contenido:

/* Ejemplo - aprenderaprogramar.com */Precio = 42; // Entero tipo int. Un número sin punto decimal se interpreta normalmente como int.importe_acumulado = 210; // Entero tipo intprofesor = “Ernesto Juárez Pérez”; // Tipo Stringaula = “A-44”; // Tipo Stringcapacidad = 1500; // Entero tipo intfunciona = true; // Tipo booleanesVisible = false; // Tipo booleandiametro = 34.25f; // Tipo float. Una f o F final indica que es float.peso = 88.77; // Tipo double. Un número con punto decimal se interpreta normalmente como double.edad = 19; // Entero tipo shortmasa = 178823411L; // Entero tipo long. Una l o L final indica que es long.letra1 = ‘h’; // Tipo char (carácter). Se escribe entre comillas simples.

Hemos planteado la declaración de variables en primer lugar y la asignación de contenido en segundo lugar y por separado porque será una forma habitual de trabajar en Java.Esto no significa que en determinadas ocasiones no podamos declarar e inicializar (asignar contenido) simultáneamente. Por ejemplo: int edad = 19; será una expresión válida y que utilizaremos en determinadas ocasiones, según iremos viendo.

La inicialización es un paso importante de cara a permitir un uso seguro de una variable. Es tan importante, que en general plantearemos que se haga como paso previo a cualquier otra cosa. Por ejemplo, si pensamos utilizar una variable denominada precio lo primero que haremos será establecer un valor de precio o, si no lo conocemos o lo vamos a establecer más adelante, estableceremos explícitamente un valor por defecto: por ejemplo precio = - 99; ó precio = 0;. Utilizar una variable sin haberla inicializado es una práctica no recomendada en Java (mal estilo de programación) que puede dar lugar a errores o al malfuncionamiento de los programas.

TIPOS DE DATOS (VARIABLES) EN JAVA.

Los primeros lenguajes de programación no usaban objetos, solo variables. Una variable podríamos decir que es un espacio de la memoria del ordenador a la que asignamos un contenido que puede ser un valor numérico (sólo números, con su valor de cálculo) o de tipo carácter o cadena de caracteres (valor alfanumérico que constará sólo de texto o de texto mezclado con números).

Como ejemplo podemos definir una variable a que contenga 32 y esto lo escribimos como a = 32. Posteriormente podemos cambiar el valor de a y hacer a = 78. O hacer “a” equivalente al valor de otra variable “b” así: a = b.

Dado que antes hemos dicho que un objeto también ocupa un espacio de memoria: ¿en qué se parecen y en qué se diferencia un objeto de una variable? Consideraremos que las variables son entidades elementales: un número, un carácter, un valor verdadero o falso… mientras que los objetos son entidades complejas que

53

Page 54: Documentación Java

pueden estar formadas por la agrupación de muchas variables y métodos. Pero ambas cosas ocupan lo mismo: un espacio de memoria (que puede ser más o menos grande).

En los programas en Java puede ser necesario tanto el uso de datos elementales como de datos complejos. Por eso en Java se usa el término “Tipos de datos” para englobar a cualquier cosa que ocupa un espacio de memoria y que puede ir tomando distintos valores o características durante la ejecución del programa. Es decir, en vez de hablar de tipos de variables o de tipos de objetos, hablaremos simplemente de tipos de datos. Sin embargo, a veces “coloquialmente” no se utiliza la terminología de forma estricta: puedes encontrarte textos o páginas web donde se habla de una variable en alusión a un objeto.

En Java diferenciamos dos tipos de datos: por un lado, los tipos primitivos, que se corresponden con los tipos de variables en lenguajes como C y que son los datos elementales que hemos citado. Por otro lado, los tipos objeto (que normalmente incluyen métodos).

Veamos los tipos de datos en Java sobre un esquema de síntesis:

Esquema de síntesis de tipos de datos en JavaEste esquema no es necesario aprendérselo de memoria en todos sus detalles, aunque sí lo iremos memorizando poco a poco a medida que lo utilicemos, por lo menos hasta tener en nuestra cabeza los nombres de todos los tipos primitivos y envoltorio y sus características (si son objetos o no y su rango aproximado). A continuación mostramos el mismo esquema en formato de tabla:

TIPOS DE DATOS EN JAVANOMBRETIPOOCUPARANGO APROXIMADOTIPOS PRIMITIVOS

(sin métodos; no son objetos; no necesitan una invocación para ser creados)byteEntero1 byte-128 a 127shortEntero2 bytes-32768 a 32767intEntero4 bytes2*109longEntero8 bytesMuy grandefloatDecimal simple4 bytes

54

Page 55: Documentación Java

Muy grandedoubleDecimal doble8 bytesMuy grandechar

Carácter simple2 bytes---booleanValor true o false1 byte---

TIPOS OBJETO

(con métodos, necesitan una invocación para ser creados)Tipos de la biblioteca estándar de JavaString (cadenas de texto)Muchos otros (p.ej. Scanner, TreeSet, ArrayList…)Tipos definidos por el programador / usuarioCualquiera que se nos ocurra, por ejemplo Taxi, Autobus, TranviaarraysSerie de elementos o formación tipo vector o matriz. Lo consideraremos un objeto especial que carece de métodos.

Tipos envoltorio o wrapper (Equivalentes a los tipos primitivos pero como objetos.)ByteShortIntegerLongFloatDoubleCharacterBoolean

Vamos a comentar distintas cuestiones:

1. Un objeto es una cosa distinta a un tipo primitivo, aunque “porten” la misma información. Tener siempre presente que los objetos en Java tienen un tipo de tratamiento y los tipos primitivos, otro. Que en un momento dado contengan la misma información no significa en ningún caso que sean lo mismo. Iremos viendo las diferencias entre ambos poco a poco. De momento, recuerda que el tipo primitivo es algo elemental y el objeto algo complejo. Supón una cesta de manzanas en la calle: algo elemental. Supón una cesta de manzanas dentro de una nave espacial (considerando el conjunto nave + cesta): algo complejo. La información que portan puede ser la misma, pero no son lo mismo.

55

Page 56: Documentación Java

2. ¿Para qué tener esa aparente duplicidad entre tipos primitivos y tipos envoltorio? Esto es una cuestión que atañe a la concepción del lenguaje de programación. Tener en cuenta una cosa: un tipo primitivo es un dato elemental y carece de métodos, mientras que un objeto es una entidad compleja y dispone de métodos. Por otro lado, de acuerdo con la especificación de Java, es posible que necesitemos utilizar dentro de un programa un objeto que “porte” como contenido un número entero. Desde el momento en que sea necesario un objeto habremos de pensar en un envoltorio, por ejemplo Integer. Inicialmente nos puede costar un poco distinguir cuándo usar un tipo primitivo y cuándo un envoltorio en situaciones en las que ambos sean válidos. Seguiremos esta regla: usaremos por norma general tipos primitivos. Cuando para la estructura de datos o el proceso a realizar sea necesario un objeto, usaremos un envoltorio.

3. Los nombres de tipos primitivos y envoltorio se parecen mucho. En realidad, excepto entre int e Integer y char y Character, la diferencia se limita a que en un caso la inicial es minúscula (por ejemplo double) y en el otro es mayúscula (Double). Esa similitud puede confundirnos inicialmente, pero hemos de tener muy claro qué es cada tipo y cuándo utilizar cada tipo.

4. Una cadena de caracteres es un objeto. El tipo String en Java nos permite crear objetos que contienen texto (palabras, frases, etc.). El texto debe ir siempre entre comillas. Muchas veces se cree erróneamente que el tipo String es un tipo primitivo por analogía con otros lenguajes donde String funciona como una variable elemental. En Java no es así.

5. Hay distintos tipos primitivos enteros. ¿Cuál usar? Por norma general usaremos el tipo int. Para casos en los que el entero pueda ser muy grande usaremos el tipo long. Los tipos byte y short los usaremos cuando tengamos un mayor dominio del lenguaje.

6. ¿Cuántos tipos de la biblioteca estándar de Java hay? Cientos o miles. Es imposible conocerlos todos.

7. ¿Un array es un objeto? Los arrays los consideraremos objetos especiales, los únicos objetos en Java que carecen de métodos.

Concepto de array: serie de elementos, cada uno de los cuales lleva asociado un índice numérico 0, 1, 2, 3, … , n-1

¿QUÉ ES UNA CLASE JAVA?

Hasta ahora hemos visto pequeños fragmentos de código de ejemplo. Vamos a tratar de escribir un código más ajustado a la realidad de la programación Java. Para ello vamos a definir de qué partes consta normalmente una clase Java.

Las partes habituales las identificamos en este esquema:/* Ejemplo - aprenderaprogramar.com */Clase Taxi { --- > EL NOMBRE DE LA CLASE Propiedades: --- >También denominadas atributos o campos (fields)Matrícula identificativaDistrito en el que operaTipo de motor diesel o gasolina Constructor de la clase --- > Definición de qué ocurre cuando se crea un objeto del tipo definido por la clase Operaciones disponibles: --- > Métodos de la clase Asignar una matrícula

56

Page 57: Documentación Java

Asignar un distrito Asignar un tipo de motor}

Esto vamos a transformarlo en código usando un ejemplo. Para ello abre un nuevo proyecto en BlueJ y crea en él una clase denominada Taxi. Escribe en ella este código, aunque no entiendas algunas partes de él.

/* Ejemplo - aprenderaprogramar.com *///Esta clase representa un taxi. -- > Comentario general que puede incluir: cometido, autor, versión, etc…

public class Taxi { //El nombre de la clase private String ciudad; //Ciudad de cada objeto taxi private String matricula; //Matrícula de cada objeto taxi private String distrito; //Distrito asignado a cada objeto taxi private int tipoMotor; //tipo de motor asignado a cada objeto taxi. 0 = desconocido, 1 = gasolina, 2 = diesel

//Constructor: cuando se cree un objeto taxi se ejecutará el código que incluyamos en el constructor public Taxi () { ciudad = “México D.F.”; matricula = ""; distrito = "Desconocido"; tipoMotor = 0; } //Cierre del constructor … el código continúa …

//Método para establecer la matrícula de un taxi public void setMatricula (String valorMatricula) { matricula = valorMatricula; //La matrícula del objeto taxi adopta el valor que contenga valorMatricula } //Cierre del método //Método para establecer el distrito de un taxi public void setDistrito (String valorDistrito) { distrito = "Distrito " + valorDistrito; //El distrito del objeto taxi adopta el valor indicado } //Cierre del método public void setTipoMotor (int valorTipoMotor) { tipoMotor = valorTipoMotor; //El tipoMotor del objeto taxi adopta el valor que contenga valorTipoMotor } //Cierre del método //Método para obtener la matrícula del objeto taxi public String getMatricula () { return matricula; } //Cierre del método //Método para obtener el distrito del objeto taxi public String getDistrito () { return distrito; } //Cierre del método //Método para obtener el tipo de motor del objeto taxi public int getTipoMotor () { return tipoMotor; } //Cierre del método} //Cierre de la clase

Pulsa el botón Compile y comprueba que no haya ningún error.

Repasemos lo que hemos hecho: hemos creado una clase denominada Taxi. El espacio comprendido entre la apertura de la clase y su cierre, es decir, el espacio entre los símbolos { y } de la clase, se denomina cuerpo de la clase.

57

Page 58: Documentación Java

Hemos dicho que todo objeto de tipo Taxi tendrá los mismos atributos: una matrícula (cadena de caracteres), un distrito (cadena de caracteres) y un tipo de motor (valor entero 0, 1 o 2 representando desconocido, gasolina o diesel). Los atributos los definiremos normalmente después de la apertura de la clase, fuera de los constructores o métodos que puedan existir.

Hemos definido que cualquier objeto Taxi que se cree tendrá, inicialmente, estos atributos: como matrícula una cadena vacía; como distrito “Desconocido”; y como tipo de motor 0, que es el equivalente numérico de desconocido. La sintaxis que hemos utilizado para el constructor es public nombreDeLaClase { … }

Por otro lado, hemos establecido que todo objeto Taxi podrá realizar estas operaciones: recibir un valor de matrícula y quedar con esa matrícula asignada (setMatricula); recibir un valor de distrito y quedar con ese distrito asignado (setDistrito); recibir un valor de tipo de motor y quedar con ese valor asignado (setTipoMotor). Devolver su matrícula cuando se le pida (getMatricula); devolver su distrito cuando se le pida (getDistrito); devolver su tipo de motor cuando se le pida (getTipoMotor).

Para crear objetos Taxi pinchamos sobre el icono Taxi de la clase y con botón derecho elegimos new Taxi(). Nos aparece una ventana que nos pide el nombre del objeto. Crea 5 objetos Taxi denominados taxi1, taxi2, taxi3, taxi4 y taxi5. Cada objeto Taxi tiene tres atributos: matricula, distrito y tipoMotor. En total tendremos 5 taxis x 3 atributos = 15 atributos.

Hemos dicho que un objeto es una instancia de una clase: por eso a los atributos que hemos definido se les denomina “variables de instancia”, porque cada instancia es “portadora” de esos atributos. También es frecuente utilizar el término “campos de la clase” como equivalente. Cada clase tendrá sus campos específicos. Por ejemplo, si una clase representa una moneda sus campos pueden ser pais, nombreMoneda, valor, diametro, grosor. Si una clase representa una persona sus campos pueden ser nombre, apellidos, dni, peso y altura.

¿Para qué nos sirve la clase? Para crear objetos de tipo Taxi. Por eso se dice que en Java una clase define un tipo. Recordamos ahora la definición de clase que habíamos dado previamente: “Clase: abstracción que define un tipo de objeto especificando qué propiedades y operaciones disponibles va a tener.”

¿Por qué la clase, el constructor y los métodos se declaran public y los atributos private? Esto lo discutiremos más adelante. De momento, nos basta con saber que declararemos las clases, constructores y métodos precedidos de la palabra clave public, y que esta palabra afecta a en qué partes del programa o por parte de quién se va a poder acceder a ellos (igual que en el edificio con personas trabajando decíamos que una impresora podía tener un uso restringido a el personal de un departamento).

¿El orden campos --> constructor --> métodos es obligatorio? No, pero a la hora de programar hemos de ser metódicos y evitar el desorden. Muchos programadores utilizamos este orden a la hora de escribir clases, así que no está mal acostumbrarnos a seguir este orden.

¿Por qué en unos casos un método ocupa una línea y en otros varias líneas? Simple cuestión de espacio. Puedes escribirlo como quieras, siempre que quede bien presentado y legible. Hemos de tener claro que un método consta de dos partes: un encabezado o línea inicial y un cuerpo o contenido dentro de las llaves { }. En este curso muchas veces escribiremos métodos en una sola línea, o varias instrucciones en una sola línea, para ahorrar espacio. Sin embargo, en el trabajo como programadores el ahorro de espacio es poco relevante frente a la claridad. Lo importante es que el código sea claro.

58

Page 59: Documentación Java

¿Por qué establecemos el tipo de motor con un entero en vez de con un texto tipo String? A veces podemos definir las variables de diferentes maneras. En este caso nos resultaría también válido usar un String en vez de un int. Pero ten en cuenta una cosa: a los ordenadores les resulta más fácil analizar y manejar números que palabras. Si tenemos cien taxis en realidad no va a resultar demasiado importante elegir un texto o un número. Pero si tenemos cien mil sí puede ser relevante elegir un tipo numérico porque va a acelerar el procesado de datos.

EJERCICIO

Considera estás desarrollando un programa Java donde necesitas trabajar con objetos de tipo Persona. Define una clase Persona análoga a la que hemos visto para taxis, pero en este caso considerando los siguientes atributos de clase: nombre (String), apellidos (String), edad (int), casado (boolean), numeroDocumentoIdentidad (String). Define un constructor y los métodos para poder establecer y obtener los valores de los atributos. Compila el código para comprobar que no presenta errores. Para comprobar la corrección de tu solución puedes consultar en los foros aprenderaprogramar.com.

MÉTODOS PROCEDIMIENTO (VOID) Y FUNCIÓN (RETURN)

Volvamos sobre los objetos taxi creados y que deben aparecer en el banco de objetos en la parte inferior izquierda de la pantalla del entorno de desarrollo. Si pulsamos con botón derecho del ratón sobre ellos se nos despliegan los métodos (operaciones) disponibles para cada objeto.

Pulsa sobre el taxi1 y elige la opción String getDistrito.

La ejecución de un método se denomina habitualmente “invocación” del método o “llamada” al método. Los métodos disponibles los define la clase, pero se invocan sobre cada objeto en particular. Al invocar el método getDistrito() se nos abre una ventana de BlueJ denominada Method Result donde nos indica: returned String “Desconocido”. Le hemos pedido al objeto que nos diga cuál es su distrito y nos devuelve “Desconocido”. La razón para ello es que en el constructor de la clase incluimos una línea de inicialización de distrito para todo objeto de tipo Taxi con el valor “Desconocido”. Si en vez de ese valor hubiésemos establecido otro, ese sería el que ahora obtendríamos.

Cierra esa ventana y repite el proceso eligiendo ahora la opción void setDistrito (String valorDistrito). En el recuadro donde solicita el distrito escribe “Oeste”. No olvides incluir las comillas obligadas por tratarse de un String. Seguidamente, vuelve a invocar el método getDistrito y comprueba el resultado obtenido.

Los métodos que hemos definido en la clase Taxi podemos clasificarlos de la siguiente manera:

a) Métodos tipo función: son métodos que nos devuelven algo. Un método es tipo función si comienza con un tipo (no consideramos ahora la palabra clave public). Por ejemplo String getDistrito() comienza con el tipo String lo que significa que nos devuelve una cadena de caracteres, mientras que int getTipoMotor() comienza con el tipo int lo que significa que nos devuelve un entero. Tener en cuenta que un método tipo función devuelve solo un dato u objeto como resultado, no varios. La devolución del resultado se expresa con la palabra clave return seguida del dato u objeto a devolver, por ejemplo return tipoMotor;. La sentencia return implica que termina la ejecución del código en el método y estará típicamente en la línea final. De existir una línea por detrás de una sentencia return, nunca llegaría a ejecutarse (tendremos que matizar esto porque el uso de condicionales nos permitirá tener más de un return en un método). De forma genérica:

/* Ejemplo - aprenderaprogramar.com */

59

Page 60: Documentación Java

//Comentario descriptivo de qué hace el método public tipoValorDevuelto nombreDelMétodo (tipo parámetro1, tipo parámetro2…) {Código del métodoreturn ResultadoQueDevuelveElMétodo;}

b) Métodos tipo procedimiento: son métodos que realizan ciertas operaciones sin devolver un valor u objeto concreto. Un método es tipo procedimiento si comienza con la palabra clave void (que traducido del inglés viene siendo “vacío” o “nulo”). En estos casos podemos decir que el tipo de retorno es void. De forma genérica:

/* Ejemplo - aprenderaprogramar.com *///Comentario descriptivo de qué hace el método public void nombreDelMétodo (tipo parámetro1, tipo parámetro2…) { Código del método}

En general un método con tipo de retorno void no llevará sentencia return, aunque en Java se permite que un método de este tipo incluya la sentencia return;. Si ocurre esto, la sentencia da lugar a que el método finalice en ese punto sin ejecutar ninguna línea más de código. Solo tiene sentido su uso asociado a que se cumplan ciertas condiciones.

¿Puede un método ser al mismo tiempo función y procedimiento? Formalmente debemos evitarlo. Podríamos tratar de agrupar operaciones, pero es una situación que trataremos de evitar. Nos plantearemos como objetivo que todo método tipo función se centre en devolvernos aquello que nos interesa sin realizar otros procesos. Igualmente buscaremos que todo procedimiento realice un proceso concreto y no varios. Cada método debe realizar una tarea concreta, específica y bien definida. Un método no debe ocuparse de dos tareas.

EJERCICIO

Considera estás desarrollando un programa Java donde necesitas trabajar con objetos de tipo DiscoMusical. Define una clase DiscoMusical análoga a la que hemos visto para taxis, pero en este caso considerando los siguientes atributos de clase: titulo (String), autor (String), añoEdicion (int), formato (String), digital (boolean). Define un constructor y los métodos para poder establecer y obtener los valores de los atributos. Compila el código para comprobar que no presenta errores. Crea un objeto y comprueba sus métodos como hemos hecho con los objetos Taxi. Para comprobar la corrección de tu solución puedes consultar en los foros aprenderaprogramar.com.

MÉTODOS EN JAVA CON Y SIN PARÁMETROS

Al igual que hicimos con distrito, continúa invocando los métodos del objeto taxi1 para establecer sus valores de matrícula a “BFG-7452” y tipo de motor a 2. Los métodos que hemos definido en la clase Taxi podemos clasificarlos de otra manera:

a) Métodos que solicitan parámetros: son métodos que nos piden algo (uno o varios datos u objetos). Es decir, el método para ejecutarse necesita que se le envíe un parámetro de un tipo concreto. Los métodos que solicitan parámetros se identifican porque en los paréntesis finales incluyen uno o varios términos, por ejemplo (String valorMatricula) nos indica que el método requiere un parámetro de tipo String. Fíjate que en este caso el parámetro es un objeto tipo String. En cambio la expresión (int valorTipoMotor) nos indica que el parámetro es

60

Page 61: Documentación Java

un tipo primitivo int. Un método podría requerir varios parámetros para lo cual se indican separados por comas. Por ejemplo public int costeVivienda (int superficiem2, String zonaCiudad, int calidadesMedias).

b) Métodos sin parámetros: son métodos que no piden ningún dato u objeto para ejecutarse. Un método sin parámetros se identifica porque sus paréntesis finales están vacíos. Estos métodos no necesitan recibir información para ejecutarse.

Una cuestión importante en los métodos con parámetros es el tipo requerido. Prueba a introducir un dato erróneo. Por ejemplo, introduce el texto “gasolina” cuando te pida el tipo de motor de un taxi. El resultado es que se produce un error porque el tipo recibido no coincide con el tipo esperado. El correcto manejo de tipos es un aspecto importante en la mayor parte de lenguajes de programación, incluido Java, y será algo a lo que debamos prestar especial atención siempre que estemos desarrollando código.Los constructores funcionan en buena medida de forma similar a los métodos y también podemos definir constructores con parámetros y constructores sin parámetros. El sentido de que un constructor pida uno o varios parámetros es tener en cuenta esos parámetros a la hora de crear un objeto. Abordaremos los constructores con más detenimiento un poco más adelante.

MÉTODOS CONSULTORES (GET) Y MODIFICADORES (SET)

Continuamos con el uso de métodos en Java. Prueba a establecer distintos valores de matrícula, distrito y tipo de motor para los diferentes objetos Taxi. Prueba también a, una vez establecidos unos valores para un objeto, volver a cambiarlos por otros valores distintos.

Hay aún otra manera de clasificar los métodos que hemos definido para la clase Taxi:

a) Métodos modificadores: llamamos métodos modificadores a aquellos métodos que dan lugar a un cambio en el valor de uno o varios de los atributos del objeto.

b) Métodos consultores u observadores: son métodos que devuelven información sobre el contenido de los atributos del objeto sin modificar los valores de estos atributos.

Cuando se crea una clase es frecuente que lo primero que se haga sea establecer métodos para consultar (de ahí su denominación de consultores) sus atributos y estos métodos suelen ir precedidos del prefijo get (getMatricula, getDistrito, etc.) por lo que muchas veces se alude coloquialmente a ellos como “métodos get” o “getters”.

Se suele proceder de igual forma con métodos que permitan establecer los valores de los atributos. Estos métodos suelen ir precedidos del prefijo set (setMatricula, setDistrito, etc.) por lo que muchas veces se alude coloquialmente a ellos como “métodos set” o “setters”. Los métodos set son un tipo de métodos modificadores, porque cambian el valor de los atributos de un objeto.

¿Puede un método ser al mismo tiempo modificador y consultor? Es posible, pero es una situación que trataremos de evitar. Nos plantearemos como objetivo que cada método haga una cosa específica y no varias al mismo tiempo.

ESTADO DE UN OBJETO

61

Page 62: Documentación Java

Hemos comprobado que un objeto tiene unos atributos. Además, si tenemos métodos disponibles para ello, podemos cambiar varias veces el valor de estos atributos. Por ejemplo, al objeto taxi1 le podemos establecer inicialmente distrito “Oeste”, luego distrito “Norte”, “Sur”, etc.

Llamamos estado de un objeto al conjunto de valores de los atributos del objeto en un momento dado. Sobre el objeto taxi1, pulsa botón derecho y elige la opción Inspect.

El resultado es que se nos abre una ventana que se denomina “Inspector de objetos” y que refleja su estado. En este caso, nos indica que el valor de sus atributos es “BFG-7452” para la matrícula del taxi, “Distrito Oeste” para el distrito y 2 para el tipo de motor. Prueba a modificar el estado del objeto taxi1 utilizando alguno de sus métodos sin cerrar la ventana de inspección. Comprobarás que los datos se actualizan automáticamente a medida que vamos realizando cambios. Prueba a inspeccionar el estado de los distintos objetos Taxi que hayas creado.

PARÁMETROS FORMALES Y PARÁMETROS

Hemos visto que un método (o constructor) puede requerir un parámetro, con un tipo y nombre concretos. Por ejemplo tipo String y nombre del parámetro valorDistrito. A su vez valorDistrito podría ir tomando distintos valores a lo largo de una ejecución del método, por ejemplo “Norte”, “Oeste”, “Sur”, etc.

Vamos a definir dos conceptos relacionados con los parámetros:

a) Parámetro formal: es el nombre de un parámetro de un constructor o método tal y como se define en su cabecera, por ejemplo valorDistrito es un parámetro formal.

b) Parámetro actual: es el valor concreto que tiene un parámetro en un momento dado.

Prueba a escribir y compilar el siguiente código:/* Ejemplo - aprenderaprogramar.com *///Esta clase es una pruebapublic class miPrueba { public String resultado (String dimeUnString) { System.out.println ("dimeUnString inicialmente vale " + dimeUnString); dimeUnString = dimeUnString + " recibido"; System.out.println ("dimeUnString ahora vale " + dimeUnString); return "El método devuelve " + dimeUnString; }}

Ahora crea un objeto de tipo miPrueba y ejecuta el método introduciendo una cadena, por ejemplo “esperanza”. El resultado será algo similar a esto:

El parámetro formal dimeUnString es de tipo String y inicialmente toma el valor que le hayamos pasado al constructor cuando creamos el objeto. Luego su valor actual pasa a ser el valor pasado al constructor + “recibido”. Finalmente el método nos devuelve una cadena de la que forma parte el parámetro.

62

Page 63: Documentación Java

Conclusión interesante: los parámetros de métodos o constructores también almacenan valores que pueden ir cambiando. Por eso diremos que también son variables al igual que los campos, aunque conceptualmente sean cosas distintas.

Ten en cuenta una cosa: un campo es una variable que está de forma permanente asociada a un objeto y cuyo ámbito (lugares donde podemos usarla) es toda la clase. Su tiempo de vida es indefinido mientras exista el objeto al que está ligado. En cambio un parámetro formal tiene un ámbito limitado al método o constructor y tiempo de vida limitado al tiempo durante el cual se ejecuta el método o constructor. En este sentido, decimos que un parámetro es un tipo de variable local (solo podemos usarla dentro del método) y temporal (se crea al comenzar la ejecución del método y se destruye al terminar su ejecución).

Para evitar confusiones, en general trataremos de evitar modificar el contenido de un parámetro dentro del código de un método.

CONCEPTO Y FILOSOFÍA DE MÉTODOS Y CLASES EN JAVA

Hemos visto la forma habitual de organizar una clase en Java. Trataremos ahora de reflexionar sobre por qué se hacen así las cosas. Vamos a explicarlo sobre un esquema gráfico: lee el siguiente texto al mismo tiempo que miras el esquema “Funcionamiento de métodos y clases en Java” incluido a continuación.

A un objeto le llegan muchas solicitudes, que hemos representado como personas en una cola frente a un control de acceso. El control de acceso representa que todo lo que se pretenda hacer está sometido a supervisión: cualquiera no puede dar órdenes y quien puede dar órdenes no puede hacer lo que quiera. Por ejemplo, puede haber una solicitud para establecer que la ciudad del objeto pase a ser “Mérida”. El control de acceso verifica si es posible tal acción, y al no ser posible ya que no se ha definido ningún método que permita modificar el atributo ciudad, la petición es rechazada. Puede haber otra solicitud que pida información al objeto sobre qué valor tiene su atributo ciudad. El control de acceso comprueba que no existe un método que permita tal acción y la petición es rechazada.

Esquema del funcionamiento de métodos y clases en Java

Puede haber una solicitud que pida información al objeto sobre su atributo distrito: es una operación permitida y se entrega la información (el estado del objeto no cambia).

Dentro del objeto el trabajo es ordenado. Hay métodos específicamente encargados de preparar información para servirla (tipo función). Otros métodos se encargan de hacer manipulaciones en el objeto.

En resumen, la clase define qué se puede hacer y qué no se puede hacer. El objeto funciona como una entidad que trabaja de forma ordenada y especializada. Este planteamiento difiere del que existía en los lenguajes de programación primigenios, donde se podían hacer modificaciones a variables desde cualquier lugar y sin control. Esto en sí no es un problema, el problema venía a posteriori cuando los programadores hacían un mal uso de esa “libertad”.

En la programación actual, se trabaja en equipos en algunos casos de cientos o miles de personas que desarrollan código por separado. Para evitar que se hagan cosas inadecuadas, se utilizan mecanismos de control que favorecen que la programación sea de calidad. En Java no existe un “control de acceso” tal y como lo hemos representado en nuestro esquema, pero sí existen distintos mecanismos de control como la declaración del ámbito y accesibilidad a las variables y clases (public, private, protected, etc.) y la obligación de uso de métodos para realizar operaciones sobre objetos impidiendo su manipulación directa.

63

Page 64: Documentación Java

SIGNATURA DE UN MÉTODO. INTERFAZ O INTERFACE.

El esquema planteado en relación a la filosofía de clases y métodos en Java tiene otras implicaciones. Una de ellas es que la persona que llega con una solicitud u orden no puede más que hacer una entrega de esa solicitud u orden, pero no puede entrar al objeto a realizar manipulaciones o coger cosas.

Lo que pasa dentro del objeto no se ve. Este principio, denominado “ocultamiento de la información”, se manifiesta de distintas maneras y es muy relevante en programación orientada a objetos. Veamos una aplicación de este principio en relación a lo que hemos explicado hasta ahora. Consideremos lo siguiente:float calcularCapacidadDeposito ()

Podemos interpretar que esto es el encabezado de un método. Y podemos extraer cierta información relevante: el método devuelve un valor numérico tipo decimal simple, el método sirve para calcular la capacidad de un depósito, y el método no requiere parámetros. El encabezado de un método se denomina signatura del método e informa de varias cosas:

a) Si el método es tipo función o tipo procedimiento.b) El tipo del valor devuelto, si es un método tipo función.c) El nombre del método.d) Los parámetros requeridos (ninguno, uno o varios) y sus tipos.

Veamos otro ejemplo de signatura:float calcularCapacidadDeposito (float valorDiametro, float valorAltura)

Con esta información sabemos lo que hace el método, pero no cómo lo hace. En general a este tipo de información que nos dice qué se hace pero no cómo, lo denominamos interfaz o interface. Esta palabra tiene distintos significados en Java que iremos viendo poco a poco. De momento, nos quedaremos con la idea de que la signatura es una interfaz de un método, porque informa de lo que hace, pero no nos dice cómo lo hace (queda oculta su implementación o desarrollo). En muchas ocasiones trabajaremos conociendo sólo la signatura de métodos y desconociendo su código de desarrollo. Esto no será problema: mientras los procesos funcionen y estén bien programados, no nos va a hacer falta conocer todo el código.

EJERCICIO

Considera estás desarrollando un programa Java donde necesitas trabajar con objetos de tipo DiscoMusical. Define las signaturas para métodos dentro dicha clase e indica si deberán ser procedimientos o funciones para los siguientes objetivos planteados:

1) Obtener la duración de una canción expresada como un número decimal en minutos (por ejemplo podría ser 3,22 minutos) recibiendo como dato el número de canción dentro del disco.

2) Pedir a un administrador de una compañía discográfica que introduzca la duración de todas las canciones (dichas duraciones se almacenarán como información del objeto). Es decir, el método se encargará de saludar al usuario y pedirle que vaya introduciendo una por una la duración de las canciones.

3) Obtener la duración del disco completo (suma de las duraciones de cada una de las canciones).

64

Page 65: Documentación Java

4) Añadir una canción al disco recibiendo como información para ello el título de la canción y su duración (se añadirá como última canción en el disco. Si el disco tenía por ejemplo 10 canciones, al añadirse una canción pasará a tener 11).

Para comprobar si tu solución es correcta puedes consultar en los foros aprenderaprogramar.com.

VARIABLES LOCALES A UN MÉTODO O CONSTRUCTOR. SOBRECARGA DE NOMBRES.

Una variable que se declara y se usa dentro de un método (o de un constructor) se dice que es una variable local. Su ámbito es sólo el método o constructor y su tiempo de vida es solo el del método, es decir, son variables temporales que se crean cuando comienza a ejecutarse el método y se destruyen cuando termina de ejecutarse.

Escribe y compila el siguiente código:/* Ejemplo - aprenderaprogramar.com */public class Estudiante { //El nombre de la clase private String nombre; //Campo de los objetos Estudiante //Constructor: cuando se cree un objeto Estudiante se ejecutará el código que incluyamos en el constructor public Estudiante () { nombre = "Pepe"; } //Cierre del constructor

//Método que devuelve true si el nombre del objeto tipo Estudiante es Pepe public boolean esPepe() { boolean seLlamaPepe = false; if (nombre == "Pepe") { seLlamaPepe = true; } return seLlamaPepe; } //Cierre del método} //Cierre de la clase

La variable seLlamaPepe es una variable local booleana. Es habitual inicializar las variables locales cuando se las declara, pero no es estrictamente necesario. Sí es obligatorio inicializar las variables en algún momento ya que no se debe considerar que tengan un valor por defecto. Crea un objeto de tipo Estudiante pulsando sobre el icono de la clase con botón derecho y eligiendo la opción new Estudiante(). Sobre el objeto que aparecerá en el banco de objetos, invoca el método esPepe().

Ahora crea otro método y trata de establecer en él la variable seLlamaPepe con valor true. El compilador lanzará un mensaje de error del tipo “cannot find symbol – variable seLlamaPepe”. ¿Por qué podemos usar la variable nombre en cualquier método mientras que la variable seLlamaPepe sólo dentro del método esPepe()? Como hemos dicho, el ámbito de una variable declarada en un método es solo ese método. El resto de métodos no conocen la variable. En cambio, un campo de la clase tiene como ámbito toda la clase y lo podemos usar en cualquier lugar del código de la clase. Hay algunas conclusiones interesantes:

1) Podemos usar el mismo nombre de variable local en muchos métodos, puesto que no van a interferir entre ellas.2) Una declaración de campo siempre la hacemos precedida de public o private. En las variables locales, estas palabras clave no se usan debido a su carácter temporal.

65

Page 66: Documentación Java

3) En los métodos tipo función con frecuencia en la sentencia return se devuelve como resultado el valor de una variable local que ha sido objeto de cálculo en el método. Tener en cuenta que no se devuelve la variable en sí (que en realidad desaparece cuando termina el método), sino su valor o contenido.

¿Puede un constructor tener variables locales? Sí. Un constructor son una serie de instrucciones. A veces muy sencillas, pero otras veces pueden requerir cálculos o procesos complejos. Por tanto, podemos usar variables locales dentro de ellos declarándolas y usándolas como si se tratara de un método. No tenemos restricciones en cuanto al código que se puede incluir en un constructor.

¿Puede una variable local ser tipo objeto? Sí. Hemos dicho que las clases definen tipos. Por ejemplo podríamos tener una variable local miTaxi1 declarada como Taxi miTaxi1;.

¿Qué ocurre si una variable local tiene el mismo nombre que un campo? Esta situación se daría si tenemos un campo declarado por ejemplo como String ciudad; y luego declaramos dentro de un método una variable de ese mismo tipo u otro distinto con el mismo nombre, por ejemplo boolean ciudad = false;. En este caso decimos que existe sobrecarga de nombres. Podemos tener problemas si no manejamos esta situación adecuadamente. Cuando empleemos en el código el nombre de la variable el compilador no es capaz de adivinar nuestro pensamiento para saber si nos referimos al campo de la clase o a la variable local del método. Este conflicto Java lo resuelve aplicando la regla de prevalencia del ámbito “más local”. Es decir, si escribimos un nombre de variable Java usa la variable “más local” disponible. Java tiene prevista la solución para poder usar simultáneamente campos y variables locales con el mismo nombre, mediante el uso de la palabra clave this. Esto lo explicaremos más adelante. Reflexionemos ahora sobre los tipos o formas de variables que hemos visto hasta el momento. Se resumen en el siguiente esquema:

EJERCICIO

Considera estás desarrollando un programa Java donde necesitas trabajar con objetos de tipo Motor (que representa el motor de una bomba para mover fluidos). Define una clase Motor considerando los siguientes atributos de clase: tipoBomba (int), tipoFluido (String), combustible (String). Define un constructor asignando unos valores de defecto a los atributos y los métodos para poder establecer y obtener los valores de los atributos. Crea un método tipo función que devuelva un booleano (true o false) denominado dimeSiMotorEsParaAgua() donde se cree una variable local booleana motorEsParaAgua de forma que si el tipo de motor tiene valor 1 tomará valor true y si no lo es tomará valor false. El método debe devolver la la variable local booleana motorEsParaAgua.

Compila el código para comprobar que no presenta errores, crea un objeto, usa sus métodos y comprueba que se obtienen resultados correctos. Para comprobar si es correcta tu solución puedes consultar en los foros aprenderaprogramar.com.

CÓMO CREAR CONSTRUCTORES EN JAVA. EJERCICIOS EJEMPLOS RESUELTOS.

Los constructores de una clase son fragmentos de código que sirven para inicializar un objeto a un estado determinado. Una clase puede carecer de constructor, pero esto no es lo más habitual. Normalmente todas nuestras clases llevarán constructor. En un constructor es frecuente usar un esquema de este tipo:

/* Ejemplo - aprenderaprogramar.com */public MismoNombreQueLaClase (tipo parámetro1, tipo parámetro2 …, tipo parámetro n ) { campo1 = valor o parámetro; campo2 = valor o parámetro;

66

Page 67: Documentación Java

. . . campo n = valor o parámetro;}

Los constructores tienen el mismo nombre que la clase en la que son definidos y nunca tienen tipo de retorno, ni especificado ni void. Tenemos aquí un aspecto que nos permite diferenciar constructores de métodos: un constructor nunca tiene tipo de retorno mientras que un método siempre lo tiene. Es recomendable que en un constructor se inicialicen todos los atributos de la clase aunque su valor vaya a ser nulo o vacío. Si un atributo se quiere inicializar a cero (valores numéricos) siempre lo declararemos específicamente: nombreAtributo = 0;. Si un atributo se quiere inicializar a contenido nulo (atributos que son objetos) siempre lo declararemos específicamente: nombreAtributo = null;. Si un atributo tipo texto se quiere inicializar vacío siempre lo declararemos específicamente: nombreAtributo = “”;. El motivo para actuar de esta manera es que declarando los atributos como nulos o vacíos, dejamos claro que esa es nuestra decisión como programadores. Si dejamos de incluir uno o varios campos en el constructor puede quedar la duda de si hemos olvidado inicializar ese campo o inducir a pensar que trabajamos con malas prácticas de programación.

La inicialización de campos y variables es un proceso muy importante. Su mala definición es fuente de problemas en el desarrollo de programas. Como regla de buena programación, cuando crees campos o variables, procede de forma inmediata a definir su inicialización.

Un constructor puede:

a) Carecer de parámetros: que no sea necesario pasarle un parámetro o varios al objeto para inicializarse. Un constructor sin parámetros se denomina “constructor general”.

b) Carecer de contenido. Por ejemplo, public Taxi () { } podría ser un constructor, vacío. En general un constructor no estará vacío, pero en algunos casos particulares puede estarlo. Si el constructor carece de contenido los campos se inicializan con valor nulo o, si son tipos definidos en otra clase, como se haya definido en el constructor de la otra clase. Excepto en casos controlados, evitaremos que existan constructores vacíos.

Si un constructor tiene parámetros, el funcionamiento es análogo al que ya hemos visto para métodos. Cuando vayamos a crear el objeto con BlueJ, se nos pedirá además del nombre que va a tener el objeto, el valor o contenido de los parámetros requeridos. Un parámetro con frecuencia sirve para inicializar el objeto como hemos visto, y en ese caso el objeto tendrá el valor pasado como parámetro como atributo “para siempre”, a no ser que lo cambiemos por otra vía como puede ser un método modificador del atributo. No obstante, en algunos casos los parámetros que recibe un constructor no se incorporarán directamente como atributos del objeto sino que servirán para realizar operaciones de diversa índole. Escribe y compila el siguiente código:

/* Ejemplo - aprenderaprogramar.com */public class Taxi { //El nombre de la clase private String ciudad; //Ciudad de cada objeto taxi private String matricula; //Matrícula de cada objeto taxi private String distrito; //Distrito asignado a cada objeto taxi private int tipoMotor; //Tipo de motor asignado a cada objeto taxi. 0 = desconocido, 1 = gasolina, 2 = diesel

//Constructor: cuando se cree un objeto taxi se ejecutará el código que incluyamos en el constructor public Taxi (String valorMatricula, String valorDistrito, int valorTipoMotor) {

67

Page 68: Documentación Java

ciudad = "México D.F."; matricula = valorMatricula; distrito = valorDistrito; tipoMotor = valorTipoMotor; } //Cierre del constructor

//Método para obtener la matrícula del objeto taxi public String getMatricula () { return matricula; } //Cierre del método

//Método para obtener el distrito del objeto taxi public String getDistrito () { return distrito; } //Cierre del método

//Método para obtener el tipo de motor del objeto taxi public int getTipoMotor () { return tipoMotor; } //Cierre del método} //Cierre de la clase

Este código es similar al que vimos en epígrafes anteriores. La diferencia radica en que ahora en vez de tener un constructor que establece una forma fija de inicializar el objeto, la inicialización depende de los parámetros que le lleguen al constructor. Además, hemos eliminado los métodos para establecer el valor de los atributos. Ahora éstos solo se pueden consultar mediante los métodos get. Pulsa con botón derecho sobre el icono de la clase y verás como la opción new Taxi incluye ahora los parámetros dentro de los paréntesis. Escoge esta opción y establece unos valores como matrícula “BFG-7452”, distrito “Oeste” y tipo de motor 2. Luego, con el botón derecho sobre el icono del objeto, elige la opción Inspect para ver su estado.Que un constructor lleve o no parámetros y cuáles tendremos que elegirlo para cada clase que programemos. En nuestro ejemplo hemos decidido que aunque la clase tiene cuatro campos, el constructor lleve solo tres parámetros e inicializar el campo restante con un valor fijo. Un constructor con parámetros es adecuado si tiene poco sentido inicializar los objetos vacíos o siempre con el mismo contenido para uno o varios campos. No obstante, siempre hay posibilidad de darle contenido a los atributos a posteriori si incluimos métodos “setters”. El hacerlo de una forma u otra dependerá del caso concreto al que nos enfrentemos.

El esquema que hemos visto supone que en general vamos a realizar una declaración de campo en cabecera de la clase, por ejemplo String ciudad;, y posteriormente inicializar esa variable en el constructor, por ejemplo ciudad = “México D.F.”;. ¿Sería posible hacer una declaración en cabecera de clase del tipo String ciudad = “México D.F.”;? La respuesta es que sí. El campo quedaría inicializado en cabecera, pero esto en general debe ser considerado una mala práctica de programación y contraproducente dentro de la lógica de la programación orientada a objetos. Por tanto de momento trataremos de evitar incluir código de ese tipo en nuestras clases y procederemos siempre a inicializar en los constructores.

EJERCICIO

Define una clase Bombero considerando los siguientes atributos de clase: nombre (String), apellidos (String), edad (int), casado (boolean), especialista (boolean). Define un constructor que reciba los parámetros necesarios para la inicialización y los métodos para poder establecer y obtener los valores de los atributos. Compila el código para comprobar que no presenta errores, crea un objeto y comprueba que se inicializa correctamente consultando el valor de sus atributos después de haber creado el objeto. Para comprobar si es correcta tu solución puedes consultar en los foros aprenderaprogramar.com.

CLASES QUE UTILIZAN OBJETOS. RELACIÓN DE USO ENTRE CLASES. DIAGRAMAS DE CLASES.

68

Page 69: Documentación Java

Hemos visto hasta ahora clases que definen tipos donde los campos son variables de tipo primitivo o String. Analicemos ahora la posibilidad de crear clases donde los atributos sean tipos que hayamos definido en otras clases.

Consideraremos que partimos de las clases Taxi y Persona ya escritas y compilando correctamente conforme a los ejemplos vistos en epígrafes anteriores.clases javaEscribe y compila el siguiente código:

/* Ejemplo - aprenderaprogramar.com *///Ejemplo de clase que utiliza tipos definidos en otras clases (usa otras clases)public class TaxiCond { private Taxi vehiculoTaxi; private Persona conductorTaxi; //Constructor public TaxiCond () { vehiculoTaxi = new Taxi (); //Creamos un objeto Taxi con el constructor general de Taxi conductorTaxi = new Persona (); //Creamos un objeto Persona con el constructor general de Persona } public void setMatricula (String valorMatricula) { vehiculoTaxi.setMatricula(valorMatricula); }

//Método que devuelve la información sobre el objeto TaxiCond public String getDatosTaxiCond () { String matricula = vehiculoTaxi.getMatricula(); String distrito = vehiculoTaxi.getDistrito(); int tipoMotor = vehiculoTaxi.getTipoMotor(); String cadenaTipoMotor = ""; if (tipoMotor ==0) { cadenaTipoMotor = "Desconocido"; } else if (tipoMotor == 1) { cadenaTipoMotor = "Gasolina"; } else if (tipoMotor == 2) { cadenaTipoMotor = "Diesel"; } String datosTaxiCond = "El objeto TaxiCond presenta estos datos. Matrícula: " + matricula + " Distrito: " + distrito + " Tipo de motor: " + cadenaTipoMotor; System.out.println (datosTaxiCond); return datosTaxiCond; } //Cierre del método} //Cierre de la clase

Analicemos ahora lo que hace este código. Creamos una clase denominada TaxiCond (que podemos interpretar como “taxi con conductor”). Los objetos del tipo TaxiCond decimos que van a constar de dos campos: un objeto Taxi y un objeto Persona. Fíjate que estamos utilizando el nombre de otra clase como si fuera el tipo de una variable “normal y corriente”. Esto es posible porque las clases definen tipos. Desde el momento en que nuestra clase utiliza tipos definidos por otras clases decimos que se establece una relación de uso: TaxiCond usa a Taxi y a Persona. El constructor de TaxiCond inicializa los objetos de este tipo para que consten de un objeto Taxi creado con el constructor por defecto y de una Persona creada con el constructor por defecto.

Para los objetos de tipo TaxiCond hemos definido dos métodos (podríamos haber definido muchos más) que son: el método modificador y con parámetros setMatricula(String valorMatricula) y el método observador y sin parámetros getDatosTaxiCond(). Un aspecto muy importante del código es que desde el momento en que usamos objetos en una clase, podemos acceder a los métodos públicos propios de esos objetos cuyo código se

69

Page 70: Documentación Java

encontrará en otra clase. Por ejemplo la invocación vehiculoTaxi.setMatricula(valorMatricula); llama un método propio de los objetos Taxi que se encuentra definido en otra clase. Es decir, todo objeto puede llamar a sus métodos públicos independientemente de dónde se encuentre.

Una vez compilado el código, en el diagrama de clases se nos muestran unas flechas discontinuas que relacionan la clase Taxicond con las clases Taxi y Persona. Estas flechas discontinuas lo que indican es que hay una relación de uso entre las clases. En algunas circunstancias BlueJ puede mantener erróneamente indicadores de relación que no son ciertos. En estos casos, las flechas pueden eliminarse seleccionándolas y con botón derecho eligiendo la opción Remove. También pueden crearse eligiendo el botón ----> en la parte superior izquierda de la pantalla y a continuación pulsando primero el icono de la “clase que usa” y luego el icono de la “clase que es usada”.

Crea un objeto de tipo TaxiCond pulsando sobre el icono de la clase y con botón derecho eligiendo new TaxiCond(). A continuación con botón derecho sobre el objeto elige la opción Inspect. La ventana que se nos muestra nos indica que el objeto consta de dos campos, pero en el recuadro correspondiente al valor de dichos campos en vez de un valor nos aparece una flecha curvada. Esta flecha lo que nos indica el que el campo no contiene un valor simple (como un entero) sino un objeto. La flecha simboliza una referencia al objeto, ya que el objeto no se puede representar directamente al ser una entidad compleja.

Pulsa sobre la flecha de referencia de cada uno de los campos y luego sobre el botón Inspect de la ventana. Se te abrirán otras dos ventanas donde puedes observar los valores de los campos de cada uno de los objetos que forman el objeto TaxiCond. Pero ten en cuenta que un objeto siempre podría tener como campo otro objeto, es decir, podríamos seguir observando “flechas” una y otra vez al ir inspeccionando objetos y esto sería una situación normal. Estamos trabajando con programación orientada a objetos, por tanto que aparezcan objetos “por todos lados” será normal.

La relación de uso entre clases es una de los tipos de relación más habituales en programación orientada a objetos. Las variables de instancia de un objeto pueden ser tanto de tipo primitivo como tipo objeto. Recordar que la variable que define un objeto no contiene al objeto en sí mismo, sino una referencia al espacio de memoria donde se encuentra. Dado que un objeto es una entidad compleja simbólicamente se representa con una línea que comienza en un punto y termina en una punta de flecha. Un objeto puede crearse e invocar sus métodos públicos desde distintas clases y decimos que esto establece una relación de uso entre clases. Por tanto, el código fuente de una clase puede ser usado desde otras clases.

Un esquema donde se representan las clases y las relaciones que existen entre ellas se denomina diagrama de clases y nos sirve para comprender la estructura de los programas. Se dice que el diagrama de clases constituye una vista estática del programa, porque es un esquema fijo de relaciones dentro del programa. Sin embargo, el que exista una relación entre clases no significa que en un momento dado vaya a existir un objeto que materialice esa relación entre clases. Es posible que el programa comience y que pase un tiempo antes de que se cree un objeto que refleje la relación entre clases. Si representáramos los objetos existentes en un momento dado y las relaciones entre ellos tendríamos una vista dinámica del programa. El inconveniente de las vistas dinámicas es que los objetos se crean, destruyen o cambian sus relaciones continuamente, por lo que representarlas resulta costoso. Por este motivo, no utilizaremos las vistas dinámicas. Sin embargo, sí usaremos con frecuencia los diagramas de clases para comprender la estructura de nuestro código.

70

Page 71: Documentación Java

Nos queda una aclaración por realizar: ¿Por qué si los tipo String son objetos BlueJ nos informa directamente de su contenido en vez de mostrar una flecha? La razón para ello estriba en que el tipo String es un objeto un tanto especial, ya que su contenido es relativamente simple comparado con el de otros objetos. Para facilitar el trabajo BlueJ nos informa directamente de su contenido, pero no podemos olvidar que un String es un objeto y esto tiene una relevancia notable como veremos más adelante.

Para completar la comprensión de la relación de uso entre clases, utiliza los métodos disponibles para el objeto TaxiCond que has creado: establece distintos valores de matrícula con el método setMatricula y visualiza los datos del objeto con el método getDatosTaxiCond. Crea además nuevos métodos que te permitan establecer el distrito y el tipo de motor de los objetos TaxiCond. Te planteamos otra reflexión: al igual que hemos definido un tipo TaxiCond que tiene dos objetos como campos, podemos definir tipos que tengan cinco, diez, quince o veinte objetos como campos. Por ejemplo, un objeto Casa podría definirse con estos campos: private Salon salonCasa; private Cocina cocinaCasa; private Baño baño1Casa; private Baño baño2Casa; private Jardin jardinCasa; private Dormitorio dormitorio1Casa; private Dormitorio dormitorio2Casa; private Dormitorio dormitorio3Casa;

Ten en cuenta que dentro de un objeto puedes tener n objetos de otro tipo. En este ejemplo, dentro de un objeto Casa tenemos dos objetos de tipo Baño y tres objetos de tipo Dormitorio. Todos los objetos Dormitorio van a tener los mismos atributos y métodos, pero cada objeto tendrá su propio estado en cada momento.

EJERCICIO

Define tres clases: Casa, SalonCasa y CocinaCasa. La clase SalonCasa debe tener como atributos numeroDeTelevisores (int) y tipoSalon (String) y disponer de un constructor que los inicialice a 0 y “desconocido”. La clase CocinaCasa debe tener como atributos esIndependiente (boolean) y numeroDeFuegos (int) y un constructor que los inicialice a false y 0. La clase Casa tendrá los siguientes atributos de clase: superficie (double), direccion (String), salonCasa (tipo SalonCasa) y cocina (tipo CocinaCasa). Define un constructor para la clase Casa que establezca a unos valores de defecto los atributos simples y que cree nuevos objetos si se trata de atributos objeto. Compila el código para comprobar que no presenta errores, crea un objeto de tipo Casa. Comprueba que se inicializan correctamente consultando el valor de sus atributos después de haber creado los objetos. Para comprobar si es correcta tu solución puedes consultar en los foros aprenderaprogramar.com.

LA SENTENCIA NEW COMO INVOCACIÓN DE UN CONSTRUCTOR EN JAVA

En el ejemplo anterior hemos visto cómo usar el entorno de desarrollo BlueJ para crear objetos en Java. La forma de creación de objetos ha sido a través del IDE y con una visualización gráfica Si

71

Page 72: Documentación Java

escribiéramos el código correspondiente a lo que hemos hecho en el ejemplo anterior usando los iconos de BlueJ podría ser algo así: 

/* Ejemplo - aprenderaprogramar.com */

Taxi taxi1 = new Taxi(); //Creación de un objeto tipo Taxi

Persona persona1 = new Persona(); //Creación de un objeto tipo Persona

TaxiCond taxiCond1 = new TaxiCond (taxi1, persona1);  /*Creación de un objeto tipo TaxiCond pasando como parámetros otros objetos creados previamente*/

 Tener en cuenta que cuando incluimos como atributo de una clase un objeto usando una sintaxis del tipo: private NombreDeLaOtraClase nombreDelObjeto;, con esta declaración estamos creando la variable apuntadora (referencia) al objeto, pero el objeto en sí mismo todavía no se ha creado. La creación del objeto en código se indica usando esta sintaxis:

nombreDelObjeto = new NombreDeLaOtraClase (parámetros requeridos por el constructor de la otra clase si los hubiera);

 Recordar que la variable nombreDelObjeto contiene una referencia (puntero) al objeto, no el objeto en sí mismo. La instrucción new implica que se producen dos acciones:

a)      Creación de un objeto de un tipo definido por una clase.

b)      Ejecución del constructor asociado.

Si una clase define varios constructores, el constructor invocado por la sentencia new es el que coincide en número y tipo de parámetros con los utilizados en la sentencia new. Por ejemplo: taxi1 = new Taxi(); invoca al constructor general, mientras que taxi1 = new Taxi (“BFG-7432”) invoca al constructor que requiere un String como parámetro. new Taxi (“BFG-7432”, “Oeste”) invocaría al constructor que requiere dos String como parámetros. new Taxi (“BFG-7432”, “Oeste”, 2) invocaría al constructor que requiere dos String y un entero como parámetros, etc. No puede haber dos constructores que requieran el mismo número y tipo de parámetros (por ejemplo dos constructores que requieran un String) porque eso generaría una ambigüedad que daría lugar a un error de compilación.

¿QUÉ ES Y PARA QUÉ SIRVE EL API DE JAVA?

Hasta ahora hemos visto ejemplos donde utilizábamos la clase System (por ejemplo en la invocación System.out.println) o la clase String (que es la clase gracias a la que podemos usar los objetos String). ¿De dónde salen estas clases si nosotros no las hemos programado como la clase Taxi o la clase Exponenciador?

La respuesta está en que al instalar Java (el paquete JDK) en nuestro ordenador, además del compilador y la máquina virtual de Java se instalan bastantes más elementos. Entre ellos, una cantidad muy importante de clases que ofrece la multinacional desarrolladora de Java y que están a disposición

72

Page 73: Documentación Java

de todos los programadores listas para ser usadas. Estas clases junto a otros elementos forman lo que se denomina API (Application Programming Interface) de Java.

La mayoría de los lenguajes orientados a objetos ofrecen a los programadores bibliotecas de clases que facilitan el trabajo con el lenguaje.

Los siguientes esquemas, parte de la documentación de Java, nos dan una idea de cómo funciona el sistema Java y de qué se instala cuando instalamos Java (el paquete JDK) en nuestro ordenador.

 

Este esquema no nos interesa analizarlo en profundidad. Lo único que queremos mostrar es que cuando instalamos Java en nuestro ordenador instalamos múltiples herramientas, entre ellas una serie de “librerías” (paquetes) a cuyo conjunto solemos referirnos como “biblioteca estándar de Java”. Las librerías contienen código Java listo para ser usado por nosotros. Ese es el motivo de que podamos usar clases como System o String sin necesidad de programarlas.

 ¿Dónde se encuentra el código de estas librerías? En los archivos que se instalan en nuestro ordenador cuando instalamos Java.

 ¿Podemos acceder al código de estas librerías? La respuesta es que no. Las biblioteca estándar de Java se facilita como código cerrado, es decir, como código máquina. No podemos acceder al código fuente. Esto tiene su lógica porque si cada persona accediera al código fuente de los elementos

73

Page 74: Documentación Java

esenciales de Java y los modificara, no habría compatibilidad ni homogeneidad en la forma de escribir programas Java.

 ¿Para qué nos sirve la biblioteca si no podemos acceder a su código fuente? Aunque no podamos acceder al código fuente, sí podemos crear objetos de los tipos definidos en la librería e invocar sus métodos. Para ello lo único que hemos de hacer es conocer las clases y la signatura de los métodos, y esto lo tenemos disponible en la documentación de Java accesible para todos los programadores a través de internet o cds de libros y revistas especializadas. ¿Te acuerdas cuando hablamos de la definición de signatura e interfaz? Esto es ahora plenamente aplicable con el API de Java: tenemos disponible información de las clases, de qué hacen y cómo podemos trabajar con ellas, aunque no dispongamos del código fuente.

CONCEPCIÓN DE PROGRAMAS EN JAVA MEDIANTE ABSTRACCIÓN Y MODULARIZACIÓN

Los programas informáticos suelen ser muy complejos como para abordarlos en su conjunto. Por ello han de usarse técnicas para dividir el problema (estrategia “divide y vencerás”) que nos permitan crear programas complejos a partir de partes más simples. Hablamos de abstracción para referirnos a partes complejas ensambladas a partir de partes simples.

 Supongamos que necesitamos un programa informático para la gestión de un hotel. El programa habrá que dividirlo para construirlo y ensamblarlo para su puesta en funcionamiento:

 

 El programador que se encarga de una parte del software usa otras partes de software desarrolladas por otros sin analizar sus detalles (se abstrae de los detalles).

Hablamos de modularización del software en alusión a dividir un programa en partes independientes que pueden ser construidas y probadas por separado para luego ensamblarlas formando un todo. De acuerdo con esta terminología “abstraer” sería subir de nivel o ensamblar, mientras que modularizar sería bajar de nivel o despiezar.

74

Page 75: Documentación Java

En programación orientada a objetos la abstracción la materializamos construyendo objetos que usan o son combinación de otros objetos más simples. De este modo podemos construir objetos de gran complejidad sin necesidad de crear un código largo y complejo.

 UN EJEMPLO DE CÓDIGO JAVA BÁSICO. CREAR CLASES CON CAMPOS, CONSTRUCTOR Y MÉTODOS

Para familiarizarnos con el código Java escribe y estudia el código que mostramos a continuación, correspondiente a dos clases. Todos los elementos que forman parte de él ya los hemos estudiado excepto la llamada this (0, 0, “” ). La palabra clave this tiene distintos usos en Java y en general podríamos interpretarla como “este objeto”.

La invocación this , o this (parámetros) supone una invocación al constructor que coincida con los parámetros que se pasan para que se ejecute. Al igual que existen formas de invocar a métodos, existen formas de invocar a constructores, y ésta es una de ellas.

El código de la primera clase sería el siguiente:

/* Ejemplo - aprenderaprogramar.com */

/* Esta clase representa un depósito cilíndrico donde se almacena aceite */

public class Deposito {

//Campos de la clase

private float diametro;

private float altura;

private String idDeposito;

//Constructor sin parámetros auxiliar

public Deposito () { //Lo que hace es llamar al constructor con parámetros pasándole valores vacíos

this(0,0,""); } //Cierre del constructor

//Constructor de la clase que pide los parámetros necesarios

public Deposito (float valor_diametro, float valor_altura, String valor_idDeposito) {

if (valor_diametro > 0 && valor_altura > 0) {

diametro = valor_diametro;

75

Page 76: Documentación Java

altura = valor_altura;

idDeposito = valor_idDeposito;

} else {

diametro = 10;

altura = 5;

idDeposito = "000";

System.out.println ("Creado depósito con valores por defecto diametro 10 metros altura 5 metros id 000" );

} } //Cierre del constructor

public void setValoresDeposito (String valor_idDeposito, float valor_diametro, float valor_altura) {

idDeposito = valor_idDeposito;

diametro = valor_diametro;

altura = valor_altura;

if (idDeposito !="" && valor_diametro > 0 && valor_altura > 0) {

} else {

System.out.println ("Valores no admisibles. No se han establecido valores para el depósito");

//Deposito (0.0f, 0.0f, ""); Esto no es posible. Un constructor no es un método y por tanto no podemos llamarlo

idDeposito = "";

diametro = 0;

altura = 0;

} } //Cierre del método

public float getDiametro () { return diametro; } //Método de acceso

public float getAltura () { return altura; } //Método de acceso

76

Page 77: Documentación Java

public String getIdDeposito () { return idDeposito; } //Método de acceso

public float valorCapacidad () { //Método tipo función

float capacidad;

float pi = 3.1416f; //Si no incluimos la f el compilador considera que 3.1416 es double

capacidad = pi * (diametro/2) * (diametro/2) * altura;

return capacidad;

}

} //Cierre de la clase

En el método setValoresDeposito nos encontramos un código un tanto extraño: un if donde las instrucciones a ejecutar se encuentran vacías. Esto es admitido en Java, tanto en un if como en un else o en otras instrucciones. En este caso, el código equivale a: “Si el idDeposito es distinto de una cadena vacía y el valor_diametro es mayor que cero y el valor_altura es mayor que cero no se hace nada, y en caso contrario se han de ejecutar las instrucciones indicadas en el else”. Este tipo de construcciones no consideramos conveniente utilizarlas frecuentemente. Tan solo pueden ser indicadas cuando queremos remarcar que en determinadas circunstancias no se debe ejecutar ninguna instrucción.

Otra cuestión a tener en cuenta es que de momento estamos desarrollando una programación informal: el sistema de comentarios no se atiene a lo establecido por el sistema de documentación de Java, y hemos incluido algunas sentencias de impresión por consola que normalmente no forman parte del código de los programas. Usaremos estas y otras técnicas informales con el fin de facilitar el aprendizaje, no porque puedan ser recomendadas como técnicas de programación.

La segunda clase sería la siguiente:

/* Ejemplo - aprenderaprogramar.com */

/*Esta clase representa un conjunto de depósitos formado por entre 2 y 3 depósitos */

public class GrupoDepositos {

//Campos de la clase, algunos de ellos son tipo objetos de otra clase

private Deposito deposito1;

private Deposito deposito2;

private Deposito deposito3;

77

Page 78: Documentación Java

private String idGrupo;

private int numeroDepositosGrupo;

//Constructor para la clase. En ella se crean objetos de otra clase.

public GrupoDepositos (int numeroDeDepositosGrupo, String valor_idGrupo) {

idGrupo = valor_idGrupo;

switch (numeroDeDepositosGrupo) {

case 1: System.out.println ("Un grupo ha de tener más de un depósito"); break;

case 2:

deposito1 = new Deposito(); /*Al crear el objeto automáticamente se llama al constructor del mismo, en este caso sin parámetros. ESTO ES EJEMPLO DE SINTAXIS DE CREACIÓN DE UN OBJETO, EN ESTE CASO DENTRO DE OTRO */

deposito2 = new Deposito();

numeroDepositosGrupo = 2;

break;

case 3: deposito1 = new Deposito(); deposito2 = new Deposito(); deposito3 = new Deposito();

numeroDepositosGrupo = 3;

break;

default: System.out.println ("No se admiten más de tres depósitos");

//Esto no evita que se cree el objeto.

break;

} //Cierre del switch

} //Cierre del constructor

public int getNumeroDepositosGrupo () { return numeroDepositosGrupo; }

public String getIdGrupo () { return idGrupo; }

78

Page 79: Documentación Java

public float capacidadDelGrupo () { //Este método usa objetos de otra clase e invoca métodos de otra clase

if (numeroDepositosGrupo == 2) { return (deposito1.valorCapacidad() + deposito2.valorCapacidad() );

} else { return (deposito1.valorCapacidad() + deposito2.valorCapacidad()+ deposito3.valorCapacidad() ); }

//Si el grupo se ha creado con un número de depósitos distinto de 2 o 3 saltará un error en tiempo de ejecución

} //Cierre del método

} //Cierre de la clase

Con botón derecho sobre el icono de la clase GrupoDepositos, crea un grupo de depósitos que conste de 3 depósitos y cuyo idGrupo sea “Grupo KHP”. Invoca los métodos que devuelven el número de depósitos del grupo, el identificador del grupo y la capacidad de los depósitos del grupo. Como capacidad deberás obtener un valor de aproximadamente 1178.1 unidades cúbicas.

Verifica con la calculadora si este valor es correcto y trata de razonar sobre por qué se obtiene este valor y no otro. Crea también distintos objetos de tipo Deposito y utiliza sus métodos. En el caso de resultados numéricos, comprueba si los resultados que te ofrece el ordenador son correctos comparándolos con los resultados que te ofrece una calculadora.

Este ejemplo de código, todavía muy elemental y rudimentario, tiene un diagrama de clases donde nos indica que la clase GrupoDepositos usa a la clase Deposito.

A modo de resumen, el siguiente esquema nos indica lo que podemos hacer con este código. De este ejemplo lo único que nos interesa es practicar cómo una clase puede usar objetos y métodos de otra clase y la sintaxis a emplear. Aunque no hemos creado ningún programa, estamos viendo cómo crear clases y objetos que intervendrán en los programas.

PALABRAS CLAVE STATIC Y FINAL. CONSTANTES EN JAVA.

En los programas que generemos usualmente intervendrán constantes: valores matemáticos como el número Pi, o valores propios de programa que nunca cambian. Si nunca cambian, lo adecuado será declararlos como constantes en lugar de cómo variables. Supongamos que queremos usar una constante como el número Pi y que usamos esta declaración:

// Ejemplo aprenderaprogramar.com

public class Calculadora {

private double PI = 3.1416;

79

Page 80: Documentación Java

public void mostrarConstantePi () { System.out.println (PI); }

… constructor, métodos, … código de la clase … }

Si creas un objeto de tipo Calculadora, comprobarás que puedes invocar el método mostrarConstantePi para que te muestre el valor por pantalla. No obstante, una declaración de este tipo presenta varios problemas. En primer lugar, lo declarado no funciona realmente como constante, sino como variable con un valor inicial. Prueba a establecer this.PI = 22; dentro del método y verás que es posible, porque lo declarado es una variable, no una constante. En segundo lugar, cada vez que creamos un objeto de tipo calculadora estamos usando un espacio de memoria para almacenar el valor 3.1416. Así, si tuviéramos diez objetos calculadora, tendríamos diez espacios de memoria ocupados con la misma información, lo cual resulta ineficiente. Para resolver estos problemas, podemos declarar constantes en Java usando esta sintaxis:

CaracterPublico/Privado static final TipoDeLaConstante = valorDeLaConstante;

En esta declaración intervienen dos palabras clave cuyo significado es importante:

a) static: los atributos miembros de una clase pueden ser atributos de clase o atributos de instancia; se dice que son atributos de clase si se usa la palabra clave static: en ese caso la variable es única para todas las instancias (objetos) de la clase (ocupa un único lugar en memoria). A veces a las variables de clase se les llama variables estáticas. Si no se usa static, el sistema crea un lugar nuevo para esa variable con cada instancia (la variable es diferente para cada objeto). En el caso de una constante no tiene sentido crear un nuevo lugar de memoria por cada objeto de una clase que se cree. Por ello es adecuado el uso de la palabra clave static. Cuando usamos “static final” se dice que creamos una constante de clase, un atributo común a todos los objetos de esa clase.

b) final: en este contexto indica que una variable es de tipo constante: no admitirá cambios después de su declaración y asignación de valor. final determina que un atributo no puede ser sobreescrito o redefinido. O sea: no funcionará como una variable “tradicional”, sino como una constante. Toda constante declarada con final ha de ser inicializada en el mismo momento de declararla. final también se usa como palabra clave en otro contexto: una clase final (final) es aquella que no puede tener clases que la hereden. Lo veremos más adelante cuando hablemos sobre herencia.

Cuando se declaran constantes es muy frecuente que los programadores usen letras mayúsculas (como práctica habitual que permite una mayor claridad en el código), aunque no es obligatorio.

Una declaración en cabecera de una clase como private final double PI = 3.1416; podríamos interpretarla como una constante de objeto. Cada objeto tendrá su espacio de memoria con un contenido invariable. Una declaración en cabecera de una clase como private static final double Pi = 3.1416; la interpretamos como una constante de clase. Existe un único espacio de memoria, compartido por todos los objetos de la clase, que contiene un valor invariable. Veamos ejemplos de uso:

// Ejemplo aprenderaprogramar.com

// Sintaxis: CaracterPublico/Privado static final TipoDeLaConstante = valorDeLaConstante;

private static final float PI = 3.1416f; //Recordar f indica que se trata de un float

80

Page 81: Documentación Java

private static double PI = 3.1416;

public static final String passwd = "jkl342lagg";

public static final int PRECIO_DEFAULT = 100;

Cuando usamos la palabra clave static la declaración de la constante ha de realizarse obligatoriamente en cabecera de la clase, junto a los campos (debajo de la signatura de clase). Es decir, un atributo de clase hemos de declararlo en cabecera de clase. Si tratamos de incorporarlo en un método obtendremos un error. Por tanto dentro del método main (que es un método de clase al llevar incorporado static en su declaración) no podemos declarar constantes de clase. Por otro lado, final sí puede ser usado dentro de métodos y también dentro de un método main. Por ejemplo una declaración como final String psswd = “mt34rsm8” es válida dentro de un método. En resumen: en cabecera de clase usaremos static final para definir aquellas variables comunes a todos los objetos de una clase.

Modifica el código de la clase Calculadora que vimos anteriormente para declarar PI como una constante de clase. Luego, intenta modificar el valor de PI usando una invocación como this.PI =22;. Comprobarás que se produce un error al compilar ya que los valores de las constantes no son modificables.

EJERCICIO

Define una clase Java denominada Circulo que tenga como atributo de clase (estático) y constante numeroPi, siendo esta constante de tipo double y valor 3.1416. Además la clase tendrá el atributo radio (tipo double) que representa el radio del círculo, y los métodos para obtener y establecer los atributos. También debe disponer de un método para calcular el área del círculo (método tipo funcion areaCirculo que devuelve el área) y la longitud del círculo (método tipo función que devuelve la longitud). Busca información sobre las fórmulas necesarias para crear estos métodos en internet si no las recuerdas. En una clase con el método main, declara el código que cree un objeto círculo, le pida al usuario el radio y le devuelva el área y la longitud del círculo.

¿Es posible crear un método en la clase Circulo para establecer el valor de numeroPi? ¿Por qué?

EJEMPLO DE HERENCIA EN JAVA. EXTENDS Y SUPER.

Para declarar la herencia en Java usamos la palabra clave extends. Ejemplo: public class MiClase2 extends Miclase1. Para familiarizarte con la herencia te proponemos que escribas y estudies un pequeño programa donde se hace uso de ella. Escribe el código de las clases que mostramos a continuación.

//Código de la clase Persona ejemplo aprenderaprogramar.com

public class Persona {

private String nombre;

private String apellidos;

81

Page 82: Documentación Java

private int edad;

//Constructor

public Persona (String nombre, String apellidos, int edad) {

this.nombre = nombre;

this.apellidos = apellidos;

this.edad = edad; }

//Métodos

public String getNombre () { return nombre; }

public String getApellidos () { return apellidos; }

public int getEdad () { return edad; }

} //Cierre de la clase

//Código de la clase profesor, subclase de la clase Persona ejemplo aprenderaprogramar.com

public class Profesor extends Persona {

//Campos específicos de la subclase.

private String IdProfesor;

//Constructor de la subclase: incluimos como parámetros al menos los del constructor de la superclase

public Profesor (String nombre, String apellidos, int edad) {

super(nombre, apellidos, edad);

IdProfesor = "Unknown"; } //Cierre del constructor

//Métodos específicos de la subclase

public void setIdProfesor (String IdProfesor) { this.IdProfesor = IdProfesor; }

public String getIdProfesor () { return IdProfesor; }

public void mostrarNombreApellidosYCarnet() {

82

Page 83: Documentación Java

// nombre = "Paco"; Si tratáramos de acceder directamente a un campo privado de la superclase, salta un error

// Sí podemos acceder a variables de instancia a través de los métodos de acceso públicos de la superclase

System.out.println ("Profesor de nombre: " + getNombre() + " " + getApellidos() +

" con Id de profesor: " + getIdProfesor() ); }

} //Cierre de la clase

//Código de test aprenderaprogramar.com

public class TestHerencia1 {

public static void main (String [ ] Args) {

Profesor profesor1 = new Profesor ("Juan", "Hernández García", 33);

profesor1.setIdProfesor("Prof 22-387-11");

profesor1.mostrarNombreApellidosYCarnet();}

} //Cierre de la clase

El diagrama de clases y el resultado del test son del tipo que mostramos a continuación:

herencia, java

Profesor de nombre: Juan Hernández García con Id de profesor: Prof 22-387-11

Los aspectos a destacar del código son:

a) La clase persona es una clase “normal” definida tal y como lo venimos haciendo habitualmente mientras que la clase Profesor es una subclase de Persona con ciertas peculiaridades.

b) Los objetos de la subclase van a tener campos nombre, apellidos y edad (heredados de Persona) y un campo específico IdProfesor. El constructor de una subclase ha de llevar obligatoriamente como parámetros al menos los mismos parámetros que el constructor de la superclase.

83

Page 84: Documentación Java

c) El constructor de la subclase invoca al constructor de la superclase. Para ello se incluye, obligatoriamente, la palabra clave super como primera línea del constructor de la subclase. La palabra super irá seguida de paréntesis dentro de los cuales pondremos los parámetros que requiera el constructor de la superclase al que queramos invocar. En este caso solo teníamos un constructor de superclase que requería tres parámetros. Si p.ej. hubiéramos tenido otro constructor que no requiriera ningún parámetro podríamos haber usado uno u otro, es decir, super(nombre, apellidos, edad) ó super(), o bien ambos teniendo dos constructores para la superclase y dos constructores para la subclase. Ejemplo:

En la superclase: public Persona() {

nombre = "";

apellidos = "";

edad = 0; }

public Persona (String nombre, String apellidos, int edad) {

this.nombre = nombre;

this.apellidos = apellidos;

this.edad = edad; }

En la subclase: public Profesor () {

super();

IdProfesor = "Unknown";}

public Profesor (String nombre, String apellidos, int edad) {

super(nombre, apellidos, edad);

IdProfesor = "Unknown"; }

Modifica el código de las clases Persona y Profesor para que queden con dos constructores tal y como hemos mostrado aquí. Crea objetos de ambos tipos en BlueJ y prueba sus métodos.

¿Qué ocurre si olvidamos poner super como primera línea de la subclase? Hay dos posibilidades: si la superclase tiene un constructor sin parámetros, el compilador incluirá en segundo plano super de forma automática y no saltará un error. De cualquier manera se considera contrario al buen estilo de programación, ya que no queda claro si se trata de un olvido. Por ello incluiremos siempre la palabra

84

Page 85: Documentación Java

clave super. La otra posibilidad es que no haya un constructor sin parámetros, en cuyo caso saltará un error.

A modo de resumen: la inicialización de un objeto de una subclase comprende dos pasos. La invocación al constructor de la superclase (primera línea del constructor: super…) y el resto de instrucciones propias del constructor de la subclase.

EJERCICIO

Se plantea desarrollar un programa Java que permita la gestión de una empresa agroalimentaria que trabaja con tres tipos de productos: productos frescos, productos refrigerados y productos congelados. Todos los productos llevan esta información común: fecha de caducidad y número de lote. A su vez, cada tipo de producto lleva alguna información específica. Los productos frescos deben llevar la fecha de envasado y el país de origen. Los productos refrigerados deben llevar el código del organismo de supervisión alimentaria. Los productos congelados deben llevar la temperatura de congelación recomendada. Crear el código de las clases Java implementando una relación de herencia desde la superclase Producto hasta las subclases ProductoFresco, ProductoRefrigerado y ProductoCongelado. Cada clase debe disponer de constructor y permitir establecer (set) y recuperar (get) el valor de sus atributos y tener un método que permita mostrar la información del objeto. Crear una clase testHerencia2 con el método main donde se cree un objeto de cada tipo y se muestren los datos de cada uno de los objetos creados.

MODIFICADORES DE ACCESO JAVA: PUBLIC, PRIVATE, PROTECTED.

Hasta ahora habíamos dicho que una subclase no tiene acceso a los campos de una superclase de acuerdo con el principio de ocultación de la información. Sin embargo, esto podría considerarse como demasiado restrictivo.

Decimos que podría considerarse demasiado restrictivo porque limita el acceso a una subclase como si se tratara de una clase cualquiera, cuando en realidad la relación de una superclase con una subclase es más estrecha que con una clase externa. Por ello en diferentes lenguajes, Java entre ellos, se usa un nivel de acceso intermedio que no es ni public ni private, sino algo intermedio que se denomina como “acceso protegido”, expresado con la palabra clave protected, que significa que las subclases sí pueden tener acceso al campo o método.

El modificador de acceso protected puede aplicarse a todos los miembros de una clase, es decir, tanto a campos como a métodos o constructores. En el caso de métodos o constructores protegidos, estos serán visibles/utilizables por las subclases y otras clases del mismo package. El acceso protegido suele aplicarse a métodos o constructores, pero preferiblemente no a campos, para evitar debilitar el encapsulamiento. En ocasiones puntuales sí resulta de interés declarar campos con acceso protegido.

La sintaxis para emplear esta palabra clave es análoga a la que usamos con las palabras public y private, con la salvedad de que protected suele usarse cuando se trabaja con herencia. Desde un objeto de una subclase podremos acceder o invocar un campo o método declarado como protected, pero no podemos acceder o invocar a campos o métodos privados de una superclase. Declara un campo de una clase

85

Page 86: Documentación Java

como protected y en un test crea un objeto de la subclase y trata de acceder a ese campo con una invocación directa del tipo interino43.IdProfesor = “54-DY-87”.

Java admite una variante más en cuanto a modificadores de acceso: la omisión del mismo (no declarar ninguno de los modificadores public, private o protected). En la siguiente tabla puedes comparar los efectos de usar uno u otro tipo de declaración en cuanto a visibilidad de los campos o métodos:

MODIFICADOR

CLASE

PACKAGE

SUBCLASE

TODOS

public

protected

No

No especificado

No

86

Page 87: Documentación Java

No

private

No

No

No

EJERCICIO

Considera que estás desarrollando un programa Java donde trabajas con la superclase Profesor y la subclase ProfesorEmerito. Crea el código para estas clases que cumpla los requisitos que indicamos.

Como atributos de la superclase tendremos nombre (String), edad (int) y añosConsolidados (int) declarados como protected.

En la subclase se trabajará con el campo adicional añosEmerito declarado como private.

Un método de la subclase será double obtenerSalarioBase () que obtendrá el salario base como (925 + añosConsolidados * 33.25 + 47.80 * añosEmerito).

Intenta acceder directamente al campo añosConsolidados desde la subclase (como si fuera un campo más de la subclase) para implementar este método. ¿Es posible sin utilizar una invocación a super ni un método get? ¿Qué ocurre si el atributo en la superclase lo declaras private?

PARA QUÉ SIRVEN LAS INTERFACES EN JAVA

Si una interfaz define un tipo (al igual que una clase define un tipo) pero ese tipo no provee de ningún método podemos preguntarnos: ¿qué se gana con las interfaces en Java? La implementación (herencia) de una interfaz no podemos decir que evite la duplicidad de código o que favorezca la reutilización de código puesto que realmente no proveen código.  

En cambio sí podemos decir que reúne las otras dos ventajas de la herencia: favorecer el mantenimiento y la extensión de las aplicaciones. ¿Por qué? Porque  al definir interfaces permitimos la existencia de variables polimórficas y la invocación polimórfica de métodos. En el diagrama que vimos anteriormente tanto árboles como arbustos, vehículos y personas son de tipo Actor, de modo que podemos generar código que haga un tratamiento en común de todo lo que son actores. Por ejemplo, podemos necesitar una lista de Actores. Podemos declarar una variable como de tipo Actor (aunque no puedan existir instancias de Actor) que permita referenciar alternativamente a objetos de las distintas subclases de la interfaz.

Un aspecto fundamental de las interfaces en Java es hacer lo que ya hemos dicho que hace una interfaz de forma genérica: separar la especificación de una clase (qué hace) de la implementación (cómo lo

87

Page 88: Documentación Java

hace). Esto se ha comprobado que da lugar a programas más robustos y con menos errores. Pensemos en el API de Java. Por ejemplo, disponemos de la interfaz List que es implementada por las clases ArrayList y LinkedList (y también por otras varias clases).

 El hecho de declarar una variable de tipo lista, por ejemplo List <String> miLista; nos dice que miLista va a ser una implementación de List, pero todavía no hemos definido cuál de las posibles implementaciones va a ser. De hecho, el código podría definir que se implementara de una u otra manera en función de las circunstancias usando condicionales. O a nivel de programación, mantendríamos la definición como List y nos permitiría comprobar el rendimiento de distintas configuraciones (hacer funcionar miLista bien como ArrayList bien como LinkedList viendo su rendimiento). La variable declarada se crea cuando escribimos miLista = new LinkedList <String> (); o también se puede usar la sintaxis: List <String> miLista = new LinkedList <String> ();

Usar una u otra implementación puede dar lugar a diferentes rendimientos de un programa. ArrayList responde muy bien para la búsqueda de elementos situados en posiciones intermedias pero la inserción o eliminación de elementos puede ser más rápida con una LinkedList. Declarando las variables simplemente como List tendremos la posibilidad de que nuestro programa pase de usar un tipo de lista a otro tipo.

Como List es un tipo, podemos especificar los métodos para que requieran List y después enviarles como parámetro bien un ArrayList bien un LinkedList sin tener que preocuparnos de hacer cambios en el código en caso de que usáramos uno u otro tipo de lista. En esencia, usando siempre List, el único sitio donde habría que especificar la clase concreta sería donde se declara la creación de la variable, con lo cual todo nuestro código (excepto el lugar puntual donde se crea la variable) es independiente del tipo de lista que usemos y esto resulta ventajoso porque pasar de usar un tipo de lista a usar otro resultará muy sencillo.

Los métodos de ArrayList en algunos casos definen los métodos abstractos de List, y en otros casos son específicos. Recordar que en List todos los métodos son abstractos por ser una interfaz, aunque no se indique específicamente en la documentación del API de Java. Recordar también que List, por ser una interfaz no tiene constructores y no es instanciable. Al ver la documentación del API nos puede parecer una clase, pero la ausencia de constructor (aparte del propio nombre en el encabezado) delata que no se trata de una clase.

 Interface List<E>

88

Page 89: Documentación Java

All Superinterfaces: Collection<E>, Iterable<E>

All Known Implementing Classes: AbstractList, AbstractSequentialList, ArrayList, AttributeList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector

Otra ventaja clara de las interfaces es que nos permiten declarar constantes que van a estar disponibles para todas las clases que queramos (implementando esa interfaz). Nos ahorra código evitando tener que escribir las mismas declaraciones de constantes en diferentes clases.

 EJEMPLO SENCILLO DE INTERFACE EN JAVA

Vamos a ver un ejemplo simple de definición y uso de interface en Java. Las clases que vamos a usar y sus relaciones se muestran en el esquema. Escribe el código y ejecútalo.

 

public interface Figura {  // Ejemplo aprenderaprogramar.com

float PI = 3.1416f;   // Por defecto public static  final. La f final indica que el número es float

float area();   // Por defecto abstract public

} //Cierre de la interface

 

public class Cuadrado implements Figura { // La clase implementa la interface Figura

89

Page 90: Documentación Java

private float lado;

public Cuadrado (float lado) { this.lado = lado; }

public float area() { return lado*lado; }

} //Cierre de la clase ejemplo aprenderaprogramar.com

 

public class Circulo implements Figura{ // La clase implementa la interface Figura

private float diametro;

public Circulo (float diametro) { this.diametro = diametro; }

public float area() { return (PI*diametro*diametro/4f); }

} //Cierre de la clase ejemplo aprenderaprogramar.com

 

public class Rectangulo implements Figura{ // La clase implementa la interface Figura

private float lado; private float altura;

public Rectangulo (float lado, float altura) { this.lado = lado; this.altura = altura; }

public float area() { return lado*altura; }

} //Cierre de la clase ejemplo aprenderaprogramar.com

 

import java.util.List; import java.util.ArrayList; //Test ejemplo aprenderaprogramar.com

public class TestInterface {

90

Page 91: Documentación Java

    public static void main (String [ ] Args) {

        Figura cuad1 = new Cuadrado (3.5f); Figura cuad2 = new Cuadrado (2.2f); Figura cuad3 = new Cuadrado (8.9f);

        Figura circ1 = new Circulo (3.5f); Figura circ2 = new Circulo (4f);

        Figura rect1 = new Rectangulo (2.25f, 2.55f); Figura rect2 = new Rectangulo (12f, 3f);

        List <Figura> serieDeFiguras = new ArrayList <Figura> ();

        serieDeFiguras.add (cuad1); serieDeFiguras.add (cuad2); serieDeFiguras.add (cuad3);

        serieDeFiguras.add (circ1); serieDeFiguras.add (circ2); serieDeFiguras.add (rect1); serieDeFiguras.add (rect2);

        float areaTotal = 0;

        for (Figura tmp: serieDeFiguras) {      areaTotal = areaTotal + tmp.area();     }

        System.out.println ("Tenemos un total de " + serieDeFiguras.size() + " figuras y su área total es de "  +

        areaTotal + " uds cuadradas")  } } //Cierre del main y de la clase

El resultado de ejecución podría ser algo así:

Tenemos un total de 7 figuras y su área total es de 160.22504 uds cuadradas

 En este ejemplo comprobamos que la interface Figura define un tipo. Podemos crear un ArrayList de figuras donde tenemos figuras de distintos tipos (cuadrados, círculos, rectángulos) aprovechándonos del polimorfismo. Esto nos permite darle un tratamiento común a todas las figuras. En concreto, usamos un bucle for-each para recorrer la lista de figuras y obtener un área total.

IMPLEMENTAR UNA INTERFACE DEL API JAVA. EJEMPLO.

El API de Java define interfaces que aparte de usarlas para definir tipos, nosotros podemos implementar en una clase propia en nuestro código. Esto tiene cierta similitud con hacer una redefinición de un método (ya hemos visto cómo redefinir métodos como toString()), pero no es exactamente lo mismo. Para empezar, algunos métodos como toString() están definidos en la clase Object. Estos métodos declarados en la clase Object los podemos redefinir en una clase propia sin necesidad de escribir nada en cabecera de la clase, puesto que por defecto todo objeto hereda de Object. Para utilizar interfaces, como la interfaz Comparable, habremos de escribir en cabecera de la clase:

91

Page 92: Documentación Java

public class NombreDeLaClase implements Comparable <NombreDeLaClase> { … }

 Por ejemplo public class Persona implements Comparable <Persona>.

 ¿Qué interés tiene implementar una interface del API si no nos proporciona código ninguno? Tal y como dijimos en su momento, una interface puede verse en relación a la programación como una norma urbanística en una ciudad. Si lees la documentación de la interfaz, aunque no proporciona código, sí proporciona instrucciones respecto a características comunes para las clases que la implementen y define qué métodos han de incluirse para cumplir con la interfaz y para qué servirán esos métodos. Si implementamos la interface, lo que hacemos es ajustarnos a la norma. Y si todos los programadores se ajustan a la misma norma, cuando un programador tiene que continuar un programa iniciado por otro no tiene que preguntarse: ¿qué método podré usar para comparar varios objetos de este tipo y ponerlos en orden? Y no hay que preguntárselo porque en general los programadores se ciñen a lo establecido por el API de Java: para comparar varios objetos y ponerlos en orden (“orden natural”) se implementa la interfaz Comparable y su método compareTo(). Y además, ya sabemos qué tipo ha de devolver ese método y cómo ha de funcionar, porque así lo indica la documentación de la interface.

Muchas clases del API de Java ya tienen implementada la interface Comparable. Por ejemplo la clase Integer tiene implementada esta interfaz, lo que significa que el método compareTo() es un método disponible para cualquier objeto de tipo Integer.

No podemos conocer ni todas las clases ni todas las interfaces del API de Java. No obstante, a medida que vayamos realizando programas y adquiriendo práctica con Java, nos daremos cuenta de que algunas clases e interfaces son muy usadas. A base de usarlas, iremos memorizando poco a poco sus nombres y métodos. Otras clases o interfaces las usaremos ocasionalmente y recurriremos a la consulta de documentación del API cada vez que vayamos a usarlas. Y otras clases o interfaces quizá no lleguemos a usarlas nunca.

 EJERCICIO

Se plantea desarrollar un programa Java que permita representar la siguiente situación. Una instalación deportiva es un recinto delimitado donde se practican deportes, en Java interesa disponer de un método int getTipoDeInstalacion(). Un edificio es una construcción cubierta y en Java interesa disponer de un método double getSuperficieEdificio(). Un polideportivo es al mismo tiempo una instalación deportiva y un edificio; en Java interesa conocer la superficie que tiene y el nombre que tiene. Un edificio de oficinas es un edificio; en Java interesa conocer el número de oficinas que tiene.

Definir dos interfaces y una clase que implemente ambas interfaces para representar la situación anterior. En una clase test con el método main, crear un ArrayList que contenga tres polideportivos y dos edificios de oficinas y utilizando un iterator, recorrer la colección y mostrar los atributos de cada elemento. ¿Entre qué clases existe una relación que se asemeja a la herencia múltiple?

92

Page 93: Documentación Java

/** * Este metodo lee una imagen bmp, gif, jpg, png y la * guarda en el atributo dbi del tipo BufferedImage * @param frame Ventana sobre la que se despliega el cuadro * de dialogo JFileChooser */

public void leeImagen(JFrame frame) { JFileChooser fc = new JFileChooser();

// Elimina el filtro *.*

fc.setAcceptAllFileFilterUsed(false);

//Crea el filtro para las extensiones validas

FileNameExtensionFilter extFiltro = new FileNameExtensionFilter( "Images", "bmp", "gif", "jpg", "png");

// Establece el filtro para las extensiones validas

fc.setFileFilter(extFiltro);

//Despliega el cuadro de dialogo para seleccionar la imagen a abrir

int returnVal = fc.showOpenDialog(frame);

// Si se selecciono una imagen

if (returnVal == JFileChooser.APPROVE_OPTION) {

// Obtiene el objeto File de la imagen seleccionada

file = fc.getSelectedFile(); try {

// lee la imagen y la guarda en el atributo obi del tipo BufferedImage

BufferedImage obi = ImageIO.read(file);

// Hace que la referencia dbi apunte a obi

dbi = obi; } catch (IOException e) { JOptionPane.showMessageDialog(frame, "Error al cargar imagen"); return; } } }

___________________________________________

93

Page 94: Documentación Java

PROGRAMA MONTADO Y PROBADO = PROYECTO. JAVA: metodosio2

*/ public class metodosio2 { /** * @param args the command line arguments */ public static void main(String[] args) { String userDir = System.getProperty("user.dir"); String separador = System.getProperty("file.separator"); System.out.println("Directorio del usuario: " + userDir); System.out.println("Separador: " + separador); File file1 = new File(userDir); System.out.println("Ruta abstracta del directorio del usuario: " + file1); File file2 = new File("src metodosio2.java"); System.out.println("Caracteristicas del archivo: src metodosio2.java: "); System.out.println("Nombre: " + file2.getName()); System.out.println(file2.getName() + (file2.exists()? " ": " no ") + "existe"); System.out.println("Tamaño " + file2.length() + " bytes"); System.out.println("Ruta: " + file2.getPath()); System.out.println("Ruta abstracta: " + file2); System.out.println("Ruta absoluta: " + file2.getAbsolutePath()); System.out.println("Ruta abstracta absoluta: " + file2.getAbsoluteFile()); System.out.println(file2.getName() + (file2.isFile()? " ": " no ") + "es un archivo"); System.out.println(file2.getName() + (file2.isDirectory()? " ": " no ") + "es un directorio");

___________________________________________________System.out.println("n"); System.out.println("Caracteristicas del padre de: srcpruebasPruebaFile.java: "); System.out.println("Ruta: " + file2.getParent()); System.out.println("Ruta abstracta: " + file2.getParentFile()); System.out.println("Ruta absoluta: " + file2.getParentFile().getAbsolutePath()); System.out.println("Ruta abstracta absoluta: " + file2.getParentFile().getAbsoluteFile()); System.out.println(file2.getParent() + (file2.getParentFile().isFile()? " ": " no ") + "es un archivo"); System.out.println(file2.getParent() + (file2.getParentFile().isDirectory()? " ": " no ") + "es un directorio"); File dir[] = file1.listFiles(); System.out.println("Archivos del directorio del usuario: "); for(File file: dir) { System.out.println(file); }

http://www.javaya.com.ar/detalleconcepto.php?codigo=88&inicio

Métodos con parámetros.

Un método puede tener parámetros:

public void [nombre del método]([parámetros]) { [algoritmo]}

Los parámetros los podemos imaginar como variables locales al método, pero su valor se inicializa con datos que llegan cuando lo llamamos. Estos parámetros son propios (exclusivos) del método, pueden tener el mismo nombre de un atributo de clase, pero tienen diferente ámbito y duración. En este caso, para hacer que los parámetros del método sean las variables de la clase, hay que redactar la siguiente sentencia:

94

Page 95: Documentación Java

This. parámetro = variable con el mismo nombre (ej: this.x = x)

Problema 1:

Confeccionar una clase que permita ingresar valores enteros por teclado y nos muestre la tabla de multiplicar de dicho valor. Finalizar el programa al ingresar el -1.

Programa:

import java.util.Scanner;public class TablaMultiplicar { //método cargarValor sin parámetros:

public void cargarValor() {//Código: operaciones a ejecutar//Crea un nuevo objeto de nombre “teclado” pertenece a la clase Scanner

Scanner teclado=new Scanner(System.in);//declara una variable propia de nombre “valor”

int valor;//Método do:

do {//pide ingresar un valor por teclado:

System.out.print("Ingrese valor:"); valor=teclado.nextInt(); if (valor!=-1) {//invoca al método calcular (que está más adelante) Y le asigna el valor recibido a su parámetro (int v)

calcular(valor); } } while (valor!=-1); }//método con parámetros (int v) para calcular los valores de la tabla de multiplicar del valor recibido en su invocación public void calcular(int v) { for(int f=v;f<=v*10;f=f+v) { System.out.print(f+"-"); } }//método principal, en el cual se crea un Nuevo Objeto llamado “tabla” public static void main(String[] ar) { TablaMultiplicar tabla = new TablaMultiplicar();//este objeto “tabla” llama al método “cargarValor”, ya que de no declararse esta sentencia, el programa entero no haría nada, pues el método inicial no arrancaría.

tabla.cargarValor(); }}

En esta clase no hemos definido ningún atributo, ya que el objeto de la clase Scanner lo requerimos en un solo método, por ello lo definimos como una variable local.

95

Page 96: Documentación Java

El método calcular recibe un parámetro de tipo entero, luego lo utilizamos dentro del método para mostrar la tabla de multiplicar de dicho valor, para esto inicializamos la variable f con el valor que llega en el parámetro. Luego de cada ejecución del for incrementamos el contador f con el valor de v.

public void calcular(int v) { for(int f=v;f<=v*10;f=f+v) { System.out.print(f+"-"); } }

Un método puede no tener parámetros como hemos visto en problemas anteriores o puede tener uno o más parámetros (en caso de tener más de un parámetro los mismos se separan por coma)

El método cargarValores no tiene parámetros y tiene por objetivo cargar un valor entero por teclado y llamar al método calcular para que muestre la tabla de multiplicar del valor que le pasamos por teclado:

public void cargarValor() { Scanner teclado=new Scanner(System.in); int valor; do { System.out.print("Ingrese valor:"); valor=teclado.nextInt(); if (valor!=-1) { calcular(valor); } } while (valor!=-1); }

Como vemos al método calcular lo llamamos por su nombre y entre paréntesis le pasamos el dato a enviar (debe ser un valor o variable entera)

En este problema en la main solo llamamos al método cargarValor, ya que el método calcular luego es llamado por el método cargarValor:

public static void main(String[] ar) { TablaMultiplicar tabla; tabla=new TablaMultiplicar(); tabla.cargarValor(); }

Métodos que retornan un dato.

Un método puede retornar un dato:

public [tipo de dato] [nombre del método]([parámetros]) { [algoritmo] return [tipo de dato]}

Cuando un método retorna un dato en vez de indicar la palabra clave void previo al nombre del método indicamos el tipo de dato que retorna. Luego dentro del algoritmo en el momento que queremos que finalice el mismo y retorne el dato empleamos la palabra clave return con el valor respectivo.

96

Page 97: Documentación Java

Problema 2:

Confeccionar una clase que permita ingresar tres valores por teclado. Luego mostrar el mayor y el menor.

Programa:

import java.util.Scanner;public class MayorMenor { public void cargarValores() { Scanner teclado=new Scanner(System.in); System.out.print("Ingrese primer valor:"); int valor1=teclado.nextInt(); System.out.print("Ingrese segundo valor:"); int valor2=teclado.nextInt(); System.out.print("Ingrese tercer valor:"); int valor3=teclado.nextInt(); int mayor,menor; mayor=calcularMayor(valor1,valor2,valor3); menor=calcularMenor(valor1,valor2,valor3); System.out.println("El valor mayor de los tres es:"+mayor); System.out.println("El valor menor de los tres es:"+menor); } public int calcularMayor(int v1,int v2,int v3) { int m; if(v1>>v2 && v1>v3) { m=v1; } else { if(v2>v3) { m=v2; } else { m=v3; } } return m; } public int calcularMenor(int v1,int v2,int v3) { int m; if(v1<v2 && v1<v3) { m=v1; } else { if(v2<v3) { m=v2; } else { m=v3; } } return m; } public static void main(String[] ar) { MayorMenor maymen=new MayorMenor(); maymen.cargarValores(); }

97

Page 98: Documentación Java

}

Si vemos la sintaxis que calcula el mayor de tres valores enteros es similar al algoritmo visto en conceptos anteriores:

public int calcularMayor(int v1,int v2,int v3) { int m; if(v1>v2 && v1>v3) { m=v1; } else { if(v2>v3) { m=v2; } else { m=v3; } } return m; }

Lo primero que podemos observar que el método retorna un entero y recibe tres parámetros:

public int calcularMayor(int v1,int v2,int v3) {

Dentro del método verificamos cual de los tres parámetros almacena un valor mayor, a este valor lo almacenamos en una variable local llamada "m", al valor almacenado en esta variable lo retornamos al final con un return.

La llamada al método calcularMayor lo hacemos desde dentro del método cargarCalores:

mayor=calcularMayor(valor1,valor2,valor3);

Debemos asignar a una variable el valor devuelto por el método calcularMayor. Luego el contenido de la variable mayor lo mostramos:

System.out.println("El valor mayor de los tres es:"+mayor);

La lógica es similar para el cálculo del menor.

METODOShttp://elvex.ugr.es/decsai/java/pdf/4B-methods.pdf

____________________Podemos hacer un resumen de los atributos que pueden tener campos, métodos o clases:

Campo: {private | public | protected} {final} {static}

Método: {private | public | protected} {final | abstract} {static}

Clase: {public} {final | abstract}

Sólo se puede especificar uno de los atributos puestos en la misma llave.

98

Page 99: Documentación Java

Las palabras private, protected y public son atributos de un campo o un método y su significado es el siguiente:

private: El campo o método sólo es visible dentro de la clase donde se define.

protected: El campo o método es visible en la clase en donde se define y desde otras clases del mismo paquete y en cualquiera de sus subclases (estén o no en el mismo paquete).

public: El campo o método es visible en cualquier clase.

Ninguna de las anteriores: El campo o método es visible en cualquiera de las clases pertenecientes al paquete en donde se define.

Al declarar una clase se puede especificar que es pública usando el atributo public. De este modo la clase podrá ser usada por cualquier otra clase. Si la clase no es pública entonces la clase sólo puede ser usada dentro del paquete que la contiene.

STATIC:Sirve para crear miembros que pertenecen a la clase, y no a una instancia de la clase. Esto implica, entre otras cosas, que no es necesario crear un objeto de la clase para poder acceder a estos atributos y métodos.

En ocasiones es necesario o conveniente generar elementos que tomen un mismo valor para cualquier número de instancias generadas o bien invocar/llamar métodos sin la necesidad de generar instancias, y es bajo estas dos circunstancias que es empleado el calificador static.

Dos aspectos característicos de utilizar el calificador static en un elemento Java son los siguientes:

- No puede ser generada ninguna instancia (uso de new) de un elemento static puesto que solo existe una instancia.

- Todos los elementos definidos dentro de una estructura static deben ser static ellos mismos, o bien, poseer una instancia ya definida para poder ser invocados.

NOTA: Lo anterior no implica que no puedan ser generadas instancias dentro de un elemento static; no es lo mismo llamar/invocar que crear/generar.

FINAL:Indica que una variable, método o clase no se va a modificar, lo cuál puede ser útil para añadir más semántica, por cuestiones de rendimiento, y para detectar errores.

- Si una variable se marca como final, no se podrá asignar un nuevo valor a la variable.- Si una clase se marca como final, no se podrá extender la clase.- Si es un método el que se declara como final, no se podrá sobreescribir.

Algo muy a tener en cuenta a la hora de utilizar este modificador es que si es un objeto lo que hemos marcado como final, esto no nos impedirá modificar el objeto en sí, sino tan sólo usar el operador de asignación para cambiar la referencia. Por lo tanto:+ expand source

99

Page 100: Documentación Java

NOTA: Una variable con modificadores static y final sería lo más cercano en Java a las constantes de otros lenguajes de programación.

ABSTRACT:La palabra clave abstract indica que no se provee una implementación para un cierto método, sino que la implementación vendrá dada por las clases que extiendan la clase actual. Una clase que tenga uno o más métodos abstract debe declararse como abstract a su vez._______________________

bueno tengo varias clases y en una en especifo ya estan setiadas las variables y nesesito su contenido en otra clase como las llamo ? ya las declare publicas pero no se como llamarlas desde la otra clase

declarelas privada y haga un metodo que devuelva dicha variables, solo tendrias que hacer lo siguienteclase x = new clase;int y = x.obtenervariable();

el metodo en la clase "clase" seriaprivate int variable_y = 0;Public int obtenervariable(){return variable_y;}

No se puede hacer lo que quieres, las variables pueden ser globales o locales, si son globales iran justo debajo de la declaracion de la clase pero tampoco se las podra llamar si no es a traves de un objeto, si son locales quiere decir que solo funcionan dentro del metodo donde fueron creadas.

Si quisieras llamar una variable desde otro clase primero deberias crear un objeto de esa otra clase asi: NombreClase NombreObjeto=new NombreClase(); donde NombreObjeto sera el nombre que vas a usar para acceder a esa clase y NombreClase sera el

nombre de la clase que quieres usar. Asi mismo las clases que quieras usar deben estar en el mismo paquete por lo que antes incluso de declarar la clase en un archivo deberas declarar el paquete donde se agrupan esas clases

package NombrePaquete; Si no estan las dos clases en el mismo paquete es imposible poder cojer informacion de otra clase. Y por ultimo una vez tengas las 2 clases en el mismo paquete y creado el objeto simplemente deberas

escribir lo siguiente: NombreObjeto.NombreVariable; Con eso accederias a la variable del objeto aunque no es la forma estandar, la forma estandar seria

usando getters para acceder a las variables(atributos) del objeto y los setters para modificar los valores de los atributos.

100

Page 101: Documentación Java

Otra opción sería declarar las variables como atributos estáticos de la clase. así, solo hay una en tiempo de ejecución y todas las llamadas a la variable son al mismo lugar, algo asi como:

public class Variable {public static int variableEntera = 0;}

Así ya la puedes acceder como Variable.variableEntera.

otra opción, que a fin de cuentas es la misma gata pero revolcada, es crear atributos estáticos privados en la clase e implementar accesores.

public class Variable {private static String variableString = "";

public String getVariableString(){return variableString;}

public void setVariableString(String valor){variableString = valor;}}

Ahora, la pregunta de los 64 millones, porque las variables son estáticas? Con lo estático creas "atributos" o "variables" de clase, los cuales no requieres instanciar un objeto de la clase para poderlas usar. Si no fueran estáticas, cada vez que hagas un new Variable(); te crearía un objeto nuevo con los atributos vacíos y moriría cada vez que el código o función o bloque sobre el que está corriendo termine.

______________

Modificadores de clases y métodos: STATIC, FINAL, ABSTRACT.

STATIC:Sirve para crear miembros que pertenecen a la clase, y no a una instancia de la clase. Esto implica, entre otras cosas, que no es necesario crear un objeto de la clase para poder acceder a estos atributos y métodos.

En ocasiones es necesario o conveniente generar elementos que tomen un mismo valor para cualquier número de instancias generadas o bien invocar/llamar métodos sin la necesidad de generar instancias, y es bajo estas dos circunstancias que es empleado el calificador static.

Dos aspectos característicos de utilizar el calificador static en un elemento Java son los siguientes:

- No puede ser generada ninguna instancia (uso de new) de un elemento static puesto que solo existe una instancia.

101

Page 102: Documentación Java

- Todos los elementos definidos dentro de una estructura static deben ser static ellos mismos, o bien, poseer una instancia ya definida para poder ser invocados.

NOTA: Lo anterior no implica que no puedan ser generadas instancias dentro de un elemento static; no es lo mismo llamar/invocar que crear/generar.

FINAL:Indica que una variable, método o clase no se va a modificar, lo cuál puede ser útil para añadir más semántica, por cuestiones de rendimiento, y para detectar errores.

- Si una variable se marca como final, no se podrá asignar un nuevo valor a la variable.- Si una clase se marca como final, no se podrá extender la clase.- Si es un método el que se declara como final, no se podrá sobreescribir.

Algo muy a tener en cuenta a la hora de utilizar este modificador es que si es un objeto lo que hemos marcado como final, esto no nos impedirá modificar el objeto en sí, sino tan sólo usar el operador de asignación para cambiar la referencia. Por lo tanto:+ expand source

NOTA: Una variable con modificadores static y final sería lo más cercano en Java a las constantes de otros lenguajes de programación.

ABSTRACT:La palabra clave abstract indica que no se provee una implementación para un cierto método, sino que la implementación vendrá dada por las clases que extiendan la clase actual. Una clase que tenga uno o más métodos abstract debe declararse como abstract a su vez.

http://www.disi.unal.edu.co/~gjhernandezp/Java/MaterialDeClase/Teoria/pdf/03-Modifiers_cont.pdf

_________________

Tu nuevo código hotmail es GWPPM-ZCD4Y-WXCLL-X8KJF-TNYF4

23.- Crear proyecto, package y ficheros para una aplicación NetBeansAl crear un proyecto NetBeans, por defecto, crea un package y dentro un fichero .java en modo texto.

Pero podemos añadir mas packages y dentro de los packages podemos añadir mas ficheros en modo texto o grafico o borrar los que no interesen.

En toda la aplicación solo será necesario que haya una clase con el método main que es impresicindible para poder ejecutarla. En realidad puede haber mas métodos main en otros ficheros de la aplicación. Asi podremos probarlo y ejecutarlo de manera independiente sin lanzar toda la aplicacion, pero para ejcutar la aplicacion solo se podra hacer desde el fichero con metodo main que hemos definido.

a) Crear proyectoEsta es la ventana que se muestra de NetBeans una vez instalado.Marco con una flecha donde aparecerá la aplicación que voy a crear.1.1.- Crear una aplicaciónPara ello despliego el menu File y elijo "New Proyect"

102

Page 103: Documentación Java

Esta es la ventana que se muestra, como la opción es realizar una aplicación selecciono las opciones que he marcado en la captura:Tras pulsar Next se muestra esta ventana:En ella he puesto el nombre que quiero a la aplicación, he seleccionado el directorio donde quiero guardarlo (también se puede dejar por defecto) y he marcado para que cree automáticamente una clase con el método main.

Pulso Finish y esto es lo que se muestra:Vemos:

La nueva aplicación en la ventana Projetscon su package (multiplicacion2012) y su fichero Multiplicacion2013 En la ventana de trabajo (Source) vemos el código creado por defecto en modo texto: una clase y dentro de ella su método main que indica que esta clase es ejecutable. Esta clase funciona en modo texto, asi que si queremos trabajar en modo gráfico tenemos que instanciar en ella una llamada a una clase en modo gráfico, tambien podemos borrarla y crear una clase con un frame (modo gráfico) que incorpora también un metodo main. Vemos también la ventana de salida de datos (Output). Ahora tendremos que añadir código para que realice la tarea que nos interese.

En la ventana de trabajo aparecen palabras como:

package (paquete): Permite identificar clases que pertenecen a la misma aplicación. En esta ocasión se ha creado al crear el la aplicación, pero también pueden añadirse nuevos packages. public class: En este caso es una clase, esta seria la clase principal. Pueden haber otras clases (en flecha verde donde empieza y donde termina) public static void main: Está dentro de la clase principal, es el método main necesario para ejercutar las aplicación (en flecha azul donde empieza y donde termina)

Si ejecutamos (botón derecho sobre el listado) nos dará el mensaje que vemos en la ventana de salida/Output: "BUILD SUCCESSFUL (total time: 0 seconds)".

b) Crear un fichero en NetBeansEl primer fichero se ha creado al generar la aplicación porque asi hemos indicado, contiene la clase principal y dentro de ella el método main si hemos marcado la opción al crear la aplicación.Si necesitamos más ficheros primero tenemos que crearlo y luego rellenarlo a mano con el código que necesitemos (o con copiar y pegar):Para crearlo: botón derecho sobre package multiplicacion2012MET2-->New--> Se despliega la ventana de la siguiente captura:

Con Java Main Class podemos crear una clase con el método main. En realidad puede haber varios ficheros con su clase y metodo main. La ventaja es que pueden ejecutarse de manera independiente, aunque tambien de manera integrada con las correspondientes llamadas desde el fichero que hará de lanzador de la aplicación (en este caso los metodos main en otros ficheros no interfieren). Esto es interesante mientras estamos programando. Con Java Class crearemos un fichero con una clase y sin método main, ideal para incluir en él los métodos, las variables y operaciones con ellas que luego podremos instanciar (ver 04.3.- Variables, clases, métodos)

103

Page 104: Documentación Java

y clases secundarias si es necesario). También podemos crar otro package, jFrame, jPanel... Si pulsamos Other... salen más opciones, aunque no tienen un frecuente uso.

Nota:

Para crear un fichero en modo gráfico seleccionaremos la opción "JFrame Form" Si hay ficheros en modo texto que no interesen pueden borrarse: fichero-->boton derecho-->eliminar

Se despliega esta ventana, escribimos el nombre y pulsamos Finish:

Se crea el fichero y dentro de él una clase. Ya solo queda copiar a mano o cortar y pegar el código que queramos ejecutar.Es importante que el nombre de la clase que copiamos y pegamos coincida con el del fichero, si no, podemos cambiarlo a manoEn este caso hemos creado una clase sin método Main, con lo que no podremos ejecutarla directamente. Pero si de manera indirecta a traves de una instancia (ver 04.3.- Variables, clases, métodos) en la clase principal (main).c) Crear un packagePor defecto ya se crea uno que contiene el/los ficheros de la aplicación. Pero podemos crear mas.

104

Page 105: Documentación Java

Botón derecho sobre el proyecto, en este caso MetodosMultiplicacion2012, o tambien sobre "Source Package". Seguimos la secuencia de la captura o, si no se muestra lo que queremos crear pulsamos en Other... y lo seleccionamos desde las opcions que nos muestra.En este caso pulsamos Java Package:

En este ejemplo hemos creado una aplicación que funciona en modo texto. El procedimiento es muy parecido para crear aplicaciones en modo grafico ver apartado b) Crear un fichero en NetBeans (nota)

105

Page 106: Documentación Java

http://es.slideshare.net/JhomaraLuzuriaga/programacion-en-java-2

Programacion en JAVA 2

1. 1. PROGRAMACIÓN GRÁFICA CON COMPONENTES SWING

Swing es una biblioteca gráfica para Java. Incluye widgets para interfaz gráfica de usuario. Una interfaz es lo que le permite a un usuario comunicarse con unprograma a través de componentes visuales como cajas de texto, botones,desplegables, tablas, etc.

1.1. COMPONENTE Un componente no es más que un objeto que representa un elemento de unainterfaz gráfica y que en su mayoría tienen una representación gráfica. Se puededividir en dos tipos:1. Simples o atómicos: Son los que no están formados por otros componentes: Ejemplo: Etiquetas, botones, cajas de texto.2. Contenedores: Son componentes que pueden contener a otros. Contenedores de Alto Nivel: Son aquellos que brindan un espacio dentro de la pantalla para todos los elementos de una interfaz gráfica. Ejemplo: Frames, Applet. Contenedores intermedios: Permiten agrupar y organizar los componentes de una interfaz gráfica dentro de un contenedor de alto nivel. Ejemplo: PanelesEl patrón de desarrollo que utiliza SWING es MVC (Modelo Vista Controlador), quepermite dividir una aplicación en 3 partes: o Modelo: Datos o Vista: Interfaz gráfica o Controlador: Permite manejar las interacciones del usuario con la interfaz gráfica y a su vez manejar los cambios entre la vista y el modelo.

1.2. JERARQUÍA DE COMPONENTESTodos los componentes para el diseño de una interfaz gráfica obedecen a unajerarquía de clases.La clase principal es java.awt.Component de la cual se heredan componentescomo java.awt.Button, java.awt.Label, etc..., y también se hereda la clasejava.awt.Container que representa a un objeto contenedor. Los componentessimples derivan de la clase JComponent, mientras los contenedores de la claseWindow.

2. Container Window JComponent PanelFrame Dialog AbstractButton JTextComponent ….. AppletJFrame JDialog JButton ….. JTextField JTextArea …..

1.3. CONTENEDORES

1.3.1. Clase JFrameJAVA Frame es el componente, control u objeto principal de una aplicacion visual o gráfica en java. Para crear un Frame deberemos crear una instancia de JFrame, y si deseamos modificar algunas propiedades de la ventana debemos crear una clase queextienda de JFrame.

Ejemplo:import javax.swing.*;class Frame extends JFrame { //el constuctor public Frame(){ //Este es uno de los métodos que nuestra clase Frame ha //heredado de JFrame. Pone un título a la ventana setTitle("Hola!!!"); //método heredado que le da un tamaño a la ventana setSize(300,200); setVisible(true); }}Las ventanas JFrame son invisibles por defecto, se debe modificar la propiedad pordefecto de JFrame de manera que nuestra ventana sea visible, para esto sesobreescribe el método con el parámetro true.setVisible(true)

106

Page 107: Documentación Java

Algunos métodos de JFrame son: setResizable(boolean): Permite hacer modificable el tamaño de la ventanasetState(int): Modificar el tamaño de la ventana, recibe como parámetro un valor entero que corresponde a una constante de JFrame, que puede ser:JFrame.NORMAL, JFrame.ICONFIED.setExtendedState(int): Permite ampliar los estados de una ventana.setLocationRelativeTo(Component): Ubicar un componente en base a un segundo componente enviado como parámetro. Para ubicar la ventana en el centro de la pantalla el parámetro deberá ser null. EJERCICIO: Crear un proyecto DiseñoVentanas y en una clase ejecutable crear 5 ventanas,cada una visualizada en un estado diferente (minimizado, maximizado,max_horizontal, max_vertical, y normal centrado), estableciendo un título en cadauna con el estado de la ventana.

1.3.2. Clase JDialog: JDialog es un Componente que sirve para presentar diálogos que son ventanas auxiliares que se presentan cuando se registra un evento dentro de un programa,sirven para prevención o en su defecto se puede utilizar para dar información sobre algo, los diálogos que JDialog muestra pueden ser modales o no modales, estoquiere decir que si son modales la ventana del diálogo bloquea las entradas a otras ventanas, este tipo de diálogos se pueden hacer también con JOptionPane.Todos los diálogos dependen de un frame, las modificaciones que se le hagan alframe afectaran a el diálogo, en caso de que el frame sea cerrado, minizado omaximizado, sus diálogos tendrán el mismo comportamientoUn JDialog siempre deberá tener un componente Parent del cual se derive, que debe ser un contenedor de alto nivel y su efecto modal o no, de manera quecuando se crea una instancia de esta clase se deberá establecer estos parámetros.Ejemplo:Frame ventana= new Frame();JDialog cuadroDialogo= new JDialog(ventana, true);

En este caso hemos creado un JDialog cuyo parent es un JFrame ventana. LosJDialog obedecen un evento, es decir se mostrarán cuando sobre el parent serealice algún evento que invoque la aparición del JDialog.

1.3.3. Clase JPanel: JPanel es un objeto de los llamados "contenedores". Es así porque sirven para contener otros objetos.Una de las ventajas de añadir paneles sobre nuestro frame es que los paneles al derivar de JComponent poseen el método paintComponent que permite dibujar y escribir texto sobre el panel de modo sencillo.Para añadir un JPanel a nuestro frame primero obtenemos uno de los objetos que forman el frame: el “panel contenedor” (content pane). Para ello invocaremos al método getContentPane de nuestro JFrame.

El objeto que nos devuelve será detipo Container:Container [nombre_del_contentpane] = frame.getContentPane();A continuación invocamos al método add del Container obtenido para añadir el panel, pasándole el propio panel al método:[nombre_del_contentpane].add(nombre_del_panel);

Ejemplo:import javax.swing.*;import java.awt.event.*;import java.awt.*;

class Frame extends JFrame {

public Frame(){ setTitle("Hola!!!"); setSize(300,200); //Le pido al Frame su objeto contenedor Container contentpane = getContentPane();

107

Page 108: Documentación Java

//Creo un objeto de tipo JPanel JPanel panel = new JPanel(); //Añado el panel en el objeto contenedor del frame contentpane.add(panel); //Pongo el color de fondo del panel de color rojo panel.setBackground(Color.RED); }}

Para agregar componentes a un panel se utiliza el método add: panel.add(new JButton(“Click aquí”));Si no señalamos la ubicación de los componentes en el panel, éstos se ubicanconforme se vayan añadiendo de manera horizontal, uno después de otro en todoel ancho de la ventana.Para visualizar el Frame que hemos creado se añade a la clase el método maindentro del cual se creará un objeto de nuestra clase Frame. La clase JFrameimplementa la interfaz Runneable, la cual permite ejecutar y visualizar el Framehasta que el usuario lo cancele.public static void main(String[] args) { new Frame();}

1.4. ALGUNOS COMPONENTES SIMPLES

Todos los contenedores así como los componentes tienen propiedades que se pueden modificar mediante los métodos de la clase que corresponden, así como sus respectivos constructores. Clase JLabelEs una etiqueta de texto que podemos colocar al lado de cualquier componente para darle una indicación al usuario de cuál es la función de dicho componente. También se puede emplear a modo de título.JLabel label = new JLabel("1 x 7 = 7");Clases JTextArea, JTextPane y JTextField Son componentes básicos del Swing de Java y su función principal es la de capturar texto ingresado desde teclado por el usuario. Clase JTextField Está pensado para obtener texto del usuario, este tecleará en él y cuando pulse intro podremos disponer del texto que tecleó. Únicamente se puede recoger unalínea de texto.

EJEMPLO:public class Frame1 extends JFrame {public Frame1() { setTitle("DATOS"); setSize(300, 200); JLabel lbl1 = new JLabel("Nombre"); JTextField txt1 = new JTextField(18); JLabel lbl2 = new JLabel("Edad"); JTextField txt2 = new JTextField(10); Container contentpane = getContentPane(); JPanel panel = new JPanel(); panel.setBackground(Color.CYAN); panel.add(lbl1); panel.add(txt1); panel.add(lbl2); panel.add(txt2); contentpane.add(panel); setVisible(true);}}

EJECUCIÓN Clase JPasswordField Al igual que los anteriores permite al Usuario ingresar un texto que es reemplazado por un carácter que oculta lo que se escribe, por ejemplo: *. Se emplea para pedirle passwords al usuario y evitar que puedan ser leídas por alguien.

108

Page 109: Documentación Java

Clase JButtonEsta clase nos permite crear botones, cuya acción al pulsar será programado conel manejo de eventos. Para crear un botón podemos utilizar los siguientes constructores: JButton() Crea un botón sin etiqueta JButton(String label) Crea un botón con una etiqueta de texto JButton t=new JButton(“Derecha”);

EJEMPLO:public Frame2() { setTitle("DATOS"); setSize(300, 200); JLabel lbl1 = new JLabel("Nombre"); JTextField txt1 = new JTextField(18); JLabel lbl2 = new JLabel("Edad"); JTextField txt2 = new JTextField(10); Container contentpane = getContentPane(); JPanel panel = new JPanel(); panel.add(lbl1); panel.add(txt1); panel.add(lbl2); panel.add(txt2); panel.add(new JButton("Click aquí")); contentpane.add(panel); setVisible(true);}EJERCICIO:Escriba 4 métodos para cambiar el estado de un botón, una etiqueta y un cuadro de texto

Clase JComboBox Permite seleccionar un objeto (opción) de una lista que se visualiza al dar click en la pestaña de este componente. Los constructores de la clase son:JComboBox(ComboBoxModel amodel); Requiere un objeto Modelo para el ComboBoxJComboBox(Object [] items);Crea un combo, cuyos items corresponderán al arreglo de objetos.JComboBox(Vector? items);Crea un combo, cuyos items corresponderán a los elementos del Vector.

EJEMPLO:

public class Selector extends JFrame { public Selector() { setTitle("Selector!!!"); setSize(300, 200); String[] opciones = {"Arriba", "Abajo", "Derecha", "Izquierda", "Todas las direcciones"}; JComboBox cmbLista = new JComboBox(opciones); Container contentpane = getContentPane(); JPanel panel = new JPanel(); panel.add(cmbLista); contentpane.add(panel); setLocationRelativeTo(null); setVisible(true); }}

Clase JCheckbox Se trata de un componente empleado para tomar información del usuario sobre cosas del tipo “sí”, “no”.Dos de los constructores de un JCheckBox son: JCheckBox(String) Crea un JCheckBox con etiqueta o JCheckBox(String,boolean) Crea un JCheckBox con etiqueta y aparece seleccionado

109

Page 110: Documentación Java

Clase JRadioButtonDos de los constructores de un JRadioButton son: o JRadioButton (String) Crea un JRadioButton con etiqueta o JRadioButton(String,boolean) Crea un JRadioButton con etiqueta y aparece seleccionado. Para utilizar este componente debe ser añadido a un grupo de manera que permita seleccionar una sola opción entre las del grupo. Para ello se utiliza el componente ButtonGroup.

Ejemplo: ButtonGroup bg= new ButtonGroup(); JRadioButton rb1=new JRadioButton("Radio1"); JRadioButton rb2=new JRadioButton("Radio2"); bg.add(rb1); bg.add(rb2); ... panel.add(rb1); panel.add(rb2); ... ...Ejercicio:Crea una clase EjercicioSwing que extienda de JFrame y que contenga loscomponentes de la siguiente figura. El tamaño del Frame será de (260 x 250). 10. 2. LAYOUT MANAGERS

2.1. Concepto El layout manager es el encargado de decidir en qué posiciones se renderizarán los componentes, que tamaño tendrán, que porción del contenedor abarcarán, etc. Un contenedor es un componente Java que puede contener otros componentes. Si queremos cambiar el layout manager de un contenedor en un momento dado, tan sólo tendremos que llamar al método:contenedor.setLayout(LayoutManager layout); Si en cualquier momento decidimos encargarnos nosotros mismos de la gestión decomponentes tan sólo tendremos que escribir:contenedor.setLayout(null); Cada componente de nuestro interfaz gráfico tiene asignada una coordenadahorizontal, una coordenada vertical, una longitud y una anchura determinadas. Estos valores serán los que se utilizarán para renderizar el componente enpantalla.La clase java.awt.Component nos ofrece una serie de métodos para poder modificar los valores de los atributos anteriores: public void setSize(Dimension size); public void setBounds(Rectangle r);

2.2. Layout null Muchos deciden no utilizar layouts para ubicar los componentes de la ventana, en este caso el Layout se establece a Null y en el código se decide la posición de cada botón y qué tamaño ocupa.contenedor.setLayout(null); // Eliminamos el layoutcontenedor.add (boton); // Añadimos el botón boton.setBounds (10,10,40,20); // Botón en posicion 10,10 con ancho 40 pixels y alto 20 Esto, no es recomendable. Si se expande la ventana los componentes seguirán en su sitio, no se expandirán con la ventana.

Si cambiamos de sistema operativo, resolución de pantalla o fuente de letra, los componentes no se visualizaránestéticamente bien.

2.3. FlowLayout Es el que tienen los paneles por defecto. Los objetos se van colocando en filas enel mismo orden en que se añadieron al contenedor. Cuando se llena una fila se pasa a la siguiente. Tiene tres posibles constructores: FlowLayout(); Crea el layout sin añadirle los componentes.FlowLayout(FlowLayout.LEFT[RIGTH][CENTER]); Indica la alineación de los componentes: a la izquierda, derecha o centro.

110

Page 111: Documentación Java

FlowLayout(FlowLayout.LEFT, gap_horizontal,gap_vertical); Además de la alineación de los componentes indica un espaciado (gap) entre losdistintos componentes, de tal modo que no aparecen unos junto a otros.FlowLayout respeta siempre el tamaño preferido de cada componente. Los componentes de cada fila se encuentran equiespaciados por un espacio de 5puntos horizontal y verticalmente. Primero se establece el layout a utilizar, luego se añaden los componentes al panel.contenedor.setLayout(new FlowLayout());contenedor.add(boton);contenedor.add(textField);contenedor.add(checkBox);

Ejemplo: import javax.swing.*; import java.awt.*; class TestFlowLayout extends JFrame{ public static void main(String[] args) { TestFlowLayout frame = new TestFlowLayout (); JPanel panel = new JPanel(); JButton boton1 = new JButton("botón 1"); JButton boton2 = new JButton("Este es el botón 2"); JButton boton3 = new JButton("botón 3"); panel.add(boton1); panel.add(boton2); panel.add(boton3); frame.setContentPane(panel); frame.setSize(350, 150); frame.setTitle("Prueba de FlowLayout"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }

2.4. BorderLayout Este layout distribuye los componentes en cinco zonas predeterminadas: son norte(NORTH), sur (SOUTH), este (EAST), oeste (WEST) y centro (CENTER). Si no especificamos ninguna región por defecto el componente se inserta en el centro delcontenedor.

Posee dos contructores:BorderLayout();BorderLayout(int gap_horizontal, int gap_vertical);El segundo creará el layout dejando los espacios horizontales y verticales entre susdistintas zonas. Al momento de añadir componentes se debe especificar en el método add la región donde queremos añadir el componente:panel.add(componente_a_añadir, BorderLayout.NORTH);

Ejemplo: class TestBorderLayout extends JFrame{ public static void main(String[] args) { TestBorderLayout frame = new TestBorderLayout (); Container panel = frame.getContentPane(); JButton norte = new JButton("Norte"); JButton sur = new JButton("Sur"); JButton este = new JButton("Este"); JButton oeste = new JButton("Oeste"); JButton centro = new JButton("Centro"); panel.add(norte, BorderLayout.NORTH);

111

Page 112: Documentación Java

panel.add(sur, BorderLayout.SOUTH); panel.add(este, BorderLayout.EAST); panel.add(oeste, BorderLayout.WEST); panel.add(centro, BorderLayout.CENTER); frame.setSize(350, 250); frame.setTitle("Prueba de BorderLayoutLayout"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);} }}

2.5. GridLayout Distribuye los componentes de un contenedor en celdas y se ordenarán en el orden como sean añadidas, de izquierda a derecha y de arriba hacia abajo.El GridLayout es adecuado para hacer tableros, calculadoras en que todos losbotones son iguales, etc.

14. Todas las cuadrículas serán del mismo tamaño y crecerán o se harán más pequeñas hasta ocupar toda el área del contenedor. Hay dos posiblesconstructores:GridLayout(int filas, int columnas);GridLayout(int columnas, int filas, int gap_horizontal, intgat_vertical);Especifica espaciados verticales y horizontales entre las cuadrículas.

Ejemplo: import javax.swing.*; import java.awt.*;

class TestGridLayout extends JFrame{ public static void main(String[] args) { TestGridLayout frame = new TestGridLayout(); Container container = frame.getContentPane(); int X = 3; int Y = 3; container.setLayout(new GridLayout(X, Y)); for (int i = 0; i < X; i++) { for (int j = 0; j < Y; j++) { container.add(new JButton(i + "x" + j)); } } frame.setSize(350, 250); frame.setTitle("Prueba de BorderLayoutLayout"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }

2.6. GridBagLayout El GridBagLayout es de los layouts más versátiles y complejos de usar. Es como el GridLayout, pone los componentes en forma de matriz (cuadrícula), pero permite que las celdas y los componentes en ellas tengan tamaños variados. Las celdas se crean a medida que se agregan los componentes. Es posible hacer que un componente ocupe varias celdas Un componente puede expandirse o no con su celda Si no se expande, puede quedar en el centro de la celda o pegarse a sus bordes o esquinas. Las columnas al igual que las filas pueden ensancharse o no al estirar la ventana y la proporción podemos decidirla GridBagConstraints es una clase en cuyos atributos se guarda información de cómo y dónde añadir el componente. GridBagConstraints.gridx nos dice la posición x del componente, es decir, el número de columna en la que está el componente, siendo la columna 0 la primera columna de la izquierda. GridBagConstraints.gridy nos dice la posición y del componente, es decir, el número de fila en la que está el componente, siendo la fila 0 la primera fila de la parte de arriba. c.gridx=1, c.gridy=0c.gridx=0, c.gridy=0c.gridx=0, c.gridy=1 c.gridx=1, c.gridy=1 c.gridx=2, c.gridy=0

112

Page 113: Documentación Java

GridBagConstraints.gridwidth nos dice cuántas celdas en horizontal debe ocupar el componente. El ancho del componente. GridBagConstraints.gridheight nos dice cuantas celdas en vertical debe ocupar el componente. El alto del componente. Su valor puede ser: Un número cardinal, en este caso indica exactamente el número de filas o columnas que ocupará el componente. GridBagConstraints.RELATIVE, indica que el componente ocupará el espacio disponible desde la fila o columna actual hasta la última fila o columna disponibles. GridBagConstraints.REMAINDER, indica que el componente es el último de la fila actual o columna actual. c.gridwidth=GridBagCostraints.RELATIVE c.gridwidth=GridBagCostraints.REMAINDER c.gridheigth=1 c.gridheigth=1 c.gridwidth=1 c.gridheigth=1c.gridwidth=GridBagCostraints.RELATIVEc.gridheigth=GridBagConstraints.RELATIVE c.gridwidth=GridBagCostraints.REMAINDER c.gridheigth=GridBagConstraints.REMAINDER c.gridwidth=GridBagCostraints.REMAINDER c.gridheigth=GridBagConstraints.RELATIVE Algunas constantes de esta clase son: Anchor establece la alineación del componente, se utiliza cuando el éste es más pequeño que el área utilizada: NORTH, SOUTH, EAST, WEAST, NORTHWEST, SOUTHWEST, NORTHEAST, SOUTHEAST y CENTER.

Fill establece el relleno de la celda: HORIZONTAL, VERTICAL, BOTH, NONEEn este caso las celdas ocupan todo el contenedor, pero eso es debido a que se hautilizado los atributos weightx y weighty.weightx y weightyLos atributos weightx y weighty especifican el porcentaje de espacio libre queocupará una celda determinada.En el ejemplo anterior si no utilizamos estos atributos tendríamos:

Este espacio libre (flechas verdes) se dividirá entre todas las celdas queespecifiquen valores dentro de los atributos weightx y weighty. La forma deespecificar el espacio que quiere ocupar cada componente es mediante un númeroentre 0.0 y 1.0. Este número representa al porcentaje de espacio libre que ocuparácada celda.InsetsEl atributo insets es un objeto de la clase java.awt.Insets cuyo constructor es:Insets(int top, int left, int bottom, int right)

Los parámetros del constructor especifican el espacio que se dejará de márgen.Veamos un ejemplo: Ejemplo:Frame que distribuye los siguientes componentes:

public class TestGridBagLayout extends JFrame{

public static void main(String[] args) { TestGridBagLayout f=new TestGridBagLayout(); Container container = f.getContentPane(); container.setLayout(new GridBagLayout()); ((JPanel) container).setBorder( BorderFactory.createTitledBorder("Entrada al sistema")); GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.4; c.weighty = 1.0; c.gridwidth = GridBagConstraints.RELATIVE; c.gridheight = GridBagConstraints.RELATIVE; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; c.insets = new Insets(2, 5, 2, 0); container.add(new JLabel("Usuario"), c);//Se debe definir los parámetros para cada uno de los componentes.

113

Page 114: Documentación Java

c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = GridBagConstraints.RELATIVE; c.weightx = 1.0; c.insets = new Insets(2, 0, 2, 5); container.add(new JTextField(), c); c.gridwidth = GridBagConstraints.RELATIVE; c.gridheight = GridBagConstraints.REMAINDER; c.weightx = 0.4; c.insets = new Insets(2, 5, 2, 0); container.add(new JLabel("Contraseña"), c); c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = GridBagConstraints.REMAINDER; c.weightx = 1.0; c.insets = new Insets(2, 0, 2, 5); container.add(new JTextField(), c); f.setSize(220, 110); f.setTitle("Login"); f.setVisible(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }}Resultado: 2.7. BoxLayout Este layout manager es uno de los más sencillos y de los más útiles. Aquí los componentes son agrupados horizontal o verticalmente dentro del contenedor que los contiene. Los componentes no se solapan de ningún modo. La anidación de paneles utilizando este layout manager nos puede permitir crear interfaces muycomplejos como nos permite GridBagLayout pero a costa de la creación de objetos pesados como son paneles.El constructor de BoxLayout es muy simple:public BoxLayout(Container objetivo, int eje);Donde el parámetro entero eje puede tomar los valores: X_AXIS, los componentes se organizan de izquierda a derecha y en horizontal. Y_AXIS, los componentes se organizan de arriba a abajo y en vertical. LINE_AXIS, los componentes se organizan como si estuviesen en una línea. Para ello se tiene en cuenta la propiedad ComponentOrientation del contenedor.

Si esta propiedad es horizontal entonces los componentes se organizarán horizontalmente y además según su valor lo harán de izquierda a derecha o de derecha a izquierda. En otro caso se organizarán verticalmente de arriba a abajo. PAGE_AXIS, los componentes se organizan como si estuvieran en una página. Para ello se tiene en cuenta la propiedad ComponentOrientation del contenedor. Los componentes se organizan en el orden en el que se añaden al contenedor.En el caso de organización horizontal, BoxLayout intentará que todos los componentes del contenedor tengan la misma altura, siendo esta la máxima de loselementos del contenedor. En caso de que no sea posible, BoxLayout intentaráalinearlos a todos horizontalmente de modo que sus centros coincidan en una línea horizontal imaginaria que los atraviese, de manera similar, si la organización es vertical.

A menudo, en lugar de utilizar BoxLayout directamente, se utiliza la clase Box quees un contenedor ligero que tiene como layout manager un BoxLayout y que ofrecemétodos que hacen que su manejo sea muy sencillo.

EJEMPLO:import java.awt.*;import javax.swing.*;

public class TestBoxLayout extends JFrame {

public static void main(String[] args) { TestBoxLayout f = new TestBoxLayout(); Container container = f.getContentPane(); container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS)); ((JPanel) container).setBorder( BorderFactory.createTitledBorder("Demo BoxLayout")); JPanel panel1 = new JPanel(); panel1.setBorder(BorderFactory.createTitledBorder("Panel1"));

114

Page 115: Documentación Java

JPanel panel2 = new JPanel(); panel2.setBorder(BorderFactory.createTitledBorder("Panel2")); panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS)); for (int i = 0; i < 3; i++) { panel1.add(new JButton("Botón número " + i)); panel2.add(new JButton("Botón número " + i)); } container.add(panel1); container.add(panel2); f.setSize(285, 300); f.setTitle("Demo BoxLayout"); f.setVisible(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }}

2.8. SpringLayout Este layout manager está únicamente disponible a partir de la versión 1.4 del JDK.SpringLayout define los componentes que estarán dentro del interfaz y la relación entre estos componentes, es decir, el espacio que habrá entre ellos. SpringLayout intentará respetar siempre que pueda el tamaño preferido de los componentes. El espacio entre los componentes se define utilizando objetos Spring. Cada objetoSpring tiene cuatro propiedades, sus tamaños máximo, mínimo y preferido junto con su tamaño actual. (x, y, width, height)Todos estos objetos Spring se acumulan formando un conjunto de restricciones que estarán en un objeto de tipo SpringLayout.Constraints.Para crear un objeto Spring:Spring.constant(min, pref, max);Spring.constant(int valor); El método para ubicar un componente aplicando constraint tespecto de otro:putConstraint(borde, componente, constraint, borde, componenteRelativo);

Ejemplo:

public class TestSpringLayout extends JFrame {

public static void main(String[] args) { TestSpringLayout f=new TestSpringLayout(); SpringLayout sl=new SpringLayout(); Container container = f.getContentPane(); container.setLayout(sl); ((JPanel)container).setBorder(BorderFactory.createTitledBorder( "Entrada al sistema")); JLabel lblUsuario =new JLabel("Usuario"); JLabel lblContraseña=new JLabel("Contraseña"); JTextField txtUsuario=new JTextField(10); JTextField txtContraseña=new JTextField(10); container.add(lblUsuario); container.add(txtUsuario); container.add(lblContraseña); container.add(txtContraseña); sl.putConstraint(SpringLayout.WEST, lblUsuario, Spring.constant(30),SpringLayout.WEST,container); sl.putConstraint(SpringLayout.NORTH, lblUsuario, Spring.constant(20),SpringLayout.NORTH,container); sl.putConstraint(SpringLayout.WEST,txtUsuario, Spring.constant(35),SpringLayout.EAST,lblUsuario); sl.putConstraint(SpringLayout.NORTH, txtUsuario, Spring.constant(20),SpringLayout.NORTH,container); sl.putConstraint(SpringLayout.WEST, lblContraseña, Spring.constant(30),SpringLayout.WEST,container); sl.putConstraint(SpringLayout.NORTH, lblContraseña, Spring.constant(25),SpringLayout.NORTH,lblUsuario); sl.putConstraint(SpringLayout.WEST,txtContraseña, Spring.constant(15),SpringLayout.EAST,lblContraseña);

115

Page 116: Documentación Java

sl.putConstraint(SpringLayout.NORTH, txtContraseña, Spring.constant(25),SpringLayout.NORTH,txtUsuario); f.setSize(250, 150); f.setTitle("Login"); f.setVisible(true); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }}

EJERCICIO:Diseñe la siguiente pantalla utilizando el Layout más indicado para la ubicación delos componentes en el Frame

25. 3. ALGUNOS COMPONENTES COMPLEJOS

3.1. Componentes contenedores de otros. Clase JMenuBarEs una barra de menús, en ella se pueden añadir los siguientes componentes:Clase JMenu: Es una opción de la cual se pueden desplegar mas opciones.Clase JMenuItem: Es una opción final (no desplega mas opciones) JMenu JMenuBar JMenuItem

EJEMPLO:public class VentanaMenu extends JFrame{

public JMenuBar barraMenu=new JMenuBar(); public VentanaMenu(){ super("Test Menu"); setSize(300,200); agregarComponentes(); } public void agregarComponentes(){ JMenu mnArchivo=new JMenu("Archivo"); mnArchivo.add(new JMenuItem("Nuevo")); mnArchivo.add(new JMenuItem("Guardar",new ImageIcon(getClass().getResource("zip.gif")))); mnArchivo.add(new JMenuItem("Abrir")); mnArchivo.add(new JMenuItem("Cerrar")); barraMenu.add(mnArchivo); JMenu mnEditar=new JMenu("Editar"); JMenu mnAyuda=new JMenu("Ayuda"); barraMenu.add(mnEditar); barraMenu.add(mnAyuda); BorderLayout bl=new BorderLayout(); this.getContentPane().setLayout(bl); this.getContentPane().add(barraMenu,BorderLayout.NORTH); } public static void main(String[] args) { new VentanaMenu().setVisible(true); } }

RESULTADO:Ejercicio: Modifique la clase anterior para: Agregar al Menu Archivo el menu Guardar Como y a éste los ítems: Imagen, Texto, Articulo Completo. Agregar en el Menu Editar los ítems: Deshacer, Rehacer, Seleccionar Todo, Buscar. Agregar una imagen en los Menus de la barra principal. Clase JScrollPaneEs un panel que permite visualizar un componente de un tamaño mayor que el disponible, mediante el uso de barras de desplazamiento. Como su nombre lo indica, funciona como un contenedor, de manera que podemos agregar un componente que requiera mayor espacio en el Frame.JLabel imagen=new JLabel(new ImageIcon(getClass().getResource("/imagenes/imagen1.jpg")));JScrollPane panel=new JScrollPane(imagen);

116

Page 117: Documentación Java

Clase JSplitPane Permite visualizar dos componentes, uno a cada lado, con la posibilidad demodificar la cantidad de espacio otorgado a cada uno. Se puede agregar un contenedor como un JPanel en cada lado del Split y este a su vez contener más componentes. Además se puede modificar una propiedad que indica la disposición de los componentes: horizontal o vertical.//espacio del primer componente con respecto del segundo split.setDividerLocation(150); //separación entre componentes del Splitsplit.setDividerSize(20);//cambiando el componente de la izquierda y derecha split.setLeftComponent(componenteIzquierda);split.setRightComponent(componenteDerecha);EJERCICIO:SPLITPANE Y SCROLLPANE Ubicar el primer componente con mayor ventaja que el segundo, con respecto altamaño del contenedor principal y una división de 20pix.

Clase JTabbedPane Permite definir varias hojas con pestañas, que pueden contener otros componentes. El componente básico de cada hoja debe ser un Panel que es el que agrupe el resto de componentes. Para agregar más hojas basta con añadir un panel al TabbedPane. Ejemplo: JTabbedPane tabbed=new JTabbedPane();tabbed.add("Tabbed 1", new JPanel()); tabbed.add("Tabbed 2",new JPanel());

3.2. COMPONENTES CON MODELO DE DATOS. Los componentes que permiten mostrar un listado o un conjunto de objetos sepueden crear a partir de un modelo de datos. Por ejemplo un componente sencillo como el JComboBox contiene un arreglo de objetos.

3.2.1. JLIST Un componente JList permite administrar una lista de elementos de tipo Object con una representación en String Los constructores de la clase JList son: JList() JList(ListModel dataModel) JList(Object[ ] listData) JList(Vector? listData) El segundo constructor recibe un objeto tipo ListModel, como ésta es una interfaceutilizaremos una clase que la implementa:

DefaultListModel DefaultList Model modeloLista=new DefaultListModel();Un objeto de esta clase puede implementar el método addElement(Object o).modeloLista.addElement(“Elemento1”);//Object de tipo String.modeloLista.addElement(“Elemento2”);JList lista=new JList(modeloLista);// Se crea un JList con el modelo de elementos.

Ejemplo:

public class Lista extends JFrame{

private JList listaCursos;private DefaultListModel modeloListaCursos;public Lista() { agregarComponentes(); setTitle("CURSOS"); setContentPane(p); setSize(250, 200)}public void agregarComponentes() { modeloListaCursos=new DefaultListModel(); modeloListaCursos.addElement("C++");

117

Page 118: Documentación Java

modeloListaCursos.addElement("Java"); modeloListaCursos.addElement("OpenOffice"); modeloListaCursos.addElement("Linux"); modeloListaCursos.addElement("Phyton"); listaCursos=new JList(modeloListaCursos); JPanel p=new JPanel(); p.setBorder(BorderFactory.createTitledBorder("Lista de Cursos")); p.add(listaCursos);}public static void main(String []args){ new Lista().setVisible(true);}}

Resultado:

EJERCICIO Crear un Proyecto denominado Componentes Avanzados y dentro del paquete ventanas diseñar un clase VentanaPrincipal que extienda de JFrame y que téngalos constructores necesarios para modificar sus propiedades.Crear una clase ComponenteLista que permita utilizar la VentanaPrincipal para añadir un JList similar al ejemplo, que contenga la lista de 5 estudiantes del salón.

3.2.2. JTABLE JTable es uno de los componentes con APIs más extensas y también son complejos, esa complejidad le permite ser más personalizable y potente. Los constructores que proporciona esta clase son: JTable() JTable(int numRows, int numColumns)JTable(Object[][] rowData, Object[] columnNames)JTable(TableModel dm)JTable(TableModel dm, TableColumnModel cm)JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm)JTable(Vector rowData, Vector columnNames)

El primer constructor permite crear un JTable con las propiedades por defecto, elsegundo crea la tabla como una matríz de numRows x numColumns.Vamos a ver un ejemplo utilizando el constructor, que permite crear una tabla conuna matriz de datos (rowData) y los nombres de las columnas contenidos en unarray de String.Nuestro primer ejemplo tendrá las siguientes columnas:

String[] columnNames = {"Nombre", "Apellido", "Pasatiempo", "Años de Practica", "Soltero(a)"}; Y utilizaremos el siguiente array para su contenido: Object[][] data = { {"Maria", "Castro", "Esquiar", new Integer(5), newBoolean(false)}, {"Lucas", "Herrera", "Patinar", new Integer(3), newBoolean(true)}, {"Kthya", "Espinoza", "Escalar", new Integer(2), newBoolean(false)}, {"Marco", "Molina", "Correr", new Integer(7), newBoolean(true)}, {"Angela", "Díaz", "Nadar", new Integer(4), newBoolean(false)}};La creación de una tabla con estos datos sería:JTable table = new JTable(data, columnNames);

Ejemplo:import java.awt.BorderLayout;import java.awt.Dimension;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTable;public class

118

Page 119: Documentación Java

EjemploTabla1 extends JFrame{

public EjemploTabla1() { super("Ejemplo 1"); //array bidimensional de objetos con los datos de la tabla Object[][] data = { {"Maria", "Castro", "Esquiar", new Integer(5), new Boolean(false)}, {"Lucas", "Herrera", "Patinar", new Integer(3), new Boolean(true)}, {"Kthya", "Espinoza", "Escalar", new Integer(2), new Boolean(false)}, {"Marco", "Molina", "Correr", new Integer(7), new Boolean(true)}, {"Angela", "Díaz", "Nadar", new Integer(4), new Boolean(false)}}; //array de Strings con los títulos de las columnas String[] columnNames = {"Nombre", "Apellido", "Pasatiempo", "Años de Practica", "Soltero(a)"}; //se crea la Tabla JTable table = new JTable(data, columnNames); table.setPreferredScrollableViewportSize(new Dimension(500, 70)); //Creamos un JscrollPane y le agregamos la JScrollPane scrollPane = new JScrollPane(table); //Agregamos el JScrollPane al contenedor getContentPane().add(scrollPane, BorderLayout.CENTER); } public static void main(String[] args) { EjemploTabla1 frame = new EjemploTabla1(); frame.pack(); frame.setVisible(true); }}

Modelo de tabla Los modelos de tabla son objetos que implementan la interface TableModel; a través de ellos es posible personalizar mucho más y mejor el comportamiento delos componentes JTable, permitiendo utilizar al máximo sus potencialidades.Todas las tablas cuentan con un modelo de tabla, aunque en el ejemplo 1 no sehaya especificado, existe uno por omisiónLa clase AbstractTableModel es la que implementa directamente ala interface TableModel, aunque es esta clase la que se recomienda extender para utilizarla como modelo de tabla, existe un modelo de tabla predeterminado quefacilita mucho el trabajo con tablas. Este modelo predeterminado es la clase DefaultTableModel DefaultTableModel Esta clase tiene el siguiente diagrama de herencia:java.lang.Object | +-javax.swing.table.AbstractTableModel | +-javax.swing.table.DefautTableModelNuevamente, antes de comenzar a utilizar esta clase, veremos cuales sonlos constructores con que cuenta: DefaultTableModel() DefaultTableModel(int numRows, int numColumns) DefaultTableModel(Object[][] data, Object[] columnNames) DefaultTableModel(Object[] columnNames, int numRows) DefaultTableModel(Vector columnNames, int numRows) DefaultTableModel(Vector data, Vector columNames)

Utilizaremos el constructor que nos permite crear un DefaultTableModel, a partir de los datos con que ya contamos del ejemplo anterior: Por lo tanto, el constructor queda así: DefaultTableModel dtm= new DefaultTableModel(data, columnNames); Despues de haber creado el modelo de tabla, dtm en el ejemplo, se creala tabla con el constructor correspondiente:

119

Page 120: Documentación Java

JTable table = new JTable(dtm);Una vez hecho esto, cualquier modificación que se realice sobre el modelo detabla se reflejará directamente en la tabla. Agregar una columna: String[] newColumn= {"Contabilidad", "Informatica", "Medicina", "Musica", "Diseño"}; dtm.addColumn("Carrera",newColumn); Agregar una fila: Object[] newRow={"Jose", "Ordóñez", "Tenis", new Integer(5), new Boolean(false), "Pera"}; dtm.addRow(newRow); Modificar una celda en especial, en este ejemplo la celda ubicada en la columna 1, fila 1: dtm.setValueAt("Catherine", 1, 1);

Puedes revisar los métodos que proporciona la clase DefaultTableModel paraconocer qué otras cosas puedes realizar con ella.

Ejemploimport javax.swing.JTable;import javax.swing.table.DefaultTableModel;import javax.swing.JScrollPane;import javax.swing.JPanel;import javax.swing.JFrame;

public class EjemploTabla2 extends JFrame { public EjemploTabla2() { super("Ejemplo 2"); //array bidimencional de objetos con los datos de la tabla Object[][] data = { {"Maria","Castro", "Esquiar", new Integer(5), new Boolean(false)}, {"Lucas", "Herrera", "Patinar", new Integer(3), new Boolean(true)}, {"Kthya","Espinoza", "Escalar", new Integer(2), new Boolean(false)}, {"Marco", "Molina", "Correr", new Integer(7), new Boolean(true)}, {"Angela","Díaz", "Nadar", new Integer(4), new Boolean(false)}}; //array de Strings con los títulos de las columnas String[] columnNames = {"Nombre", "Apellido", "Pasatiempo", "Años de Practica", "Soltero(a)"}; //creamos el Modelo de la tabla con los datos anteriores DefaultTableModel dtm= new DefaultTableModel(data, columnNames); //se crea la Tabla con el modelo DefaultTableModel final JTable tabla = new JTable(dtm); // una vez creada la tabla con su modelo // podemos agregar columnas String[] newColumn= {"Contabilidad", "Informatica", "Medicina", "Musica", "Diseño" }; dtm.addColumn("Carrera",newColumn); //filas Object[] newRow={"José", "Ordóñez", "Tenis", new Integer(5), new Boolean(false), "Informatica"}; dtm.addRow(newRow); //o modificar una celda en especifico dtm.setValueAt("Sofía", 1, 1); //se define el tamaño tabla.setPreferredScrollableViewportSize(new Dimension(500, 70)); //Creamos un JscrollPane y le agregamos la JTable JScrollPane scrollPane = new JScrollPane(tabla); //Agregamos el JScrollPane al contenedor getContentPane().add(scrollPane, BorderLayout.CENTER); } public static void main(String[] args) {

120

Page 121: Documentación Java

EjemploTabla2 frame = new EjemploTabla2(); frame.pack(); frame.setVisible(true); }}

AbstractTableModel Con esta clase es posible implementar, de una manera más completa y eficiente,los métodos necesarios para crear un modelo de tabla.Para crear un modelo de tabla personalizado, lo primero que necesitamoses extender la clase AbstractTableModel. class MyTableModel extends AbstractTableModel { ..... }Como es una clase Abstracta debemos de implementar los 3 métodos siguientes:

class MyTableModel extends AbstractTableModel { public int getRowCount(){ ... } public int getColumnCount(){ ... } public Object getValueAt(int row, int column){ ... } }Con la implementación de los métodos anteriores, las celdas de la tabla NO serán editables y NO se podrán modificar los valores de cada una de ellas. Si deseamos tener un mecanismo para modificar los valores de las celdas dela tabla, tenemos que sobrescribir el método setValueAt de la

clase AbstractTableModel:class MyTableModel extends AbstractTableModel { ... ... public void setValueAt(Object value, int row, int col) { ... } }

Y, si la modificación de los valores de las celdas, se hace directamente sobre ellas,necesitamos indicar a nuestro modelo de tabla que las celdas de la tabla seráneditables, esto se hace sobrescribiendo el método

isCellEditable:

class MyTableModel extends AbstractTableModel { ... public boolean isCellEditable(int row, int col) { ... } }Ya lo único que haría falta sería agregar los nombres de las columnas de nuestra tabla y definir su contenido inicial:class MyTableModel extends AbstractTableModel { final String[] columnNames = { ... } final Object[][] data = { ... } ... }

JTable invoca un método del modelo de tabla para determinar eleditor/renderer predeterminado que utilizará para mostrar el valor de cada celda. Por ejemplo para celdas con valores booleanos utilizará check boxs; este métodoes: getColumnClass, y también es recomendable implementarlo:

class MyTableModel extends AbstractTableModel { ... public Class getColumnClass(int c) { ... } }EjercicioCrear un proyecto ProyectoTablaSwing dentro del cual tendremos el paquetemodelo con las clases ModeloTablaEstudiante y Estudiante: Estudiante - id: int - nombre: String - apellido: String - carrera: String - modulo: String - paralelo: String - promedio: doubleAdicionalmente un paquete presentacion contiene la clase

121

Page 122: Documentación Java

VentanaEstudiantesque será el frame con la tabla de estudiantes. Diseña una clase Ejecutable que permita crear 5 estudiantes y almacenarlos enun Vector de manera que se pueda crear el Modelo de la tabla con estos datos. JTreeAl igual que JTable su creación se basa en un modelo que permite definir el nodo raíz y los nodos hoja del componente.

Algunos de sus constructores son: JTree() JTree(Object[] value) Retorna un JTree cuyos nodos hoja serán los objetos contenidos en el Array value. JTree(TreeModel newModel) Crea una instancia de JTree en base al modelo del parámetro JTree(TreeNode root) Crea un JTree con un nodo raíz TreeNode. JTree(Vector<?> value) Crea un JTree con cada elemento especificado en el Vector como hijos de un nodo raíz que no es mostrado. TreeNode es la interfaz que permite generar los nodos del árbol, sin embargo porsu naturaleza no podemos crear objetos de ella. Existen algunas clases que implementan esta interfaz y de las cuales podemos hacer uso.DefaultMutableTreeNode Esta clase permite crear objetos TreeNode para añadirlos a un JTree; como es necesario tener un Nodo principal crearemos primeramente éste y luegoañadiremos sus nodos hoja utilizando el constructor que recibe como parámetro elnombre del nodo:

DefaultMutableTreeNode nodoPrincipal=new DefaultMutableTreeNode("Nodo Principal");DefaultMutableTreeNode nodo1=new DefaultMutableTreeNode("Nodo 1");DefaultMutableTreeNode nodoSub1=new DefaultMutableTreeNode("Nodo hijo 1");nodo1.add(nodoSub1);nodoPrincipal.add(nodo1);

Ahora crearemos el árbol con el nodo principal, utilizando el cuarto constructor delos antes mencionados:JTree arbol=new JTree(nodoPrincipal);EJERCICIOPara el ejercicio utilizaremos el Proyecto ComponentesAvanzados de modo quepodamos reutilizar la clase VentanaPrincipal para crear el frame que contendráun árbol con la clasificación de los animales.

4. EVENTOS

4.1. ¿Qué es un evento? Todos los sistemas operativos están constantemente atendiendo a los eventos generados por los usuarios. Estos eventos pueden ser: pulsar una tecla, mover elratón, hacer clic con el ratón, pulsar el ratón sobre un botón o menú (Java distingueentre simplemente pulsar el ratón en un sitio cualquiera o hacerlo, por ejemplo, enun botón). El sistema operativo notifica a las aplicaciones que están ocurriendo estos eventos, y ellas deciden si han de responder o no de algún modo a este evento.

4.2. Gestión de EventosPara hacer que el manejador escuche los eventos de otro objeto se emplea elmétodo add[nombre_evento]Listener.

Ejemplo:frame.addMouseListener(manejador);Este método permite registrar eventos del ratón asociados a un objeto frame. Esto se denomina Registro de Receptores específicos para los eventos. El objetofuente utiliza esta lista para notificar a cada receptor que ha sucedido un evento delos que controla.Hay algunas clases de eventos que involucran a más de un evento, tal es el casodel ratón. Por tanto, la clase que implementa el manejador de eventos del ratóndebe sobreescribir todos los métodos declarados en la interfaz MouseListener,tales como mousePressed, mouseReleased, mouseClicked, mouseMoved y otros.

122

Page 123: Documentación Java

Para facilitar el manejo de estos eventos, se han definido un número de clases intermedias, conocidas como clases adaptadores (Adapters), para no tener que sobreescribir todos los métodos de la interfaz cuando se requiere controlar un solotipo de evento. De esta manera podemos definir dos caminos para acceder a los Oyentes de loseventos para un componente específico: Implementando la interfaz, lo cual implica sobreescribir todos sus métodos. public class EventoMouse implements MouseListener{... Extendiendo una clase adaptadora, con lo cual se sobreescriben solo los métodos deseados. public class EventoMouse extends MouseAdapter{...Los eventos están agrupados de acuerdo a su naturaleza en los siguientes grupos: ActionListener: acciones sobre componentes. WindowListener: cierre o manipulación una ventana (Frame/Dialog). MouseListener: presión de un botón del mouse mientras el cursor está sobre el componente. MouseMotionListener: movimiento del mouse sobre un componente. ComponentListener: visibilidad del componente. FocusListener: obtención del foco del teclado.

ListSelectionListener: selección de ítems dentro de una lista. A continuación en la siguiente se lista las principales interfaces junto a susrespectivas clases “Adapter” y los métodos que poseen para los componentes:

Listener interface y Adapter Metodos ActionListener actionPerformed(ActionEvent)AdjustmentListener adjustmentValueChanged(AdjustmentEvent)ComponentListener componentHidden(ComponentEvent)ComponentAdapter componentShown(ComponentEvent) componentMoved(ComponentEvent) componentResized(ComponentEvent)ContainerListener componentAdded(ContainerEvent)ContainerAdapter componentRemoved(ContainerEvent)FocusListener focusGained(FocusEvent)FocusAdapter focusLost(FocusEvent)KeyListener keyPressed(KeyEvent)KeyAdapter keyReleased(KeyEvent) keyTyped(KeyEvent)MouseListener mouseClicked(MouseEvent)MouseAdapter mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent)MouseMotionListener mouseDragged(MouseEvent)MouseMotionAdapter mouseMoved(MouseEvent)WindowListener windowOpened(WindowEvent)WindowAdapter windowClosing(WindowEvent) windowClosed(WindowEvent) windowActivated(WindowEvent) windowDeactivated(WindowEvent) windowIconified(WindowEvent) windowDeiconified(WindowEvent)ItemListener itemStateChanged(ItemEvent)ListSelectionListener valueChanged(ListSelectionEvent)

123

Page 124: Documentación Java

Ejemplo1. Vamos a trabajar con un evento que permite finalizar la ejecución del programa al momento de cerrar la VentanaBase, ya que de otro modo seguirá ejecutándose.

public class VentanaBase extends JFrame {

public VentanaBase() {setTitle("Evento WindowClosing"); setSize(new Dimension(300, 200)); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { JOptionPane.showMessageDialog(null,"El programa finalizara cuando pulse Aceptar"); System.exit(0); } }); }

public static void main(String[] args) { new VentanaBase().setVisible(true); }}

En el ejemplo añadimos un escuchador WindowListener al frame e implementamosel método windowClosing.2. Añadimos a la VentanaBase un botón salir para cerrar la Ventana mostrando un cuadro de confirmación.

salir.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { int opc=JOptionPane.showConfirmDialog(null,"Esta seguro de cerrar la Ventana"); if(opc==0){ System.exit(0); } } });

Ejemplo

ItemListener ItemListener es un manejador que escucha todos los eventos relacionados con laselección o cambio de algún ítem en un componente que implica selección.Vamos a crear una clase JFrame como la siguiente: Para manejar los eventos generados a partir de la selección de los ChekBox,construiremos una clase que implemente la interfaz ItemListener de manera quepodamos sobreescribir el método itemStateChanged (ItemEvent e)Trabajamos con la clase Font para cambiar el estilo de la Fuente del TextField

private class CheckBoxListener implements ItemListener { private int valBold = Font.PLAIN; private int valItalic = Font.PLAIN; @Override public void itemStateChanged(ItemEvent e) { if (e.getSource() == bold) { if (e.getStateChange() == ItemEvent.SELECTED) { valBold = Font.BOLD; } else { valBold = Font.PLAIN; } } if (e.getSource() == italic) {

124

Page 125: Documentación Java

if (e.getStateChange() == ItemEvent.SELECTED) { valItalic = Font.ITALIC; } else { valItalic = Font.PLAIN; } } ... ... }}

Añadimos el escuchador a los componentes del Frame (CheckBox):JCheckBox bold = new JCheckBox("Bold");JCheckBox italic = new JCheckBox("Italic");CheckBoxListener handler = new CheckBoxListener();bold.addItemListener(handler);bold.addItemListener(handler);

Es el mismo objeto listener que añadimos a todos los CheckBox ya que es un soloobjeto el que va a recibir los eventos y va a realizar los cambios seleccionados.

Ejemplo:MouseMotionListenerpublic class Ventana extends JFrame{

public Ventana(){ setTitle("Evento Mouse"); setSize(new Dimension(250, 150)); setLocationRelativeTo(null); final JPanel panel1=new JPanel(); panel1.setBackground(Color.gray); final JButton boton =new JButton("Boton"); boton.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e){ boton.setCursor(new Cursor(Cursor.MOVE_CURSOR)); } }); panel1.add(boton); panel1.addMouseMotionListener(new MouseMotionAdapter(){ public void mouseMoved(MouseEvent e){ panel1.setCursor(new Cursor(Cursor.HAND_CURSOR)); } }); this.add(panel1); this.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); setVisible(true); }}

5. GRÁFICOS EN SWING

Todos los contenedores en swing permiten ser redibujados (repaint) en tiempo de ejecución, es decir añadir algún componente modificar posiciones, pintar sobre el contenedor, etc. Esto se debe a que un contenedor

125

Page 126: Documentación Java

swing deriva dejava.awt.Container, y de esta manera a sus métodos.Uno de ellos es el métodopaint(Graphics g)dibuja un gráfico (Graphics) en el contenedor.

La clase Graphics permite diseñaralgunas formas como: Lineas drawLine(int x1, int y1, int x2, int y2) Dibuja una línea usando el color actual entre los puntos (x1, y1) y (x2, y2) en el sistema de coordenadas del grafico Circulos drawOval(int x, int y, int width, int height) Dibuja un óvalo en la posición x, y, el ancho y alto del círculo. Polígono drawPolygon(int[] xPoints, int[] yPoints, int nPoints) Dibuja un poligono cerrado definido por arreglos de (x, y) coordenadas.Rectángulo drawRect(int x, int y, int width, int height) Dibuja un rectángulo en (x, y) con su tamaño width, height. drawString(String str, int x, int y) Dibuja el texto del String srt usando el contexto actual del gráfico y el actual color de fuente. Para dibujar formas con relleno usa los métodos: fill3DRect(int x, int y, int width, int height, boolean raised) fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) fillOval(int x, int y, int width, int height) fillPolygon(int[] xPoints, int[] yPoints, int nPoints) fillRect(int x, int y, int width, int height) fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)

Ejemplo:g.fillOval(10,5, 4, 4); dibujará un óvalo relleno en un cuadrado de 4x4 en la posición (10,5) del contedordonde se dibuja.

EJEMPLO JFrame Pintor:

public class Pintor extends JFrame {

private int cuentaPuntos = 0;private JLabel j=new JLabel("Van: "+cuentaPuntos+" puntos"); // arreglo de 2000 referencias a java.awt.Pointprivate Point puntos[] = new Point[ 2000 ]; // configurar GUI y registrar manejador de eventos de ratónpublic Pintor() {super( "Un programa simple de dibujo" );//crear una etiqueta y colocarla en la parte SOUTH del BorderLayoutgetContentPane().add( new JLabel( "Arrastre el ratón para dibujar" ),BorderLayout.SOUTH );getContentPane().add( j,BorderLayout.NORTH );addMouseMotionListener( new MouseMotionAdapter() { // clase interna anónima // almacenar coordenadas de arrastre y llamar a repaint public void mouseDragged( MouseEvent evento ) { if ( cuentaPuntos < puntos.length ) { puntos[ cuentaPuntos ] = evento.getPoint(); ++cuentaPuntos; repaint(); j.setText("Van: "+cuentaPuntos+" puntos, le quedan:" +(2000-cuentaPuntos)+"puntos"); } } } // fin de la clase interna anónima ); // fin de la llamada a addMouseMotionListener setSize( 400, 200 );

126

Page 127: Documentación Java

setVisible( true ); } // fin del constructor de Pintor// dibujar óvalo en un cuadro delimitador de 4x4 en ubicación especifica public void paint( Graphics g ){ super.paint( g ); // borra el área de dibujo for ( int i = 0; i < puntos.length && puntos[ i ] != null; i++ )g.fillOval( puntos[ i ].x, puntos[ i ].y, 4, 4 ); } public static void main( String args[] ) {Pintor aplicacion = new Pintor();aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); }}

6. GENERADOR DE INTERFACES DE NETBEANS El IDE

Netbeans permite crear interfaces gráficas de manera visual, es decir agregar a un Frame los componentes que deseamos tan solo con arrastrar el componente desde la paleta hasta el Frame y modificar sus propiedades.Para crear un Frame podemos seleccionar del Proyecto new JFrame en lugar de Java Class. De esta manera se creará una clase con algunos atributos ypropiedades de JFrame, incluyendo el método main que permitirá visualizar elFrame al ejecutar la clase. VENTANAS DEL GENERADOR DE INTERFAZ GRÁFICAAl agregar un contenedor de JFrame a un proyecto el programa abre el formularioen una ficha del Editor con una barra de herramientas que incluye varios botones. El formulario se abre en la vista Diseño del generador de interfaces gráficas deusuario y aparecen automáticamente tres ventanas adicionales en las esquinas delprograma, que permiten navegar, organizar y editar los formularios de la interfaz gráfica de usuario a medida que los genera. Las diferentes ventanas del generador de interfaces gráficas de usuario incluyen:

Área de diseño: Ventana principal del generador de interfaces gráficas de usuario para crear y editar formularios de interfaz gráfica de usuario de Java. Los botones Origen y Diseño de la barra de herramientas permiten ver el código fuente de una clase o la vista gráfica de sus componentes de la interfaz gráfica de usuario. Los botones adicionales de la barra de herramientas permiten acceder cómodamente a los comandos habituales, por ejemplo para elegir entre los modos de selección o conexión, alinear componentes, definir el comportamiento de cambio automático del tamaño de los componentes o pre visualizar los formularios. Inspector: Proporciona una representación, tanto visual como no visual, de todos los componentes de la aplicación en forma de jerarquía de árbol. El inspector también permite visualizar el componente del árbol que se está editando en el generador de interfaces gráficas de usuario, así como organizar los componentes en los paneles disponibles.

Paleta: Lista personalizable de los componentes disponibles que contiene fichas para los componentes de JavaBeans, JFC/Swing y AWT, así como administradores de diseño. Ventana de propiedades: Muestra las propiedades del componente seleccionado en el generador de interfaces gráficas de usuario y las ventanas Inspector, Proyectos o Archivos.Método initComponents()El código del método initComponents() es generado al momento que se añadencomponentes al frame, es decir las propiedades y eventos que se agreguen a loscomponentes, de manera que no se pueden editar desde aquí. La única manera de modificar o aumentar código a éste método es mediante lapestaña Code del panel Properties en la vista diseño: Crear el componente Antes de crear el componente Después de crear el componente Para inicializar el valor del componente Después de inicializar el componente ..........

PRÁCTICA 1.

127

Page 128: Documentación Java

Crear un proyecto denominado ProyectoSwing. 2. Crear una clase PrimerFrame en un paquete denominado presentacion. 3. Agregar los siguientes componentes y modificar sus propiedades de diseño:Diseño: Asignamos nombres a cada componente: Modificar el layout del panel Operaciones a BoxLayout El cuadro de texto de Resultado no debe ser editable. Agregamos los eventos a cada botón de las operaciones:

Una vez seleccionado el evento estaremos en la vista Source en donde está todo el código generado al agregar y modificar los componentes. Modificamos el contenido del método actionPerformed de cada botón: El resultado será el siguiente: Codificar los eventos de cada botón y controlar las excepciones para el ingreso de texto en los campos de número.EJERCICIO:Leer un archivo de texto desde un programa en java que permita leer y modificar elcontenido en un JTextArea.Utilice el patrón Modelo – Vista – Controlador para manejar los archivos

Uso de JFileChooser para buscar y abrir el archivo. Uso de JFileColor para cambiar el color de fondo del área de texto y el color de fuente. Uso del paquete java.io para la lectura y escritura del Archivo.EJERCICIO:Elabore un programa que permita administrar en una tabla (JTable) los datos de losestudiantes. Utilizar el patrón MVC, de manera que la tabla pueda almacenar los estudiantes como objetos. Trabajar los eventos que permiten actualizar los datos de la tabla al agregar, modificar o eliminar Utilizar la opción binding de Netbeans para obtener los datos del Estudiante.

BIBLIOGRAFÍA 1. PÉREZ Gustavo Guillermo, Aprendiendo Java y Programación Orientada a Objetos. http://compunauta.com/forums/linux/programacion/java/ebook.html 2. DEITEL Paul. Como programar en Java 7/e. Pearson Education. 2007. 3. Micael Gallego & Soto Montalvo, Interfaces Gráficas en Java. Ramón Areces, 2005. http://gavab.escet.urjc.es/wiki/download/mp/material/Modulo- Ev-Tema2-1.pdf 4. PAVÓN GÓMEZ Santiago Dpto. Ingeniería Sistemas Telemáticos Univ. Politécnica de Madrid http://jungla.dit.upm.es/~santiago/docencia/apuntes/Swing/ 5. El tutorial Java de Sun: http://java.sun.com/docs/books/tutorial 6. Tutorial Java Básico Versión 3.0 http://www.javahispano.org 7. API Java de Sun (version 6): http://java.sun.com/javase/6/docs/apiProgramacion 2 Jhomara Luzuriaga

___________________________________-Transformaciones de imágenes = http://www.lcc.uma.es/~galvez/ftp/libros/Java2D.pdf http://www.alammi.info/2congreso/memorias/Documentos/martes/TRANSFORMGEOMETRICAS.pdf

Crop

You can crop or subset an image by providing an x,y offset from the upper left corner of the image and a width/height.javaxt.io.Image image = new javaxt.io.Image("/cup.jpg");image.crop(130,50,80,50);

Original Image Image Crop

128

Page 129: Documentación Java

Skew

You can adjust the corners of the image to arbitrary pixel coordinates. This can be used to add perspective to your images.javaxt.io.Image image = new javaxt.io.Image("/cup.jpg");int width = image.getWidth();int height = image.getHeight();image.setCorners(20, 70, //UL width-70, 0, //UR width+20, height-50, //LR 50, height); //LL

Original Image Skewed ImageAccessing Raw Bytes

Note that you can access the raw pixels via the getByteArray() method.byte[] b = image.getByteArray();

By default, this returns a jpeg compressed image. You can specify an output formatbyte[] b = image.getByteArray("tif");

You can access the raw pixels via the getBufferedImage() method.java.awt.image.BufferedImage bi = image.getBufferedImage();

________________________________

129

Page 130: Documentación Java

http://www.escet.urjc.es/~gperez/Interfaces/practicas/practica0.pdf CLASES Y JERARQUIA DE PANELES Y COMPONENTES

Practica0 de Swing1. Programa Java tipo consolapublic class Clase0 {public static void main(String[] args) {System.out.println("Hola Mundo");System.out.println("Estamos en clase de Interfaces de Usuario");}}2. Programa grafico Java2.1 Elementos gráficos en Java.Cada uno de los elementos de un interfaz gráfic o de usuario en Java se representa por una instancia de una determinada clase. Por ejemplo, si queremos que nuestro interfaz tenga un botón, tendremos que, entre otras cosas, instanciar un objeto de la clase JButton

. Para configurar los aspectos gráficos de los componentes usaremos métodos en la clase determinada. Por ejemplo, podremos cambiar el texto del botón usando el método void setText(String texto) de la clase JButton.En el siguiente cuadro se muestran los distintos tipos de elementos que se pueden encontrar en Swing y el nombre de la clase que los representa:

Componentes atómicosJLabel – Etiqueta, muestra imágenes y texto. El texto se puede formatear con etiquetas HTML.JButton – BotónJCheckBox – Casilla de verificaciónJRadioButton – Botón de radio, usado para seleccionar una opción entre variasJToggleButton – Botón que se queda presionado al pulsarleJComboBox – Control que muestra un elemento y pulsando en una flecha se pueden ver otros elementosJScrollBar – Barra de desplazamiento, usada en los contenedores que permiten que su contenido sea más grande que ellos. Nunca usaremos este componente directamente.JSeparator – Usado en los menus y barras de herramientas para separar opciones.JSlider - DeslizadorJSpinner – Campo de texto con botones para elegir el elemento siguiente o anterior. Se puede usar para números, fechas o elementos propios.JProgressBar – Barra de progreso

Componentes complejosJTable – TablaJTree - ÁrbolJList – Lista de elementosJFileChooser – Selector de ficherosJColorChooser – Selector de colorJOptionPane – Cuadro de diálogo personalizable Ingeniería Informática Swing

Componentes de textoJTextField – Campo de texto

130

Page 131: Documentación Java

JFormattedTextField – Campo de texto formateadoJPasswordField – Campo de texto para contraseñasJTextArea – Area de textoJTextPane – Area de texto formateado y con imágenesJEditorPane – Area de texto formateado y con imágenes que permite la edición del contenido

Contenedores JPanel – ContenedorJScrollPane – Contenedor con barras de desplazamientoJSplitPane – Contenedor dividido en dos partesJTabbedPane – Contenedor con pestañasJDesktopPane – Contenedor para incluir ventanas dentroJToolBar – Barra de herramientas

Contenedores de alto nivelJFrame – Ventana de aplicaciónJDialog – Cuadro de diálogoJWindow – Ventana sin marcoJInternalFrame – Ventana interna

MenusJMenu – Un botón que al ser pulsado despliega un menú.JCheckBoxMenuItem – Elemento del menú como botón de chequeo.JRadioButtonMenuItem – Elemento del menú como botón de selección.JPopupMenu – Menú de elementos.JMenuItem – Un botón que se encuentra en un menu.JMenuBar – Barra de menus.

Otros JToolBar – Barra de herramientasJToolTip – Tooltip

No vamos a ver todos los componentes en detalle. Este tutorialpretende mostrar los conceptos básicos de Swing y cómo construir interfaces potentes, pero no entra en los detalles de cada componente. Se pretende que el lectortenga la capacidad de mirar la API y comprender lo que se dice en ella sin dificultad. No obstante, a medida que vayamos avanzando, iremos dando unas nociones básicas en el uso de algunos componentes.Debido a la evolución que han sufrido los interfaces gráficos de usuario en Java, en algunos aspectos la librería de Swing es algo “confusa”.Conceptualmente , podríamos pensar que todos los componentes heredan de la clase JComponent, todos aquellos que son contenedores, heredarían de JContainer , etc...Una visión conceptual de la jerarquía de clases podría ser:

JComponentAbstractButton

JButtonJMenuItem

JMenuJCheckBoxMenuItemJRadioButtonMenuItem

JToggleButton

131

Page 132: Documentación Java

JCheckBoxJRadioButton

JScrollBarJSeparator

JPopupMenu.SeparatorJToolBar.Separator

JSliderJSpinnerJLabelJListJComboBoxJProgressBar

JToolTip

JTableJTree

JTextComponentJEditorPane

JTextPaneJTextAreaJTextField

JFormattedTextFieldJPasswordField

JContainerJToolBarJPanelJMenuBarJPopupMenuJTabbedPaneJScrollPaneJSplitPaneJLayeredPane

JDesktopPaneJTopLevelContainer

JInternalFrameJFrameJWindowJDialog

JColorChooserJFileChooserJOptionPane

Pero, como hemos comentado antes, debido a motivos de compatibilidad, la verdadera jerarquía es algo más “confusa”, aunque conceptualmente serían muy parecidas. La jerarquía de clases real que representa los elementos más importantes del interfaz de usuario es la siguiente:

132

Page 133: Documentación Java

class java.awt.Componentclass java.awt.Container

class javax.swing.JComponentclass javax.swing.AbstractButton

class javax.swing.JButtonclass javax.swing.JMenuItem

class javax.swing.JCheckBoxMenuItemclass javax.swing.JMenuclass javax.swing.JRadioButtonMenuItem

class javax.swing.JToggleButtonclass javax.swing.JCheckBoxclass javax.swing.JRadioButton

class javax.swing.JScrollBarclass javax.swing.JSeparator

class javax.swing.JPopupMenu.Separatorclass javax.swing.JToolBar.Separator

class javax.swing.JSliderclass javax.swing.JSpinnerclass javax.swing.JLabelclass javax.swing.JListclass javax.swing.JComboBoxclass javax.swing.JProgressBar

class javax.swing.JColorChooserclass javax.swing.JFileChooserclass javax.swing.JOptionPane

class javax.swing.JPopupMenuclass javax.swing.JMenuBar

class javax.swing.JToolBarclass javax.swing.JToolTip

class javax.swing.JTabbedPaneclass javax.swing.JScrollPaneclass javax.swing.JSplitPaneclass javax.swing.JLayeredPane

class javax.swing.JDesktopPaneclass javax.swing.JPanel

class javax.swing.JTableclass javax.swing.JTree

class javax.swing.text.JTextComponentclass javax.swing.JEditorPane

class javax.swing.JTextPaneclass javax.swing.JTextAreaclass javax.swing.JTextField

133

Page 134: Documentación Java

class javax.swing.JFormattedTextFieldclass javax.swing.JPasswordField

class javax.swing.JInternalFrame

class java.awt.Panelclass java.awt.Window

class java.awt.Dialogclass javax.swing.JDialog

class java.awt.Frameclass javax.swing.JFrame

class javax.swing.JWindow

Ejemplo de un componente JFRAMEJava.lang.Object

Java.awt.Component

Java.awt.Container

Java.awt.Window

Java.awt.Frame

Javax.swing.JFrame

JFRAMEEs el contenedor que emplearemos para situar en él todos los demás componentes que sean necesarios para construir una determinada interfaz.La figura 1 muestra la jerarquía de herencia de este componente desde Object, que es el objeto padre de todas las clases de Java. Sus métodos están repartidos a lo largo de todos sus ascendientes. Vamos a ilustrar esto con un ejemplo para ver el código necesario para crear un JFrame

Figura 1. Jerarquía de la herencia de JFrame

2.1.1 Pasos básicos para la creación de un entorno gráfico Una vez que hemos visto el conjunto de componentes que Swing nos proporciona, vamos a ver como se construye un interfaz de usuario sencillo. Vamos a mostrar como construir los elementos gráficos y dejamos para el siguiente apartado la gestión de eventos.El interfaz gráfico a construir estará formado por una ventana, y dentro de ésta van a aparecer un botón, una etiqueta y un cuadro de texto. Los pasos a seguir son los siguientes:-Crear una ventana de aplicación.-Crear los componentes que se muestran en dicha ventana.-Crear un contenedor.-Asociar los componentes al contenedor para que, al hacerse visible, muestre en su interior dichos componentes.-Asociar el contenedor a la ventana de aplicación para que, al hacerse visible, muestre en su interior el contenedor y por tanto, los componentes asociados.

La jerarquía de contenedores de nuestro sencillo interfaz gráfico sería:

134

Page 135: Documentación Java

Ventana de Aplicación

Contenedor

Botón Etiqueta Campo de texto

NOTA: Cuando en un gráfico vayamos a indicar que un componente se va a pintar dentro de un determinado contenedor, usaremos una línea terminada en un círculo del contenedor al componente.Crear la ventana de aplicación Para crear una ventana de aplicación hay que instanciar un objeto de la clase JFrame.Algunos métodos de esta clase relacionados con el aspecto gráfico de la ventana son:

public JFrame()– Construye una ventana inicialmente invisible.

public JFrame(String titulo)– Construye una ventana inicialmente invisible con el título indicado.

public void setTitle(String titulo)– Establece el título de la ventana.

public void setSize(int width, int height)– Establece el tamaño en píxeles de la ventana.

public void setDefaultCloseOperation(int operation)– Establece la operación que se ha de hacer cuando el usuario cierra la ventana. Los valores permitidos vienen determinados por las siguientes constantes:

Javax.swing.JFrame.EXIT_ON_CLOSE- Salir del programa.

Javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE- No hacer nada.

Javax.swing.WindowConstants.HIDE_ON_CLOSE- Ocultar la ventana (por defecto).

Javax.swing.WindowConstants.DISPOSE_ON_CLOSE– Liberar los recursos de la ventana, pero no salir del programa.public void setResizable(boolean resizable)– Establece si el usuario puede cambiar el tamaño de la ventana. Por defecto es true.

public void setExtendedState(int state)– Establece el estado de la ventana. Puede no funcionar en algunas plataformás. Los valores permitidos vienen dados por las constantes:

Java.awt.Frame.NORMAL

135

Page 136: Documentación Java

– No se encuentra ni minimizada ni maximizada.

Java.awt.Frame.ICONIFIED– Minimizada.

Java.awt.Frame.MAXIMIZED_BOTH- Maximizada.

Java.awt.Frame.MAXIMIZED_HORIZ– Maximizada horizontalmente.

Java.awt.Frame.MAXIMIZED_VERT– Maximizada verticalmente.

public void setLocation(int x, int y)– Establece la posición de la esquina superior izquierda de la ventana.

public void setVisible(boolean visible)– Muestra u oculta la ventana.

Crear los componentesPara crear un componente, basta crear una instancia de la clase determinada y configurar ese objeto para que se adapte a nuestras necesidades. Vamos a ver algunos métodos de los aspectos gráficos de algunos de los componentes más usados:

JButtonpublic JButton(String texto)- Crea un botón con el texto indicado.

JLabelpublic JLabel(String texto)- Crea una etiqueta con el texto indicado.

public String getText()- Devuelve el texto de la etiqueta.

public void setText(String texto)- Pone el texto indicado en la etiqueta.

JTextFieldpublic JTextField(int columnas)- Crea un Campo de Texto sencillo con el número de columnas especificado.

public String getText()- Devuelve el texto del campo de texto.

A medida que vayamos avanzando en el curso iremos viendo los componentes más importantes y los métodos que permiten configurar su aspecto gráfico.

136

Page 137: Documentación Java

Crear un contenedorComo hemos visto, en Swing existen muchos tipos de contenedores, dependiendo de la forma que manejen los componentes que tienen dentro. Por ejemplo, existe un contenedor con pestañas y en cada pestaña va un componente, es el JTabbedPane.También existe otro contenedor dividido en dos partes para dos componentes, y la separación puede cambiar de posición, es el JSplitPane

. El que nosotros vamos a usar, para construir nuestro sencillo interfaz, es el JPanel , el más sencillo de todos, que muestra todos los componentes a la vez distribuidos en su interior. Más adelante veremos como podemos configurar la forma de distribuir los componentes.

El método constructor de la clase JPanel es:

public JPanel()– Crea un contenedor simpleAsociar los componentes al contenedor para que los muestre al hacerse visiblePara asociar componentes a un contenedor, de forma que se muestren dentro cuando el contenedor se muestre por pantalla, usamos el siguiente método de la clase JPanel:public void add( JComponent componente )– Asocia el componente al contenedor, de forma que se muestre el componente al mostrarse el contenedor.

NOTA: Por motivos de compatibilidad la cabecera real del método es public void add(Component comp). Puesto que vamos a trabajar con Swing podemos considerar que la cabecera es la indicada.Asociar el contenedor a la ventana para que le muestre al hacerse visiblePara asociar un contenedor a la ventana de aplicación, de forma que se muestre dentro cuando la ventana se muestre por pantalla, usaremos el siguiente método de la clase JFrame:public void setContentPane(JComponent panelDeContenido) –Establece el componente pasado como parámetro como contenido de la ventana.

NOTA: Por motivos de compatibilidad la cabecera real del método es public void setContentPane(Container contentPane). Puesto que vamos a trabajar con Swing podemos considerar que la cabecera es la indicada.Ejemplo de código de una interfaz grafico//importamos la libreria, un packageimport javax.swing.*;import java.awt.event.*;import java.awt.*;//La clase frame extiende a JFrameclass frame extends JFrame {//el constructorpublic frame(){//Este es uno de los métodos que nuestra clase frame//ha heredado de JFrame. Pone un titulo a la ventanasetTitle("Hola!!!");

137

Page 138: Documentación Java

//Igual que el anterior, pero ahora le da un tamañosetSize(300,200);//Le pido al frame su objeto contenedorContainer contentpane = getContentPane();//Creo un objeto de tipo JPanelJPanel panel = new JPanel();//Creo un objeto tipo labelJLabel hola = new JLabel("Hola Mundo");JLabel hola1= new JLabel("Estamos en clase de Interfaces de Usuario");//añado el panel en el objeto contenedor del framecontentpane.add(panel);//Pongo el color de fondo del panel de color rojo//añado los labels en el objeto contenedor del framecontentpane.add(hola);contentpane.add(hola1);}}//Esta es la clase auxiliar y tiene el main de la aplicaciónpublic class ejem1{

public static void main (String[] args){

//creamos un objeto de tipo frameJFrame frame = new frame();//Hacemos que los objetos se distribuyan automaticamente en el contenedorframe.getContentPane().setLayout(new FlowLayout());

//Invoco sobre este objeto uno de los métodos que//ha heredado de frame. Hacer visible el frame. Los frame por//defecto son invisibles.//Tambien se puede con show.frame.setVisible(true);}}Ejercicio 1Ya hemos visto los métodos y clases para la creación de un sencillo interfaz de usuario, partiendo de esta información, crea la interfaz grafico teniendo en cuenta los componentes que se muestran en la Figura 2.

138

Page 139: Documentación Java

http://dis.um.es/~bmoros/Tutorial/parte14/cap14-17.html para estudiar mañana

Paneles DesplazablesAnterior | Siguiente

En anteriores programas se ha utilizado la clase JScrollPane para proporcionar una forma automática de desplazar el contenido de una ventana por parte del sistema. Esta clase permite dejar las manos libres al programador para centrarse en el código de su aplicación, sin tener que estar pendiente de tener que controlar la visibilidad de todo o parte del contenido de la ventana. Pero los ejemplos que se han visto no se centraban ninguno en la clase JScrollPane, por lo que son muy simples, pero visto que es una clase muy usada y útil, el ejemplo java1424.java es para presentar una aplicación un poco más avanzada para mostrar cómo interactúa en un programa. Además, el ejemplo hace uso de la clase JSplitPane, que permite dividir la ventana en subventanas independientes.

El programa implementa un JFrame que contiene un panel dividido en dos zonas, cada una conteniendo una instancia de un componente Swing. La zona superior de la ventana contiene un campo de texto y la inferior un gráfico, para ilustrar el hecho de que el contenido de los paneles de desplazamiento puede ser cualquiera que se elija.

El código del ejemplo se muestra a continuación y debería resultar sencillo de entender al lector, aunque hay algunos trozos sobre los que merece la pena detenerse y se comentarán a continuación.

import java.io.*;import java.awt.*;import java.awt.event.*;import com.sun.java.swing.*;import com.sun.java.swing.event.*;

class java1424 extends JPanel implements ChangeListener { private JSplitPane panelVert; private JScrollPane panelScro1; private JScrollPane panelScro2; public java1424() { setLayout( new BorderLayout() ); // Se crea una zona para presentar el texto correspondiente al fichero creaPanelSup(); // Se crea una zona inferior para mostrar el gráfico creaPanelInf(); // Se crea un panel dividido verticalmente panelVert = new JSplitPane( JSplitPane.VERTICAL_SPLIT ); add( panelVert,BorderLayout.CENTER ); // Se incorporan las dos zonas que se habían creado a las dos // partes en que se ha dividido el panel principal panelVert.setLeftComponent( panelScro1 ); panelVert.setRightComponent( panelScro2 ); }

139

Page 140: Documentación Java

public void stateChanged( ChangeEvent evt ) { // Si el evento proviene del panel principal, seguimos... if( evt.getSource() == panelScro1.getViewport() ) { // Cogemos la posición actual dentro de la vista correspondiente // al panel principal Point point = panelScro1.getViewport().getViewPosition(); // Ahora determinamos la escala correcta para las vistas, para las // dos zonas del panel principal Dimension dim1 = panelScro1.getViewport().getViewSize(); Dimension dim2 = panelScro2.getViewport().getViewSize(); float escalaX = 1; float escalaY = 1; if( dim1.width > dim2.width ) {

escalaX = (float)dim1.width / (float)dim2.width;escalaY = (float)dim1.height / (float)dim2.height;// Escalamos en función del movimientopoint.x /= escalaX;point.y /= escalaY;

} else {

escalaX = (float)dim2.width / (float)dim1.width;escalaY = (float)dim2.height / (float)dim1.height;// Escalamos en función del movimientopoint.x *= escalaX;point.y *= escalaY;

} // Movemos la otra vista en función de lo que movamos la de texto panelScro2.getViewport().setViewPosition( point ); } } private void creaPanelSup() { // Creamos el panel de la zona de texto JTextArea areaTexto = new JTextArea(); // Se carga el fichero en el área de texto, cuidando de capturar // todas las excepciones que se puedan producir try { FileReader fileStream = new FileReader( "java1424.java" ); areaTexto.read( fileStream, "java1424.java" ); } catch( FileNotFoundException e ) { System.out.println( "Fichero no encontrado" ); } catch( IOException e ) { System.out.println( "Error por IOException" ); } // Creamos el panel desplazable para el área de texto panelScro1 = new JScrollPane(); panelScro1.getViewport().add( areaTexto ); panelScro1.getViewport().addChangeListener( this );

140

Page 141: Documentación Java

} private void creaPanelInf() { // Cargamos el gráfico, o imagen , en la panatalla Icon imagenP2 = new ImageIcon( "main.gif" ); JLabel etiqP2 = new JLabel( imagenP2 ); // Creamos el panel para el gráfico panelScro2 = new JScrollPane(); panelScro2.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER ); panelScro2.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ); panelScro2.getViewport().add( etiqP2 ); panelScro2.getViewport().addChangeListener( this ); } public static void main( String args[] ) { JFrame ventana = new JFrame( "Tutorial de Java, Swing" ); ventana.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent evt ){

System.exit( 0 ); } } ); ventana.getContentPane().add( new java1424(),BorderLayout.CENTER ); ventana.setSize( 460,300 ); ventana.setVisible( true ); }}

Los métodos que se usan para crear el contenido de los subpaneles es complicado. El método creaPanelSup(), se limita a utilizar un componente JTextArea sobre el que carga el fichero que contiene el código fuente del ejemplo. y el método creaPanelInf() presenta una imagen que se desplazará en consonancia con el movimiento del panel superior.

Sin embargo, sí que hay un trozo de código interesante en el método stateChanged(), que controla los cambios producidos por acción del usuario, y es el cálculo de la escala que diferencia a los dos paneles de desplazamiento. En el programa, el cálculo de la escala no es demasiado preciso, debido a que no tiene en cuenta del todo el tamaño de los dos paneles. Si se mueve la barra horizontal en el panel superior se puede observar esta circunstancia. Con un poco más de matemáticas por parte del lector, seguro que podrá compensar el error, y a su ejercicio se deja esa corrección, simplemente indicando que hay que experimentar con los métodos getViewPosition() y getExtentSize() de la clase JViewport para conseguir que los cálculos sean correctos.

141

Page 142: Documentación Java

Cuando se ejecuta el programa y se agranda la ventana, se puede ver una imagen semejante a la que reproduce la imagen siguiente.

Ahora, los movimientos sobre la barra de desplazamiento vertical en el panel superior hacen que la imagen que esta en el panel inferior se desplace al mismo tiempo. Quiza esto no le parezca al lector demasiado práctico, pero muestra cómo se puede conseguir el desplazamiento de un panel con respecto a otro; y este tipo de funcionalidad sí que es de uso frecuente en muchas aplicaciones, y aquí se muestra una forma muy sencilla de poder implementarla.

Otro detalle importante es la ausencia de barras de desplazamiento en el panel inferior, a pesar de que la imagen es mucho más grande que el tamaño de la subventana. Las líneas de código siguientes:

panelScro2.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER ); panelScro2.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );

son las que permiten fijar las características de las barras de desplazamiento, y en este caso se indica que no deben estar presentes.

hola,tengo este problema, quiero mostrar una imagen de 125x100 cmts con 40 pixeles por cmt = 5000x4000 pixeles, creé un JScrollPane de 5020x4020 pixeles, le agrego el Jlabel, le añado la imagen a la propiedad icon (directamente en el IDE), no me muestra la imagen, peor, no la acepta en la propiedad.He tratado con método y código escrito en la clase, pero tampoco la muestra.Cuál puede ser el problema???si quieres te envío la imagen, está en jpg con solo 2,86MB.Te agradezco tu ayuda.

142

Page 143: Documentación Java

http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.htmlEl sistema de coordenadas que proporciona Java para dibujar no es el más adecuado para la representación de funciones matemáticas. En primer lugar no está orientado a la forma convencional de trabajar de utilizar los ejes de coordenadas con el origen en el centro y los cuatro cuadrantes. En segundo lugar los píxel no son las unidades más convenientes para trabajar. El paquete Java 2D ofrece un sistema para cambiar las coordenadas. Una transformación afín de un plano se puede definir de la forma:

$x' = ax + by + c$

$y'= dx + ey + f $

[ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ] [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ] [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]

@ConstructorProperties(value={"scaleX","shearY","shearX","scaleY","translateX","translateY"})public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12)Constructs a new AffineTransform from 6 floating point values representing the 6 specifiable entries of the 3x3 transformation matrix.Parameters:m00 - the X coordinate scaling element of the 3x3 matrixm10 - the Y coordinate shearing element of the 3x3 matrixm01 - the X coordinate shearing element of the 3x3 matrixm11 - the Y coordinate scaling element of the 3x3 matrixm02 - the X coordinate translation element of the 3x3 matrixm12 - the Y coordinate translation element of the 3x3 matrix

public static AffineTransform getTranslateInstance(double tx, double ty)Returns a transform representing a translation transformation. The matrix representing the returned transform is: [ 1 0 tx ] [ 0 1 ty ] [ 0 0 1 ] Parameters:tx - the distance by which coordinates are translated in the X axis directionty - the distance by which coordinates are translated in the Y axis directionReturns:an AffineTransform object that represents a translation transformation, created with the specified vector.

public static AffineTransform getScaleInstance(double sx, double sy)Returns a transform representing a scaling transformation. The matrix representing the returned transform is:

143

Page 144: Documentación Java

[ sx 0 0 ] [ 0 sy 0 ] [ 0 0 1 ] Parameters:sx - the factor by which coordinates are scaled along the X axis directionsy - the factor by which coordinates are scaled along the Y axis directionReturns:an AffineTransform object that scales coordinates by the specified factors.

public static AffineTransform getShearInstance(double shx, double shy)Returns a transform representing a shearing transformation. The matrix representing the returned transform is: [ 1 shx 0 ] [ shy 1 0 ] [ 0 0 1 ] Parameters:shx - the multiplier by which coordinates are shifted in the direction of the positive X axis as a factor of their Y coordinateshy - the multiplier by which coordinates are shifted in the direction of the positive Y axis as a factor of their X coordinateReturns:an AffineTransform object that shears coordinates by the specified multipliers.Since:

Las transformaciones de este tipo tienen la propiedad de que las líneas se transforman en líneas y los conjuntos de líneas paralelas se transforman en conjuntos de líneas paralelas. Para crear una transformación de este tipo usamos el constructor:

AffineTransform t = new AffineTransform(a, b, c, d, e, f);

void setTransform(double m00, double m10, double m01, double m11, double m02, double m12)Sets this transform to the matrix specified by the 6 double precision values.

public static final int TYPE_GENERAL_TRANSFORMThis constant indicates that the transform defined by this object performs an arbitrary conversion of the input coordinates. If this transform can be classified by any of the above constants, the type will either be the constant TYPE_IDENTITY or a combination of the appropriate flag bits for the various coordinate conversions that this transform performs.

Por ejemplo, el método paintComponent puede aplicar una transformación que le permita hacer que el origen esté en el centro del panel de visualización, para ello tiene que establecer la transformación de coordenadas a una traslación:

g2.translate(getWidth()/2, getHeight()/2);

Existen cuatro tipos de transformaciones fundamentales:

144

Page 145: Documentación Java

Distorsión: manteniendo una línea fija, deslizar todas las líneas paralelas a ella una distancia proporcional a la distancia que hay desde la línea fija.

objetoGráfico.shear(double sx, double xy)

Constructores de la clase Shape3D:

Shape3D();

Construye e inicializa el objeto sin ningún tipo de referencia a un objeto componente.

Shape3D(Geometry g);

Construye e inicializa un objeto hoja con referencia al objeto de geometría ‘g’. La referencia a un objeto de apariencia es nulo.Constructor de GeometryArray:

GeometryArray(int cantidadVértices, int formatoVértices);

Construye un objeto vacío con el número de vértices y el formato indicado. En el indicador de formato se puede utilizar los constantes unidos por el operador ‘OR’. Los constantes indicadores de formato son:

COORDINATES. Se utiliza un array de coordenadas. Éste es obligatorio. NORMALS. Array de superficies normales. COLOR_3. Colores sin transparencia.3.3.3 Dibujo de polígonos3.3.3.1 Triángulos

El siguiente código de ejemplo crea dos triángulos.

private Node CrearTriángulo() {

TriangleArray triángulo = new TriangleArray(6, TriangleArray.COORDINATES|

TriangleArray.COLOR_3);

triángulo.setCoordinate(0, new Point3f(-0.8f, 0.5f, 0.0f));

triángulo.setCoordinate(1, new Point3f(-0.8f,-0.5f, 0.0f));

triángulo.setCoordinate(2, new Point3f( 0.0f,-0.5f, 0.0f));

triángulo.setCoordinate(3, new Point3f( 0.0f, 0.5f, 0.0f));

triángulo.setCoordinate(4, new Point3f( 0.8f,-0.5f, 0.0f));

triángulo.setCoordinate(5, new Point3f( 0.8f, 0.5f, 0.0f));

145

Page 146: Documentación Java

triángulo.setColor(0, new Color3f(1.0f, 0.0f, 0.0f)); // Rojo

triángulo.setColor(1, new Color3f(0.0f, 1.0f, 0.0f)); // Verde

triángulo.setColor(2, new Color3f(0.0f, 0.0f, 1.0f)); // Azul

triángulo.setColor(3, new Color3f(1.0f, 1.0f, 0.0f)); // Amarillo

triángulo.setColor(4, new Color3f(0.0f, 1.0f, 1.0f)); // Cián

triángulo.setColor(5, new Color3f(1.0f, 0.0f, 1.0f)); // Violeta

Shape3D forma = new Shape3D(triángulo);

return forma;

}En la figura 3.7 se muestra el resultado. Se coge los vértices de tres en tres para dibujar los triángulos. El orden de los vértices en el array es importante. Tiene que ponerse en orden antihorario si se quiere que la cara visible sea la frontal.Se puede crear polígonos más complejos basados en triángulos. El siguiente ejemplo hace esto.

private Node CrearTriángulo() {

int contadorTira[] = {4, 5};

TriangleStripArray triángulo = new TriangleStripArray(9, TriangleArray.COORDINATES|

TriangleArray.COLOR_3, contadorTira);

// Primera tira

triángulo.setCoordinate(0, new Point3f(-0.8f, 0.5f, 0.0f));

triángulo.setCoordinate(1, new Point3f(-0.8f,-0.4f, 0.0f));

triángulo.setCoordinate(2, new Point3f(-0.2f, 0.5f, 0.0f));

triángulo.setCoordinate(3, new Point3f(-0.3f,-0.5f, 0.0f));

// Segunda tira

triángulo.setCoordinate(4, new Point3f( 0.1f, 0.5f, 0.0f));

triángulo.setCoordinate(5, new Point3f( 0.0f,-0.5f, 0.0f));

146

Page 147: Documentación Java

triángulo.setCoordinate(7, new Point3f( 0.3f,-0.5f, 0.0f));

triángulo.setCoordinate(6, new Point3f( 0.3f, 0.2f, 0.0f));

triángulo.setCoordinate(8, new Point3f( 0.8f, 0.0f, 0.0f));

Color3f rojo = new Color3f(1.0f, 0.0f, 0.0f); // Rojo

Color3f verde = new Color3f(0.0f, 1.0f, 0.0f); // verde

Color3f azul = new Color3f(0.0f, 0.0f, 1.0f); // azul

triángulo.setColor(0, rojo);

triángulo.setColor(1, verde);

triángulo.setColor(2, azul);

triángulo.setColor(3, rojo);

triángulo.setColor(4, verde);

triángulo.setColor(5, azul);

triángulo.setColor(6, rojo);

triángulo.setColor(7, verde);

triángulo.setColor(8, azul);

Shape3D forma = new Shape3D(triángulo);

return forma;

}

La figura 3.9 muestra el resultado. La clase TriangleStripArray es similar a la clase LineStripArray. En el ejemplo se crea dos polígonos. El primero consta de 4 vértices que forma dos triángulos. El segundo tiene 5 vértices formando 3 triángulos.

Para agrupar dibujos formando una imagen = https://books.google.com.co/books?id=M6reV4TGyIQC&pg=PA40&lpg=PA40&dq=coordenadas+float+or+double+en+java&source=bl&ots=jeoUoh2t

147