RECOPILADO POR: ING.

HERBERT ORLANDO MONGE

1

ACLARATORIO
Este manual ha sido recopilado con el unico objetivo de ser utilizado, en la materia programación III, Universidad de el Salvador, Facultad Multidisciplinaria Paracentral.

Se han utilizado como apuntes bases los siguientes manuales: 1. El lenguaje de programación java TM. Java Sun. 2. Java2, Abraham Otero. 2003 3. Fundamentos de Java. Mc GrawHill. En este manual no estan contemplados todos los metodos y clases de Java, se recomienda consultar la documentación de java Sdk en www.sun.com.

2

INDICE 1.0 INTRODUCCIÓN. ............................................. 9
1.1 Historia del lenguaje. ................................................................................................ 9 1.2 ¿Qué es Java? ........................................................................................................... 9 1.3 ¿Qué lo hace distinto de los demás lenguajes? .......................................................... 9 1.3.1 ¿Qué se puede programar con Java?................................................................. 10 1.3.2 ¿Es fácil de aprender? ...................................................................................... 10 1.3.3 Características del lenguaje. ............................................................................. 10 1.4 La Máquina Virtual Java (JVM). ............................................................................ 12 1.5 El entorno de desarrollo JDK. ................................................................................. 13 1.5.1 ¿Dónde conseguirlo? ....................................................................................... 13 1.6 CARACTERÍSTICAS DE JAVA ........................................................................... 13 1.6.1 Simple ............................................................................................................. 13 1.6.2 Orientado a Objetos ......................................................................................... 14 1.6.3 Distribuido ...................................................................................................... 14 1.6.4 Robusto ........................................................................................................... 14 1.6.5 Seguro ............................................................................................................. 14 1.6.6 Portable ........................................................................................................... 14 1.6.7 Arquitectura Neutral ........................................................................................ 14 1.6.8 Rendimiento medio.......................................................................................... 14

2.0 CONCEPTOS DE P.O.O ................................. 15
2.1 ¿Qué es p.O.O? ...................................................................................................... 15 2.2 ¿Qué es un objeto? ................................................................................................. 15 2.2.1 Características de los Objetos .......................................................................... 15 2.2.2 Definición de objetos. ...................................................................................... 15 2.3 CLASES ................................................................................................................ 16 2.4 Mensaje .................................................................................................................. 16 2.5 Herencia ................................................................................................................. 16 2.6 Polimorfismo.......................................................................................................... 17 2.7 Encapsulacion ........................................................................................................ 18

3.0 VISIÓN GENERAL Y ELEMENTOS BÁSICOS ................................................................. 18 DEL LENGUAJE. .................................................. 18
3.1 Mi primer programa. .............................................................................................. 19 3.2 Comentarios. .......................................................................................................... 20 3.3 Variables y Tipos de Datos ..................................................................................... 21 3.3.1 Tipos de Variables ........................................................................................... 21 3.3.2 Nombres de Variables ...................................................................................... 22 3.4 Operadores de Java................................................................................................. 23 3.4.1 Operadores Aritméticos ................................................................................... 23 3.4.2 Operadores Relacionales y Condicionales ........................................................ 25
3

3.4.3 Operadores de Desplazamiento ........................................................................ 25 3.4.4 Operadores de Asignación ............................................................................... 27 3.4.5 Expresiones ..................................................................................................... 27 3.5 CADENAS DE CARACTERES ............................................................................ 29 3.5.1 Concatenación ................................................................................................. 29 3.5.2 Subcadenas ...................................................................................................... 29 3.5.3 Comparación de cadenas.................................................................................. 30

4.0 CONTROL DE FLUJO EN JAVA ................ 31
4.1 SENTENCIAS CONDICIONALES ....................................................................... 31 4.1.1 If then Else ...................................................................................................... 31 4.2 BUCLES ................................................................................................................ 33 4.2.1 Bucle while ..................................................................................................... 33 4.2.2 Bucle do while ................................................................................................. 34 4.2.3 Bucle for.......................................................................................................... 34 4.2.4 Break y continue .............................................................................................. 35 4.3 RETURN ............................................................................................................... 35

5.0 OBJETOS Y CLASES ..................................... 36
5.1 INTRODUCCIÓN ................................................................................................. 36 5.2 CLASES Y HERENCIA ........................................................................................ 36 5.2.1 Definición de una clase .................................................................................... 37 5.2.1.1 Modificadores de clases ................................................................................ 37 5.2.2 Modificadores de métodos y variables ............................................................. 39 5.2.2.1 Modificadores de variables ........................................................................... 39 5.2.2.2 Modificadores de un método ......................................................................... 39 5.2.3 Herencia .......................................................................................................... 39 5.2.4 Creación y referencia a objetos ........................................................................ 40 5.2.5 this .................................................................................................................. 41 5.2.6 super ................................................................................................................ 42 5.3 INTERFACES ....................................................................................................... 42 5.5 Clases Abstractas: .................................................................................................. 44 5.6.1 Tamaño de un arreglo .......................................................................................... 47 5.7 La clase String ........................................................................................................ 47 5.8 Argumentos de la linea de ordenes. ........................................................................ 48

6.0 Applets ............................................................... 49
6.1 Introducción ........................................................................................................... 49 6.2 Ciclo de vida .......................................................................................................... 49 6.3 Argumentos............................................................................................................ 51 6.4 Gráficas .................................................................................................................. 53 6.5 Tipo de letra ........................................................................................................... 55 6.6 Color ...................................................................................................................... 56 6.7 Imágenes ................................................................................................................ 56

7.0 Abstract Window Toolkit y Eventos .............. 58
7.1 Etiquetas............................................................................................................ 58 7.2 Gestion de Botones ............................................................................................. 58
4

7.3 Checkboxes ........................................................................................................ 60 7.5 TextField ........................................................................................................... 63 7.7 TextArea ............................................................................................................ 66 7.8 Componentes avanzados ..................................................................................... 68 7.8.1 Paneles ............................................................................................................ 68 7.8.2 Canvas (Lienzos) ............................................................................................. 70 7.8.3 Áreas de texto .................................................................................................. 72 7.8.4 Listas ............................................................................................................... 75 7.8.5 Frames ............................................................................................................. 78 7.8.6 Diálogos .......................................................................................................... 80

8.0 Gestores de diseño ............................................ 83
8.1 Gestores de diseño .................................................................................................. 83 8.1.1 FlowLayout ..................................................................................................... 85 8.1.2 BorderLayout .................................................................................................. 86 8.1.3 CardLayout...................................................................................................... 88 8.1.4 GridLayout ...................................................................................................... 89 8.1.5 GridBagLayout ................................................................................................ 90

9.0 EVENTOS ......................................................... 98
¿Qué es un evento? ...................................................................................................... 98 El modelo de delegación de eventos ............................................................................. 98 Gestión de eventos en Java. .......................................................................................... 99

10.0 EXCEPCIONES ........................................... 112
10.1- ¿QUÉ SON LAS EXCEPCIONES? .................................................................. 112 10.2.- DETECCIÓN DE ERRORES .......................................................................... 113 10.3.- MANEJO DE EXCEPCIONES ........................................................................ 113 10.4.- FINALLY ........................................................................................................ 115 10.5.- LANZAMIENTO DE EXCEPCIONES ........................................................... 117 10.6.- JERARQUÍA DE EXCEPCIONES .................................................................. 117 10.7.- CREACIÓN DE EXCEPCIONES .................................................................... 119 10.8.- OBTENCIÓN DE INFORMACIÓN DE UNA EXCEPCIÓN .......................... 120 10.9.- RESUMEN EXCEPCIONES EXPLÍCITAS-IMPLÍCITAS ............................. 122 10.10.- EXCEPCIONES Y HERENCIA .................................................................... 122 10.11.- NORMAS EN EL USO DE EXCEPCIONES ................................................. 123 10.12.- EJEMPLOS.................................................................................................... 124

11.0 THREADS. .................................................... 127
11.1 ¿Qué son los threads? ......................................................................................... 127 11.1.1 Un ejemplo, mejor que mil palabras. ............................................................ 127 11.1.2 Otro ejemplo ................................................................................................ 128 11.1.3 Y otro ejemplo más. ..................................................................................... 129 11.2 Estado de un thread. ........................................................................................... 130 11.3 Creación de threads. ........................................................................................... 131 11.4.1 currentThread(). ........................................................................................... 132 11.4.2 isAlive(). ..................................................................................................... 132 11.4.3 sleep(). ......................................................................................................... 133
5

208 Introducción ............ 150 Componentes Swing frente a componentes AWT .................................................................................................................................................................................................................................................................................................................... 175 JLayeredPane ........6 yield().................................................................................................................................. ............................5 Threads y sincronismo........................................................................................ 200 JColorChooser............... 180 Componentes atómicos .......................4................ 146 11.......................... ..........................................................................................................................7 join()........................... 198 Componentes que muestran información estructurada ............4........................................ ....................................................................................... ......................................................................................................................................................... 168 JTabbedPane .......................... 187 JMenu ............................... 183 JRadioButton ............................. 136 11............................................................... 185 JComboBox .......... ....................................................................................................................................................2 Sección crítica.................................... 150 JFC y Swing .......................0 Swing ............................................. 133 11....................................................................................................................................................................................................................... ............................5................4....................................................................................................................................... 181 JCheckbox.........................................................................................8.................................................................. 208 características de Swing ......................................................................... JOptionPane .....................................................................................................................................................................................8 Grupos de threads.......................................................................................................... 171 JToolBar ...7 Threads Daemon..................................................................................................................................................................... 153 JFrame ..................... 180 componentes atómicos de Swing ............................. 139 11............ 134 11............. 144 11............3 Monitores.................................................................................................................................... 181 JButton.......................... ................................................................................... 157 JDialog.................. ..... 193 Componentes para mostrar información ...................................................... 188 JSlider ...........................1 Creación de grupos de threads.................. 167 JPanel. 176 Interfaces de usuario en Java: .................... 145 11........................4 suspend()........................................ 136 11............................................................................................................................................................................... 180 Componentes para obtener información ......................................................... 208 El gestor de diseño BoxLayout ..................................................................................... 134 11............................ 196 JLabel . 135 11............................................................................................................4.................. 136 11............................................ 198 JProgressBar ..................5........................................ 209 6 ............. 200 JFileChooser ..................................................................................... 205 Interfaces de usuario en Java: otras . 151 Contenedores de alto nivel .......5 wait()..................6 Prioridad de un thread.................................................................. 159 JApplet . 196 JToolTip..........5...........................................................................................1 El paradigma productor/consumidor ........................................................................................................................................................................... 146 12..................11.. 167 Contenedores intermedios .......................................

........2 JDBC es un API de bajo nivel y una base para API‟s de alto nivel...........1 Apertura de una conexión ..........................................3 Realización de Statement ......... 239 2........................ 241 3..............................1 Mantenimiento de la lista de drivers disponibles.......... 228 1.2 Ejecución de sentencias usando objetos Statement..............................3 JDBC y URL‟s ....................................... 236 2.........................................................................4 El subprotocolo “odbc” ...1.............1 JavaSoft Framework ................................................... 238 2...................................1................................ .......6 Envío de Sentencias SQL .............................................................................................. 238 2...1...................................... .7 Transacciones ......................................... LA CLASE DriverManager .............................................................. 244 4...................1..................1 Creación de objetos Statement ......................................2 Productos JDBC........... 227 1............................... 233 1................. 228 1.................. 235 2... 229 1.........1 ¿Qué hace JDBC? ..........0 CONEXIONES A BASES DE DATOS CON JAVA ............................................1 ¿Qué es JDBC?.......................................................................................................................... ............................ .................... 243 4............................5 Registro de subprotocolos ................8 Niveles de aislamiento de transacciones .. 219 1..1... 235 2..............................................2 Uso general de URL‟s...........................................................................................3 JDBC frente a ODBC y otros API‟s ..................2 Establecer una conexión ............................................................................................................ LA CLASE Statement ........1 Vista preliminar ........................................... 245 4.........1......................................................................................1...2.1................................................ 231 1........ 244 4... CONEXIÓN .................... 232 1. 238 2.....................................................................................................1.................................................1................................. 235 2............ 213 Ejemplos de Swing .... 241 3.............1................1............. INTRODUCCION JDBC ..1................ 245 5............................. 243 4.................1................................. 246 7 ........1 Vista Preliminar ....................................1 Vista Preliminar ...................................Estableciendo el Look & Feel......................................................................................4 Cerrar objetos Statement..2...................1.............1........ 241 3................. .1........................2 Tipos de drivers JDBC .......... 235 2.1........ 243 4.................................... 234 2................................................. 227 1...................................... 240 3...............5 SQL Conforme ...............

8 .

Buscaban un nombre que evocara la esencia de la tecnología (viveza. El proyecto finalizó en 1992 y resultó un completo fracaso debido al excesivo coste del producto. propiciado por la WWW. Sun ha sabido manejar inteligentemente el éxito obtenido por su lenguaje. en un proceso por etapas que arranca en 1990. ¿es simplemente otro lenguaje más? Definitivamente no. 1. y como tal es válido para realizar todo tipo de aplicaciones profesionales. animación. interactividad …). creados por el compilador de Java. Entonces. fomentando su uso entre la comunidad informática y extendiendo las especificaciones y funcionalidad del lenguaje. El lenguaje Java fue creado por Sun Microsystems Inc. 9 . A partir de este momento. caliente y que a muchos programadores les gusta beber en grandes cantidades: una taza de café (Java en argot Inglés americano2). 1. Incluye una combinación de características que lo hacen único y está siendo adoptado por multitud de fabricantes como herramienta básica para el desarrollo de aplicaciones comerciales de gran repercusión. El nombre “Java” surgió en una de las sesiones de “brainstorming” celebradas por el equipo de desarrollo del lenguaje. el lenguaje se difunde a una velocidad vertiginosa. El nombre del lenguaje tuvo que ser cambiado ya que existía otro llamado Oak.1 Historia del lenguaje. Se ejecutan indistintamente en una gran variedad de equipos con diferentes microprocesadores y sistemas operativos. el precursor de Java. Desde entonces. Sun lanzó las primeras versiones de Java a principios de 1995. De momento. Java fue elegido de entre muchísimas propuestas. 1. Puede conseguirse un JDK (Java Developer's Kit) o Kit de desarrollo de aplicaciones Java gratis. el lenguaje se popularizó y se consiguió que una gran cantidad de programadores lo depurasen y terminasen de perfilar la forma y usos del mismo. sino únicamente algo humeante. permitiera la conexión a redes de ordenadores. únicamente quedaba del proyecto el lenguaje Oak. liderado por James Gosling. Se pretendía crear un hardware polivalente. para desarrollar un sistema para controlar electrodomésticos e incluso PDAs o Asistentes Personales (pequeños ordenadores) que.El lenguaje de Programación Java 1. Gracias a una acertada decisión de distribuir libremente el lenguaje por la Red de Redes y al auge y la facilidad de acceso a Internet. Permite escribir Applets (pequeños programas que se insertan en una página HTML) y se ejecutan en el ordenador local. Por entonces aparece Mosaic y la World Wide Web. es público.0 INTRODUCCIÓN. con un Sistema Operativo eficiente (SunOS) y un lenguaje de desarrollo denominado Oak (roble). añadiéndosele numerosas clases y funcionalidad para TCP/IP. además. con relación a alternativas similares. No se sabe si en un futuro seguirá siéndolo. tras lo cual el grupo se disolvió. Después de la disolución del grupo de trabajo.2 ¿Qué es Java? Java es un lenguaje de desarrollo de propósito general.3 ¿Qué lo hace distinto de los demás lenguajes? Una de las características más importantes es que los programas “ejecutables”. No es un acrónimo. De esta forma. concediéndose licencias a cualquiera sin ningún problema. año en el que Sun creó un grupo de trabajo. rapidez. son independientes de la arquitectura.

1 ¿Qué se puede programar con Java? Si tenía preconcebida la idea de que con Java sólo se programan applets para páginas web.2 ¿Es fácil de aprender? Para el colectivo de programadores que conocen la programación orientada a objetos. Aprovecha características de la mayoría de los lenguajes modernos evitando sus inconvenientes. Pequeñas aplicaciones que se ejecutan en un documento HTML. En particular los del C++. NO tiene punteros manejables por el programador. Para los programadores en C++ también es sencillo el cambio.3. y después de algún tiempo trabajando con Java. para aquellos que las desconocen. También. Es un lenguaje bien estructurado. aunque los maneja interna y transparentemente. y la facilidad y naturalidad del lenguaje Java.3. además. 1. Como con cualquier otro lenguaje de propósito general. siempre y cuando el navegador soporte Java. se han descubierto. Tiene una gran funcionalidad gracias a sus librerías (clases). “agujeros” en la seguridad3 de Java.3 Características del lenguaje. de lo contrario. está completamente equivocado. y sin esfuerzo. ya que Java impide “hacer cosas extrañas” y. un programador que está aprendiendo puede sentir la tentación de “volver” a lo que conoce (la programación tradicional). puede programarse en él cualquier cosa: Aplicaciones independientes. ya que la sintaxis es prácticamente la misma que en este lenguaje. Es fácil de aprender y está bien estructurado. Puede controlarse su seguridad frente al acceso a recursos del sistema y es capaz de gestionar permisos y criptografía. este lenguaje es ideal para aprender todos sus conceptos. A medida que se va aprendiendo. y posteriormente subsanado. 10 . Las aplicaciones son fiables. se va fomentando en el programador. Esto es bastante conveniente. aplicaciones cliente/servidor. Funciona perfectamente en red. Es intrínsecamente orientado a objetos. aplicaciones distribuidas en redes locales y en Internet. Aunque al igual que ha ocurrido con otras tecnologías y aplicaciones. En realidad. como ocurre con otros lenguajes de programación. según Sun. un buen estilo de programación orientada a objetos. sin punteros y sin necesidad de tener que controlar la asignación de memoria a estructuras de datos u objetos. Applets. 1. éste va atrapando a quien se acerca a él.Se pueden escribir aplicaciones para intraredes.3. ya que en cada paso de su aprendizaje se va comprobando que las cosas se hacen en la forma natural de hacerlas. sin sorpresas ni comportamientos extraños de los programas. hay pocos programadores que no lo consideren como “su favorito”. Ya que Java es un lenguaje de propósito general. Para todo aquel que no conozca la programación orientada a objetos. no permite “abandonar” la programación orientada a objetos. A medida que se van comprobando las ventajas de la programación orientada a objetos. como ocurre con los navegadores HotJava y las últimas versiones de Netscape y el explorador de Internet de Microsoft. 1. la seguridad frente a virus a través de redes locales e Internet está garantizada. no puede ser de otra forma. el cambio a Java puede ser realmente sencillo.

¿El lenguaje es Compilado o Interpretado? Ni una cosa ni la otra. Una vez “compilado” el programa. limpio y práctico. Genera aplicaciones con pocos errores posibles. Esta JVM se encarga de leer los bytecodes y traducirlos a instrucciones ejecutables directamente en un determinado microprocesador.El manejo de la memoria no es un problema. Que el programa deba ser “interpretado” no hace que sea poco eficiente en cuanto a velocidad. es realmente sencillo aprender Java. no necesitaba ser compatible con versiones anteriores de ningún lenguaje como ocurre con C++ y C. es necesario un “intérprete”. De esta forma. A pesar de que puede considerarse como una evolución del C++ no acarrea los inconvenientes del mismo. necesita de un proceso previo de compilación. ya que la interpretación se hace prácticamente al nivel de código máquina. es decir. El lenguaje Java puede considerarse como una evolución del C++. Incorpora Multi-Threading (para permitir la ejecución de tareas concurrentes dentro de un mismo programa). Gracias a que fue diseñado “partiendo de cero” ha conseguido convertirse en un lenguaje orientado a objetos puro. por lo que en este libro se hará referencia a dicho lenguaje frecuentemente. Para ejecutarlo. Aunque estrictamente hablando es interpretado. ya que Java fue diseñado “partiendo de cero”. de una forma bastante eficiente. La sintaxis es parecida a la de este lenguaje. se crea un fichero que almacena lo que se denomina bytecodes o j_code (pseudocódigo prácticamente al nivel de código máquina). la JVM (Java Virtual Machine) máquina virtual Java. es posible compilar el programa en una estación UNIX y ejecutarlo en otra con Windows95 utilizando la máquina virtual Java para Windows95. la gestiona el propio lenguaje y no el programador. una vez superado el aprendizaje de la programación orientada a objetos. No permite programar mediante otra técnica que no sea la programación orientada a objetos (POO en adelante) y. Por ejemplo. es 11 .

puede ser aminorada por los compiladores Just-InTime (JIT). Esta deficiencia en cuanto a la velocidad.mucho más rápido que cualquier otro programa interpretado como por ejemplo Visual Basic. La máquina virtual Java es la idea revolucionaria 4 del lenguaje.4 La Máquina Virtual Java (JVM). el lenguaje contiene estructuras para la detección de excepciones (errores de ejecución previstos) y permite obligar al programador a escribir código fiable mediante la declaración de excepciones posibles para una determinada clase reutilizable. 1. El lenguaje Java es robusto. Además. como Netscape o Internet Explorer. principalmente porque la gestión de memoria y punteros es realizada por el propio lenguaje y no por el programador. Un compilador JIT transforma los bytecodes de un programa o un applet en código nativo de la plataforma donde se ejecuta. por lo que es más rápido. Bien es sabido que la mayoría de los errores en las aplicaciones vienen producidos por fallos en la gestión de punteros o la asignación y liberación de memoria. Las aplicaciones creadas en este lenguaje son susceptibles de contener pocos errores. Suelen ser incorporados por los navegadores. Es la entidad que proporciona la independencia de plataforma para los programas Java “compilados” en byte-code. 12 . aunque es más lento que el mismo programa escrito en C++.

com http://www. que consiste.Un mismo programa fuente compilado en distintas plataformas o sistemas operativos. No dispone de un entorno de desarrollo integrado (IDE). 1.exe 1.5 El entorno de desarrollo JDK.exe El generador de archivos fuentes y de cabecera (. Su sintaxis es la de C++ “simplificada”.1 Simple Es un lenguaje sencillo de aprender. televisores. Los creadores de Java partieron de la sintaxis de C++ y trataron de eliminar de este todo lo que resultase complicado o fuente de errores en este lenguaje.exe El visualizador de applets: appletviewer. Esta JVM se carga en memoria y va traduciendo “al vuelo”. que nos ayudarán a ver para que tipo de problemas está pensado Java: 1. en un compilador y un intérprete (JVM) para la línea de comandos. los byte-codes a código máquina. creando toda la estructura de directorios. La JVM no ocupa mucho espacio en memoria. pero es suficiente para aprender el lenguaje y desarrollar pequeñas aplicaciones.c y .exe y javaw.h) para clases nativas en C: javah. básicamente.exe Un desensamblador de clases: javap. 13 .5. piénsese que fue diseñada para poder ejecutarse sobre pequeños electrodomésticos como teléfonos. ya que se supone que el compilador de Java traduce el fichero fuente a código ejecutable por una máquina que únicamente existe en forma virtual (aunque se trabaja en la construcción de microprocesadores que ejecuten directamente el byte-code). Esto es lógico.javasoft.1 ¿Dónde conseguirlo? El Kit de desarrollo puede obtenerse en las direcciones siguientes: http://www. etc. genera el mismo fichero en byte-code.exe El intérprete: java.exe El depurador: jdb. Existe una versión distinta de esta JVM para cada plataforma. si un mismo programa en byte-code puede ser ejecutado en distintas plataformas es porque existe un traductor de ese byte-code a código nativo de la máquina sobre la que se ejecuta. Evidentemente.sun. La herramienta básica para empezar a desarrollar aplicaciones o applets en Java es el JDK (Java Developer’s Kit) o Kit de Desarrollo Java.6 CARACTERÍSTICAS DE JAVA A continuación haremos una pequeña redacción de las características del lenguaje.com El entorno para Windows está formado por un fichero ejecutable que realiza la instalación. Esta tarea es realizada por la JVM. 1. El kit contiene básicamente: El compilador: javac.6.exe El generador de documentación: javadoc.

1. si bien es cierto que los avances en las máquinas virtuales remedian cada vez más estas decisiones de diseño.6. con lo que se evita la sobrecarga de trabajo asociada a la interpretación del bytecode. 1. Java lo hace siempre en little edian para evitar confusiones. que no precisa de la máquina virtual para ser ejecutado. En general no permite realizar cualquier acción que pudiera dañar la máquina o violar la intimidad del que visita la página web. 1. Mac o Windows. mientas que bajo Windows lo hace en big endian. 1. Java garantiza que ningún Applet puede escribir o leer de nuestro disco o mandar información del usuario que accede a la página a través de la red (como.7 Arquitectura Neutral El código generado por el compilador Java es independiente de la arquitectura: podría ejecutarse en un entorno UNIX.3 Distribuido Java está muy orientado al trabajo en red. Así mismo C++ bajo UNIX almacena los datos en formato little endian.6. en Java todo.6.) es un objeto. Por otro lado la programación gráfica empleando las librerías Swing es más lenta que el uso de componentes nativos en las interfaces de usuario.. (ej: if(a=b) then . Esto permite que los Applets de una web pueda ejecutarlos cualquier máquina que se conecte a ella independientemente de que sistema operativo emplee (siempre y cuando el ordenador en cuestión tenga instalada una máquina virtual de Java).1. sino que este se ejecuta mediante una máquina virtual.. puede tener un tamaño de 16. En general en Java se ha sacrificado el rendimiento para facilitar la programación y sobre todo para conseguir la característica de neutralidad arquitectural.. Esto es así gracias al uso de compiladores just in time. a excepción de los tipos fundamentales de variables (int. En éste un entero. y guardan el resultado de dicha conversión.6.8 Rendimiento medio Actualmente la velocidad de procesado del código Java es semejante a la de C++.5 Seguro Sobre todo un tipo de desarrollo: los Applet. No obstante por norma general el programa Java consume bastante más memoria que el programa C++.2 Orientado a Objetos Posiblemente sea el lenguaje más orientado a objetos de todos los existentes. 32 o más bits. 14 . sino que además debe simular un sistema operativo y hardware virtuales (la máquina virtual). Esto no ocurre así en C++. todas las implementaciones de Java siguen los mismos estándares en cuanto a tamaño y almacenamiento de los datos. Por otro lado el uso de estos protocolos es bastante sencillo comparandolo con otros lenguajes que los soportan. siendo lo única limitación que el entero sea mayor que un short y menor que un long int. ya que no sólo ha de cargar en memoria los recursos necesario para la ejecución del programa. compiladores que traduce los bytecodes de Java en código para una determinada CPU. El motivo de esto es que el que realmente ejecuta el código generado por el compilador no es el procesador del ordenador directamente.6. por ejemplo. hay ciertos pruebas estándares de comparación (benchmarks) en las que Java gana a C++ y viceversa. por ejemplo. 1. long. por ejemplo.. volviéndolo a llamar en caso de volverlo a necesitar.6.4 Robusto El compilador Java detecta muchos errores que otros compiladores solo detectarían en tiempo de ejecución o incluso nunca. HTTP y FTP. el compilador Java no nos dejaría compilar este código.6 Portable En Java no hay aspectos dependientes de la implementación. char.6. UDP. la dirección de correo electrónico). Estos son programas diseñados para ser ejecutados en una página web. 1. soportando protocolos como TCP/IP.

2. Un objeto es una unidad que contiene datos y las funciones que operan sobre esos datos. colas. Gráficamente: 15 . 2. Pueden heredar propiedades de otros objetos.0 CONCEPTOS DE P. sin necesidad del uso de de librerías específicas (como es el caso de C++). Esto le permite además que cada Thread de una aplicación java pueda correr en una CPU distinta. si la aplicación se ejecuta en una máquina que posee varias CPU.1 Características de los Objetos Se agrupan en tipos denominados clases. la carga entre varias CPU. Soportan ocultación de datos.2 ¿Qué es un objeto? Un objeto es una colección de datos. Contienen datos internos que definen su estado actual. Las aplicaciones de C++ no son capaces de distribuir. Los datos y las funciones se encapsulan en una única entidad: objeto.6. Ejemplo: listas.2.1. 2. Tienen métodos que definen su comportamiento.9 Multithread Soporta de modo nativo los threads. de modo transparente para el programador. utilizadas para operar sobre esos datos. Pueden comunicarse con otros objetos enviando o pasando mensajes. junto con las funciones asociadas. 2. Los objetos son como los tipos abstractos de datos. encapsulación (o encapsulamiento) y polimorfismo junto con los conceptos de objetos.1 ¿Qué es p. métodos y mensajes.2 Definición de objetos. Encapsulación (encapsulamiento) de datos y ocultación de datos.O? Técnica de programación que utiliza objetos como bloque esencial de construcción. etc.O.O. Un tipo abstracto de datos es un tipo de dato definido por el programador junto con un conjunto de operaciones que se pueden realizar sobre ellos.2. clases.O 2. La potencia real de los objetos reside en las propiedades que soportan: herencia.

ejecutando uno de sus métodos. 2. • Instancia de clase = objeto 2. • Además de las características compartidas con otros miembros de la clase.4 Mensaje • Un mensaje es simplemente la petición de un objeto a otro objeto para que ése se comporte de una determinada manera. • Paso de mensajes: invocación o llamada de un método de un objeto. • Son como plantillas o modelos. cada subclase tiene sus propias características particulares.5 Herencia • Es la propiedad que permite a los objetos construirse a partir de otros objetos.3 CLASES • Una clase es un tipo definido por el usuario que determina las estructuras de datos y las operaciones asociadas con ese tipo. se crea una instancia de clase.2. • Ejemplo: • El principio de este tipo de división es que cada subclase comparte características comunes con la clase de la que se deriva. • Cuando se construye un objeto de una clase. 16 .

flotantes. • Ejemplo: Operación sumar. se puede definir la operación de sumar dos cadenas: concatenación. el cual difiere de una figura a otra. • También se puede aplicar a la propiedad que poseen algunas operaciones de tener un comportamiento diferente dependiendo del objeto (o tipo de dato) sobre el que se aplican. • Polimorfismo es la capacidad del código de un programa para ser utilizado con diferentes tipos de datos u objetos. • La herencia impone una relación jerárquica entre clases en la cual una clase hija hereda de su clase padre. • Herencia múltiple: la clase recibe propiedades de mas de una clase base. O además. Cada objeto reacciona a este mensaje haciendo el cálculo correspondiente de la superficie. 17 .• La herencia permite definir nuevas clases a partir de clases ya existentes. • En un lenguaje de programación el operador + representa la suma de dos números ( x + y ) de diferentes tipos: enteros. • Herencia simple: la clase solo puede recibir características de otra clase base. 2.6 Polimorfismo • Polimorfismo: significa la cualidad de tener más de una forma. • De modo similar: suponiendo un número de figuras geométricas que responden todas al mensaje Calcular _ superficie.

• Las funciones polimórficas son aquellas funciones que pueden evaluarse y/o ser aplicadas a diferentes tipos de datos de forma indistinta. a otras partes del programa u otros objetos. 3. El cuerpo de las clases comienza con una llave abierta({) y termina con una llave cerrada (}). como mínimo. no son accesibles fuera del mismo objeto. Para que un programa se pueda ejecutar.7 Encapsulacion El encapsulamiento consiste en la propiedad que tienen los objetos de ocultar sus atributos. e incluso los métodos. debe contener una clase que tenga un método main con la siguiente declaración: public static void main( String args [] ) 18 . •Los tipos polimórficos. un programa estará formado por uno o varios ficheros fuente y en cada uno de ellos habrá definida una o varias clases. En un fichero fuente puede declararse una o más clases y tendrá un aspecto similar a este: class Clase1 { … } class Clase2 { … } … class ClaseN { … } Una clase está formada por una parte correspondiente a la declaración. pero sí que puede asegurarse que la misma contendrá. Dentro del cuerpo de la clase se declaran los atributos y los métodos de la clase. Así nacen los conceptos de funciones polimórficas y tipos polimórficos. Por esta razón. la palabra reservada class y el nombre que recibe la clase. por su parte. 2. son aquellos tipos de datos que contienen al menos un elemento cuyo tipo no está especificado.• El concepto de polimorfismo se puede aplicar tanto a funciones como a tipos de datos. y otra correspondiente al cuerpo de la misma: Declaración de clase { Cuerpo de clase } En la plantilla anterior se ha simplificado el aspecto de la Declaración de clase. El lenguaje obliga a la programación orientada a objetos y no permite la posibilidad de programar mediante ninguna otra técnica que no sea ésta. En Java. La forma natural de construir una clase es la de definir una serie de atributos que. en general.0 VISIÓN GENERAL Y ELEMENTOS BÁSICOS DEL LENGUAJE. prácticamente todo son clases (objetos). sino que únicamente pueden modificarse a través de los métodos que son definidos como accesibles desde el exterior de esa clase.

La extensión del mismo debe ser . que es descendiente. Entre las llaves de la clase Hola. } } El lenguaje Java. al igual que C. Las llaves no sirven únicamente para marcar el inicio y el fin de una clase.java (ATENCIÓN: Es importante que tenga el mismo nombre que la clase “Hola”. hay que teclear: javac Hola. class Hola { public static void main(String args[]) { System. Todo lo que se encuentre entre la llave abierta ( { ) y la llave cerrada ( } ) pertenece a la clase Hola. se estará en un punto bastante cercano a los conocimientos básicos necesarios para entenderlos. Este ejemplo habrá que crearlo mediante un editor cualquiera y guardar el fichero con el nombre Hola.println("Hola.java Para compilar el programa. En el ejemplo existen. vamos a ver qué estructura debería tener el típico programa con el que se empieza en cualquier lenguaje de programación y que proporciona una primera visión de la sintaxis del lenguaje y que comienza a transmitir una serie de sentimientos de aceptación o de rechazo en el programador. El programa simplemente mostrará en pantalla el mensaje “hola. únicamente tiene un método: main. No se pretende que. aunque el sistema operativo empleado no haga esta distinción. También hay que comentar que en el nombre del fichero fuente también se hace distinción entre mayúsculas y minúsculas a la hora de compilarlo.class u Hola.java El resultado de la ejecución será la visualización en pantalla del mensaje: Hola. este es mi primer programa Explicación del programa Hola.1 Mi primer programa. Se utilizan para marcar principio y final de bloques de código y se interpretan mediante el método LIFO (Last In First Out) donde el último en entrar es el primero en salir.3. mundo” y terminará. contiene muchos de los conceptos de la programación orientada a objetos en Java. pero sí que puede afirmarse que una vez comprendida y asimilada su filosofía. de la clase Object. otras llaves abierta y cerrada dentro del método main(). al no indicar nosotros que herede de otra clase. En nuestro ejemplo. distinguiendo entre mayúsculas y minúsculas).java El compilador creará un fichero que se llama Hola. se declaran los atributos y los métodos de la clase. este es mi primer programa"). se aprendan y comprendan la totalidad de los aspectos de la POO y la sintaxis del Java. La primera línea del programa declara una clase llamada Hola. 19 . En primer lugar.java línea a línea: Este simple programa. además de las llaves abierta y cerrada de la clase.out. a partir del mismo. Que se interpreten mediante el método LIFO significa que la llave cerrada ( } ) del método main() parentiza el bloque abierto por la última llave ( { ) antes de ésta. distingue entre mayúsculas y minúsculas.class que contiene el código bytecode (“pseudoejecutable”) Para ejecutarlo: java Hola Se escribe únicamente el nombre de la clase Hola y no Hola. a pesar de no ser muy extenso. por lo que es importante transcribirlo literalmente.

out. Únicamente sirven para documentar. Este método pertenece al atributo out. cabe mencionar que esta clase es static (no hemos declarado ningún objeto de la clase System). un vector de strings. Se pueden compilar clases que no posean método main(). por tanto. pero el intérprete Java no podrá ejecutarlas inicialmente. Como curiosidad (de momento). static: indica que la clase no necesita ser instanciada para poder utilizar el método al que califica. void: indica que la función main no devuelve ningún valor. (No se crea ninguna instancia u objeto de la clase Hola). También indica que el método es el mismo para todas las instancias que pudieran crearse.2 Comentarios. pero una vez conocidos y asimilados los conceptos de la POO (Programación Orientada a Objetos) el programa es bastante sencillo y lógico. este es mi primer programa"). puede ser llamado desde otras clases. por tanto. y. Para aquellos que conozcan C++ pensarán que es bastante parecido a lo que habrían escrito en su “lenguaje favorito”. 3. un String) y después realizar un retorno de carro y nueva línea. Hay una regla sencilla que nunca falla: El método main() siempre se declara de la misma forma: public static void main(String args[]) La instrucción que realmente realiza el trabajo efectivo de nuestro programa es la siguiente: System. Veremos en posteriores capítulos que la forma de crear los applets es distinta y no necesita declarar este método. como parámetro. Declaración del método main(): public: indica que el método main() es público y. ¿Un poco complicado para simplemente mostrar un mensaje en pantalla? Es posible que sí lo sea para aquellos que aún no conocen la programación orientada a objetos. encargado de mostrar un valor a través de la salida estándar (en nuestro caso. aunque sí pueden ejecutarse si son llamadas desde otro método en ejecución. Sirven para aumentar la facilidad de comprensión del código y para recordar ciertas cosas sobre el mismo. Los comentarios en los programas fuente son muy importantes en cualquier lenguaje. Ejemplo: /* Esto es un comentario que 20 . Son porciones del programa fuente que no serán compiladas. no ocuparán espacio en el fichero “ejecutable”. Si no se han comprendido muy bien todos estos conceptos no importa. Este atributo se encuentra incluido dentro de la clase System. no se utilice.Todo programa independiente escrito en Java empieza a ejecutarse(como en C) a partir del método main(). Si un comentario debe ocupar más de una línea. Este colectivo comprobará que es mucho más fácil que C y tiene algunas ventajas. hay que anteponerle /* y al final */. aunque como es nuestro caso.println("hola. Este línea indica que se va a ejecutar el método println(). El método main debe aceptar siempre. de momento. que contendrá los posibles argumentos que se le pasen al programa en la línea de comandos. Todo método main() debe ser público para poder ejecutarse desde el intérprete Java (JVM).

println(“Adiós”). } No puede ponerse código después de un comentario introducido por // en la misma línea. su formato. ya que desde la aparición de las dos barras inclinadas // hasta el final de la línea es considerado como comentario e ignorado por el compilador. datos) que actúan y sobre las que se actúa. basta con poner dos barras inclinadas: // Ejemplo: for (i=0.3. 21 . los caracteres.3 Variables y Tipos de Datos Las variables son las partes importantes de un lenguaje de programación: ellas son las entidades (valores. En Java tenemos los arrays. Existe otro tipo de comentario que sirve para generar documentación automáticamente en formato HTML mediante la herramienta javadoc . las clases y los interfaces como tipos de datos referenciados.out. etc. Existen dos categorias de datos principales en el lenguaje Java: los tipos primitivos y los tipos referenciados. Los tipos primitivos contienen un sólo valor e incluyen los tipos como los enteros. Una declaración de variable siempre contiene dos componentes. su tamaño y una breve descripción de cada uno: Los tipos referenciados se llaman así porque el valor de una variable de referencia es una referencia (un puntero) hacia el valor real.. El tipo de la variable determina los valores que la variable puede contener y las operaciones que se pueden realizar con ella.ocupa tres líneas */ Si el comentario que se desea escribir es de una sola línea. 3..i++) // comentario de bucle { System.1 Tipos de Variables Todas las variables en el lenguaje Java deben tener un tipo de dato. 3. el tipo de la variable y su nombre: tipoVariable nombre. La tabla siguiente muestra todos los tipos primitivos soportados por el lenguaje Java. i<20. coma flotante.

Hay ciertas excepciones a la norma aquí descrita: Java solo tiene dos tipos de operadores enteros: uno que aplica para operar datos de tipo long. Si una variable está compuesta de más de una palabra. esta ha de ser.long <. el Ruso o el Hebreo. por lo que el resultado de dicha operación será un int siempre. De este modo cuando operemos un byte con un byte. 2. Si es de rango superior no habrá problemas. -Si cualquier operando es float y no hay ningún double todos se convertirán a float.int <. Esto es importante para que los programadores pueden escribir código en su lenguaje nativo. -Si cualquier operando es long y no hay datos reales todos se convertirán en long. Del mismo modo estas normas se extenderán para int. no deben tener el mismo nombre que otras variables cuyas declaraciones aparezcan en el mismo ámbito. los nombres de variables empiezan por un letra minúscula. short y byte. Este tipo de operación (almacenar el contenido de una variable de jerarquía superior en una de jerarquía inferior) se denomina cast. Veamos una ejemplo para comprender su sintaxis: class Cast { public static void main(String[] args) { int i = 9. al menos. en Java. Debe ser un identificador legal de Java comprendido en una serie de caracteres Unicode. arriesgándonos a perder información en el cambio. Estas conversiones sólo nos preocuparán a la hora de mirar en que tipo de variable guardamos el resultado de la operación. Unicode es un sistema de codificación que soporta texto escrito en distintos lenguajes humanos. La regla número 3 implica que podría existir el mismo nombre en otra variable que aparezca en un ámbito diferente. Un nombre de variable Java: 1. los nombres de las variables empiezan con una letra minúscula (los nombres de las clases empiezan con una letra mayúscula). 22 .3. como 'nombreDato' las palabras se ponen juntas y cada palabra después de la primera empieza con una letra mayúscula. No puede ser el mismo que una palabra clave o el nombre de un valor booleano (true or false) 3.k. así. y otro que emplea para operar datos de tipo int. Por convención.3 CONVERSIÓN ENTRE TIPOS NUMÉRICOS Las normas de conversión entre tipos numéricos son las habituales en un lenguaje de programación: si en una operación se involucran varios datos numéricos de distintos tipos todos ellos se convierten al tipo de dato que permite una mayor precisión y rango de representación numérica.short <byte.float <.168 caracteres. por ejemplo: -Si cualquier operando es double todos se convertirán en double. 3.Unicode perminte la codificación de 34. el Griego. Es posible convertir un dato de jerarquía “superior” a uno con jerarquía “inferior”. La “jerarquía” en las conversiones de mayor a menor es: double <. de una jerarquía mayor o igual a la jerarquía de la máxima variable involucrada en la operación.3. Esto le permite utilizar en sus programas Java varios alfabetos como el Japonés. un short con un short o un short con un byte Java empleará para dicha operación el operador de los datos tipo int. Por convención.2 Nombres de Variables Un programa se refiere al valor de una variable por su nombre.

. Se dice que una operación evalúa su resultado. System. En todos los números enteros y de coma flotante. relacionales y condicionales.incluyendo + (suma).3F.out.4. es decir aparecen entre los dos operandos: op1 operator op2 Además de realizar una operación también devuelve un valor.4 Operadores de Java Los operadores realizan algunas funciones en uno o dos operandos.3. System. Es muy útil dividir los operadores Java en las siguientes categorías: aritméticos. / (división).println("i: "+i + " j: " +j). 3.println("m: "+m). daría error al compilar. j = k.out. El valor y su tipo dependen del tipo del operador y del tipo de sus operandos.out. float m = 2. La notación de prefijo significa que el operador aparece antes de su operando: operador operando La notación de sufijo significa que el operador aparece después de su operando: operando operador Todos los operadores binarios de Java tienen la misma notación. los operadores aritméticos (realizan las operaciones de aritmética básica como la suma o la resta) devuelven números. Los operadores que requieren dos operandos se llaman operadores binarios. k = (int)j. Por ejemplo.(resta). * (multiplicación).println("j: " + j + " k: " +k). y % (módulo). El tipo de datos devuelto por los operadores aritméticos depende del tipo de sus operandos: si sumas dos enteros.out.println("j: " + j + " k: " +k). obtendrás un entero.//no necesita cast System.float j = 47. el resultado típico de las operaciones aritméticas.9F. puedes utilizar este código Java para sumar dos números: sumaEsto + aEsto O este código para calcular el resto de una división: divideEsto % porEsto 23 . //float m = 2. } } 3. lógicos y de desplazamiento y de asignación. //empleo de un cast System.1 Operadores Aritméticos El lenguaje Java soporta varios operadores aritméticos . Por ejemplo. Los operadores que requieren un operador se llaman operadores unarios. ++ es un operador unario que incrementa el valor su operando en uno. El operador = es un operador binario que asigna un valor del operando derecho al operando izquierdo. Por ejemplo. Los operadores unarios en Java pueden utilizar la notación de prefijo o de sufijo.

prt("i : " + i). primero //incrementa y luego imprime por consola prt("i++ : " + i++). prt("i : " + i). prt("i : " + i). Invocando a prt podremos //imprimir por consola la cadena de caracteres que le pasemos static void prt(String s) { System. // Pre-decremento.: " + i--).println(s). primero //decrementa i y luego lo imprime por consola prt("i-. // Post-decremento.out.que decrementa en uno el valor de su operando. primero imprime //i por consola y luego de decrementa. Ejemplo: class Incremento{ public static void main(String[] args) { int i = 1.//i por lo tanto vale 3 prt("--i : " + --i).Esta tabla sumariza todas las operaciones aritméticas binarias en Java: Operador Uso + op1 + op2 op1 .tienen versiones unarias que seleccionan el signo del operando: Además. ++ que incrementa en uno su operando. // Pre-incremento. y -.op2 * op1 * op2 / op1 / op2 % op1 % op2 Descripción Suma op1 y op2 Resta op2 de op1 Multiplica op1 y op2 Divide op1 por op2 Obtiene el resto de dividir op1 por op2 Nota: El lenguaje Java extiende la definición del operador + para incluir la concatenación de cadenas. // Post-incremento. existen dos operadores de atajos aritméticos.//Ahora i vale 1 } //esto nos ahorrara teclear. prt("++i : " + ++i). Los operadores + y . } } 24 . primero imprime //“2” por consola y luego incrementa i.

Así no se llamará a System. en esta situación se puede determinar el valor de && sin evaluar el operador de la derecha.4. el segundo operando de un operador relacional no será evaluado. la parte izquierda del operando de && evalúa a false.read() y no se leerá un carácter de la entrada estándar. En un caso como este.esto es. Esta tabla sumariza los operadores relacionales de Java: Frecuentemente los operadores relacionales se utilizan con otro juego de operadores. Java no evalúa el operando de la derecha. Uno de estos operadores es && que realiza la operación Y booleana .in.3 Operadores de Desplazamiento Los operadores de desplazamiento permiten realizar una manipulación de los bits de los datos.read() != -1)) Si count es menor que NUM_ENTRIES. Por eso. para construir expresiones de decisión más complejas. El operador && sólo devuelve true si los dos operandos son verdaderos. para determinar si el índice es mayor que 0 o menor que NUM_ENTRIES (que se ha definido préviamente como un valor constante): 0 < index && index < NUM_ENTRIES Observa que en algunas situaciones.in. Por ejemplo. La siguiente línea de código utiliza esta técnica para determinar si un índice de un array está entre dos límites. los operadores condicionales.2 Operadores Relacionales y Condicionales Los valores relacionales comparan dos valores y determinan la relación entre ellos. Similarmente. Por ejemplo puedes utilizar dos operadores relacionales diferentes junto con && para determinar si ambas relaciones son ciertas.4.3. != devuelve true si los dos operandos son distintos. Aquí tienes tres operadores condicionales: El operador & se puede utilizar como un sinónimo de && si ambos operadores son booleanos. Esta tabla sumariza los operadores lógicos y de desplazamiento disponibles en el lenguaje Java: 25 . | es un sinonimo de || si ambos operandos son booleanos . 3. Consideremos esta sentencia: ((count > NUM_ENTRIES) && (System.

Los tres operadores de desplazamiento simplemente desplazan los bits del operando de la izquierda el número de posiciones indicadas por el operador de la derecha. Por ejemplo: 13 >> 1 Desplaza los bits del entero 13 una posición a la derecha. La representación binaria del número 13 es 1101. La función "and" activa los bits resultantes cuando los bits de los dos operandos son 1. la representación binaria de 12 es 1100 y la de 13 es 1101. Si quieres evaluar los valores 12 "and" 13: 12 & 13 El resultado de esta operación es 12. Los desplazamientos ocurren en la dirección indicada por el propio operador. puedes ver que los dos bits de mayor peso (los dos bits situados más a la izquierda de cada número) son 1 así el bit resultante de cada uno es 1. El resultado de la operación de desplazamiento es 110 o el 6 decimal. La función "y" activa el bit resultante si los dos operandos son 1. Los otros operadores realizan las funciones lógicas para cada uno de los pares de bits de cada operando. Observe que el bit situado más a la derecha desaparece. O inclusiva significa que si uno de los dos operandos es 1 el resultado es 1. de otra forma el resultado es 0. ¿Por qué? Bien. Un desplazamiento a la izquierda es equivalente a multiplicar por dos. Entonces si colocas en línea los dos operandos y realizas la función "and". Los dos bits de menor peso se evalúan a 0 porque al menos uno de los dos operandos es 0: 1101 & 1100 -----1100 El operador | realiza la operación O inclusiva y el operador ^ realiza la operación O exclusiva. 26 . Un desplazamiento a la derecha de un bit es equivalente. pero más eficiente que. dividir el operando de la izquierda por dos.

4. las expresiones se utilizan para calcular y asignar valores a las variables y para controlar el flujo de un programa Java. Las dos líneas de código anteriores son equivalentes. 27 .4. Esta tabla lista los operadores de asignación y sus equivalentes: 3. Además del operador de asignación básico. 3. supón que quieres añadir un número a una variable y asignar el resultado dentro de la misma variable. Definición: Una expresión es una serie de variables. operadores y llamadas a métodos (construida de acuerdo a la sintaxis del lenguaje) que evalúa a un valor sencillo. lógicas o de bits y una operación de asignación al mismo tiempo. Entre otras cosas. Puedes ordenar esta sentencia utilizando el operador += así i += 2.4 Operadores de Asignación Puedes utilizar el operador de asignación =.O exclusiva significa que si los dos operandos son diferentes el resultado es 1. de otra forma el resultado es 0: Y finalmente el operador complemento invierte el valor de cada uno de los bites del operando: si el bit del operando es 1 el resultado es 0 y si el bit del operando es 0 el resultado es 1. Específicamente. para asignar un valor a otro. Java proporciona varios operadores de asignación que permiten realizar operaciones aritméticas. como esto: i = i + 2. El trabajo de una expresión se divide en dos partes: realizar los cálculos indicados por los elementos de la expresión y devolver algún valor.5 Expresiones Las expresiones realizan el trabajo de un programa Java.

in. La expresión count++ devuelve un entero porque ++ devuelve un valor del mismo tipo que su operando y count es un entero. esta expresión obtiene un resultado diferente dependiendo de si se realiza primero la suma o la división: x + y / 100 Puedes decirle directamente al compilador de Java cómo quieres que se evalúe una expresión utilizando los paréntesis ( y ). cadenas. en la expresión anterior x + y / 100.in. Por ejemplo. por eso. el orden en que se evalúan los componentes de una expresión compuesta. El valor devuelto por != es true o false dependiendo de la salida de la comparación. por lo tanto. para aclarar la sentencia anterior.read() != -1 utiliza el operador !=. esto no es cierto para todas las expresiones. Los operadores con mayor precedencia se evalúan antes que los operadores con un precedencia relativamente menor. Una expresión de llamada a un método devuelve el valor del método.El tipo del dato devuelto por una expresión depende de los elementos utilizados en la expresión. System.. etc. También habrás podido concluir del ejemplo anterior.read() es un operando válido para != porque devuelve un entero. Como has podido ver. Sin embargo.read() devuelve un entero. La tabla siguiente muestra la precedencia asignada a los operadores de Java. En esta sentencia los operandos son System. el compilador evaluará primero y / 100. no importa el orden en que se evalúe la expresión porque el resultado de la multiplicación es independiente del orden.in. toma la siguiente expresión compuesta: x * y * z En este ejemplo particular. Los operadores con una precedencia más alta se evalúan primero.in. el valor devuelto por System. Por ejemplo.read() y -1. El método System. El operador división tiene una precedencia mayor que el operador suma. él decide basándose en la precedencia asignada a los operadores y otros elementos que se utilizan dentro de una expresión. Así x + y / 100 es equivalente a: x + (y / 100) Para hacer que tu código sea más fácil de leer y de mantener deberías explicar e indicar con paréntesis los operadores que se deben evaluar primero. se podría escribir: (x + y)/ 100.read() != -1 compara dos enteros. Si no le dices explícitamente al compilador el orden en el que quieres que se realicen las operaciones. Los operadores se han listado por orden de precedencia de mayor a menor.in. 28 .read() se ha declarado como un entero. Java te permite construir expresiones compuestas y sentencias a partir de varias expresiones pequeñas siempre que los tipos de datos requeridos por una parte de la expresión correspondan con los tipos de datos de la otra..read() y -1. Por ejemplo. La segunda expresión contenida en la sentencia System.in. La salida es siempre la misma sin importar el orden en que se apliquen las multiplicaciones. Lo operadores con la misma precedencia se evalúan de izquierda a derecha. Por ejemplo. Recuerda que este operador comprueba si los dos operandos son distintos. así el tipo de dato de una expresión de llamada a un método es el mismo tipo de dato que el valor de retorno del método. Otras expresiones devuelven valores booleanos.in. Así System. la expresión System.

//cadena vacía String e = “Hola”. Su sintaxis es: Nombre_String. String. String saluda_pepe = “”. Lo ilustraremos con un ejemplo: String saludo = “hola”. //no inicializado String e =””.2 Subcadenas En la clase String hay un método que permite la extracción de una subcadena de caracteres de otra.5. saludo = saludo + “ “ + n. saluda_pepe = saludo + nombre.5. en su lugar hay una clase. que es la que soporta las distintas operaciones con cadenas de caracteres.substring((int)posición_inicial. 29 . int n = 5. //inicialización y asignación juntas. La definición de un String es: String e . de tal modo que es perfectamente correcto: String saludo = “hola”.5 CADENAS DE CARACTERES En Java no hay un tipo predefinido para cadenas de caracteres.// saluda_pepe toma el valor holaPepe La sencillez de Java en el manejo de cadenas de caracteres llega incluso más allá: si una cadena la intentamos encadenar con otro tipo de variable automáticamente se convierte la otra variable a String.// saludo toma el valor “hola 5” 3. es decir “sumando” cadenas de caracteres obtenemos la concatenación de estas.1 Concatenación La concatenación en Java es increíblemente sencilla: se realiza con el operador +. A continuación veremos algunas operaciones básicas soportadas por la clase String: 3. String nombre = “Pepe”.3.(int)posición_final).

Si alguna vez deseamos realizar algún otro tipo de operación y queremos ver si la soporta Java podemos hacerlo consultando la ayuda on-line de la clase Math.println(s). String saludo = “hola”.Donde posición_inicial y posición_final son respectivamente la posición del primer carácter que se desea extraer y del primer carácter que ya no se desea extraer. String saludo2 ="hola".// subsaludo toma el valor “ho” Puede extraerse un char de una cadena. Devuelve true si son iguales y false si son distintos. //Imprime por consola la subcadena formada por los caracteres //comprendidos entre el caractero 0 de saludo y hasta el //carácter 2. en Java se distingue entre //mayúsculas y minúsculas. Subsaludo = saludo.2)). para ello se emplea el método charAt(posición). por lo que no es necesario crear un objeto de dicha clase.5. Su sintaxis general es: Math.4 Exponenciación En Java a diferencia que en otros lenguajes no existe el operador exponenciación.equals(cadena2). 3. Ejemplo: 30 .metodo(argumentos). siendo posición la posición del carácter que se desea extraer.equals(saludo2)).3 Comparación de cadenas Se empleo otro método de String: equals. String subsaludo = “”.2). Son distintos.substring(0. //Concatena saludo con un espacio en blanco y con el valor de //la variable n prt(saludo +" " + n). El siguiente ejemplo permitirá ilustrar estas operaciones con Strings: class Cadena { public static void main(String[] args) { String saludo = "Hola". prt("saludo == saludo2 "+ saludo.out. Si se desea realizar una operación de exponenciación se deberá invocar el método correspondiente de la clase Math de Java. } static void prt(String s) { System. //Imprime el resultado del test de igualdad entre saludo y //saludo2.lang. Tampoco existen los operadores Seno o Coseno. int n = 5. Estos métodos son estáticos. } } 3.5. sin incluir el último prt(saludo.substring(0. Su sintaxis es: cadena1. En el siguiente código aparecen ejemplos.

i)). Pasemos a ver sus principales tipos. prt("j^i : " + Math.pow(j.Las estructuras de control de flujo de Java son la típicas de cualquier lenguaje de programación.sin(i)). .println(s). En caso contrario se sigue ejecutando ignorando el Grupo de sentencias.1. por lo que supondremos que todos estáis familiarizados con ellas y se explicaran con poco detenimiento. 4. para evitarlo se introducen estructuras de control de flujo. else{ Grupo_n de sentencias} 31 .j=2. If(condicion) { Grupo de sentencias} else{ Grupo2 de sentencias} Si condición toma el valor true se ejecuta Grupo de sentencias. en caso contrario se ejecuta Grupo2 de sentencias. El grupo de sentencias se ejecuta solo si la condición toma un valor true.0 CONTROL DE FLUJO EN JAVA El modo de ejecución de un programa en Java en ausencia de elementos de control de flujo essecuencial. Esto nos permite hace programas muy limitados. If(condicion) { Grupo de sentencias} else if (condicion2){ Grupo2 de sentencias} else if (condicion3){ Grupo3 de sentencias} . //Imprime por consola la cadena de caracteres “Cos i : “ //concatenado con el resultado de calcular el coseno de i prt("Cos i : " + Math. En ambos casos se continúa ejecutando el resto del código.cos(i)). } //esto nos ahorrara teclear static void prt(String s) { System. prt("Sen i : " + Math.class Exponente { public static void main(String[] args) { int i = 45. } } 4.1 SENTENCIAS CONDICIONALES Ejecutan un código u otro en función de que se cumplan o no una determinada condición. .out.1 If then Else Su modo más simple de empleo es: If(condicion) { Grupo de sentencias} Condición es una valor tipo boolean. 4. es decir una instrucción se ejecuta detrás de otra y sólo se ejecuta una vez.

Este último else es opcional. case valor4 : Grupo de sentencias4. pero no perfecto.println(test(5.Si condición toma el valor true se ejecuta Grupo de sentencias. break. y así sucesivamente hasta acabarse todas las condiciones. strings. 5)). Además para colmo esta comparación de igualdad sólo admite valores tipo char o cualquier tipo de valores enteros menos long.out. por poner un caso. se le sacaría partido a esta sentencia si aceptase desigualdades). break. System. System.. int b) y que // devolverá -1 si a < b. Si el valor coincide se ejecuta su respectivo grupo de secuencias. else result = 0. // . En ambos casos se continúa ejecutando el resto del código. Ha llegado el momento de justificar la crítica hecha a los creadores de Java. break.. Este tipo de estructura tiene sus posibilidades muy limitadas. case valor5 : Grupo de sentencias5. else if(val < val2) result = -1. case valor2 : Grupo de sentencias2. si condicion2 toma el valor true se ejecuta Grupo2 de sentencias. static int test(int val. } public static void main(String[] args) { //Imprimimos por consola el resultado de realizar unos //cuantos test. no ingún otro tipo de condición (sería fácil pensar ejemplos dónde. break. Prueba de ello es esta sentencia: está tan poco flexible como en C++.. return result. incluída la del default. int val2) { int result = 0. default: statement.println(test(5. Ilustraremos esto con el siguiente ejemplo: class Ejemplo1 { // Método que podremos invovar como test(int a. Expliquemos su sintaxis antes de dar los motivos de esta crítica: switch(selector) { case valor1 : Grupo de sentencias1. System. Si no se encuentra ninguna coincidencia se ejecutan las sentencias de default. case valor3 : Grupo de sentencias3.2 Switch Los creadores de Java trataron de hacer de este lenguaje una versión simplificada y mejorada del lenguaje de C++. if(val > val2) result = +1... 10)).out. Su trabajo fue bastante bueno. +1 si a > b y 0 si a == b... Si no se pusieran los break una vez que se encontrase un valor que coincida con el selector se ejecutarían todos los grupos de sentencias. break. } Se compara el valor de selector con sentencias_n. No podemos comparar contra reales. 5)).1.out. } } 4. 32 . Si no se cumple ninguna se ejecuta Grupo_n de sentencias. ya que en las condiciones sólo se admite la igualdad.println(test(10.

default: //Si no era ninguna de las anteriores imprimimos consonante. break. //Se transforma el número aleatorio entre 97y 97 + 26 en el //carácter correspodiente a su parte entera.out. Ejecutará 100 veces el código que tiene dentro. char c = (char)(Math. i++) { //Math.out. Esto es en muchas ocasiones fuente de errores.2 BUCLES Son instrucciones que nos permiten repetir un bloque de código mientras se cumpla una determinada condición.out.random()*26 será un número real aleatorio entre 0 y //26.print(c + ": ").random() es un métod estático que genera un número real //aleatorio entre 0 y 1. System.2. switch(c) { case 'a': case 'e': case 'i': case 'o': case 'u': //Si el carácter es „a‟. Será un carácter //aleatorio. „o‟ o „u‟ imprimimos //vocal. Al sumarle un carácter.println("vocal"). Su sintaxis es: while(condición){ Grupo de sentencias} Ilustramos su funcionamiento con un ejemplo: 33 . 4. System. de hecho en el ejemplo que empleamos para ilustrar esta sentencia aprovechamos esta característica: class Ejemplo2 { public static void main(String[] args) { //Bucle for. //Math.1 Bucle while Cuando en la ejecución de un código se llega a un bucle while se comprueba si se verifica su condición. „i‟. } } } } 4. Pasemos a ver sus tipos. System.println("consonante"). for(int i = 0. que por la disposición de los caracteres Unicode //será un letra del abecedario.random() * 26 + 'a').También se le podría criticar el hecho de que una vez cumplidas una condición se ejecuten todas las sentencias si no hay instrucciones break que lo impidan. „a‟ el carácter se transforma a //un enteroy se le suma. aunque también hay que reconocer que a veces se le puede sacar partido. i < 100. „e‟. „a‟ = 97. si se verifica se continua ejecutando el código del bucle hasta que esta deje de verificarse.

System.class Ejemplo3 { public static void main(String[] args) { double r = 0. System. }while(condición). por lo que tenemos garantizado que el código se va a ejecutar al menos una vez. c < 128.out. }}} 4. 34 .out.println(r). (int)c es el entero //correspondiente al carácter c.99d). //Lo imprime por consola. } while(r < 0.99d) { //Genera un nuevo r aleatario entre 0 y 1.expresion2. Expresion2 es la condición que se le impone a la variable del bucle y expresion3 indica una operación que se realiza en cada iteración a partir de la primera (en la primera iteración el valor de la variable del bucle es el que se le asigna en expresion1) sobre la variable del bucle.random().2.} Expresion1 es una asignación de un valor a una variable.2.99 sigue ejecutando el cuerpo del bucle. No es necesaria while(r < 0. la variable-condición del bucle. //Mientras que r < 0.expresion3){ Grupo de sentecias. Dependerá del caso concreto si es más conveniente emplear un bucle while o do while. //La d significa double.random().println(r). sólo que aquí la condición va al final del código del bucle. //Idéntico al ejemplo anterior.3 Bucle for Su formato es el siguiente: for(expresion1. La sintaxis de do while es: do { Grupo de sentencias. c++) //Imprime los caracteres correspondientes a los números //enteros comprendidos entre 0 y 128. } } 4. solo que ahora la condición //está al final del bucle.2 Bucle do while Su comportamiento es semejante al bucle while. Obsérvese como el ejemplo anterior implementado mediante un bucle independientemente del valor de r ejecutará al menos una vez el código de su cuerpo: do while class Ejemplo4 { public static void main(String[] args) { double r. r = Math. class Ejemplo5 { public static void main(String[] args) { for( char c = 0. do { r = Math.

35 . } } 4. // Lazo infinito del cual se sale con break: while(true) { i++. El encontrarse una sentencia break en el cuerpo de cualquier bucle detiene la ejecución del cuerpo del bucle y sale de este. //Si I es divisible entre 9 se imprime System. // Salimos del lazo if(i%10 != 0) continue.//Salto a la siguiente iteración System.out. pero sí de una sentencia íntimamente relacionada con estos. Cuando se llama a un procedimiento ( que en POO se denominó método) al encontrarse con una sentencia return se pasa el valor especificado al código que llamó a dicho método y se devuelve el control al código invocador.out.println("valor: " + (int)c +" caracter: " + c). i++) { if(i == 74) break. } int i = 0. int j = i * 27. continuándose ejecutando el código que hay tras el bucle.out. Su misión tiene que ver con el control de flujo: se deja de ejecutar código secuencialmente y se pasa al código que invocó al método. Continue también detiene la ejecución del cuerpo del bucle. // teminamos aqui el bucle //Salto a la siguiente iteración si i no es divisible entre 9 if(i % 9 != 0) continue. sino que se pasa a la siguiente iteración de este. i < 100.4 Break y continue No se tratan de un bucle.println(i). } } } 4. Esta sentencia también se puede usar para forzar la salida del bloque de ejecución de una instrucción condicional (esto ya se vio con switch).println(i). ya que es la sentencia que le permite devolver al método un valor. Podíamos haber esperado ha hablar de métodos para introducir esta sentencia.3 RETURN Sus funciones son las mismas que en C++. pero en esta ocasión no se sale del bucle. En el ejemplo 1 ya se ha ejemplificado su uso.System. Observaremos el funcionamiento de ambos en un mismo ejemplo: class Ejemplo6 { public static void main(String[] args) { for(int i = 0. entre otras cosas.2. if(j == 1269) break. con control de flujo. Esta sentencia también está profundamente relacionada con los métodos. pero hemos decidido introducirla aquí por tener una función relacionada.

reales y char. Por ser desconocida para los demás objetos podemos en cualquier momento modificarla sin que a los demás les importe.0 OBJETOS Y CLASES Como ya hemos comentado Java es un lenguaje totalmente orientado a objetos. C++.. Si analizamos lo que hemos dicho hasta aquí de los objetos veremos que estos parecen tener dos partes bastante diferenciadas: la parte que gestiona los mensajes. y al final hay que juntar todos estos con el programa central que los llama. Object Oriented Programing). varios o ningún dato y nos devuelve un dato a cambio.2 CLASES Y HERENCIA Una clase es la “plantilla” que usamos para crear los objetos. A un objeto no le importa en absoluto como está implementado otro objeto. los trozos de código que se podían emplear en varias ocasiones a lo largo del programa (reusar) se escribían en forma de procedimientos que se invocaban desde el programa. Todos los objetos pertenecen a una determinada clase. totalmente desconocida para los demás objetos (a veces no es así. Un objeto que se crea a partir de una clase se dice que es una instancia de esa clase. En Java todo es un objeto. Si hay que repartir un programa de grandes dimensiones entre varios programadores a cada uno se le asignan unos cuantos objetos. por ejemplo.. que código tiene o deja de tener.5. ¿qué es un objeto? y ¿qué es la programación orientada a objetos?. Pero bien. programación orientada o objetos (en la literatura suele aparecer como OOP. En los años 70 se empezó a imponer con fuerza otro estilo de programación: POO. siendo frecuente encontrar problemas al unir estos trozos de código. 5. Según los códigos se fueron haciendo más grandes y complejos este estilo de programación se hacía más inviable: es difícil programar algo de grandes dimensiones con este estilo de programación. y además cada programador tendrá total libertad para llevarla a cabo como él considere oportuno. La otra parte es el mecanismo por el cual se generan las acciones requeridas por los mensajes el conjunto de variables que se emplean para lograr estas acciones. Un programa era un código que se ejecutaba. y que no podremos cambiar en el futuro sin modificar los demás objetos (sí es posible añadir nuevos métodos para dar nuevas funciones al objetos sin modificar los métodos ya existentes). La única posibilidad de repartir trozos de código relativamente independientes entre programadores son los procedimientos. 5. en principio. que variables usa. sólo le importa a que mensajes es capaz de responder.. independientes entre si. y esta era la única capacidad de reuso de código posible. Aquí simplemente daremos unas nociones muy básicas de programación orientada a objetos que nos permitan empezar a adentrarnos en el mundo de Java. a excepción de los tipos básicos de variables enteras. mucho más que. Un mensaje es la invocación de un método de otro objeto. Aquí un programa no es un código que llama a procedimientos. y en lo único que tendrán que ponerse de acuerdo entre ellos es en los mensajes que se van a pasar. simplificándole además la tarea al programador. la forma en que un programador implemente sus objetos no influye en absoluto en lo que los demás programadores hagan.1 INTRODUCCIÓN En los años 60 la programación se realizaba de un modo “clásico” (no orientado a objetos). que ha de ser conocida por los demás. Esto es así gracias a que los objetos son independientes unos de otros (cuanta mayor sea la independencia entre ellos de mayor calidad serán). Las distintas clases tienen distintas relaciones de herencia entre si: una clase puede 36 . que dialogan entre ellos pasándose mensajes para llegar a resolver el problema en cuestión. pero es lo ideal en un buena OOP). La OOP permite abordar con más posibilidades de éxito y con un menor coste temporal grandes proyectos de software. hay libros enteros escritos sobre objetos y metodologías de programación orientada a objetos sin abordar ningún lenguaje de programación en concreto . Esta segunda parte es. Responder a estas preguntas no es en absoluto trivial. Un método es muy semejante a un procedimiento de la programación clásica: a un método se le pasan uno. aquí un programa es un montón de objetos.

Por motivos de simplicidad y dada la corta duración de este curso ignoraremos la existencia del concepto de package en la explicación de los siguientes conceptos. } } 5.out.println(edad). Sólo podemos tener una clase public por unidad de compilación. en ese caso la clase derivada o clase hija hereda los métodos y variables de la clase de la que se deriva o clase padre. toda referencia al término “package”. } public void get_edad(){ System.out. Declaración de métodos. String nombre. Ejemplo: class Animal{ int edad. nombre_clase_padre es el nombre de la clase padre.println(nombre). nombre_clase es el nombre que le queramos dar a nuestra clase. } public void get_nombre(){ System. Ninguno: La clase es “amistosa”.1 Modificadores de clases public: La clase es pública y por lo tanto accesible para todo el mundo. Será accesible para las demás clases del package. } Los campos que van entre corchetes son optativos. al menos durante este curso. Vamos a continuación a profundizar en todos estos conceptos y a explicar su sintaxis en Java.println("Hola mundo"). de la cual hereda los métodos y variables. Los modificadores indican las posibles propiedades de la clase. Según los parámetros que se le pasen se invocará a uno u otro método: Ejemplo: Modificaremos un poco la clase animal anterior. Veamos que opciones tenemos: 5. 5. En general en lo que al alumno respecta se recomienda ignorar.out. observar que tiene métodos con el mismo nombre: 37 .1.2 Sobrecarga de métodos Java admite lo que se llama sobrecarga de métodos: puede haber varios métodos con el mismo nombre pero a los cuales se les pasan distintos parámetros.2. o haremos breves referencias a este concepto sin dar demasiadas explicaciones.1. final: Indicará que esta clase no puede “tener hijo”. aunque es posible no tener ninguna.derivarse de otra. Por motivos de tiempo no abordaremos en este curso que es un package. En cuanto al contenido del último corchete ya se explicará más adelante su significado. En Java todas las clases tienen como primer padre una misma clase: la clase Object.1 Definición de una clase La forma más general de definición de una clase en Java es: [Modificador] class nombre_clase [extends nombre_clase_padre] [implements interface] { Declaración de variables. sin embargo mientras todas las clases con las que estemos trabajando estén en el mismo directorio pertenecerán al mismo package y por ello serán como si fuesen públicas. public void nace(){ System. Como nunca trabajaremos en varios directorios asumiremos que la ausencia de modificador es equivalente a que la clase sea pública.2.2. abstract: Se trata de una clase de la cual no se puede instanciar ningún objeto. no se puede derivar ninguna clase de ella.

.). } public void nace(){ System.out.1.. public void nace(){ System. } public void get_nombre(){ System.println(nombre +" " +edad).} public void get_nombre(){ System.println("Hola mundo"). nombre = _nombre. } } 5.out. class Animal{ int edad. Como cualquier método.out.println(edad).out. String nombre.out.println(nombre). } public void get_nombre(int i){ System.out..3 Constructores Constructores son métodos cuyo nombre coincide con el nombre de la clase y que nunca devuelven ningún tipo de dato.2. String nombre. Ejemplo: Veamos la clase Animal y sus constructores. } public void get_nombre(int i){ System. Cuando creamos un objeto (ya se verá más adelante como se hace) podemos invocar al constructor que más nos convenga. } public void get_edad(){ System.println(nombre). un constructor admite sobrecarga. Los constructores se emplean para inicializar los valores de los objetos y realizar las operaciones que sean necesarias para la generación de este objeto (crear otros objetos que puedan estar contenidos dentro de este objeto.println("Hola mundo").out.out. no siendo necesario indicar que el tipo de dato devuelto es void. abrir un archivo o una conexión de internet..class Animal{ int edad. } public void get_edad(){ System.println(nombre +" " +edad).println(edad). } } 38 . String _nombre){ //constructor con 2 argumentos edad = _edad. public Animal(){ //constructor por defecto } public Animal(int _edad.

Más adelante se explicará que es esto. static: Estática. sólo pueden acceder a ella las clases hijas de la clase que posee la variable y las que estén en el mismo package. puede ser accedida por cualquier miembro del package. esta variable es la misma para todas las instancias de una clase. todas comparten ese dato. Math. 5. por lo tanto. } 39 .2.1 Modificadores de variables public: Pública.5. protected: Protegida. private: Privada. Pueden acceder a ella todas las instancias de la clase (cuando decimos clase nos estamos refiriendo a todas sus posibles instancias) static: Estática. Para nosotros será equivalente a que fuese público. String nombre.2. puede acceder todo el mundo a este método. Podemos heredar de una clase.3 Herencia Cuando en Java indicamos que una clase “extends” otra clase estamos indicando que es una clase hija de esta y que. final: Final. public Animal(){ } public Animal(int _edad. puede acceder todo el mundo a esa variable.cos son dos ejemplos de métodos estáticos. hereda todos sus métodos y variables. 5. Ninguno: Es “amistoso”. Math. Es un método que no se puede “sobrescribir”. Si una instancia lo modifica todas ven dicha modificación. Este es un poderoso mecanismo para la reusabilidad del código.2 Modificadores de un método public: Pública.sin. nombre = _nombre. private: Privada. String _nombre){ edad = _edad. protected: Protegido.2. sólo pueden acceder a ella las clases hijas de la clase que posea el método y las que estén en el mismo package.2 Modificadores de métodos y variables Antes de explicar herencia entre clases comentaremos cuales son los posibles modificadores que pueden tener métodos y variables y su comportamiento: 5. es un método al cual se puede invocar sin crear ningún objeto de dicha clase. Veamos un ejemplo: class Animal{ protected int edad. Desde un método estático sólo podemos invocar otros métodos que también sean estáticos. se trata de un método que no podrá ser cambiado por ninguna clase que herede de la clase donde se definió. nadie salvo la clase misma puede acceder a estas variables. nadie salvo la clase misma puede acceder a estos métodos. por lo cual partimos de su estructura de variables y métodos. puede ser accedida por cualquier miembro del package. y luego añadir lo que necesitemos o modificar lo que no se adapte a nuestros requerimientos. Ninguno: Es “amistosa”. Para nosotros erá equivalente a que fuese pública.2.2.2.

} //Método estático que recibe un objeto de tipo perro e //invoca a su método get_edad() static void get1(Perro dog){ //El método get_edad() no está definido en perro.public void nace(){ System. mes = 1.nombre). anio = 1900.println(nombre).println("Hola mundo"). } public void get_nombre(){ System. } } 5.println(nombre +" " +edad).mes. inicializarlo es darle un valor a estas variables. nombre ="Tobi". } Perro(int edad.out. } public void get_nombre(int i){ System. Para crear un objeto se utiliza el comando new.get_edad(). super(edad.out.out.out. Fecha(){ dia=1.4 Creación y referencia a objetos Aunque ya hemos visto como se crea un objeto vamos a formalizarlo un poco. Veámoslo sobre un ejemplo: class Fecha{ int dia. } public static void main (String[] args){ //Creamos un objeto de tipo perro Perro dog = new Perro(8. Crear el objeto es sinónimo de reservar espacio para sus variables."Bambi").2. String nombre){ //Esta sentencia invoca a un constructor de la clase padre. dog. lo ha //heredado de animal. } public void get_edad(){ System.get1(dog).println(edad). } } public class Perro extends Animal{ Perro(){ //constructor vacio edad = 0. //Invocamos al método estátioco get1 pasándole el objeto // Perro.ano. Un objeto en el ordenador es esencialmente un bloque de memoria con espacio para guardar las variables de dicho objeto. } 40 .

dia = 8. así por ejemplo en el ejemplo anterior un_dia. mes = 1. Una vez creado un objeto será posible acceder a todas sus variables y métodos públicos. nano){ dia= ndia.. El empleo de this ha de ser //siempre en la primera línea dentro del constructor. . ano = nano.5 this Es una variable especial de sólo lectura que proporciona Java.Fecha (int _dia. reservando espacio para sus variables. int _mes. numero_cuenta = a. 41 . Si la variable fuese privada solo podrían acceder a ella sus instancias: class Fecha{ private int dia. Contiene una referencia al objeto en el que se usa dicha variable. Fecha un_dia = new Fecha(8. para acceder a ella tendríamos que hacerlo mediante métodos que nos devolviesen su valor. ano = _anio. ano = 1900.2.nuevo_numero()). int _anio){ dia= _dia. como está sin inicializar apuntara a null..12. Con el segundo inicializamos el objeto al que apunta hoy. 5.mes. mes = nmes. } } De este modo no podríamos acceder a las variables de la clase fecha. } Fecha (int ndia.ano. tomando el objeto hoy el valor 1-1-1900. Con el primer comando hemos creado un puntero que apunta a una variable tipo fecha. nmes. Con esta sentencia creamos una variable que se llama un_dia con valor 8-12-2005.. this(n. Fecha(){ dia=1.2005). A esto se le denomina encapsulación. } } Fecha hoy. A veces es útil que un objeto pueda referenciarse a si mismo: class Cliente{ public Cliente(String n){ //Llamamos al otro constructor. El constructor las inicializará. Esta es la forma correcta de programar OOP: no debemos dejar acceder a las variables de los objetos por otro procedimiento que no sea paso de mensajes entre métodos.. int a){ nombre = n. Cuenta. hoy = new Fecha(). mes = _mes. } public Cliente (String n.

} } class GatoMagico extends Gato { boolean gente_presente.println("Miau").2. String nombre){ //this. public String nombre = "Bob". Sin embargo para no privar a Java de la potencia de la herencia múltiple sus creadores introdujeron un nuevo concepto: el de interface.. esto es. sin embargo los creadores de Java decidieron no implementar la herencia múltiple por considerar que esta añade al código una gran complejidad (lo que hace que muchas veces los programadores que emplean programas que sí la soportan no lleguen a usarla). que ya se ha visto en ejemplos anteriores es diferenciar entre variables locales de un método o constructor y variables del objeto. Veámoslo con un ejemplo: interface Animal1{ public int edad = 10. con dos diferencias: sus métodos están vacíos. } 5. Una interface es formalmente como una clase. 5.out.6 super Del mismo modo que this apunta al objeto actual tenemos otra variable super que apunta a la clase de la cual se deriva nuestra clase : class Gato { void hablar(){ System.. como ya se empleó en un ejemplo.println("Hola"). void hablar(){ if(gente_presente) //Invoca al método sobreescrito de la clase padre super.out. else System.} . this. } Otro posible uso de this. public Animal(int edad.3 INTERFACES En Java no está soportada la herencia múltiple. no hacen nada.edad = variable del objeto perro //edad = variable definida sólo dentro del constructor this. 42 .hablar()..edad =edad. En principio esto pudiera parecer una propiedad interesante que le daría una mayor potencia al lenguaje de programación. } } Uno de los principales usos de super es. no está permitido que una misma clase pueda heredar las propiedades de varias clases padres..nombre=nombre. y a la hora de definirla en vez de emplear la palabra clave “class” se emplea “inteface”. llamar al constructor de la clase padre.

43 . y es obligatorio darles un valor dentro del cuerpo de la interface. void get_nombre(int i). public void nace(). Veámoslo con un ejemplo de una clase que implementa la anterior interface: interface Animal1{ public int edad = 10. } ***************************************************** public class Perro1 implements Animal1{ Perro3(){ get_nombre().out. sólo public.println(nombre +" " +i). se le han de pasar los mismos datos. Para que un método sobrescriba a otro ha de tener el mismo nombre.out.println("hola mundo"). get_nombre(8).out. public void get_nombre().edad = 8. } Cabe preguntarnos cual es el uso de una interface si sus métodos están vacíos. } public void get_nombre(int i){ System. } //Compruébese como si cambiamos el nombre del método a nac() //no compila ya que no henos sobreescrito todos los métodos //de la interfaz. Si no tuviera el mismo modificador el compilador nos daría un error y no nos dejaría seguir adelante. ha de devolver el mismo tipo de dato y ha de tener el mismo modificador que el método al que sobrescribe. public String nombre = "Bob". //Compruébese como esta línea da un error al compilar debido //a intentar asignar un valor a una variable final // dog. } public static void main (String[] args){ Perro1 dog = new Perro1(). Además no pueden llevar modificadores private ni protected. public void get_nombre().println(nombre ). public void nace(){ System. } public void get_nombre(){ System. void get_nombre(int i). cuando una clase implementa una interface lo que estamos haciendo es una promesa de que esa clase va a implementar todos los métodos de la interface en cuestión. Su función es la de ser una especie de constantes para todos los objetos que implementen dicha interface. Bien. } } Las variables que se definen en una interface llevan todas ellas el atributo final. Si la clase que implementa la interface no “sobrescribiera” alguno de los métodos de la interface automáticamente esta clase se convertiría en abstracta y no podríamos crear ningún objeto de ella.public void nace().

println(nombre +" " +i). // Un ejemplo sencillo de una clase abstracta.Animal3{ Perro2(){ get_nombre(). public String nombre = "Bob". // en las clases abstractas se permiten métodos concretos void callmetoo() { 44 . } public void get_nombre(){ System.Animal2.println(nombre ). en la que solo s defina una forma generalizada que será compartida por todas las subclases.Por último decir que aunque una clase sólo puede heredar propiedades de otra clase puede implementar cuantas interfaces se desee. public void nace(). es decir.out. Veamos un ejemplo de múltiples interfaces interface Animal1{ public int edad = 10.out. no podemos cambiar este valor } public void nace(){ System. abstract class A { abstract void callme(). //edad = 10. } ********************************* interface Animal2{ public void get_nombre().out. } public static void main (String[] args){ Perro2 dog = new Perro2(). } ********************************** interface Animal3{ void get_nombre(int i). }} 5. } ********************************* public class Perro2 implements Animal1. recuperándose así en buena parte la potencia de la herencia múltiple. dejando que cada subclase complete los detalles necesarios.5 Clases Abstractas: Cuando se quiere definir una superclase en la que se declare la estructura de una determinada abstracción sin implementar completamente cada método. get_nombre(8). } public void get_nombre(int i){ System.println("hola mundo").

Figura(double a.out. }} class B extends A { void callme() { System. } // area es ahora un método abstracto abstract double area().out. dim2 = b. // Mejora de la clase figura con una clase abstracta. }} *********************************** class Triangulo extends Figura { 45 . }} observación:  No se declaran objetos de la clase A. b. ya que el polimorfismo de java en tiempo de ejecución se implementa mediante la referencia a las superclases. b. abstract class Figura { double dim1. si es posible crear referencias a objetos. b). return dim1 * dim2.").").  Aunque no es posible crear instancia de las clases abstractas.  Las clase abstractas pueden incluir tanta implementación como sea necesario.println("Dentro del método area para un Rectangulo.println("implementación de método callme en B.System. double b) { dim1 = a.callmetoo(). ya que no es posible crear una instancia de una clase abstracta.println("Este es un método concreto"). } // se sobreescribe area para un rectangulo double area() { System.out. double b) { super(a.callme(). } ************************ class Rectangulo extends Figura { Rectangulo(double a. }} class AbstractApp { public static void main(String args[]) { B b = new B(). double dim2.

Triangulo(double a, double b) { super(a, b); } // sobreescribiendo el area para un triangulo double area() { System.out.println("Dentro del método area para un Triangulo."); return dim1 * dim2 / 2; }} ************************************** class AbstractaApp { public static void main(String args[]) { // Figura f = new Figure(10, 10); // esto no es correcto ahora Rectangulo r = new Rectangulo(9, 5); Triangulo t = new Triangulo(10, 8); Figura figref; // esto es correcto no se crea ningun objeto figref = r; System.out.println("Area es: " + figref.area()); figref = t; System.out.println("Area es :" + figref.area()); }}

5.6 Utilizacion de final con herencia
La palabra clave final impide que su contenido sea modificado, tiene tres utilizaciones. 1. Para crear el equivalente de un constante con nombre. Ej. Final int Nuevo=1; 2. Para impedir la sobreescritura (con herencia) class A { final void meth() { System.out.println("Este es un método final."); }} **************************** class B extends A { void meth() { // ERROR! No esta permitida la sobreescritura. System.out.println("Ilegal!"); }} 3. utilizacion para impedir la herencia. final class A { // ... } // La siguiente classe es ilegal. class B extends A { // ERROR! No puede haber subclase de A // ... } static: Cuando se declara un miembro como static, se puede acceder al mismo antes de que cualquier de su clase sea, y sin referencia a ningún objeto. Se pueden declarar tanto

46

métodos como a atributos como static. El ejemplo mas habitual de un miembro static es main(), este se declara static, ya que debe ser llamado antes de que exista cualquier objeto. class StaticDemo { static int a = 42; static int b = 99; static void callme() { System.out.println("a = " + a); }} class StaticApp { public static void main(String args[]) { StaticDemo.callme(); System.out.println("b = " + StaticDemo.b); }} Salida: a=42; b=99; En este ejemplo dentro de main() se accede al metodo static callme() y a la variable b fuera de su clase.

5.6.1 Tamaño de un arreglo
El tamaño de una matriz, el numero de elementos se encuentra en su variable de instancia length. // Demostración de la longitud de una matriz de datos. class Length { public static void main(String args[]) { int a1[] = new int[10]; int a2[] = {3, 5, 7, 1, 8, 99, 44, -10}; int a3[] = {4, 3, 2, 1}; System.out.println("longitud de a1 es " + a1.length); System.out.println("longitud de a2 es " + a2.length); System.out.println("longitud de a3 es " + a3.length); }}

5.7 La clase String
La clase String tiene varios métodos que pueden ser utilizados entre ellos están:  Se puede comprobar la igualdad de dos cadenas mediante equals().  Se puede obtener la longitud de una cadena mediante length().  Se puede obtener el carácter que ocupa una posición determinada dentro de una cadena con charAt(). La forma general de estos objetos es : boolean equals (objeto String) int length() char charAt(int indice) class StringApp { public static void main(String args[]) { String strOb1 = "Primera Cadena"; String strOb2 = "Segunda Cadena"; String strOb3 = strOb1; System.out.println("Longitud de strOb1: " + strOb1.length()); System.out.println("El caracter de la posicion 3 de strOb1: " + strOb1.charAt(3));
47

if(strOb1.equals(strOb2)) System.out.println("strOb1 == strOb2"); else System.out.println("strOb1 != strOb2"); if(strOb1.equals(strOb3)) System.out.println("strOb1 == strOb3"); else System.out.println("strOb1 != strOb3"); }} ********************************** // Ejemplo de matrices de cadena de caracteres. class StringApp1 { public static void main(String args[]) { String matriz[] = { "uno", "dos", "tres" }; for(int i=0; i<matriz.length; i++) System.out.println("matriz[" + i + "]: " + matriz[i]); }} ****************************************

5.8 Argumentos de la linea de ordenes.
En ocasiones, es necesario pasar información a un programa que se esta ejecutando. Esto se lleva a cabo pasando los argumentos de la línea de ordenes a main().

// Presentación de todos los argumentos de la linea de ordenes. class LineaApp { Java LineaApp esto es una prueba 100 public static void main(String args[]) { 1 for(int i=0; i<args.length; i++) Salida: System.out.println("args[" + i + "]: " +args[i]); args[0]:esto .... args[5]:-1 }} jgrasp opcion run ..... run arguments

48

6.0 Applets
6.1 Introducción
Un applet es un programa en Java que se incrusta en una página HTML para agregarle funcionalidad. Como por seguridad los applets están limitados a no poder accesar el medio ambiente de la computadora donde corren su principal utilidad es para hacer interfaces gráficas de aplicaciones de bases de datos. Por supuesto la base de datos debe residir en la computadora de donde vino el applet. También se pueden programar juegos, programas interactivos que complementen un texto en línea o que ilustren un concepto en particular, simulaciones, etc.

6.2 Ciclo de vida
Los applets tienen un ciclo de vida durante el cual realizan algunas actividades. Cada actividad tiene asignado un método que el navegador llama en el momento adecuado. Las principales actividades son: • Inicio. Se hace cuando se carga el applet por primera vez y corresponde al método init(). • Comienzo. Se hace cuando el applet comienza a correr, ya sea después del inicio o si fué detenido. Corresponde al método start(). • Detención. Un applet se detiene cuando el usuario accesa otra página en su navegador. Corresponde al método stop(). • Destrucción. Permite liberar recursos al finalizar el applet. Corresponde al método destroy(). • Dibujo. Actualiza la salida del applet en la pantalla. Corresponde al método paint(Graphics g). Se invoca cada vez que se necesita que el applet sea redibujado, ya sea al saltar al primer plano, al moverse la pantalla o cuando vuelve a correr después de estar detenido. Es importante recalcar que ninguno de estos métodos es invocado en forma explícita. El navegador los invoca en forma automática dependiendo de si el applet necesita inicializarse o si está comenzando o si necesita volver a pintar lo que el applet haya dibujado. Un applet debe extender a la clase Applet. Esta clase proporciona implementaciones vacías de los 5 métodos. Es responsabilidad del programador de applets sobreponer los métodos que vaya a utilizar. No es necesario sobreponer todos, en la práctica casi siempre solo se sobreponen o el método init() o el paint(), rara vez los dos a la vez. Ejemplo: import java.awt.Graphics; import java.awt.Font; import java.awt.Color; import java.applet.*; public class EjemploApplet extends Applet { Font f = new Font ("TimesRoman", Font.BOLD, 36); public void paint (Graphics g) { g.setFont (f);
49

g.setColor (Color.red); g.drawString ("Mi primer Applet !!!", 5, 40); } }

Codigo html: <html> <head> <title>EjemploApplet Applet</title> </head> <body> <h1>EjemploApplet Applet</h1> <hr> <applet code="EjemploApplet.class" width=300 height=300 codebase="." archive="" alt="Your browser understands the &lt;APPLET&gt; tag but isn't running the applet, for some reason." > Your browser is ignoring the &lt;APPLET&gt; tag! </applet> <hr> </body> </html>

50

public void init () { 51 .Graphics. al centro (Center) o a la derecha (Right). mssg. Este método recibe como argumento un string con el nombre del argumento y devuelve un string con el valor correspondiente a ese argumento o el valor null si el argumento no existe.*.Color.. String desde. import java.applet. la cual tiene un atributo para el nombre del argumento y otro para el valor. import java.3 Argumentos Los applets pueden recibir argumentos desde el archivo HTML con la etiqueta <PARAM>. Esta etiqueta puede tener varios argumentos. Dentro del método init() se puede recuperar los valores de los argumentos usando el método getParameter().awt.BOLD. 36). La etiqueta <PARAM> va dentro de la etiqueta <APPLET>.awt. los principales son: • CODE – Indica el nombre del archivo compilado. 6. • ALIGN – Permite alinear el applet a la izquierda (Left). import java.awt. • HEIGHT – Es la altura de dicha área en pixeles. Si el archivo de clase está en la misma carpeta que la página HTML (lo más recomendable) basta con poner el nombre. import java. Los argumentos se pasan cuando el applet se inicializa. public class EjemploArgumento extends Applet { Font f = new Font ("TimesRoman". Font. pero se pueden ejecutar applets remotos poniendo la dirección http completa. para. • WIDTH – Indica el ancho en pixeles del área dentro de la página HTML que el navegador apartará para uso del applet. Ejemplo:Un applet que lee tres argumentos y escribe un mensaje en la pantalla.Font.Como se puede ver en el listado anterior la etiqueta <APPLET> es la que incrusta el applet en la página HTML.

5. if (desde == null) desde = "aqui".red). 40). mssg = getParameter ("mensaje").drawString ("El mensaje es: " + mssg. g. para = getParameter ("para").desde = getParameter ("desde").drawString ("Desde " + desde + " para " + para.setColor (Color.class" WIDTH=600 HEIGHT=400> <PARAM NAME=desde VALUE="San Vicente"> <PARAM NAME=para VALUE="todos"> <PARAM NAME=mensaje VALUE="Este es Java applet !!!"> </APPLET> </BODY> </HTML> 52 . 5.setColor (Color. g. } public void paint (Graphics g) { g.setFont (f).green). g. if (mssg == null) mssg = "no hay mensaje". } } Codigo html: <HTML> <HEAD> <TITLE>Ejemplo con Argumentos !!!</TITLE> </HEAD> <BODY> <P><H2>Bienvenido a Programacion III:</H2><P> <APPLET CODE="EjemploArgumento. if (para == null) para = "alla". 80). g.

r_hor. rectángulos. • drawRoundRect (x. • drawArc (x. Un valor de 90 significa que se dibujará un cuarto de arco en contra de las manecillas del reloj. Al dibujar sobre este objeto se dibuja dentro del applet y los resultados se desplegarán en la pantalla. ancho. El polígono se cierra en forma automática porque siempre se dibuja una línea entre el último punto y el primero. y) indica la coordenada donde comienza el texto. Si ancho es igual que alto. El argumento grados_ini indica desde que grado se comienza a dibujar el arco. alto) – Dibuja un rectángulo hueco. y) y la anchura y altura por ancho y alto respectivamente. Los argumentos son los mismos que en el método anterior. • drawPolyline (x[]. Los argumentos son los mismos que en el método anterior. el 180 al oeste y el 270 al sur. y2) – Dibuja una línea recta entre los puntos (x1. Los argumentos r_hor y r_ver determinan que tan lejos de los limites del rectángulo debe comenzar el redondeo en las esquinas. r_ver) – Dibuja un rectángulo hueco con las esquinas redondeadas. largo_grados) – Dibuja un arco hueco. Los arreglos x y y guardan respectivamente las coordenadas x y y de cada una de las esquinas del polígono. y. alto. El argumento n es el número de puntos (el tamaño de los arreglos x y y). • fillRect (x. • drawPolygon (x[]. En los applets el método paint recibe un objeto de tipo Graphics. Si pensamos en los puntos cardinales el grado 0 está al este. alto. el punto (x. x2. polígonos y arcos. alto) – Dibuja un óvalo hueco. grados_ini. y. el 90 al norte. r_ver) – Dibuja un rectángulo lleno con el color actual y redondeado en las esquinas. • fillPolygon (x[]. x. y) y que el óvalo se dibuja inscrito en el rectángulo. y[]. • drawLine (x1. ancho.Dibuja un rectángulo lleno con color actual. El origen. • drawString (s. el punto (0. n) – Dibuja un polígono lleno con el color actual. el rectángulo se convierte en cuadrado y el óvalo se convierte en círculo. • fillRoundRect (x. Por último largo_grados indica la longitud del arco y la dirección de dibujo. círculos. y. Esta clase tiene métodos para dibujar líneas. con la esquina superior izquierda en el punto (x. ancho.4 Gráficas La librería de Java incluye la clase Graphics para hacer dibujos sencillos. Hay que aclarar que todos los argumentos son de tipo int. alto) Dibuja un óvalo lleno con el color actual. y2). y) – Escribe el texto almacenado en el string s. y) está fuera del óvalo. ancho. La forma más fácil de entender el resultado de este método es imaginar que se dibuja un rectángulo imaginario con una anchura de ancho pixeles y una altura de alto pixeles.0) está en la esquina superior izquierda del área reservada para el applet en la página HTML. El punto (x. ancho. y1) y (x2.6. y[]. • drawRect (x. alto. y. La esquina superior izquierda está dada por el punto (x. El sistema de coordenadas está en pixeles. es decir. • drawOval (x. Los primeros 4 argumentos tienen el mismo sentido que en los dos métodos anteriores. ancho. y. alto) . y. Por lo tanto. La X crece hacia la derecha en forma horizontal y la Y crece hacia abajo en forma vertical. n) – Dibuja un polígono hueco. y[]. r_hor. El resultado se puede pensar que es un polígono sin cerrar. La clase Graphics tiene los siguientes métodos. • fillOval (x. Los argumentos son los mismos que en el método anterior. n) – Dibuja una línea quebrada. ancho. y. y1. Los primeros 4 argumentos tienen el mismo sentido que en los dos métodos anteriores. en cambio un valor de –90 también indica un cuarto de arco pero en el sentido de las manecillas del 53 .

110. import java. 312). 130.applet. 177. // La cubierta g. 89). 250. 250. Los argumentos son los mismos que en el método anterior. 50. largo_grados) – Dibuja un arco lleno con el color actual. • fillArc (x. 125. Igualmente un valor de 180 significa medio arco y dependiendo del signo es la dirección. Ejemplo: import java.reloj. 40. 58). 181. g. y.awt. 160). 119. grados_ini.fillArc (78. 175. 40. public class Dibujo extends Applet { public void paint (Graphics g) { // la plataforma g. 130. 96. 160).drawArc (85. 180).fillArc (173. // La base g. g.Graphics. 89). 290).drawLine (175. // Las motas g.*.drawArc (85. } } 54 . 177.fillRect (0. 250. 62. -65.drawLine (85. 40. g. g.drawLine (125. 120. g. 40). 157. base. 87. 100. altura. 40. 290. 63. 50. g.fillOval (120. -174).drawLine (215. 40.

public class Fondo extends Applet { public void paint (Graphics g) { Font f1 = new Font ("Times Roman". 18). Font.ITALIC. Font.ITALIC.drawString ("Este es texto en negrita y cursiva".setFont (f1).drawString ("Este es texto normal". Los tipos de letra disponibles se pueden saber usando esta instrucción: String fontlist[] = GraphicsEnvironment. 100). Se pueden mezclar dos o más estilos con un el signo +. } } 55 .PLAIN (estilo normal). Ejemplo: import java.setFont (f4).drawString ("Este es texto en cursiva". import java.setFont (f2). Font f2 = new Font ("Times Roman".Font.getLocalGraphicsEnvironment().setFont (f3).awt. 10. Font f4 = new Font ("Times Roman". g. 18). g.BOLD (estilo en negritas) o Font. g. g.BOLD.getAvailableFontFamilyNames ().Graphics.drawString ("Este es texto en negrita". 18). Para cambiar el tipo de letra se invoca al método: setFont (f) donde f es un objeto de tipo Font. Font. 75). Font f3 = new Font ("Times Roman".*. g. Font.applet. 50). 25).PLAIN.5 Tipo de letra Para cambiar el tipo de letra hay que crear una instancia de la clase Font.BOLD + Font. g. El primer argumento es el nombre del tipo de letra. El tercer argumento es el tamaño en puntos del tipo de letra y depende de cada tipo de letra.awt.ITALIC (estilo en cursiva o itálico). 18). 10. g. import java. por ejemplo se puede indicar Font. Font.ITALIC. puede valer Font. El segundo argumento es el estilo.6. Font f = new Font ("TimesRoman". 24). 10. Font. g. 10.BOLD.BOLD + Font.

setColor (c1).6. 240.216 colores distintos. 60). Cambia el color de lo que se haya dibujado sin importar el color en el que se dibujó. g.orange.drawString ("Ovalo lleno". g. 255. g. etc. 60).setColor (c2). 20).fillOval (5. • setForeground (c). g. 150. Color. g. Color.drawString ("Circulo hueco". 130.Graphics.white. verde y azul respectivamente. 60.black.lightGray).777. nombre).red). Color c2 = new Color (40.fillOval (150. Color. g. 220). g y b es la cantidad de rojo. 5. Se puede usar alguno de los colores ya definidos en la clase Color como Color.drawOval (5.gray. 200).0. g. 5. 120). g. El argumento c es un objeto de tipo Color. 60).yellow.drawOval (150. 100. 120). Color. Color. 100.0) representa el negro y el (255. donde URL es la dirección donde está la imagen y nombre es el nombre del archivo que contiene la imagen. 20). g. 30. 30.6 Color Para cambiar el color hay que crear una instancia de la clase Color: Color c = new Color (r.drawString ("Ovalo hueco".awt. import java. Color.awt. g. donde r. • setBackground (c).drawString ("Circulo lleno". Cambia el color del fondo al color c.red. El (0. 60). g.7 Imágenes Un applet pueden desplegar imágenes en formato GIF y JPEG.blue. Cambia el color actual para las operaciones de dibujo a partir de este momento. setBackground (Color. public class CambioColor extends Applet { public void paint (Graphics g) { Color c1 = new Color (120. 30. b). 150. Para la variable URL hay 3 opciones: 56 . } } 6. en el rango de 0 a 255. 60.applet.Color. Lo primero es crear una instancia de la clase Image. Hay 3 funciones para cambio de color: • setColor (c). En total hay 256 3 = 16. Image mi_imagen = getImage (URL. 130. 255) el blanco.setColor (Color. Ejemplo: import java. g.*. import java.

class). entonces poner: Image imagen = getImage (new URL ("http://www. c) Usar la dirección relativa a donde está el applet compilado (archivo . this).foo. "foo.gif"). g.drawImage (img. this). g. donde imagen es un objeto de tipo Image. Si el directorio images está abajo de donde está el código objeto. donde). this). int alto = img. (int) (ancho * 1. Ejemplo: Para una imagen que se llama disco.drawImage (img. } } 57 . Para desplegar la imagen: drawImage (imagen.foo.getHeight (this). ypos. (int) (alto * 1.5).Graphics. Si el directorio images está abajo de donde está la página. xpos.getWidth (this). x y y son las coordenadas de la esquina superior izquierda de la imagen. ancho / 4. import java. xpos. xpos. (int) (alto * 1.drawImage (img. "disco.applet. la variable donde es el nombre del objeto que va a actuar como observador de la imagen que en el caso de los applets es el mismo applet.5 + 10). g.com/images".awt. public class Imagenes extends Applet { Image img. entonces poner: Image imagen = getImage (getDocumentBase (). b) Usar la dirección relativa con respecto a donde está la página HTML. } public void paint (Graphics g) { int ancho = img. // 25 % g. ypos.5). this). // 100 % xpos += (ancho / 2) + 10. xpos.*. "images/foo. alto / 4. Si la imagen esta en: http://www. // 50 % xpos += (ancho / 4) + 10. alto / 2.gif").gif.gif import java.awt. y.a) Poner la dirección absoluta. Las variables ancho y alto indica el ancho y el alto en pixeles con que se va a desplegar la imagen. Por último. xpos. "images/foo.Image. ancho / 2.gif"). x. // distorsionado xpos += (int) (ancho * 1. ypos. g. ancho / 2.com/images/foo. // 150 % xpos += ancho + 10.drawImage (img. int xpos = 10. ypos.drawImage (img. this).5). alto.gif"). public void init () { img = getImage (getCodeBase (). ypos = 10. import java. ypos. entonces poner: Image imagen = getImage (getCodeBase (). ancho.

Para definir un botón hay que crear un objeto de tipo Button indicando el texto que desplegará el botón: Constructores: Button(). Label(String str).*. Button(String str) Una vez creado el boton se le puede asignar un Label llamando a setLabel(). lbl3. import java.1 Etiquetas Una etiqueta es un texto no editable que despliega un letrero en la pantalla. add (lbl2). Label lbl3 = new Label(). si queremos obtener el texto de una etiqueta se utiliza el metodo getText(). Label.RIGHT). Label. Label lbl2 = new Label ("Etiqueta dos".RIGHT. public void init () { lbl3.LEFT.2 Gestion de Botones Un botón es un componente gráfico que activa algún evento cuando se le oprime usando el ratón. add (lbl).setText("Etiqueta tres"). Se puede establecer el alineamiento del string dentro de la etiqueta utilizando el método setAlignment().7. add (lbl3).applet.setAlignment(Label.0 Abstract Window Toolkit y Eventos 7.CENTER Se puede establecer o cambiar el texto de la etiqueta con el método setText(). int how) El valor de how debe ser cualquiera de estas constantes: Label. }} 7.awt. Para definir una etiqueta hay que crear un objeto de tipo Label indicando el texto de la etiqueta y opcionalmente una alineación: Constructores: Label(). public class LabelApplet extends Applet { Label lbl = new Label ("Etiqueta uno"). tambien se puede obtener su etiqueta con getLabel() Gestionar Botones: Cada vez que se pulsa un botón. Para obtener el alineamiento de la etiqueta se utiliza el método getAlignment() Ejemplo: import java. Label(String str. Label. se genera un evento de acción que se envía a cualquier 58 .*.CENTER).

*.equals("Boton 1")){ msg="Presiono el Boton 1". import java. public void init (){ btn1 = new Button ("Boton 1"). La etiqueta se obtiene llamando al método getActionCommand() sobre el objeto ActionEvent que se pasa a actionPerformed().btn2. } public void actionPerformed(ActionEvent ae){ String str=ae. Cada auditor implementa la interfaz ActionListener. btn1.drawString(msg. se muestra un mensaje que indica que boton se ha pulsado.event. } public void paint(Graphics g ){ g. Cada vez que se pulsa un botón.getActionCommand(). add (btn1).*. Como argumento a este método se pasa un objeto ActionEvent. btn2 = new Button ("Boton 2"). btn2.6. public class Boton1Applet extends Applet implements ActionListener { String msg="". add (btn2). if (str.*.awt.50).auditor que previamente haya registrado un interés por recibir información de eventos de acción que generan cada componente. Ejemplo: import java. Button btn1. que es al que se llama cuando ocurre un evento. import java. Esta interfaz define el método actionPerformed(). } else { msg="Presiono el Boton 2". } repaint(). } } 59 .addActionListener(this).awt.addActionListener(this).applet.

cbg1).applet. Para definir un checkbox hay que crear un objeto de tipo Checkbox indicando un texto como etiqueta y opcionalmente un booleano para indicar si de entrada está marcada o no. CheckboxGroup (String str. Checkbox cbext = new Checkbox ("extranjero". Para marcar (o desmarcar) desde un programa un checkbox se usa el método setState() pasando un argumento booleano que indique el nuevo estado. cbg2). Label lb2 = new Label ("Nacionalidad"). Se puede obtener la etiqueta asociada al checkbox llamando al método getLabel(). cbg2). boolean on). Checkbox cbsal = new Checkbox ("salvadoreño". CheckboxGroup cbgroup). CheckboxGroup cbGroup. import java.awt. Los checkbox se pueden utilizar individualmente o como parte de grupo: Constructores: Checkbox(). false. Checkbox cbs = new Checkbox ("soltero". Para establecer un determinado estado. Checkbox cbc = new Checkbox ("casado". cbg1). boolean on).7. true. } } 60 . Checkbox cbv = new Checkbox ("viudo".*. Checkbox(String str. // desmarca el checkbox cb1. CheckboxGroup cbg1 = new CheckboxGroup (). cbg1). Checkbox(String str).setState (false). se puede llamar a setState(). Checkbox(String str. true. Llamado al método setLabel() se establece la etiqueta. Para obtener el estado inicial de un checkbox. add (cbc).*. CheckboxGroup cbg2 = new CheckboxGroup (). Los checkboxes se pueden agrupar de tal forma que solo un checkbox de ese grupo pueda estar activado a la vez. public void init (){ add (lb1). hay que llamar a getState(). Ejemplo: dos grupos de checkbox import java. boolean on. add (cbsal). false. add (cbv). false. add (cbext). cb1. public class Checkbox1Applet extends Applet { Label lb1 = new Label ("Estado civil"). add (cbs). add (lb2).3 Checkboxes Un checkbox es un componente que tiene dos estados: marcado o no marcado.

addItemListener(this). import java.awt.getLabel(). solaris=new Checkbox("Solaris". } } 61 .cbg.getSelectedCheckbox(). msg+=cbg. linux. public void init (){ cbg=new CheckboxGroup(). Esta interfaz define el metodo itemStateChanged().*. Como argumento de este metodo se pasa un objeto ItemEvent.true). linux. Ejemplo: import java. add (win98). } public void itemStateChanged(ItemEvent ie){ repaint(). win98=new Checkbox("Window98".false). win98. import java.*. g.cbg.6. add (solaris). solaris. Cada auditor implementa la interfaz ItemListener.applet. que encapsula la inforarmacion sobre el evento. public class Checkbox2Applet extends Applet implements ItemListener{ String msg="".*.50).addItemListener(this).cbg.awt. CheckboxGroup cbg. Checkbox win98. add (linux).drawString(msg. solaris. } public void paint(Graphics g){ msg="Seleccion Actual : ". se genera un evento que se envía a cualquier auditor que previamente se haya registrado para recibir información de los eventos que se producen desde ese componente. linux=new Checkbox("Linux".false).Gestión de Checkbox Cada vez que se selecciona o se deselecciona un checkbox.event.addItemListener(this).

7.4 Choices Un choice se utiliza para crear una lista pop-up de elementos para qu el usuario pueda elegir uno de ellos. Por tanto un control choice es un menú del cual se puede escoger solo una opción. Para usar un choice hay que declarar un objeto de tipo Choice y luego usar el método add para agregar la lista de opciones. Choice solo define un constructor por defecto que crea una lista vacia. Para añadir una seleccion a la lista, hay que llamar a addItem() o a add() que tienen los siguientes formatos: void addItem(String nombre) void add(String nombre) donde nombre corresponde al nombre del elemento que se añade. Los elementos se añaden a la lista en el orden en que se llama a add() o a addItem(). Para saber que opción fue seleccionada se usa el método getSelectedIndex() o al método getSelectedItem(). El metodo getSelectedItem() devuelve un string que contiene el nombre del elemento, y getSelectedIndex() devuelve la posición del elemento considerando que el primer elemento esta en la posición 0. Por defecto se selecciona el primer elemento que se añade a la lista. Para obtener el numero de elementos que hay en la lista, hay que llamar al método getItemcount(). Se puede establecer el elemento que tiene que estar seleccionado utilizando el método select() tanto con un entero que indique la posición del elemento (empezando a contar desde cero) como con un string que tenga el nombre que aparece en la lista estos métodos son: int getItemCount(), void select(int index), void select (String nombre) Dada una posición se puede obtener el nombre del elemento que esta en esa posición llamando al método getItem(), que tiene el siguiente formato: String getItem(int index) Gestión de listas Choice Cada vez que se hace una selección, se genera un evento que se envía a todo auditor que se haya registrado para recibir la información de los eventos que ese componente. Cada auditor debe implementar la interfaz ItemListener, que define el método itemStateChanged(). Se pasa como argumento a este metodo un objeto de la clase ItemEvent. Ejemplo:
import java.awt.*; import java.awt.event.*; import java.applet.*;
62

public class Choice1Applet extends Applet implements ItemListener { Choice ch_deportes; String msg=""; public void init (){ ch_deportes=new Choice(); ch_deportes.addItem ("Fútbol"); ch_deportes.addItem ("Beísbol"); ch_deportes.addItem ("Hockey"); ch_deportes.addItem ("Natacion"); add (ch_deportes); //se registran para recibir eventos de elemento ch_deportes.addItemListener(this); } public void itemStateChanged(ItemEvent ie){ repaint(); } public void paint(Graphics g){ msg="Deporte seleccionado : "; msg+=ch_deportes.getSelectedItem(); g.drawString(msg,6,100); } }

7.5 TextField
Un campo de texto es un componente que permite capturar y editar una línea de texto. Para usar un campo de texto hay que crear un objeto de tipo TextField que es una subclase de TextComponent indicando el número de caracteres de ancho y opcionalmente un texto inicial, proporciona los siguientes constructores: TextField(), TextField(int numc), TextField(String str), TextField(String str, int numc) Donde: numc determina el número de caracteres del campo de texto. Para establecer un determinado texto se llama al método setText() y para obtener un string del campo de texto se utiliza getText(). Se puede seleccionar una parte del texto con select(), y para obtener el texto completo seleccionado se llama s getSelectText().

63

Forma general: String getSelectText(), void select(int inicio, int fin) El usuario también puede modificar el contenido del campo de texto llamando a setEditable(). También puede determinar si es editable o no llamando a isEditable(). Forma general: Booleam isEditable(), void setEditable(boolean valor) Puede que haya ocasiones en que interese que no se vea el texto que introduce, esto se hace llamando a setEdhoChar(). Se puede chequear un campo de texto para ver si esta en este modo con el metodo echoCharIsSet() y ver que caracter se va a ver llamando al metodo getEchoChar().
Ejemplo: import java.awt.*; import java.applet.*; public class TextFieldApplet extends Applet { TextField tf1 = new TextField (10); TextField tf2 = new TextField ("Nombre de la ciudad",30); TextField tf3 = new TextField (15); public void init (){ add (tf1); add (tf2); tf3.setEchoChar ('*'); add (tf3); }}

Gestión de un TextField Como los campos de texto gestionan sus propias funciones de edicion, generalmente el programa no tendra que ocuparse de los eventos de teclas individuales que ocurran dentro de un campo de texto. Pero puede que se quiera responder cuado el usuario pulse la tecla ENTER; y si esto ocurre, se genera un evento de accion. Ejemplo:
import java.awt.*; import java.awt.event.*; import java.applet.*; public class TextField1Applet extends Applet implements ActionListener { TextField tf1,tf2,tf3; public void init(){ Label lbl1=new Label("Departamento : ",Label.RIGHT); Label lbl2=new Label("Ciudad :",Label.RIGHT); Label lbl3=new Label("Codigo : ",Label.RIGHT); tf1= new TextField (10); tf2 = new TextField ("Nombre de la ciudad",30); tf3 = new TextField (15); tf3.setEchoChar ('*'); add (lbl1); add (tf1); add (lbl2); add (tf2); add (lbl3); add (tf3);
64

// se registran los eventos tf1.addActionListener(this); tf2.addActionListener(this); tf3.addActionListener(this); } public void actionPerformed(ActionEvent ae){ repaint(); } public void paint(Graphics g){ g.drawString ("Departamento :"+tf1.getText(),6,60); g.drawString ("Ciudad :"+tf2.getText(),6,80); g.drawString ("Texto seleccionado de Ciudad :"+tf2.getSelectedText(),6,100); g.drawString ("Codigo :"+tf3.getText(),6,120); } }

7.6 List. La clase List proporciona una lista de selección compacta, con desplazamiento, que permite realizar selecciones múltiples. A diferencia de Choice que solo muestra un único objeto que se puede seleccionar en el menú, se puede construir un objeto List que muestre cualquier numero de opciones en una ventana. También se puede configurar de manera que puedan realizar selecciones múltiples. Constructors: List(), List(int num), List (int num, boolean multiple) Métodos: void add(String nombre), void add(String nombre, int index): para añadir una lista. En listas que solo permiten seleccionar un único elemento se determina si este esta seleccionado con los métodos getSelectedItem() o con getSelectedIndex(), el primero devuelve un string con el nombre del elemento y el segundo devuelve la posición del elemento. En las listas que permiten seleccionar mas de un elemento se utilizan los métodos getSelectedItems() o getSelectedIndexes(). String [] getSelectedItems() int[] getSelectedIndexes() Para obtener el numero de elementos que hay en la lista hay que llamar a getItemCount(), que devuelve un array con las posiciones seleccionados actualmente. Se puede establecer el elemento que tiene que estar seleccionado con el método select(), pasándole un entero que indique la posición del elemento. Gestión de Listas: Es necesario implementar la interfaz ActionListener. Cada vez que se de dobleclick en un elemento List se genera un evento de la clase ActionEvent. Puede utilizarse getActionCommand(), para guardar el nombre del elemento recién seleccionado. Cada vez que se selecciona un evento con un solo click, se genera un objeto de la clase ItemEvent. Se puede utilizar su método getStateChange() para determinar si una selección o deseleccion ha desencadenado ese evento. Si se utiliza getItemSelectable() devuelve una referencia al objeto que ha desencadenado ese evento.
65

Ejemplo:
//con doble click import java.awt.*; import java.awt.event.*; import java.applet.*; public class ListaApplet extends Applet implements ActionListener { List lista; final Color[] colores={Color.red, Color.green, Color.blue}; int indice; public void init() { lista=new List(3,false); //se añaden los elementos de la lista lista.add("Rojo"); lista.add("Verde"); lista.add("Azul"); lista.select(0); //se añaden la listas al contenedor add(lista); //registrando eventos lista.addActionListener(this); } public void actionPerformed(ActionEvent ae){ indice=lista.getSelectedIndex(); repaint(); } public void paint(Graphics g){ g.setColor(colores[indice]); g.fillRect(2, 2, 100, 50); } }

7.7 TextArea. Editor multilineas.
Constructores: TextArea(), TextArea(int numlin, int numchar), TextArea(String str), TextArea(String str, int numli, int numchar), TextArea(String str, int numlin, int numchar, int sbar). Donde numlin especifica la altura en lineas del area de texto, numchar especifica la anchura en caracteres. Se puede especificar un texto inicial con str. Tambien se puede especificar con sbar las barras de desplazamiento que va a tener el control, puede tomar los siguientes valores: SCROLLBARS_BOTH, SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE, SCROLLBARS_VERTICAL_ONLY.
66

TextArea es una subclase de TextComponent. Por tanto, soporta los metodos getText(), setText(), getSelectedText(), select(), isEditable() y setEditable(). TextArea añade los siguientes metodos: void append(String str), void insert(String str, int index), void replaceRange(String str, int inicio, int fin). El metodo append() añade el string especificado en str al final del texto actual. El metodo insert() inserta el string que se pasa en str en el punto especificado en index. Para reemplazar texto hay que llamar a replaceRange(), que reemplaza los caracteres desde inicio a fin con el texto que esta en str.
Ejemplo: import java.awt.*; import java.applet.*; import java.awt.event.*; // Presentamos dos areas de texto y un boton para imprimir el contenido public class AreaTexto extends Applet implements ActionListener{ String texto=""; TextArea t1,t2; public void init() { Button boton = new Button( "Aceptar" ); // Creamos las dos areas de texto, una con el constructor de // defecto del Componente y otra con un texto por defecto y // limitada su longitud a 40 columnas t1 = new TextArea(); t2 = new TextArea( "Aqui no se puede editar",5,40 ); // Hacemos que no sea editable t2.setEditable( false ); add( t1 ); add( t2 ); add( boton ); boton.addActionListener(this); } // Solo controlaremos el evento generado por el boton public void actionPerformed(ActionEvent ae ) { // Si pulsamos el boton, imprimimos en la consola el contenido // del campo de texto que se haya escrito String str=ae.getActionCommand(); if( str.equals("Aceptar") ) { texto = t1.getText(); } repaint(); } public void paint(Graphics g){ g.setColor(Color.red); g.drawString(texto,20,300); } }

67

7.8 Componentes avanzados 7.8.1 Paneles
Un panel es un componente contenedor y como tal puede contener otros componentes de AWT. Se utilizan para eliminar la restricción que imponen los diseños de que solo cabe un componente por celda o por zona y poder programas interfaces gráficas complejas. Un panel tiene su propio diseño y sus propios componentes como botones, campos de texto, etc. Los paneles a su vez pueden contener otros paneles que a su vez tengan otros componentes. No hay restricción en el número de paneles ni en el nivel de anidación. Parar usar un panel hay que crear un objeto de tipo Panel. Panel p = new Panel (); Como se dijo anteriormente los paneles pueden tener su propio diseño especificado con el método setLayout. p.setLayout (diseño); Todo lo que se ha dicho sobre agregar componentes con el método add es válido para los paneles. p.add (botón); p.add (checkbox); El uso de paneles puede mejorar el diseño de una interface gráfica evitando que los componentes se vean alineados como si estuvieran en una parrilla gigante. Una regla de diseño especifica que los componentes que están relacionados entre sí se coloquen juntos en un panel. El ejemplo a continuacion presenta un applet que utiliza 3 paneles en un diseño de parrilla vertical. El panel de en medio tiene a su vez dos paneles para que sus componentes no se amontonen en un solo lado.

import java.awt.*; import java.applet.*;
68

public class testPanel extends Applet { Panel pnl_1 = new Panel (); Panel pnl_2 = new Panel (); Panel pnl_3 = new Panel (); Panel pnl_4 = new Panel (); Panel pnl_5 = new Panel (); Checkbox cb_1 = new Checkbox ("Opcion uno"); Checkbox cb_2 = new Checkbox ("Opcion dos"); Checkbox cb_a = new Checkbox ("Opcion A"); Checkbox cb_b = new Checkbox ("Opcion B"); Checkbox cb_c = new Checkbox ("Opcion C"); Label lbl_1 = new Label ("Soy etiqueta"); Choice ch_1 = new Choice (); Choice ch_2 = new Choice (); Button btn_1 = new Button ("Soy un boton"); Button btn_2 = new Button ("Soy otro boton"); public void init () { setBackground (Color.lightGray); setLayout (new GridLayout (3, 1)); add (pnl_1); add (pnl_2); add (pnl_5); // panel 1 pnl_1.setLayout (new FlowLayout (FlowLayout.LEFT)); pnl_1.add (cb_1); pnl_1.add (cb_2); // panel 2 pnl_2.setLayout (new BorderLayout ()); // panel 3 pnl_3.setLayout (new GridLayout (3, 1)); pnl_3.add (cb_a); pnl_3.add (cb_b); pnl_3.add (cb_c); pnl_2.add ("West", pnl_3); // panel 4 pnl_4.setLayout (new GridLayout (1, 3, 30, 10)); pnl_4.add (lbl_1); ch_1.add ("A"); ch_1.add ("B"); ch_1.add ("C"); ch_2.add ("1"); ch_2.add ("2"); pnl_4.add (ch_1); pnl_4.add (ch_2); pnl_2.add ("East", pnl_4); // panel 5 pnl_5.setLayout (new FlowLayout (FlowLayout.CENTER, 10, 30)); pnl_5.add (btn_1); pnl_5.add (btn_2);
69

} }

7.8.2 Canvas (Lienzos)
Un lienzo es un componente cuya principal utilidad es desplegar gráficas o imágenes. Debido a que no puede contener otros componentes por lo general no se usa en forma directa sino a través de programar una clase que extienda a la clase Canvas. public miCanvas extends Canvas { La clase Canvas define un método paint vacío. La clase que extienda a Canvas sobrepone el método paint para dibujar o desplegar una imagen de la misma forma en que lo hace el método paint de un applet. Si se revisa el manual de Java encontraremos que tanto la clase Canvas como la clase Applet son subclases de la clase Component y de ella heredan el método paint. La clase Component representa objetos que pueden ser desplegados en la pantalla y pueden interactuar con el usuario. Otras subclases de Component son precisamente las clases que definen los componentes que ya vimos como Panel, Button, TextField, etc. El ejemplo siguiente presenta un applet que del lado izquierdo coloca un lienzo donde dibuja una lámpara sobre una mesa y del lado derecho un panel donde hay dos choices que controlan el color con que se dibujan la mesa y la lámpara. La clase miCanvas es la que realmente hace el dibujo en su método paint y además tiene que definir dos métodos para que el applet le avise si cambia el color. La figura muestra la salida del applet.

70

add ("Negro"). // oidores color_mesa. 18)).add (color_lampara). lbl_1). Choice color_mesa = new Choice (). pnl_1.add ("Negro").*.BOLD. color_mesa.setFont (new Font ("TimesRoman". Label lbl_1 = new Label ("La lampara de Aladino").getSelectedIndex ()).event.add ("Rojo").add (lbl_2). pnl_1. Choice color_lampara = new Choice (). import java.add ("Rojo"). color_mesa.ItemListener () { public void itemStateChanged (ItemEvent e) { mc.event. Label lbl_2 = new Label ("Color de la mesa"). mc = new miCanvas ()). color_mesa. color_lampara. color_mesa.*.add (lbl_3). pnl_1 = new Panel ()).awt. add ("North".getSelectedIndex ()).add ("Verde").awt.add ("Azul"). add ("Center". public class testCanvas extends Applet { miCanvas mc. lbl_1.add ("Azul").add ("Verde"). pnl_1.applet. } }). 1)). color_lampara. } }). } } 71 . Panel pnl_1. Label lbl_3 = new Label ("Color de la lampara").import java. public void init () { setLayout (new BorderLayout ()). import java.setLayout (new GridLayout (4. pnl_1. color_lampara.cambiaColorMesa (color_mesa.awt.awt.event.cambiaColorLampara (color_lampara. color_lampara.ItemListener () { public void itemStateChanged (ItemEvent e) { mc. pnl_1. color_lampara. add ("East". Font.*.add (color_mesa).addItemListener ( new java.addItemListener ( new java.

setColor (Color. 89). g. } public void cambiaColorMesa (int c) { color_mesa = c.setColor (Color. 50.drawLine (85. case 2 : g. Si el texto es más grande que el tamaño con el que se despliega el área de texto automáticamente se colocan barras de scroll horizontales o verticales según sea el caso. -65. int color_lampara = 0. 180).fillRect (0.black).drawArc (85. repaint (). break. La diferencia es que. 290).red). break. 40).drawArc (85. 50.setColor (Color. 250. 119.setColor (Color. 250.setColor (Color. } } 7. 290.3 Áreas de texto Un área de texto es un componente que se utiliza para leer datos de entrada de manera semejante al campo de texto. case 1 : g. case 3 : g.setColor (Color. 63. 120.red). g.setColor (Color.class miCanvas extends Canvas { int color_mesa = 0. 96. } g. 175.fillArc (173. } public void cambiaColorLampara (int c) { color_lampara = c. 72 . g.green). 100. 181. 40.drawLine (175.fillOval (120. 125. case 1 : g.setColor (Color.blue). g. 89). 62. 40. 312). 130. // dibuja la mesa switch (color_lampara) { case 0 : g. 40. public void paint (Graphics g) { switch (color_mesa) { case 0 : g. // dibuja la base g. break. 40.blue). break. break. } g. mientras el campo de texto puede leer solo una línea de texto. 58). g.drawLine (125. 40. el área de texto puede leer varias. 130. case 3 : g. 250. // dibuja las motas g. break. 160). 110. 157. break. -174). break.black). 160). repaint ().fillArc (78. case 2 : g. 177.8.drawLine (215.green). // dibuja la cubierta g. 177. 87.

10. como si fuera una sola cadena de caracteres. Cuando desde un programa se altera el texto de un área de texto es responsabilidad del programador insertar saltos de línea ('\n') dentro del string para que el texto se visualice por renglones. Se puede asignar texto desde el programa con el método setText. al oprimir el botón de Cuenta. 60). 60). TextArea ta1 = new TextArea ().Para utiliza un área de texto hay que crear un objeto de tipo TextArea pasando como argumentos al constructor en forma opcional un string inicial. El texto capturado se puede recuperar llamando al método getText. La figura muestra la salida del programa. es decir. String s = ta1.getText (). 73 .SCROLLBARS_NONE).setText ("Esto es una línea\nEsto es otra línea"). el área de texto lo trata como un string. 60. TextArea. Después de escribir un texto cualquiera en la primera área de texto. // 10 renglones y 60 columnas TextArea ta3 = new TextArea ("hola mundo". A pesar de que el texto esté en varias líneas. El siguiente ejemplo presenta un applet con dos áreas de texto. 10. // el tamaño se deja al diseño TextArea ta2 = new TextArea (10. ta2. un tamaño preferido de desplegado en renglones y columnas y un indicador para que despliegue o no barras de scroll de inicio. la segunda área de texto despliega el número de líneas y de caracteres que se escribieron. // texto inicial TextArea ta4 = new TextArea ("hola".

5.length () + " caracteres"). GridBagConstraints gbc = new GridBagConstraints ().awt. // text area de abajo gbc.weighty = 33.gridy = 0.import java.event.addActionListener ( new java. gbc.gridwidth = 1. gbc.weighty = 33. gbc. gbc. public class ta extends Applet { GridBagLayout gbl = new GridBagLayout (). import java.anchor = GridBagConstraints.getText ().gridx = 0. TextArea ta1 = new TextArea ("Escribe algo"). for (int i = 0. int k = 0.setConstraints (btn. gbc. gbc. public void init () { setLayout (gbl).charAt (i) == '\n') k++.weightx = 0.applet.gridx = 0. gbc. gbc). ta2.setConstraints (ta2.awt.weightx = 0. Button btn = new Button ("Cuenta").awt. gbc.gridheight = 1. gbc. gbl.CENTER.ActionListener () { public void actionPerformed (ActionEvent e) { String s = ta1. add (btn).gridheight = 1. add (ta1). gbc. i < s.fill = GridBagConstraints.*. gbc. gbl.weightx = 100. gbl. gbc).fill = GridBagConstraints.gridwidth = 1. i++) if (s.gridy = 1. gbc.gridwidth = 1. add (ta2).CENTER. gbc.*. 25). TextArea ta2 = new TextArea ("Soy una textarea". // text area de arriba gbc.weighty = 33.CENTER. gbc.setText ("Escribiste\n" + k + " renglones\n" + s. 74 .gridheight = 1.NONE.fill = GridBagConstraints.gridy = 2. gbc). btn.gridx = 0.anchor = GridBagConstraints. gbc.setConstraints (ta1.NONE. gbc.NONE. gbc.*. import java.length (). gbc. gbc. gbc.event. // boton gbc.anchor = GridBagConstraints. gbc.

int opciones[] = lst3. La figura muestra la salida del programa.add ("opción dos").} }). en la parte inferior se despliegan las opciones que fueron seleccionadas en el choice y en las listas. Para usar una lista hay que crear un objeto de tipo List pasando como argumentos opcionales el número de opciones que estarán visibles y un indicador si la liste permite o no opciones múltiples. List lst1 = new List (). // permite escoger una opción List lst2 = new List (5). int opción = lst1.getSelectedIndex (). // cinco opciones visibles a la vez List lst3 = new List (5. En las listas que permiten la selección de únicamente un elemento el método getSelectedIndex devuelve la posición del elemento seleccionado. // permite opciones múltiples Las opciones se agregan con el método add.8.getSelectedIndexes (). lst2. true). El listado ejemplo presenta un applet con un choice. una lista que permite seleccionar un solo elemento y una lista que permite selección múltiple. lst2.add ("opción uno"). } } 7. Al oprimir el botón. 75 . En las listas que permiten múltiples selecciones el método getSelectedIndexes devuelve un arreglo de enteros con las posiciones de los elementos seleccionados.4 Listas Una lista es similar al choice que permite seleccionar de entre varias opciones de una lista con dos diferencias: su presentación es en forma de lista y permite seleccionar más de una opción.

gbc. gbc. gbc. 76 . gbc. gbc.NONE.anchor = GridBagConstraints. import java.add ("opcion 3").add ("opcion 1"). gbc. gbc. gbc).event.add ("opcion 2"). gbc.weightx = 33. gbc. lst_2.awt. Label lbl_1 = new Label ("En el choice la opcion es: "). lst_1.applet. gbc. gbc).anchor = GridBagConstraints. gbc. // choice chs_1.add ("opcion 4").fill = GridBagConstraints. gbl. gbc. Label lbl_2 = new Label ("En la lista 1 la opcion es: "). import java. gbc.*.CENTER.fill = GridBagConstraints. Choice chs_1 = new Choice (). gbc. add (lst_2).gridy = 0.add ("opcion 4").setConstraints (lst_2. gbc. gbc. // lista 2 gbc. add (chs_1).gridwidth = 1.import java. GridBagConstraints gbc = new GridBagConstraints (). lst_2.CENTER.*.add ("opcion 3").weighty = 0. gbc.add ("opcion 1"). public void init () { setLayout (gbl). gbc.awt. chs_1. lst_2. // boton de revisar gbc.add ("opcion 3"). gbc).gridy = 1. gbc.setConstraints (lst_1. gbl.gridy = 0.gridheight = 1. List lst_1 = new List ().gridx = 0.anchor = GridBagConstraints.weightx = 33.weighty = 0.*. add (lst_1).add ("opcion 2"). Label lbl_3 = new Label ("En la lista 2 las opciones son: "). chs_1.gridheight = 1.weightx = 33.add ("opcion 1").NONE. gbc. // una sola seleccion List lst_2 = new List (4. lst_1. gbc.NONE. gbl. lst_1.CENTER.gridy = 0. gbc. // seleccion multiple Button btn_revisar = new Button ("Revisar"). // lista 1 lst_1. lst_1. gbc. public class lst extends Applet { GridBagLayout gbl = new GridBagLayout ().fill = GridBagConstraints.weighty = 40.gridx = 0.gridwidth = 1.add ("opcion 2"). true).gridx = 1.gridwidth = 1.setConstraints (chs_1. lst_2. gbc.gridheight = 1.gridx = 2.add ("opcion 5").

event. // etiqueta 3 gbc.NONE.gridheight = 1.weightx = 0. gbc. gbc. } } 77 . gbc.getSelectedIndex ()). gbc.gridwidth = 1.fill = GridBagConstraints.gridx = 2. gbl. gbc.setConstraints (lbl_1. lbl_3. gbc.weighty = 40.weighty = 0. for (int i = 0.anchor = GridBagConstraints. gbc.gridheight = 1. i++) mssg. gbc. } }).setText ("En la lista 1 la opcion es: " + lst_1. gbc.ActionListener () { public void actionPerformed (ActionEvent e) { lbl_1. gbc.toString ()).weightx = 0.gbc.addActionListener ( new java.gridheight = 1.length.weighty = 0. StringBuffer mssg = new StringBuffer ("En la lista 2 las opciones son: ").awt.fill = GridBagConstraints. gbl.setConstraints (lbl_3. gbc. // oidor btn_revisar.append (idx[i] + " ").gridy = 2. gbc. gbc. add (lbl_1).getSelectedIndex ()).gridx = 1. gbc. gbc). gbc. i < idx. gbl.fill = GridBagConstraints. gbc. gbc.NONE.setText ("En el choice la opcion es: " + chs_1. // etiqueta 1 gbc.CENTER.NONE. gbc.setConstraints (lbl_2. gbc.getSelectedIndexes (). add (lbl_2).NONE.anchor = GridBagConstraints. gbc).gridwidth = 3.gridheight = 1.setText (mssg. add (lbl_3). // etiqueta 2 gbc.anchor = GridBagConstraints. gbc.gridx = 0.weighty = 20.fill = GridBagConstraints. gbc. int idx[] = lst_2.gridwidth = 1. gbc. gbc). add (btn_revisar). gbl. gbc).setConstraints (btn_revisar. gbc.CENTER.gridy = 2. gbc.gridy = 2. gbc.CENTER.anchor = GridBagConstraints.gridwidth = 1. gbc.weightx = 0.CENTER.weightx = 0. lbl_2.

// 400 pixeles de ancho y 300 pixeles de alto frm.awt.*.setLayout (new GridLayout (4. un menú de barra. // hace visible el frame El método dispose elimina el frame y libera la memoria. y otras características típicas de las ventanas. 300).event. maximizar o cerrar.WindowAdapter () { public void windowClosing (WindowEvent e) { frm. frm.awt. dependiendo del sistema operativo. import java. frm. frm. cuenta con un título. frm. El método setVisible hace que el frame sea visible o de vuelta invisible mediante un argumento booleano que puede valer true (la ventana se hace visible) o false (el frame se hace invisible). Frame frm = new Frame ("titulo de la ventana").setSize (400.dispose ().applet.add (new Button ("soy un botón")). import java. El frame puede tener su propio diseño y componentes. La figura muestra la salida de este programa. Para usar un frame hay que crear un objeto de tipo Frame pasando como parámetro el título de la ventana. Se invoca cuando el frame ya no va a ser utilizado. indicadores para minimizar. frm. un campo de texto y un botón y luego lo hace visible. import java.awt. 100). Se le puede asignar un tamaño en pixeles usando el método setSize o indicarle las coordenadas de su esquina superior izquierda con setLocation. esta inactivo. Es necesario crear un oidor de la clase WindowAdapter y registrarlo usando el método addWindowListener para indicarle al frame que se destruya al oprimir ese indicador. // 200 en x y 100 en y Cuando se crea un nuevo frame. Por default el indicador de cerrar ventana.*. } }).setVisible (true). que en Windows tiene una marca de cruz y está en la parte superior derecha del frame.5 Frames Un frame es una ventana que. Un frame es un componente contenedor y como tal puede tener su propio diseño y contener otros componentes de AWT.event. frm.addWindowListener ( new java.*. public class frm extends Applet { 78 . 1)).add (new Label ("soy una etiqueta")).7.dispose (). frm. le agrega una etiqueta.setLocation (200. El siguiente ejemplo presenta un applet que crea un frame.8. éste es invisible.

TextField tf_nombre = new TextField (20).setSize (400. frm_1.gridwidth = 1.gridwidth = 1.add (btn_ok). gbc. Button btn_ok = new Button ("OK"). // layout de la ventana frm_1. gbc. gbl.gridy = 0.anchor = GridBagConstraints. frm_1.WEST.gridx = 1. Label lbl_applet = new Label ("aqui es el applet"). gbc. gbc. gbc.fill = GridBagConstraints.setVisible (true). // boton de ok gbc.gridx = 0.anchor = GridBagConstraints. // textfield de nombre gbc. gbc. gbc). gbl. 300). gbc.gridheight = 1.lightGray).CENTER.gridy = 1.WEST. gbc.NONE. GridBagConstraints gbc = new GridBagConstraints (). gbc. // etiqueta de nombre gbc. gbc.weightx = 30.setConstraints (btn_ok. gbc.setConstraints (lbl_nombre.fill = GridBagConstraints.add (lbl_nombre).weighty = 0. gbc. gbc. Panel pnl_1 = new Panel ().Frame frm_1 = new Frame ("Mi ventanita"). gbl.weighty = 20.setLayout (gbl).weightx = 70.gridheight = 1.event.setLocation (100. frm_1.gridx = 0.addWindowListener ( new java. gbc.WindowAdapter () { 79 . public void init () { // layout del applet setBackground (Color. gbc).weighty = 80.setConstraints (tf_nombre. gbc. gbc. 150).gridheight = 1. gbc). GridBagLayout gbl = new GridBagLayout (). add (lbl_applet).weightx = 0.NONE. setLayout (new FlowLayout (FlowLayout. frm_1. // oidor frm_1.NONE. Label lbl_nombre = new Label ("Nombre").anchor = GridBagConstraints.gridwidth = 2. gbc. frm_1.gridy = 0. gbc. frm_1.fill = GridBagConstraints.LEFT)). gbc. gbc.add (tf_nombre). gbc.awt.

Para usar un diálogo hay que crear un objeto de tipo Dialog pasando como argumento obligatorio el frame al cual están ligados y opcionalmente un argumento string con el título del diálogo y una variable booleana para indicar si el diálogo es modal o no modal. true). } }). Por estos motivos y por lo general. no tienen indicadores de maximizar ni de minimizar y pueden operar en forma modal.dispose (). setVisible. // tiene título y es modal Los métodos setLayout. Dialog dlg1 = new Dialog (frame). // el diálogo es no modal por default Dialog dlg2 = new Dialog (frame. true). dispose y addWindowListener 80 . Las diferencias son que los diálogos necesitan tener un frame ligado a ellos. } } 7. setLocation. // el diálogo es modal Dialog dlg3 = new Dialog (frame. los diálogos se utilizan en forma modal y para avisar de errores en el programa o pedir datos al usuario. "titulo".public void windowClosing (WindowEvent e) { frm_1.6 Diálogos Un diálogo es semejante a un frame en el sentido que es una ventana que puede tener su propio diseño y contener a otros componentes. add. Un diálogo modal impide que sean accesadas otras ventanas hasta que el diálogo sea cerrado. setSize.8.

tienen la misma funcionalidad que en los frames. import java. Dialog dlg_1.awt. "título". La figura muestra la salida del programa antes de cerrar el diálogo.*. Frame frm_1 = new Frame ("Ventanita"). usando el método getParent. Label lbl_error = new Label ("El frame no se abrira hasta cerrar este dialogo"). Object tmp = getParent (). public class dlgm extends Applet { GridBagLayout gbl = new GridBagLayout (). import java. Para que un applet pueda usar un diálogo necesita hacer referencia a la ventana del navegador que lo contiene. true).*. dlg_1 = new Dialog ((Frame) tmp. Button btn_ok = new Button ("Cerrar").*. El ejemplo presenta un applet que abre un diálogo modal y por lo tanto se bloquea. true). GridBagConstraints gbc = new GridBagConstraints (). import java.getParent ().awt. dlg1 = new Dialog ((Frame) tmp.getParent ().event.applet. hasta encontrar un objeto de tipo Frame y pasar como argumento ese objeto al constructor del diálogo. Una forma de conseguirlo es obtener los componentes padres del applet. while (! (tmp instanceof Frame)) tmp = ((Component) tmp). "Dialogo modal". Label lbl_hola = new Label ("Hola"). while (! (tmp instanceof Frame)) tmp = ((Component) tmp). 81 . Al cerrar el diálogo el programa puede continuar y abre un frame. public void init () { // Dialog Object tmp = getParent ().

addWindowListener ( new java. // Agrega los oidores btn_ok. gbc.setLocation (100.gridy = 1. // Frame frm_1.awt. lbl_hola.setLayout (new BorderLayout ()). frm_1.gridy = 0.ActionListener () { public void actionPerformed (ActionEvent e) { dlg_1.CENTER.gridheight = 1. gbc.gridx = 0. gbc. lbl_hola). frm_1.CENTER.event. frm_1. frm_1.setSize (400. gbc. gbc.dispose ().setConstraints (lbl_error. gbc.setVisible (true).add (lbl_error).setConstraints (btn_ok. // Boton de ok gbc. frm_1.gridwidth = 1.NONE.setLayout (gbl). } }). gbc. dlg_1. dlg_1. gbc).setVisible (true). gbl.weighty = 90. 120).NONE.PLAIN. gbc. gbc. 150).anchor = GridBagConstraints.weightx = 100.gridheight = 1.WindowAdapter () { public void windowClosing (WindowEvent e) { frm_1.setForeground (Color. }} 82 . frm_1. gbc. gbc). 300).fill = GridBagConstraints. 36)). gbc.gridx = 0. // Etiqueta de error gbc.gridwidth = 1.dlg_1. dlg_1. Font.addActionListener ( new java.add (btn_ok).dispose (). gbc. gbc.add ("Center".weightx = 0.awt.pack ().green). dlg_1. dlg_1. dlg_1.fill = GridBagConstraints. gbc. } }).setLocation (90.setResizable (false).setFont (new Font ("Times Roman". gbl.event.weighty = 10.anchor = GridBagConstraints.

El Container actúa de intermediario entre la ventana y los componentes que él almacena pasándoles a estos los mensajes que a él le llegan desde la ventana. que puede almacenar cualquier tipo de objeto que derive de la clase Container (normalmente bien controles o bien otros gestores de diseño). aunque muchas de las clases que implementan los gestores de diseño y el tratamiento de eventos se encuentran dentro del paquete JAVA. 8. un objeto del tipo deseado de gestor de diseño con el que se desea trabajar. qué gestor de diseño se asignará al contenedor. es decir. Veamos. o dicho de otro modo. que es la que se encuentra en la raíz de la jerarquía de clases.awt. es necesario que estos estén contenidos en un gestor de diseño. quien a partir de ahora ya sabe con qué gestor deseamos trabajar. se puede especificar con cual o cuales de los gestores de diseño disponibles en Java se quiere trabajar. es a través de la clase Container como podemos establecer el o los gestores de diseño que la ventana va a utilizar para implementar los componentes que ésta manejará. Puesto que existen diferentes gestores de diseño incluidos en el lenguaje Java y puesto que además podemos construir nuestros propios gestores de diseño. siempre que se crea un Container. de otro modo no funcionarán correctamente.  Desde el punto de vista de la jerarquía de clases de Java. en éste veremos lo común a los dos tipos de componentes. un gestor de diseño es un "estilo de visualización". un gestor de diseño es un interfaz. la siguiente línea de código: this.setLayout(new FlowLayout()). como ya hemos comentado. vamos a tratar dos características del interfaz de usuario en los programas Java. El operador new devuelve un gestor de diseño del tipo FlowLayout. El gestor de diseño es parte del Container. Comencemos por lo tanto. Lo que vamos a ver en este capítulo es aplicable tanto a componentes AWT como a componentes Swing (que los veremos en el siguiente capítulo). de hecho. viendo qué es un gestor de diseño desde tres puntos de vista diferentes:   Desde el punto de vista del lenguaje.8.  Desde el punto de vista operativo.AWT y del subpaquete java. y deriva directamente de la clase Object. Lo que se hace pasándole al método setLayout() de la clase Container. Veamos esto de una forma más detenida. los gestores de diseño y los eventos.1 Gestores de diseño Los gestores de diseño (Layout Managers) tienen una gran importancia en el leguaje Java. es el mecanismo que el lenguaje incorpora para conseguir crear aplicaciones que tengan la misma apariencia a través de las diferentes plataformas en las que éstas pueden ejecutarse. El modo de interactuar con un gestor de diseño es muy simple: basta con especificar con cual de los disponibles queremos trabajar y añadirle componentes. para poder incorporar controles en una ventana (ya sea de una aplicación o de un applet). Sin embargo. éste objeto es recogido por el método setLayout() de la clase Container. un Gestor de diseño es una propiedad del contenedor. Los eventos y gestores de diseño específicos de los componentes Swing los veremos en los próximos capítulos en los que se abordará Swing.events. se hace necesario indicar con cual de los disponibles deseamos trabajar. 83 . vamos a continuar con la creación de interfaces de usuario en Java. por ejemplo.0 Gestores de diseño Introducción A lo largo de este capítulo.

. Los layouts por defecto para los contenedores de swing son los mismos que para sus homónimos de AWT. . public void setMinimumSize(Dimenstion size). Si queremos cambiar el layout manager de un contenedor en un momento dado. JFrame frame = new JFrame().Component nos ofrece una serie de métodos para poder modificar los valores de los atributos anteriores: public void setSize(Dimension size). el intérprete Java no les hace ningún caso y los objetos muestran un tamaño que nosotros no queríamos. frame. una longitud y una anchura determinadas. tan sólo tendremos que llamar al método: contenedor. public void setMaximumSize(Dimension size). Por su parte la clase javax.. Para ello algo tan simple como lo que aparece aquí: this.add( new Button( "Uno" ) ).setSize(400. frame.add(button). button. Veamos un ejemplo: . Los componentes como hemos dicho son objetos que forman parte de nuestro interfaz gráfico.La clase Container dispone del método add(). Cada componente tiene asignada una coordenada horizontal. JButton button = new JButton(). ver que aunque utilizas estos métodos. Si en cualquier momento decidimos que estamos hartos de un layout manager y queremos encargarnos nosotros mismos de la gestión de componentes tan sólo tendremos que escribir: contenedor.setLayout(null). La clase java. public void setBounds(Rectangle r). cuando conoces el funcionamiento de los layouts.. Estos valores serán los que se utilizarán para renderizar el componente en pantalla.getContentPane().25)).300).setMaximumSize(new Dimension(80.setVisible(true).awt. una coordenada vertical. Es muy frustrante.JComponent tiene métodos diferentes: public void setPreferredSize(Dimension size). que permite añadir componentes. a un objeto de la clase Container le podemos añadir bien controles o bien otros gestores de diseño.. 84 ..setLayout(LayoutManager layout). Hay pequeñas variaciones de estos métodos pero su función es la misma.swing. frame.. Como ya hemos comentado.

c. 8.add ( b1 ) . } 85 .add ( b2 ) . JButton b3 = new JButton ( "Botón largo " ) . c. sigue con la siguiente. Este gestor. Sin embargo. JButton b5 = new JButton ( "E" ) . A continuación vamos a comentar los distintos gestores de diseño que podemos encontrar dentro del paquete JAVA. import java. Este tamaño suele ser dependiente de la plataforma y el layout manager intentará respetarlo siempre que sea posible y siempre que lo permitan sus políticas de layout.1 FlowLayout El gestor de diseño FlowLayout. class EjemploFlowLayout extends JFrame{ public EjemploFlowLayout( ) { Container c = getContentPane ( ) . es también el más simple de todos. además de ser el gestor de diseño por defecto de los applets.*. lo que pasa es que después de añadirlo al frame es el layout manager de éste el que toma el control del interfaz y el que pasa a decidir el nuevo tamaño del botón. Es decir. distribuye los controles de izquierda a derecha llenando el ancho del contenedor de arriba a abajo.event. los controles fluyen (Flow).*.AWT. c.*. tras ejecutar el programa veremos como nuestro botón es considerablemente más grande. JButton b2 = new JButton ( "B" ) . Si creamos un pequeño programa que contenga las líneas de código anteriores y lo ejecutamos. import javax. JButton b4 = new JButton ( "D" ) . inicialmente podríamos pensar que se verá un botón de 80 puntos de largo por 25 de ancho.awt.1. Los cinco gestores de diseño son los que se comentan a continuación. En el ejemplo anterior. c. JButton b1 = new JButton ( "A" ) .setLayout (new FlowLayout ( ) ) .swing. si que se establece el tamaño máximo de 80x25 para el botón. Es decir.awt. En los distintos ejemplos se han utilizado botones para poner de manifiesto las diferentes distribuciones que los distintos gestores de diseño hacen del espacio ya que el gestor es invisible. c. actuando con los controles como lo hace un editor de textos con las palabras.Aunque no lo he dicho. El último aspecto importante a tener en cuenta es el significado del atributo preferredSize. Ejemplo: import java. por lo que nuestra llamada a setMaximumSize() no hace ningún efecto. c. cuando acaba con una fila de controles.add ( b3 ) . ¿Qué es lo que ha pasado? ¿Por qué no nos ha hecho caso? La realidad es que cuando utilizamos layout managers no sirve de nada intentar establecer a la fuerza el tamaño de los componentes ya que será el layout el que siempre tenga la última palabra1.add ( b5 ) . Este atributo indica el tamaño que a un componente le gustaría tener.add ( b4 ) . todos los layout managers implementan la interfaz LayoutManager directa o indirectamente (a través de LayoutManager).

panel.200) .swing. en la versión que ya conocemos. panel.setVisible(true).*. Container panel = frame. BorderLayout divide el espacio de un contenedor en cinco regiones diferentes. JButton centro = new JButton("Centro"). frame. BorderLayout. panel. } } 86 . BorderLayout. Estas regiones son: North. panel.add(norte.NORTH).setDefaultCloseOperation(JFrame. import java. en este caso se utiliza el método add() de la clase Container.2 BorderLayout BorderLayout es el layout manager por defecto para frames por lo que al igual que FlowLayout su aprendizaje es indispensable.SOUTH). frame.add(oeste.} }). South. public class TestBorderLayout extends JFrame { public static void main(String[] args) { TestBorderLayout frame = new TestBorderLayout(). frame.300).setSize(400.awt.setVisible(true).EAST). JButton este= new JButton("Este"). East.add(este. BorderLayout. f. frame. JButton oeste = new JButton("Oeste").exit(0). es decir pasándole por parámetro la instancia del componente AWT que queremos añadir.*. se utiliza primero el método setLayout() pasándole por parámetro una instancia del gestor de diseño que se va a utilizar en nuestra ventana.setSize (200 . JButton norte = new JButton("Norte").public static void main (String [ ] args ) { EjemploFlowLayout f = new EjemploFlowLayout ( ) .setTitle("Prueba de BorderLayoutLayout"). f. JButton sur= new JButton("Sur").add(sur. y se corresponden con su situación dentro del contenedor en el que se encuentran. f. West y Center. BorderLayout.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. En el bucle se van añadiendo botones a la ventana.1. Veamos más claramente lo que quiere decir esto con un ejemplo sencillo: import javax.WEST).getContentPane(). panel.EXIT_ON_CLOSE). 8.add(centro.CENTER). } } Como se puede observar. BorderLayout.

CENTER // Por defecto Existe una manera alternativa de especificar donde queremos colocar los componentes y es pasando como parámetros al método add en lugar de los atributos anteriores las cadenas siguientes: “North” “South” “East” “West” “Center” Este método no está recomendado porque es demasiado propenso a errores. Cuando añadimos un componente en las posiciones norte o sur. sería bastante normal colocar una barra de herramientas en el panel norte de nuestra ventana. Por lo tanto tenemos que tener cuidado con donde insertamos los componentes. Si no especificamos ninguna región por defecto el componente se inserta en el centro del contenedor. dejando el panel central para el resto del interfaz. Por ejemplo. Si insertamos un componente en una región donde había otro componente previamente.WEST BorderLayout. ya que si nos equivocamos en una simple letra el compilador no nos avisará de nuestro error y por lo tanto podremos llevarnos sorpresas al ejecutar el programa.EAST BorderLayout. Aunque ya las hemos visto en el código las resumiremos de nuevo: BorderLayout. el que se encontraba en el contenedor desaparecerá y el nuevo ocupará su lugar. Con los componentes de las posiciones este y oeste pasa lo contrario. 87 . Por último el objeto que se situe en la zona central ocupará el resto de espacio disponible.Como podemos ver en el código f uente anterior. una barra de estado en el panel sur y quizás un árbol de navegación en el panel izquierdo o derecho. Para finalizar con este layout manager vamos a hablar de como trata el tamaño de los componentes. es muy útil para muchas aplicaciones. Border-Layout respeta su longitud y ajusta su altura hasta que ocupe la totalidad de la altura del contenedor o hasta que se encuentre con los componentes del norte o del sur. BorderLayout. al añadi r un elemento al BorderLayout tenemos que especificar la región en la cual lo queremos añadir.SOUTH BorderLayout.NORTH BorderLayout. por su estructura. BorderLayout respeta su alto mientras que la longitud del mismo se ajusta hasta ocupar todo el ancho del contenedor.

Container container = frame.add(label1.8.EXIT_ON_CLOSE).add(label2.*. JPanel panelComponentes = new JPanel(). Los componentes a medida que se insertan en el contenedor van formando una secuencia.event. En este layout manager los componentes ocuparán todo el tamaño disponible en el contenedor. JLabel label1 = new JLabel(“Componente 1”). frame. import java. import java. panelComponentes. JLabel label4 = new JLabel(“Componente 4”).NORTH). frame. 88 . siguiente. al añadir componentes tendremos que fijarnos en que el orden en el que los añadamos al contenedor será el orden en el que serán recorridos por el layout manager. Veamos un ejemplo simple: import javax. JLabel label2 = new JLabel(“Componente 2”).3 CardLayout CardLayout es un layout manager ligeramente diferente a todos los demás ya que tan sólo muestra en un instante dado un único componente.next(panelComponentes). Por último.awt. panelComponentes.setLayout(layout). public void previous(Container contenedor). JButton siguiente = new JButton(“siguiente”). El método más común para añadir un componente es: public void add(Component componente. Este método inserta un componente dentro de un contenedor y le asigna un nombre.swing. String nombre).getContentPane(). frame. container. este nombre lo podremos utilizar con el método show para mostrar el componente directamente. panelComponentes. CardLayout layout = new CardLayout(). BorderLayout. Un contenedor que tenga asignado un CardLayout podrá tener cualquier número de componentes en su interior pero sólo uno se verá en un instante dado.300). BorderLayout. panelComponentes.setTitle("Prueba de BorderLayoutLayout").”3”).”2”).addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { layout.setDefaultCloseOperation(JFrame. panelComponentes.*.*.”4”).add(panelComponentes. Para seleccionar el componente que queremos mostrar en cada momento disponemos de varios métodos: public void first(Container contenedor). public void show(Container container.add(label4. public void next(Container contenedor).awt. public void last(Container contenedor).1. JLabel label3 = new JLabel(“Componente 3”).CENTER). String nombre). container.add(label3. public class TestCardLayout extends JFrame { public static void main(String[] args) { TestCardLayout frame = new TestCardLayout().add(siguiente. } }).setSize(400.”1”).

1. es decir.awt. i++) { 89 . por lo que no existe una forma preestablecida de interactuar con los controles para cambiar de unas fichas a otras.swing. El problema que este gestor de diseño tiene es que la implementación que en Java se ha hecho de él.setVisible(true). Es similar a los controles de pestaña o "tabs" de Windows. y las fichas (o tarjetas si se prefiere) no tienen la correspondiente pestaña asociada. container.frame. import java. Cada fila y cada columna tiene el mismo tamaño y el área del contenedor se distribuye equitativamente entre todas las celdas. for (int i = 0.*. Este tercer gestor permite manejar varias "fichas intercambiables". de forma tal que sólo una esté visible a la vez y ocupando todo el área del contenedor. en un conjunto de filas y columnas. Con un botón podemos ir avanzando de etiqueta. Este layout manager es muy sencillo y muy útil especialmente cuando tenemos un panel que variará su contenido en función de alguna parte de nuestro interfaz (una combo box por ejemplo). int X = 3. Al pulsar el botón se muestra la etiqueta siguiente llamando al método next() de CardLayout. int Y = 3. siendo necesario crear este mecanismo programáticamente con los inconvenientes de pérdida de tiempo y esfuerzo que esto supone. } } El ejemplo es muy sencillo y muestra un contenedor con varias etiquetas. Veamos un ejemplo simple de funcionamiento: import javax. De todo esto se deduce que GridLayout no respetará el tamaño preferido de los componentes que insertemos en cada una de las celdas. no es completa.4 GridLayout GridLayout divide el espacio de un contenedor en forma de tabla. Container container = frame. En el capítulo siguiente veremos que los componentes Swing ofrecen una clase llamada JTabbedPane que representa un componente en el que se pueden elegir las distintas fichas (paneles) a través de los paneles que presenta.getContentPane(). i < X. podemos utilizar un CardLayout que nos ahorra gran cantidad de trabajo. o en lugar de eliminar los componentes e insertar otros nuevos.setLayout(new GridLayout(X. En lugar de eliminar el panel e insertar otro nuevo. El número de filas y columnas se especifica en el constructor. public class TestGridLayout extends JFrame { public static void main(String[] args) { TestGridLayout frame = new TestGridLayout().Y)).*. es decir. si creamos un GridLayout con cero filas y tres columnas e insertamos cuatro componentes el GridLayout será lo suficientemente inteligente como para saber que tiene que crear dos filas. 8. Si pasamos cero como el número de filas o columnas el layout manager irá creando las filas y columnas en función del número de componentes y del valor de la otra dimensión.

frame. o que una celda pudiese ocupar varias posiciones. Con este layout manager tenemos control absoluto sobre las posiciones que ocuparán los objetos en el interfaz final. GridLayout es un layout manager realmente muy simple y como tal su utilidad se encuentra bastante reducida. este layout manager proporciona una serie de ventajas sobre el resto: • Permite la creación de interfaces de usuario complejos.EXIT_ON_CLOSE).setDefaultCloseOperation(JFrame. Afortunadamente.1.5 GridBagLayout GridBagLayout es el layout manager más poderoso y eficaz con mucha diferencia. j++) { container. 8.setVisible(true).for (int j = 0..add(new JButton(i + “ x “ + j)). } } frame. Con GridBagLayout podemos imitar facilmente el comportamiento del resto de layout managers a parte de poder crear con el interfaces mucho más complejas. Suele ser útil a la hora de crear partes del interfaz de usuario que necesiten representar una matriz de componentes o incluso para interfaces que tengan en si una forma matricial. etc.setSize(400. j < Y. o dejar celdas vacías. frame. GridBagLayout.setTitle("Prueba de BorderLayoutLayout").300). Como se puede ver todas las celdas tienen el mismo tamaño y los botones ocupan la totalidad de la celda. Lo realmente interesante sería que algunas celdas pudiesen tener tamaños diferentes a las demás.. } } En la figura anterior vemos el resultado de ejecutar el ejemplo. esto es justamente lo que nos permite el próximo layout manager que veremos. Ventajas y desventajas GridBagLayout es el layout manager que más pavor causa entre los programadores Java. frame. Odiado por unos y alabado por otros. 90 .

Los paneles son objetos bastante pesados y tener una gran cantidad de los mismos puede influir perjudicialmente en el rendimiento de nuestro programa. Cuando queremos crear un interfaz de usuario combinando el resto de layout managers vistos hasta el momento a menudo terminamos con un número grande de paneles anidados. Pero como todo. • El código necesario para crear un interfaz de usuario es considerablemente más grande que con el resto de layout managers y además suele ser un código bastante complicado y díficil de comprender y por lo tanto de mantener. A continuación vamos a ver los atributos importantes. también tiene sus inconvenientes: • Requiere un tiempo de aprendizaje bastante grande. sin embargo la experiencia dice que poner este atributo es recomendable ya que permite saber en que elemento nos encontramos de una manera visual. No sólo es necesario comprender su funcionamiento sino que también es necesario haber hecho bastantes ejemplos para llegar a dominarlo. GridBagLayout a fondo GridBagLayout basa su funcionamiento en una clase auxiliar que establece restricciones a los componentes. Con GridBagLayout se pueden crear interfaces exactamente iguales pero con un único panel con lo que nuestra interfaz será mucho más ligera. Estas restricciones especifican exactamente como se mostrará cada elemento dentro del contenedor. Comprendiendo a la perfección su significado no habrá ningún interfaz que se nos resista. Básicamente lo que indican 91 . no voy a mostrar la totalidad de atributos para no complicar las cosas a los menos experimentados.Layout sea un juego de niños. La clase GridBagConstraints posee bastantes atributos que nos permiten configurar el layout de un contenedor a nuestro gusto. Vamos a ir viendo los atributos más importantes de esta clase y de una forma gráfica para que se entienda mejor: gridx y gridy Estos dos atributos especifican las coordenadas horizontal y vertical del componente que vamos a insertar en el grid. En la última parte de este apartado veremos como podemos crear una serie de clases auxiliares con las que solucionaremos estos dos inconvenientes y que harán que utilizar GridBag. La siguiente figura muestra gráficamente lo que indican los atributos gridx y gridy: gridwidth y gridheight Este otro par de elementos junto con gridx y gridy son la base de GridBagLayout. Realmente no siempre es necesario establecer su valor ya que en los casos más simples nos llegaría con gridwidth y gridheight.• Las interfaces construidas son más ligeras. GridBagConstraints.

REMAINDER. indica que el componente es el último de la fila actual o columna actual. • GridBagConstraints.gridheight=GridBagConstraints. En el segundo y tercer componente en lugar de ponerle uno como valor de gridwidth hemos de poner RELATIVE y REMAINDER.Siempre y cuando no se use gridx y gridy. • GridBagConstraints.RELATIVE.RELATIVE c. ocupará todo el espacio hasta el último componente. Analicemos la figura anterior para comprender el significado de estos dos atributos. es decir. Técnicamente sólo sería necesario poner REMAINDER ya que es el único que necesita conocer el GridBagLayout para saber que se ha acabado la fila.REMAINDER c. En la primera fila tenemos tres componentes. Todos los componentes ocupan una celda en horizontal y en vertical luego su gridwidth y gridheight ha de ser igual a uno. indica que el componente ocupará el espacio disponible desde la fila o columna actual hasta la última fila o columna disponibles. Ambos tienen como gridheight RELATIVE ya que se encuentran en la penúltima fila.gridwidth y gridheight es el número de celdas que ocupará un componente dentro del GridBagLayout. c. El primer componente tiene de gridwidth REMAINDER.gridheight=1 c.gridheight=1 c. en este caso indica exactamente el número de filas o columnas que ocupará el componente.gridwidth=GridBagConstraints.gridwidth=GridBagConstraints.1 En la segunda fila tenemos dos componentes.gridwidth=1 c.gridheight=1 c.gridwidth=GridBagConstraints.RELATIVE 92 .RELATIVE c. En la figura se puede ver como se cumple esto que acabo de decir ya que el componente abarca dos celdas y la última se deja para el último cuyo gridwidth es RELATIVE. su valor puede ser: • Un número cardinal. 1.

• VERTICAL: El componente ocupará todo el espacio vertical de la celda mientras que su longitud será la que tenga como preferida.gridwidth=GridBagConstraints.REMAINDER c. Como veis es bastante sencillo. fill El atributo fill especifica el espacio que ocupará el componente dentro de la celda. WEAST.gridheight=GridBagConstraints. SOUTHWEST.gridwidth=GridBagConstraints.REMAINDER c. gridwidth y gridheight especifican el número de celdas horizontal y vertical que abarcará un componente. Los valores que puede tomar este atributo están definidos como variables estáticas dentro de la clase GridBagConstraints y son: NORTH. • BOTH: El componente ocupará la totalidad de la celda Veámoslo en una imágen: 93 .gridheight=GridBagConstraints. SOUTH. SOUTHEAST y CENTER. Como intuiréis indican la orientación de los componentes dentro de la celda que ocupan. Además podemos utilizar los valores especiales REMAINDER y RELATIVE para indicar que un componente ha de ocupar todo el espacio restante o todo el espacio hasta el último componente. NORTHWEST. anchor Este atributo es mucho más sencillo.c. Veamos una figura que nos aclare las cosas: En la imágen anterior las líneas punteadas marcan el espacio que ocupa cada una de las celdas del contenedor.REMAINDER c.RELATIVE Por último en la tercera fila tan sólo tenemos un componente con gridwidth REMAINDER y gridheight REMAINDER. NORTHEAST. Los valores que puede tomar también son variables estáticas de la clase GridBagConstraints: • NONE: El componente ocupará exactamente el tamaño que tenga como preferido • HORIZONTAL: El componente ocupará todo el espacio horizontal de la celda mientras que su altura será la que tenga como preferida. EAST. En este ejemplo he colocado cada uno de los componentes con un anchor diferente para que podáis apreciar fácilmente el efecto que tiene este atributo. anchor especifica la posición que ocupará un componente dentro de una celda.

pero eso es debido a que he utilizado los atributos weightx y weighty. Hay que tener mucho cuidado porque al contrario de lo que pueda parecer si no indicamos nada las celdas no ocuparán la totalidad del contenedor. Fijaros en la figura anterior. Como habéis podido observar hasta ahora no ha habido nada complicado. Todos los atributos que hemos visto son bastante sencillos de comprender y prácticamente ya estaríamos en disposición de crear un interfaz complejo con GridBagLayout. weightx y weighty Estos dos atributos son la clave de los dolores de cabeza que GridBagLayout le da a tanta gente. en este caso las celdas si que ocupan todo el contenedor. Mirar lo que sucede si hago el mismo ejemplo anterior sin estos atributos: He puesto las líneas que marcan el espacio ocupado por las celdas en rojo para que se vea mejor. Como veis las celdas tienen de largo la longitud máxima de los componentes y de alto la altura máxima de los componentes.Como antes. la respuesta como cabía esperar son los atributos weightx y weighty. 94 . ¿Cómo hacemos entonces para que las celdas ocupen la totalidad del contenedor?. Sin embargo existe un pequeño problema que veremos a continuación. Como se puede apreciar en la figura según el valor del atributo anchor los componentes abarcarán más o menos espacio. las líneas marcan los bordes de las celdas. A medida que vamos añadiendo componentes a un contenedor el layout manager va determinando en función del tamaño de los componentes el espacio que ocupan las celdas. Esto suele desconcertar a la gente ya que por mucho que se utilicen correctamente los otros atributos este comportamiento por defecto acaba por hacer que nuestros interfaces no salgan como planeabamos.

Veamos como queda el ejemplo anterior pero utilizando los atributos weightx y weighty: 95 . Sin embargo como el componente 2 tan sólo quiere el 40% del espacio libre se le asignan 50 puntos y el resto de los puntos pasan al otro componente que recibirá sus 125 puntos más los 75 puntos que sobraron del segundo componente. La forma de especificar el espacio que quiere ocupar cada componente es mediante un número entre 0. por lo tanto a cada uno le tocan 125 puntos. En el ejemplo anterior una vez añadidos los componentes queda una determinada cantidad de espacio libre tanto horizontal como vertical. Este número representa al porcentaje de espacio libre que ocupará cada celda.weightx=0.Los atributos weightx y weighty especifican el porcentaje de espacio libre que ocupará una celda eterminada. En este caso como los dos componentes han pedido la totalidad de su parte a ambos les corresponden 75 puntos.0 y 1. Veamoslo: Este espacio libre (flechas) se dividirá entre todas las celdas que especifiquen valores dentro de los atributos weightx y weighty. c. Un ejemplo: • Espacio libre 250 puntos en horizontal y 150 en vertical • Componente 1: c. Obviamente cuando estemos diseñando el interfaz no estaremos pensando en si este componente va a tener unos puntos y otro otros. éste se divide entre ambos.weighty=1. Como vimos antes se divide el espacio libre entre los componentes que lo han pedido. Como ambos componentes han pedido espacio libre.weightx=1.0 • Componente 2: c. en total 200 puntos.0.0 Veamos como se asigna el espacio horizontal. c.0. sin embargo los atributos weightx y weighty son de una ayuda inestimable para hacer que determinadas partes de nuestra interfaz sean más grandes que las otras. El espacio vertical es más sencillo.weighty=1.4.

el componente se pega literalmente al borde de la celda. int left. Si os fijáis en la figura anterior. Veamos un ejemplo: 96 . En este caso.1 como valor de weightx las celdas de la derecha ocupen tanto espacio. Lo más importante es comprender que se los porcentajes se refieren al espacio libre y que el espacio libre se determina después de insertar los componentes. es decir. en vertical o en ambas direcciones. Muy comúnmente desearemos que los componentes no estén tan pegados.Como se puede apreciar en la figura anterior cuanto mayor sea el porcentaje más espacio libre ocupará nuestra celda. que no os extrañe que poniendo 0. Esto lo conseguimos con el atributo insets. Por lo tanto.Insets cuyo constructor es: Insets(int top. int bottom. insets. insets Con todo lo que hemos visto hasta ahora tenemos más que de sobra para crear una interfaz compleja.awt. El atributo insets es un objeto de la clase java. las celdas de la derecha ocuparán el tamaño preferido del botón más grande ( “HORIZONTAL” ) más su porcentaje del espacio libre horizontal. int right) Como intuiréis los parámetros del constructor especifican el espacio que se dejará de márgen. Vamos a ver un último atributo que nos servirá de gran ayuda. cuando se insertan componentes que ocupan la totalidad de la celda ya sea en horizontal. que haya un márgen entre el borde de la celda y los componentes.

5). f.setTitle("Login").getContentPane().c).REMAINDER.BOTH.*.4. container.setVisible(true). tal como se ve en el código. ((JPanel)container).weightx=0. import java.insets = new Insets(2. c. c.weighty=1.gridwidth=GridBagConstraints.gridwidth=GridBagConstraints.RELATIVE.setDefaultCloseOperation(JFrame.5.fill=GridBagConstraints.weightx=1. Si compilais y ejecutáis el ejemplo os deberíais encontrar con la ventana siguiente: 97 .0. GridBagConstraints c = new GridBagConstraints().0.c).gridheight=GridBagConstraints.gridwidth=GridBagConstraints. c. f.setBorder(BorderFactory.weightx=0. la ventana de entrada al sistema.4.Vamos a empezar con el más sencillo.RELATIVE.add(new JLabel("Usuario"). container. c.WEST. c. c.2.add(new JTextField().REMAINDER. c.add(new JLabel("Contraseña").0. c. Veamos como sería el código para crear este interfaz: import javax.0). para no tener que estar creándolas continuamente.gridwidth=GridBagConstraints.5). c. Container container = f. Esta variable puede ser reutilizada.setSize(220.REMAINDER.weightx=1.110). c.createTitledBorder( "Entrada al sistema")).RELATIVE. c. container.insets = new Insets(2. } } Como se puede ver cada vez que añadimos un componente al contenedor hemos de pasar una variable de tipo GridBagConstraints al método add.anchor = GridBagConstraints. c.add(new JTextField(). f. c.gridheight=GridBagConstraints.c). Tened mucho cuidado de no olvidaros pasar la variable de constraints porque en otro caso el interfaz no saldrá como esperábais.setLayout(new GridBagLayout()). public class A { public static void main(String[] args) { JFrame f = new JFrame(). container. c. c.2. f.swing.2.gridheight=GridBagConstraints. c.EXIT_ON_CLOSE). c.*.c). c. container.insets = new Insets(2.2.0.gridheight=GridBagConstraints.5.0).RELATIVE.awt.REMAINDER.insets = new Insets(2. c.0.

y ellas deciden si han de responder o no de algún modo a este evento. Como ya os he comentado. ¿Qué es un evento? Todos los sistemas operativos están constantemente atendiendo a los eventos generados por los usuarios. A continuación el evento se transmite a un ”manejador de eventos” (event listener) que este asignado al componente en el que se produjo el evento. El sistema operativo notifica a las aplicaciones que están ocurriendo estos eventos. El modelo de delegación de eventos El modelo de Java se basa en la delegación de eventos: el evento se produce en un determinado componente. por ejemplo. 9. 98 . Realmente este sistema de gestión de eventos es bastante elegante y sencillo. mover el ratón. mucho más engorroso de usar y menos elegante. por ejemplo un scroll. estos atributos no son estrictamente necesarios al igual que tampoco lo son gridwidth o gridheight. consideraron que era lo suficientemente bueno. Estos eventos pueden ser pulsar una tecla. en un botón). Dónde se produce el evento se denomina “fuente del evento”. algunos diseñadores pensaron que se necesitaba dejar a un lado las librerías AWT e introducir las Swing no sintieron lo mismo del sistema de gestión de eventos. sobre todo si se compara con el sistema de gestión de eventos de Java 1.Un último punto que quería resaltar del código fuente anterior es que como podéis observar no he utilizado para nada los atributos gridx y gridy. Esta separación de código entre generación del evento y actuación respecto a él facilita la labor del programador y da una mayor claridad a los códigos.0. hacer clic con el ratón. pulsar el ratón sobre un botón o menú (Java distingue entre simplemente pulsar el ratón en un sitio cualquiera o hacerlo.0 EVENTOS El sistema de gestión de eventos de Java de la AWT es similar al de SWING. A menudo con utilizar una de las dos alternativas será suficiente pero habrá ocasiones en las que tendremos que utilizar ambos atributos. El objeto que escucha los eventos es el que se encargará de responder a ellos adecuadamente.

. el objeto fuente empaqueta información a cerca del evento generando un objeto de tipo Event (ActionEvent en este caso) e invoca el método correspondiente del manejador (actionPerformed(actionEvent)) pasándole como información el objeto de tipo Event generado. Para hacer que un objeto escuche los eventos de otro objeto se emplea el método add[nombre_evento]Listener.. Lo que la fuente de eventos le pasa al objeto encargado de escuchar los eventos es. para que escuche eventos de teclado KeyListener. responder al evento. otro objeto. manejador ha de pertenecer a una clase que implemente la interface MouseListener. En este objeto va toda la información necesaria para la correcta gestión del evento por parte del objeto que escucha los eventos.addMouseListener(manejador). que tiene un total de 7 métodos que ha de implementar.. El nombre de esta interface es siempre el nombre del evento más “Listener”: para que un objeto escuche eventos de ratón ha de implementar la interface MouseListener. manejador que ha de extender la clase Adapter correspondiente o implementar la interfaz Listener (interfaz ActionLitener en este caso). Es responsabilidad del manejador. Cuando el usuario genere el evento deseado (en este caso pulse el botón). le indicamos quién será su manejador de eventos. como no..Gestión de eventos en Java. y no de la fuente. A continuación en la siguiente tabla mostramos los 99 . El objeto que escucha los eventos ha de implementar para ello una interface. así si tuviésemos un Jframe llamado “frame” y quisiésemos que el objeto llamado “manejador” escuchase los eventos de ratón de “frame” lo haríamos del siguiente modo: frame. en este caso un botón. A la fuente del evento. por ello se dice que la fuente delega la gestión del evento en el manejador. Es un objeto tipo Event.

junto a la interface que debe implementar el objeto que escuche esos eventos y el método para asociar un objeto para escuchar dichos eventos.eventos más comunes. 100 . En la columna de la derecha se presentarán diversos componentes que pueden generar dichos eventos.

sino la clase que se encargaría de escuchar los eventos sería abstracta y no podríamos crear ningún objeto de ella. 101 . incluso aunque no los usemos.Cabe preguntarse ahora por que métodos tiene cada interface. Parece un poco estúpido implementar métodos que no hagan nada sólo porque la interface de la que heredamos los tenga. ya que hemos de implementar todos ellos.

pero nosotros sólo estaremos interesados en un método de dicha interfase: mouseClicked. Los creadores de Java también pensaron en esto y por ello para cada interface que tiene más de un método crearon una clase llamada [nombre_evento]Adapter (MouseAdapter).Así por ejemplo si estamos interesados en escuchar clics de ratón hemos de crear una clase que implemente MouseListener. Nosotros lo único que tendremos que hacer es que nuestra clase que escuche eventos extienda esta clase y sobrescriba los métodos que nos interesen. A continuación en la siguiente tabla damos un listado de las principales interfaces junto a sus respectivas clases “Adapter” y los métodos que poseen: 102 . que lo que hace es implementar todos los métodos de la interface sin hacer nada en ellos.

puede utilizar una clase que herede de una clase adaptadora de eventos del paquete java. es decir. y la fuente será el botón que lanzará el evento correspondiente.  simple y fácil de aprender. si tenemos el siguiente GUI: un botón y una caja de texto dentro de una ventana. si queremos atrapar un click del ratón. el oyente será la ventana que contiene al botón y a la caja de texto. Así por ejemplo.awt. Las clases adaptadoras las utilizaremos para simplificar nuestro código.Todos estos conceptos que estamos introduciendo acerca del tratamiento de eventos en Java. Cada conjunto de eventos tiene asociado un interfaz.event. Así por ejemplo. lo que hemos llamado oyentes. De esta forma se consigue un código más claro y limpio. Es  Ofrece una clara separación entre el código de la aplicación y del interfaz de usuario. Las clases adaptadoras permiten sobrescribir solamente los métodos del interfaz en los que se esté interesado. y como ya hemos dicho cada uno de estos interfaces declara una serie de métodos para cada uno de los eventos lógicos asociados al tipo de evento de que se trate. Un oyente en lugar de implementar un interfaz. es decir de la clase MouseAdapter. en lugar de implementar el interfaz MouseListener. heredamos de la clase adaptadora de los eventos de ratón. Dentro de la jerarquía de clases de Java hay una serie de clases para representar todos los eventos y otra serie de interfaces que definen una serie de métodos que deben implementar las clases que van a tratar los eventos. ya que implementan de forma vacía todos los métodos de un interfaz de tratamiento de eventos determinado. Otras clases que también hemos comentado y que se utilizan dentro del tratamiento de eventos en Java son las clases adaptadoras. Esto es posible debido a que las clases adaptadoras implementan el interfaz correspondiente y simplemente tienen implementaciones vacías de todos los métodos del interfaz EventListener. y queremos que al pulsar el botón aparezca un mensaje en la caja de texto. Este modelo de eventos ofrece las siguientes características:  Ofrece un estructura robusta para soportar programas Java complejos. Interfaz Métodos Clase Adaptadora ActionListener actionPerformed(ActionEvent) --AdjustmentListener adjustmentValueChanged(AdjustmentEvent) --ComponentListener componentHidden(ComponentEvent) componentMoved(ComponentEvent) componentResized(ComponentEvent) componentShown(ComponentEvent) ComponentAdapter ContainerListener componentAdded(ContainerEvent) componentRemoved(ContainerEvent) ContainerAdapter FocusListener focusGained(FocusEvent) focusLost(FocusEvent) FocusAdapter ItemListener ItemStateChanged(ItemEvent) --103 .  Facilita la creación de un código de tratamiento de eventos robusto y menos propenso a errores. solamente deberemos sobrescribir el método mouseClicked(). se verá mucho más claro cuando se muestren algunos ejemplos más adelante. Estas clases se suelen utilizar cuando se quiere hacer uso de un interfaz muy complejo del que sólo interesan un par de métodos. en lo que al tratamiento de eventos se refiere.

Se registra cada uno de ellos con el tipo adecuado de oyente. Aunque los pasos son genéricos. Por ejemplo si se está tratando de atrapar un evento ActionEvent (es decir.event. para poder hacer referencia a un interfaz concreto vamos a suponer que queremos realizar el tratamiento de eventos que se corresponde con la pulsación de un botón. ya que no tiene ningún sentido. será necesario implementar el interfaz ActionListener. A continuación vamos a comentar los pasos genéricos que se deben seguir a la hora de realizar el tratamiento de eventos en Java. Una vez hecho esto debemos crear las implementaciones de todos los métodos del interfaz que la clase debe implementar. siempre que utilizamos un interfaz con un único método vamos a implementarlo. public void actionPerformed(ActionEvent evento){ //cuerpo del método } Una vez comentado el tratamiento de eventos en Java de forma más o menos teórica vamos a comentar una serie de ejemplos para aplicar la teoría a la práctica.addActionListener(this). A continuación escribiremos la declaración de la clase para que implemente el interfaz adecuado (listener interface). Lo primero es importar el paquete java. si tenemos en cuenta el ejemplo anterior del botón.awt.KeyListener KeyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent) KeyAdapter MouseListener mouseClicked(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent) MouseAdapter MouseMotionListener mouseDragged(MouseEvent) mouseMoved(MouseEvent) MouseMotionAdapter TextListener textValueChanged(TextEvent) --WindowListener windowActivated(WindowEvent) windowClosed(WindowEvent) windowClosing(WindowEvent) windowDeactivated(WindowEvent) windowDeiconified(WindowEvent) windowIconified(WindowEvent) windowOpened(WindowEvent) WindowAdapter Como se puede apreciar en la tabla anterior. public class MiClase extends ClasePadre implements ActionListener{ Debemos determinar que componentes van a generar los eventos. una pulsación de un botón) generado por un botón. se debería escribir lo que objetoBoton.event: import java. 104 .*. Estos ejemplos además nos van a servir para repasar distintos puntos del lenguaje Java comentados hasta ahora.awt. los interfaces que únicamente poseen un método no tienen clase adaptadora correspondiente.

out. } public void windowDeiconified(WindowEvent evento){ System.*. y cuando pulsemos sobre el aspa de cerrar la ventana esta se cierre y finalice la ejecución de la aplicación. //finaliza la aplicación System. public class Ventana extends Frame implements WindowListener{ //constructor de nuestra clase public Ventana(String titulo){ //constructor de la clase padre super(titulo). Primero vamos a comenzar creando una aplicación sencilla que va a consistir simplemente en una ventana que nos va a indicar si se encuentra minimizada o no. en primer lugar. En lo concerniente al tratamiento de eventos. //paquete necesario para el tratamiento de eventos import java. } public void windowClosed(WindowEvent evento){ System.exit(0).println("Estoy minimizada"). y como hemos dicho que es una ventana. } public void windowDeactivated(WindowEvent evento){} public void windowActivated(WindowEvent evento){} public void windowOpened(WindowEvent evento){} public static void main (String[] args){ Ventana miVentana=new Ventana("Eventos"). También veremos los adaptadores MouseAdapter y WindowAdapter. el que se encarga de las pulsaciones de botones. estos tres nos ofrecen ejemplos bastante prácticos. ActionListener. sólo vamos a tratar tres de los más representativos.out.*.println("No estoy minimizada"). Vamos a comentar algunas consideraciones de carácter general. Como se puede observar hemos creado también un método constructor para nuestra clase Ventana. //tamaño de la ventana setSize(150. quien va a 105 .out. MouseListener.println("La ventana se ha cerrado"). No vamos a tratar todos los interfaces. WindowListener. En el constructor de nuestra clase indicamos quien va a ser el oyente de nuestra clase.Vamos a realizar una aplicación que vamos a ir modificando y complicando para mostrar las diferentes facetas del tratamiento de eventos en Java. es decir. } public void windowIconified(WindowEvent evento){ System.awt. hereda de la clase Frame. //se muestra la ventana setVisible(trae). } } Vamos a comentar algunos puntos importantes acerca del código anterior.event. El código de esta aplicación de ejemplo es: import java. } public void windowClosing(WindowEvent evento){ //se cierra la ventana dispose(). y el que se encarga de las ventanas.150). al ser una aplicación debe tener un método main() de arranque. el que se encarga del ratón. //se registra nuestra clase como oyente addWindowListener(this).awt. como se puede ver importamos el paquete correspondiente e indicamos que nuestra clase implementa el interfaz WindowListener.

} public static void main (String[] args){ Ventana miVentana=new Ventana("Eventos"). pero como implementamos el interfaz WindowListener debemos implementarlos aunque no tengan contenido. Como ya hemos comentado hay tres métodos del interfaz WindowListener que no nos interesan y que por lo tanto nos gustaría suprimir. también debe implementar el interfaz que define los métodos que se van a ejecutar atendiendo al evento que se produzca.fuente=fuente.*. Para ello utilizamos la línea de código addWindowListener(this). En nuestro caso hay tres métodos que no nos interesan. el código de nuestra aplicación se debe modificar como indica : import java.150). las clases adaptadoras realizan una implementación vacía de todos los métodos del interfaz con el que se corresponden.awt. que herede de la clase WindowAdapter. //nuestra clase ya no implementa el interfaz WindowListener public class Ventana extends Frame{ public Ventana(String titulo){ super(titulo). es decir. estamos registrando nuestra clase como oyente mediante la referencia this.awt. //se registra como oyente la clase que hereda la clase adaptadora addWindowListener(new AdaptadorVentana(this)). //constructor de nuestra clase adaptadora //recibe como parámetro la clase fuente del evento public AdaptadorVentana(Ventana fuente){ this. Por lo tanto si queremos hacer uso de la clase adaptadora WindowAdapter. El resto del código es bastante sencillo y considero que no necesita una mayor explicación. es decir. respectivamente. y al heredar de ellas utilizaremos únicamente los métodos del interfaz correspondiente que nos interese. ya que heredamos de la clase Frame y la herencia múltiple no se permite en Java. indicamos que el oyente de los eventos de la ventana va a ser nuestra propia clase. } } //clase que hereda de la clase adaptadora class AdaptadorVentana extends WindowAdapter{ //atributo que se utiliza como referencia a la clase //que es la fuente del evento que queremos tratar private Ventana fuente. en este caso el oyente es nuestra misma clase. Al ser nuestra clase fuente y oyente de los eventos. import java. } //contiene la implementación de los métodos que nos interesan //del interfaz WindowListener 106 . el método windowClosing() se ejecuta en el momento de cerrar la ventana y el método windowClosed() cuando ya se ha cerrado. Es decir.*.tratar los eventos. En nuestro caso no podemos heredar de una clase adaptadora. setSize(150. Los métodos windowIconified() y windowDeiconified() se ejecutarán cuando se minimice la ventana y cuando se restaure. Como ya debe saber el alumno. setVisible(true). Por lo tanto deberemos crear y definir una nueva clase que herede de la clase adaptadora del interfaz WindowListener. en este momento entran en juego las clases adaptadoras.event.

println("La ventana se ha cerrado"). dentro del método windowClosing(). aunque estos sean privados. Esta referencia es necesaria . es que no tenemos porque llevar la referencia de la clase fuente.println("Estoy minimizada"). El beneficio que podemos obtener de estas clases adaptadoras. pero puede ser bastante práctica. La clase interna va a tener acceso a todos los métodos y atributos de la clase en la que está declarada. Realmente una clase interna se sale fuera de los principios de la POO. Ahora vamos a detenernos en la clase AdaptadorVentana. } public void windowClosing(WindowEvent evento){ fuente.dispose().en este caso.println("No estoy minimizada"). siempre que exista una clase adaptadora para el evento en cuestión.out. } } Los mayores cambios se aprecian en que existe una nueva clase que va a ser la encargada de tratar los eventos.dispose(). Este atributo es necesario para tener una referencia a la clase fuente del evento. deberemos crear una clase que herede de la clase adaptadora de cada tipo de evento. System. También existe la posibilidad de utilizar la clases adaptadoras como clases internas (inner classes). } Para conseguir la referencia a la fuente del evento se pasa una instancia de la clase Ventana actual al constructor de la clase adaptadora.out. Nuestra clase Ventana. en este caso si que existe una separación clara entre clase fuente y clase oyente.out. public void windowClosing(WindowEvent evento){ fuente. a la hora de cerrar la ventana. El oyente sería la clase AdaptadorVentana y la clase fuente sería la clase principal Ventana. addWindowListener(new AdaptadorVentana(this)). public AdaptadorVentana(Ventana fuente){ this.exit(0). } Como se puede comprobar esta nueva clase contiene todos los métodos que nos interesan del interfaz WindowListener. De esta forma la clase adaptadora puede manipular y acceder al objeto de clase Ventana. Se sigue utilizando el método addWindowListener() pero en este caso se pasa por parámetro una instancia de la clase adaptadora que hemos creado nosotros. al ser sólo fuente de eventos no va a implementar el interfaz WindowListener y por lo tanto únicamente va a tener en su cuerpo el método constructor y el método main(). Una clase interna es una clase definida dentro de otra.fuente=fuente.public void windowClosed(WindowEvent evento){ System. Esta clase hereda de la clase WindowAdapter y posee un atributo denominado fuente que es de la clase Ventana. Otra cosa que cambia también en el código de nuestra aplicación es la forma en la que se registra el oyente. } public void windowIconified(WindowEvent evento){ System. 107 . } public void windowDeiconified(WindowEvent evento){ System. Si queremos tratar distintos eventos mediante clases adaptadoras.

println("No estoy minimizada").*.*. System.println("Estoy minimizada"). setSize(150. public class Ventana extends Frame{ public Ventana(String titulo){ super(titulo). System.out. //Utilizamos una clase interna anónima addWindowListener(new WindowAdapter(){ //métodos de la clase anónima public void windowClosed(WindowEvent evento){ System.*.*. public class Ventana extends Frame{ public Ventana(String titulo){ super(titulo).150).awt. } public static void main (String[] args){ Ventana miVentana=new Ventana("Eventos"). } }//se cierra la clase interna } Ahora. import java.out.println("La ventana se ha cerrado"). //ya no se indica la referencia de la clase fuente addWindowListener(new AdaptadorVentana()). } public void windowIconified(WindowEvent evento){ System.El nuevo código tendría el aspecto siguiente: import java. setvisible(true). vamos a ofrecer una posibilidad distinta a la hora de tratar los eventos en Java.awt.out.event. } public void windowClosing(WindowEvent evento){ dispose().out. setSize(150.awt. } public void windowClosing(WindowEvent evento){ //llamamos directamente al método dispose() dispose(). } //clase adaptadora interna class AdaptadorVentana extends WindowAdapter{ //Ya no es necesario el atributo fuente public void windowClosed(WindowEvent evento){ System. import java.exit(0). se puede utilizar una clase interna anónima: import java. } public void windowIconified(WindowEvent evento){ System.awt.event.out. } public void windowDeiconified(WindowEvent evento){ System.exit(0).println("Estoy minimizada").150) setVisible(true).println("No estoy minimizada").//se cierra la clase interna anónima } public static void main (String[] args){ 108 .println("La ventana se ha cerrado"). } public void windowDeiconified(WindowEvent evento){ System.out. } }).

import java.println("Buenas tardes").*.println("No estoy minimizada").addActionListener(this). se utiliza el nombre de la clase adaptadora correspondiente. } public static void main (String[] args){ Ventana miVentana=new Ventana("Eventos"). //oyente del botón. setSize(150. boton=new Button("Púlsame"). El mecanismo es muy sencillo. } } A la vista del código se puede ver que se trata de instanciar una clase sin indicar un objeto que contenga una referencia a la misma.*. El nuevo aspecto de nuestra aplicación de ejemplo se puede observar en la Figura.exit(0). ya que en realidad esta clase sólo se va a utilizar para el tratamiento de eventos y no se va a querer hacer una referencia a ella. por lo demás funciona exactamente igual a una clase interna. } public void windowDeiconified(WindowEvent evento){ System. ya que este interfaz no posee una clase adaptadora. //implementamos el interfaz para tratar la pulsación del botón public class Ventana extends Frame implements ActionListener{ private Button boton.out. WindowAdapter en nuestro caso. } public void windowClosing(WindowEvent evento){ 109 . add(boton). } class AdaptadorVentana extends WindowAdapter{ public void windowClosed(WindowEvent evento){ System. ahora vamos a añadir a nuestra aplicación un botón para que al pulsarlo escriba un mensaje en la pantalla.println("La ventana se ha cerrado"). al tener un único método llamado actionPerformed(). Una vez comentados las distintas opciones que tenemos a la hora de tratar los eventos.event.out.out. en este caso la clase Ventana boton.println("Estoy minimizada").150).out. En este caso deberemos implementar el interfaz ActionListener. public Ventana(String titulo){ super(titulo).Ventana miVentana=new Ventana("Eventos"). } public void actionPerformed(ActionEvent evento){ System. y se implementan los métodos que se consideren necesarios.awt. setVisible(true). setLayout(new FlowLayout()). import java. addWindowListener(new AdaptadorVentana()).awt. System. } public void windowIconified(WindowEvent evento){ System.

añadiendo un área de texto. } public static void main (String[] args){ Ventana miVentana=new Ventana("Eventos"). Las líneas utilizadas para añadir el botón se encuentran en el constructor.*.awt.setText("El ratón ha salido").awt. que se ejecutará al pulsar el botón. } public void mouseExited(MouseEvent evento){ area. } Para finalizar el presente capítulo modificaremos de nuevo nuestra aplicación. y por otro lado la fuente de eventos va a ser la clase Ventana y el oyente la clase interna AdaptadorVentana. } } } Como se puede observar la fuente del evento en este nuevo caso va a ser por un lado.addMouseListener(new AdaptadorRaton()).addActionListener(this). } } class AdaptadorVentana extends WindowAdapter{ 110 .out. Aquí vamos a tratar un nuevo tipo de evento. //El oyente del ratón es una nueva clase interna area.setText("El ratón ha entrado"). o por el contrario ha salido.println("Buenas tardes"). en este caso los eventos del ratón. show(). boton. en la que se escribirá si el puntero del ratón se encuentra en el área de texto.dispose(). public void actionPerformed(ActionEvent evento){ System.println("Buenas tardes"). public Ventana(String titulo){ super(titulo). } public void actionPerformed(ActionEvent evento){ System. Utilizamos la clase adaptadora. Al pulsar el botón veremos en pantalla el saludo "Buenas tardes". add(boton). boton=new Button("Púlsame"). La clase MouseAdapter es la clase adaptadora del interfaz MouseListener. private TextArea area. el botón y su oyente la clase Ventana. y lo vamos a realizar a través de la clase adaptadora MouseAdapter. la única línea digna de mención es la que registra el oyente del botón. import java. boton.out. import java.*. addWindowListener(new AdaptadorVentana()).event.addActionListener(this). pack(). } //clase adaptadora para los eventos del ratón class AdaptadorRaton extends MouseAdapter{ public void mouseEntered(MouseEvent evento){ area. La clase Ventana al implementar el interfaz ActionListener debe facilitar el método actionPerformed(). setLayout(new FlowLayout()). porque sólo nos van a interesar un par de métodos del interfaz MouseListener. add(area). area=new TextArea(). public class Ventana extends Frame implements ActionListener{ private Button boton.

El ratón salió de un componente. } public void windowIconified(WindowEvent evento){ System. respectivamente. El checkbox fue seleccionado. Se dio un enter sobre el campo de texto. El componente obtuvo o perdió el foco. } public void windowDeiconified(WindowEvent evento){ System.out.println("Estoy minimizada"). cambios en el medio ambiente del sistema (abrir.exit(0). • Eventos de foco. • Eventos de campo de texto. sin tener en cuenta el resto de los que se produzca y sin interferir entre sí. • Eventos de botón. Como se puede apreciar cada oyente se encarga de los eventos para los cuales se ha registrado. La tecla está oprimida o fue liberada. cerrar o mover una ventana) o cualquier otra actividad que pudiera afectar la operación del programa. Un evento es una acción que se genera al cambiar el estado de un componente de AWT. Para registrar el oyente del área de texto se utiliza el método addMouseListener().out. en este caso se trata de la clase AdaptadorRaton. Para que un programa atienda un evento se necesita asignar al componente un oidor o escuchador (listener en la terminología de Java). El botón fue oprimido. El ratón esta sobre un componente. Esta clase implementa los métodos mouseEntered() y mouseExited() que se lanzarán cuando en ratón entre en el área de texto o salga del mismo.println("La ventana se ha cerrado"). System. Cada vez que ocurre alguna acción de las que se listan a continuación se genera un evento que puede ser atrapado por un programa: • Eventos de ratón. que va a ser el área de texto. } public void windowClosing(WindowEvent evento){ dispose(). pulsaciones de teclas).println("No estoy minimizada"). Un evento puede ser una entrada de usuario (movimientos o clicks del ratón. Java soporta varios tipos de eventos. El foco se obtiene cuando se da un click al ratón sobre un componente. La clase Ventana ofrece un nuevo atributo que va a representar el área de texto. Alguna de las opciones del choice fue seleccionada. El ratón se movió. El botón del ratón está oprimido o fue liberado. Se está escribiendo sobre el campo de texto. Dentro del oidor se escribe el código que se desea ejecutar cuando ocurra el evento. Los eventos es la forma que tiene un programa para enterarse de que ocurrió algo y reaccionar conforme al suceso. • Eventos de checkbox. a este método se le pasa una instancia de la clase adaptadora que va a tratar los eventos del ratón. y un nuevo oyente que es la clase adaptadora AdaptadorRaton.out. • Eventos de choice. 111 . El ratón está siendo arrastrado. • Eventos de teclado.public void windowClosed(WindowEvent evento){ System. } } } En esta última versión de la aplicación de prueba tenemos una nueva fuente de eventos.

ej. En definitiva. · No se garantiza que se vayan a consultar.¿QUÉ SON LAS EXCEPCIONES? Definición: Una excepción es un evento excepcional que ocurre durante la ejecución del programa y que interrumpe el flujo normal de las sentencias. Java ofrece una solución.ArithmeticException: / by zero at Excepcion. Respecto a la segunda estrategia. otra forma de tratar con los errores: las excepciones. muchas veces no se tenga en cuenta y no se traten todos los errores. int k=i/j. el código crece considerablemente.java:4) 112 . el programa deberá: · volver a un estado estable y permitir otras operaciones. que un método devuelva un código de error como valor de retorno. uno por cada componente que pueda generar el evento en particular.main(Excepcion. En mi opinión la ventaja de los oidores anónimos sobrepasa la desventaja y por eso en este curso se definen oidores anónimos para el manejo de eventos. En las secciones siguientes vamos a revisar los eventos más utilizados que son los de botón. Esto es difícil debido a que generalmente. La ventaja de la primera estrategia es que el manejo de eventos se centraliza en un solo método. cada componente tiene su propio oidor y el código se vuelve más legible y elegante.Hay dos estrategias para definir oidores: la primera es usar una clase que tenga un solo método por cada tipo de evento que atienda todos los eventos que se generen de ese tipo. Ejemplo: class Excepcion { public static void main(String argumentos[]) { int i=5. · No sirven en los constructores.: getchar). · La lógica del programa queda oscurecida.lang. el código que detecta el error no es el que puede realizar dichas tareas.0 EXCEPCIONES 10. · intentar guardar el trabajo y finalizar. la ventaja es que no es necesario distinguir nada. Esto impide la construcción de programas robustos. es decir. Si una operación no puede completarse debido a un error. La solución más habitual a esto son los códigos de error. por ello. · Si se contemplan todos los errores. La segunda estrategia consiste en declarar oidores anónimos. La desventaja es que la cantidad de código generado se vuelve mayor. Esto presenta una serie de inconvenientes: · No siempre queda sitio para códigos de error (p. // División por cero } } Produce la siguiente salida al ser ejecutado: java. La desventaja es que ese método debe ser capaz de distinguir cuál componente fue el que generó el evento. j=0. hacen que el tratamiento de errores sea complejo y que. El que detecta el error debe informar al que pueda manejarlo. de choice y de checkbox. 10.1.

Un método especifica las excepciones que se pueden producir en él mediante la palabra throws en la declaración del método.DETECCIÓN DE ERRORES Una condición excepcional es aquella que impide la continuación de una operación. Por ejemplo: void f() throws EOFException. Es decir: try{ // Operaciones que pueden “fallar”.. que // pueden producir alguna excepción.3. } catch( <tipoDeExcepción> ref ){ // Tratamiento de esa excepción } Por ejemplo: try{ a. a. es decir. Normalmente se utilizará una clase diferente para cada tipo de error. Es decir. finaliza el método y se lanza un objeto que facilite información sobre el error ocurrido. también debe indicar qué puede fallar. En Java. Un método no sólo tienen que decir qué devuelve si todo va bien. lanzamos una excepción de E/S throw new IOException(). se lanza una excepción (throw) para que alguien que sepa manejarla la trate en un contexto superior. } 113 .. El bloque catch es el lugar al que se transfiere el control si alguna de las operaciones produce una excepción. } 10. cuando ocurre algo así. Por ejemplo: if( “error de CRC” ) // Si se produce un error de CRC.2. Para manejar excepciones hay que utilizar las palabras clave try y catch.abreFichero().. // Para lanzar una excepción hay que crear un objeto. ) throw new FileNotFoundException(). Con la palabra throw se lanza una excepción. pero no se puede continuar hasta que no se resuelva. El try delimita el grupo de operaciones que pueden producir excepciones.10... no se sabe cómo manejarla.MANEJO DE EXCEPCIONES Una vez que se detecta un error hace falta indicar quién se encarga de tratarlo. FileNotFoundException { if( .leeCabecera(). Cuando ocurre esto.. Java obliga a que un método informe de las excepciones (explícitas) que puede lanzar. if( .actualizaDatos(). a. Se ponen entre un try y un catch los métodos que pueden producir alguna excepción. // ya que una excepción es un objeto. ) throw new EOFException().

Por ejemplo: void f1( int accion ) throws EOFException { try{ if( accion == 1 ) throw new FileNotFoundException().println( “Finalización normal de f2” ). uno para cada tipo de excepción que se pueda producir.out.println( “Finalización normal de f1” ). } Si alguna de las operaciones del bloque produce una excepción.out.out. se interrumpe el bloque try y se ejecuta el catch.leeCabecera(). Un bloque try puede tener varios catch asociados.println( “Error corregido” ). a. Al finalizar éste. Si no se produce ninguna excepción el bloque catch se ignora.out. a.println( “Error de apertura” ). } catch( FileNotFoundException ref ){ System. try{ a. } void f2( int accion ) { try{ f1( accion ): } catch( EOFException e ){ System. } System. la excepción se propaga hacia atrás en la secuencia de invocaciones hasta encontrar un catch adecuado.out.println( “Error de E/S” ). } catch( IOException ref ){ System.out.abreFichero(). } catch( FileNotFoundException e ){ System.out.println( “Error corregido” ).catch( IOException ref ){ System.actualizaDatos(). } ¿ Qué pasa si se llama a f2 pasándole los valores 1 ó 2 para el parámetro acción? ¿En qué método se producen las excepciones y en cuál se tratan? 114 .println( “Error de E/S” ). se continúa normalmente. Por ejemplo. } Si se produce una excepción que no se corresponde con ningún catch indicado. else if( accion == 2 ) throw new EOFException(). } System.

Dichas operaciones se pueden situar dentro de un bloque finally.. o se trata el error o se avisa que se va a continuar sin haberlo corregido para que otro método lo corrija.. no siempre es posible tratarlos en el mismo momento en que se producen y por tanto. Por ejemplo: void f1() throws IOException { . 10. } void f2() { try{ // Alternativa 1: tratar el error en cuanto se produce f1() } catch( IOException e ){ // Tratamiento del error } } // Alternativa 2: se continúa propagando el error para que lo gestione // otro método.... de la siguiente forma: try{ // Operaciones con posibles excepciones } catch( <tipoDeExcepcion> ref ){ // Tratamiento de la excepción } finally{ // Operaciones comunes } Ejemplo: class Recurso { void reserva(){ . De todos modos. void f2() throws IOException { f1().4. } void libera(){ .. es obligatorio: · Que se maneje el error (en un catch).FINALLY Puede haber ocasiones en que se desea realizar alguna operación tanto si se producen excepciones como si no.. · Que se indique mediante throws su propagación. Es decir.Cuando se invoca a un método que lanza excepciones. en vez de dejarlos para que los gestione alguien por encima (alternativa 2). a menudo hay que recurrir a la segunda alternativa. } Es mejor intentar tratar los errores en cuanto sea posible (alternativa 1). } 115 .

libera().libera()).libera().libera().} class Ejemplo { void prueba() { Recurso recurso = new Recurso().reserva().libera(). try{ recurso. try{ recurso.reserva(). e independientemente de que ésta sea capturada o no. // Operaciones con posibles excepciones recurso. // Operaciones con posibles excepciones } catch( ExceptionA a ){ // Tratamiento del error } catch( ExceptionB b ){ // Tratamiento del error } catch( ExceptionC c ){ // Tratamiento del error } finally{ 116 . } catch( ExceptionA a ){ // Tratamiento del error recurso. } catch( ExceptionB b ){ // Tratamiento del error recurso. Para ello existe una solución mucho más elegante. la liberación del recurso siempre debe llevarse a cabo (instrucción recurso. } } } En el ejemplo anterior queda suficientemente claro que independientemente de que se produzca una excepción o no. } catch( ExceptionC c ){ // Tratamiento del error recurso. Solución con finally: class Ejemplo { void prueba() { Recurso recurso = new Recurso().

5. si se produce alguna excepción: · Si es atrapada por un catch del mismo try.out.JERARQUÍA DE EXCEPCIONES Toda excepción debe ser una instancia de una clase derivada de la clase Throwable. pero propagar throw e. Estos métodos son: · getMessage · toString · printStackTrace (imprime en la salida estándar un volcado de la pila de llamadas). } } Genera el siguiente mensaje: java.ArithmeticException at LanzaExcepcion. · Si no es atrapada.LANZAMIENTO DE EXCEPCIONES Hay situaciones en las que interesa relanzar una excepción ya atrapada.lang. · fillInStackTrace 117 . } Ejemplo: class LanzaExcepcion { public static void main(String argumentos[]) throws ArithmeticException { int i=1. interesa dar un tratamiento determinado a una excepción pero también interesa seguir propagándola hacia arriba para que en un contexto superior se siga teniendo constancia de ella. 10.6. } } } Si no se produce ninguna excepción.. es decir. De ella hereda una serie de métodos que dan información sobre cada excepción.. La ejecución continúa después del finally con normalidad. se ejecuta el finally y la excepción se propaga al contexto anterior. En cambio.println(i/j). se ejecuta éste y luego el finally. 10. Esto se hace así: catch( Exception e ){ // Salvar datos o cualquier otro tratamiento.java:5) La excepción pasaría a buscarse entre los catch de un contexto superior (los del mismo nivel se ignoran). j=2.recurso. se ejecutarán el bloque try y el finally. if (i/j< 1) throw new ArithmeticException().libera(). else System.main(LanzaExcepcion.

ClassCastException. Se utilizan las RunTimeException para indicar un error de programación. ArrayStoreException. Esta clase. IllegalAccessException. IllegalArgumentException. LinkageError. PrinterException. GeneralSecurityException. IOException. a su vez. la cual se divide en dos subclases: Error y Exception. NoSuchMethodException. Estas excepciones rara vez ocurren. ThreadDeath. y cuando así sea. CannotUndoException. NullPointerException. · Implícitas: las que derivan de RunTimeException. Si se produce una 118 . Ejemplos de este tipo de excepciones son OutOfMemoryError. etc. Las clases derivadas de Error describen errores internos de la JVM e indican errores serios que normalmente la aplicación no debería intentar gestionar. lo único que se puede hacer es intentar cerrar el programa sin perder datos. tiene otras clases derivadas.) Que representada en forma gráfica da lugar a: Figura Jerarquía de clases de las excepciones Java Todas las excepciones descienden de la clase Throwable. etc. tiene una subclase llamada RuntimeException que. Estas excepciones se clasifican en: · Explícitas: las que derivan directamente de Exception. DataFormatException. CloneNotSupportedException. etc. IndexOutOfBoundsException.) · RuntimeException (ArithmeticException. a su vez. Tampoco deberían ser lanzadas por las clases del usuario. NoSuchFieldException. VirtualMachineError) · Exception (ClassNotFoundException. Los programas en Java trabajarán con las excepciones de la rama Exception. EmptyStackException. StackOverflowError.La jerarquía de excepciones en Java es la siguiente: · Throwable · Error (AWTError. CannotRedoException.

. } } } Vemos ahora otro ejemplo en el que creamos y lanzamos una excepción de tipo RuntimeException: class MesInvalidoException extends RuntimeException {} class Ejemplo { 119 . Por ejemplo: un cast incorrecto. normalmente derivará: · de RuntimeException si se desea notificar un error de programación. i++ ) { // Imprimir cliente[i] if( “error impresión” ) throw new PrinterException(). 10. uso de un puntero null. error de conexión. Por tanto. aunque pueden producirse igualmente). La única condición es que la clase derive de la clase Throwable o de alguna derivada.7. etc. El resto de las Exception indican que ha ocurrido algún error debido a alguna causa ajena al programa (está correcto). i<clientes. ¿qué tipo de excepción debería crear? Ejemplo de creación de una excepción: class PrinterException extends Exception{} Cuando se produzca una excepción de este tipo. está avisando de que puede producirse dicho error (por causas externas al método) además de cualquier error implícito (consecuencia de un error en el código que debería ser subsanado).CREACIÓN DE EXCEPCIONES Si se necesita notificar algún error no contemplado en Java se puede crear una nueva clase de Excepción. acceso a un array fuera de rango. Los métodos deben declarar sólo las excepciones explícitas.excepción de este tipo hay que arreglar el código. · de Exception en cualquier otro caso. Las implícitas no deben declararse (el compilador no lo exige. como se puede ver en el siguiente ejemplo: class Ejemplo { void imprimirClientes( Cliente[] clientes ) throws PrinterException { for( int i=0. cuando un método declara una excepción. etc. se lanzará. En la práctica.length. Por ejemplo: un error de E/S. En un método que tiene como parámetro un entero entre 1 y 12 se recibe un 14 ¿Qué tipo de excepción se crearía para notificarlo? Si un método para listar Clientes por impresora se encuentra con que deja de responder.

println( “Sólo se han imprimido “ + e.8.out. pagina++ ) { // Imprimir cliente[ pagina ] if( “error impresión” ) throw new PrinterException( pagina ). pagina<clientes.. PrinterException( int pag ) { numPagina = pag. } } En este ejemplo no se avisa que se lanza una excepción porque es de tipo RuntimeException (implícita). } } } 120 .void setMes( int mes ) { if( mes < 1 || mes > 12 ) throw new MesInvalidoException(). como cualquier otra clase. 10.getNumPagina() ). puede tener operaciones que permitan obtener más información sobre el error. class PrinterException extends Exception { private int numPagina. } catch( PrinterException e ) { System. } int getNumPagina() { return numPagina. } } void Informe() { try{ imprimirClientes( clientes ).length. } } class Ejemplo { void imprimirClientes( Cliente[] clientes ) throws PrinterException { for( int pagina = 0.OBTENCIÓN DE INFORMACIÓN DE UNA EXCEPCIÓN Una excepción.

y que pueden ser implementados por las nuevas excepciones que se creen. } } Java obliga a atrapar las excepciones explícitas. } getMesInvalido() { return mes. } } class Ejemplo { public static void main( String[] args ) { Fecha fecha = new Fecha(). { return “Mes inválido: “ + mes. fecha. · La excepción MesInvalidoException se produce al invocar el método setMes() con el valor 14 y al no haber sido capturada por el código que realiza la invocación (el main).. se visualizará el mensaje “Mes inválido: 14” y el programador deberá darse cuenta de que existe un error en el código que llama al método setMes(). ¿qué pasa si no se atrapa una implícita. Algunos de estos métodos son: · public String getMessage() Devuelve el mensaje detallado de error de este objeto (o null si el objeto no tiene mensaje). MesInvalidoException( int m ) { mes = m. } } class Fecha { void setMes( int m ) { if( m < 1 || m > 12 ) throw new MesInvalidoException( m ). · Por defecto.Otro ejemplo con una excepción descendiente de RuntimeException: class MesInvalidoException extends RuntimeException { private int mes. que devuelve // la representación String del error. como en este caso? · El compilador no da ningún error por tratarse de una excepción implícita y el programa compila correctamente.setMes( 14 ). } public String toString() // Método heredado de la clase Throwable. 121 . el programa termina de manera anormal. La clase Throwable tiene una serie de métodos que tienen ya implementados todas las excepciones de Java (por herencia).

Es útil cuando un error que se ha producido en un lugar queremos que se indique en otro. · Indican un error externo a la aplicación. · public native Throwable fillInStackTrace() "Rellena" la pila de llamadas. · public void printStackTrace(PrintWriter s) Idem. · public void printStackTrace() Visualiza en el flujo de error estándar la traza de llamadas (backtrace) que se almacena automáticamente en todo error. un método puede declarar excepciones que no lance realmente. pero pensado para devolver el mensaje localizado de una forma más específica.RESUMEN EXCEPCIONES EXPLÍCITAS-IMPLÍCITAS Excepciones explícitas: · Derivan de Exception (no de RuntimeException). · Si se lanzan es obligatorio declararlas. Excepciones implícitas: · Derivan de RuntimeException. Así un método base puede permitir que las redefiniciones puedan producir excepciones..9. es obligatorio atraparlas o declararlas. es decir. sí pueden lanzar nuevas excepciones. Por otro lado. 122 .· public String getLocalizedMessage() Lo mismo. · Si se invoca un método que las lanza.10. no puede lanzar nuevas excepciones. no puede lanzar una excepción que no lanzaba el padre. al no heredarse. Los constructores.EXCEPCIONES Y HERENCIA Al redefinir un método se está dando otra implementación para un mismo mensaje. pero indicando el flujo al que se manda la información. si no simplemente se comporta como getMessage() · public String toString() Devuelve la representación String del error (la clase del error. devuelve el error cambiando su traza de llamadas como si se hubiera producido ahora. 10. · Indican un error de programación. class A { void f() throws EOFException { } } class B extends A { // Incorrecto void f() throws EOFException. Hay que redefinirlo. 10. básicamente). un hijo puede lanzar menos excepciones que las que declara el padre. · No se declaran: se corrigen. · Se pueden atrapar.. En caso contrario finaliza la aplicación. · public void printStackTrace(PrintStream s) Lo mismo. El nuevo método sólo podrá lanzar excepciones declaradas en el método original. FileNotFoundException {} } Es decir.

mesg2().. Norma 2: · No utilizar las excepciones para evitar una consulta.pop().mesg1(). Norma 3: · Separar el tratamiento de errores de la lógica. } } catch(ExcA a) { // Tratamiento } catch(ExcB b) { // Tratamiento } Norma 4: · No ignorar una excepción try { // operaciones. obj2.11.empty()) stack.pop(). i++) { try { obj1. } while (!stack.. i < len. } catch(ExcB b) { // Tratamiento } } try { for (int i = 0.mesg2(). } catch {EmptyStackExecution e) { . i < len. i++) { obj1.NORMAS EN EL USO DE EXCEPCIONES Norma 1: · Si una excepción se puede manejar no debe propagarse.mesg1(). for (int i = 0..10. } catch(ExcA a) { // Tratamiento } try { obj2. } catch {EmptyStackExecution e) { } // Para que calle el compilador 123 . try { stack. · Es más cómodo usar métodos que no produzcan errores. No abusar de ellas.

public static String leerLinea() { String s = "".out. } return d. return leerDoble(). System. // try { // while( (c = (char)System. } catch (java. } public static void main (String[] a) { double d1 = leerDoble( "Introduce un número real: " ). try { d = Double.io.doubleValue().lang. // Otra forma de hacerlo // // char c.valueOf( s ). } /* leerDoble() Devuelve NaN en caso de error */ public static double leerDoble() { String s = leerLinea().12.print( mens ).in. try { s = inp.NaN..EJEMPLOS Ejemplo 1: Lectura de un número por teclado class LeerTeclado { static BufferedReader inp = new BufferedReader( new InputStreamReader(System.readLine().read()) != '\n') // s += c.out. } public static double leerDoble( String mens ) { // con prompt System.io.in)).out. return leerLinea(). } catch (java.IOException e) { } } public static String leerLinea( String mens ) { // con prompt System. double d.NumberFormatException e) { d = Double.println( "La suma de ambos es: " + (d1+d2) ).print( mens ). double d2 = leerDoble( "Introduce otro: " ). } } 124 .10. // } // catch (java.IOException e) { } return s.

// no obligatorio recoger el error // pq es RuntimeException l. else aux.insertar( new Double( 2.insertarPrimero( new Integer( 2 ) )." ). public class FueraDeListaException extends IndexOutOfBoundsException { FueraDeListaException( ) { } FueraDeListaException( String s ) { super( s ). 10 ). else { if (aux == null) throw new FueraDeListaException("intentando insertar elemento más allá del fin de la lista" ). l ). 2 ). } if (posicion == 1) l = new NodoLista( o.println( "Error: " + e. l. // Llama al constructor del padre } } public class ListaEnlazada { . l.insertar( new Integer( 18 ).out.siguiente ). i++ ) { aux = aux..insertarPrimero( new Integer( 1 ) ). for (int i = 1. l. } catch (FueraDeListaException e) { System. 3 ). else l = l. int posicion ) throws FueraDeListaException { NodoLista aux = l.insertar( new Integer( 3 ). try { l.siguiente = new NodoLista( o.. 125 ..siguiente.borrarPrimero(). } } public void borrarPrimero() throws FueraDeListaException { if (l == null) throw new FueraDeListaException("intento de borrar primero en lista vacía" ). } public static void main( String[] a ) { ListaEnlazada l = new ListaEnlazada(). try { l.Ejemplo 2: Incorporación de excepciones a ListaEnlazada. public void insertar( Object o. aux.siguiente. Continuamos. } l. 1 ).insertar( new Integer( 4 ).. aux != null && i < posicion-1.getMessage() + ".5 ).

getMessage() + ".borrarPrimero(ListaEnlazada. Continuamos. error en ejecución" ). } } Salida: La salida resultado de ejecutar este main() sería la siguiente: Error: intento de borrar primero en lista vacía.println( l )..main(ListaEnlazada.insertarPrimero( new Integer(18) ).out..destruir(). ( 4 3 2. Continuamos. // de este error no se recupera el programa System. Error: intentando insertar elemento más allá del fin de la lista..out. } finally { l...5 2 1 ) FueraDeListaException: intento de borrar primero en lista vacía at ListaEnlazada.java:66) 126 . l.println( "Error: " + e..} catch (FueraDeListaException e) { System.java:42) at ListaEnlazada.println( "Aquí no se llega.borrarPrimero()." )... } System. l. Continuamos.out.

print("SI "). } } class NoThread extends Thread { public void run() { int i. En este proceso. 11. en los threads lanzados desde un mismo programa. todos los programas creados contenían un único thread. for (i=1. como ocurría en todos los programas vistos hasta ahora.1. i++) System. 11.1 Un ejemplo. Hasta el momento. ).0 THREADS. pero un programa (o proceso) puede iniciar la ejecución de varios de ellos concurrentemente. mejor que mil palabras. class UnThread { public static void main(String args[] ) { int i.1 ¿Qué son los threads? Todos los programadores conocen lo que es un proceso. Mientras en los procesos concurrentes cada uno de ellos dispone de su propia memoria y contexto.out. Un thread39 es un flujo simple de ejecución dentro de un programa. } } La salida de este programa es una serie alternativa de Síes y Noes: SI NO NO NO SI SI SI NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO SI SI SI SI SI SI SI SI SI SI SI SI SI SI SI SI En el ejemplo se declara una clase principal (UnThread) que inicia su ejecución como un proceso con un único thread mediante su método main(). se declara y se crea un thread (NoThread t = new NoThread(). Después se inicia su ejecución mediante la llamada al método de la clase 127 .start().print("NO ").i<=20. la memoria se comparte. for (i=1. una secuencia de instrucciones y tiene un final.out. utilizando el mismo contexto y recursos asignados al programa (también disponen de variables y atributos locales al thread). la mayoría diría que es un programa en ejecución: tiene un principio. Un thread no puede existir independientemente de un programa. i<=20. i++) System. NoThread t = new NoThread(). t. Puede parecer que es lo mismo que la ejecución de varios procesos concurrentemente a modo del fork() en UNIX.11. sino que se ejecuta dentro de un programa o proceso. pero existe una diferencia.

} } 128 . } } class NoThread extends Thread { public void run() { int i. con lo cuál comienza a ejecutarse el método run() redefinido en la clase NoThread (el método start() llama al método run() ).2 Otro ejemplo  class DosThreads { public static void main(String args[] ) { NoThread n = new NoThread(). Tenemos dos threads ejecutándose.print("NO ").i<=20. Una vez se inicia la ejecución del thread.start() ).start(). el tiempo de la CPU se reparte entre todos los procesos y threads del sistema. SiThread s = new SiThread(). con lo cuál.1. for (i=1. s. se intercalan instrucciones del método main() con instrucciones del método run() entre otras correspondientes a otros procesos (del sistema operativo y otros procesos de usuario que pudieran estar ejecutándose).start(). 11.Thread start() (t. i++) System.out. n.

print(++Contador+":"+SiNo+" ").out. static int Contador=0. pero comparten los atributos de clase40 (int Contador).4.i<=20. 129 . } } class SiNoThread extends Thread { private String SiNo.3. Puede comprobarse que el contador no ha funcionado todo lo correctamente que pudiera esperarse: 1. Estos dos threads se reparten el tiempo de la CPU y se ejecutan concurrentemente. Cada una de ellas con sus propios atributos de objeto (String SiNo). 11.i<=20. Una vez que finalizan su ejecución. … Esto es debido a que se ha accedido concurrentemente a una misma zona de memoria sin que se produzca exclusión mutua.start(). s. SiNoThread n = new SiNoThread("NO"). for (i=1.5.8. i++) System. SiNo=s. } public void run() { int i. i++) System.out. } } Produce la siguiente salida: 1:SI 2:SI 3:SI 5:NO 6:NO 4:SI 8:SI 9:SI 10:SI 11:SI 12:SI 13:SI 14:SI 15:SI 7:NO 17:NO 16:SI 19:SI 20:SI 21:SI 22:SI 23:SI 24:SI 25:SI 18:NO 26:NO 27:NO 28:NO 29:NO 30:NO 31:NO 32:NO 33:NO 34:NO 35:NO 36:NO 37:NO 38:NO 39:NO 40:NO En este caso se declaran dos instancias de una misma clase ( SiNoThread) y se ejecutan concurrentemente.print("SI ").1. public SiNoThread(String s) { super().2. for (i=1. class UnThreadDosInstancias { public static void main(String args[] ) { SiNoThread s = new SiNoThread("SI").6. n. al igual que en el ejemplo anterior. es: NO NO NO NO NO NO SI SI SI SI SI SI SI SI SI SI SI SI SI SI SI SI SI NO NO SI SI NO NO SI NO NO NO NO NO NO NO NO NO NO En este caso se instancian dos threads y se llama a su ejecución mediante los métodos start(). el programa termina.class SiThread extends Thread { public void run() { int i. } } La salida del programa.start().3 Y otro ejemplo más.

Un thread pasa del estado no ejecutable a ejecutable por alguna de las siguientes razones: dormido: que pase el tiempo de espera indicado por su método sleep().11.2 Estado de un thread. Un thread en este estado únicamente acepta las llamadas a los métodos start() o stop(). Un thread puede pasar al estado muerto por dos motivos: que finalice normalmente su método run() o que se llame a su método stop() desde cualquiera de sus posibles estados (nuevo thread. La llamada al método start() asigna los recursos necesarios al objeto. el thread pasará al estado ejecutable y. lo sitúa en el estado ejecutable y llama al método run() del objeto. si se le asigna la CPU. se inicializa sin asignarle recursos. ejecutable o no ejecutable). que el thread haga uso de su método wait() o que el thread esté bloqueado esperando una operación de entrada/salida o que se le asigne algún recurso. proseguirá su ejecución. 130 . El ciclo de vida de un thread puede pasar por varios estados ilustrados en la siguiente figura: Cuando se instancia un thread. Un thread en estado ejecutable puede pasar al estado no ejecutable por alguna de las siguientes razones: que sean invocados alguno de sus métodos sleep() o suspend(). momento en el cual. Esto no significa que el thread esté jecutándose (existen multitud de sistemas que poseen una sola CPU que debe ser compartida por todos los threads y procesos) sino que está en disposición de ejecutarse en cuanto la CPU le conceda su tiempo. Está en el estado nuevo Thread.

public void start() { t = new Thread(this). Se utilizará la primera forma. bloqueado: una vez finalizada una espera sobre una operación de E/S o sobre algún recurso. cuando la clase declarada no tenga que ser subclase de ninguna otra superclase. más evidente y sencilla.suspendido: que. ya casi no se usan en java2.3 Creación de threads.out. después de haber sido suspendido mediante el método suspend(). sea continuado mediante la llamada a su método resume(). Nota: Estos dos metodos. La forma en que se crean los threads como subclase de Thread ya se ha visto en puntos anteriores. Se utilizará la segunda forma cuando la clase declarada tenga que ser subclase de una superclase que no es subclase de Thread o implemente el interface Runnable.i++) System. t.start(). } public void run() { int i. for (i=1. Creación de threads utilizando la interface Runnable: class PrimerThread implements Runnable { Thread t. Pueden crearse threads de dos formas distintas: declarando una subclase de la clase Thread o declarando una clase que implemente la interface Runnable y redefiniendo el método run() y start() de la interface.println(i).i<=50. esperando: que después de una llamada a wait() se continúe su ejecución con notify() o notifyAll(). 11. } } class SegundoThread extends PrimerThread { } class ThreadRunnable { 131 .

} } En este caso se utiliza el constructor de la clase Thread: public Thread(Runnable destino). Es más. 11. ss.public static void main(String args[]) { SegundoThread s = new SegundoThread(). SegundoThread ss = new SegundoThread(). s. 4) Redefinir el método run() tal y como se hace en la otra alternativa de creación de threads (mediante subclases de Thread). Para poder después averiguarlo mediante el método: public final String getName(). cualquier subclase descendiente de esta clase poseerá también las características propias de los threads.start().2 isAlive(). Metodología para la creación del thread: 1) La clase creada debe implementar el interface Runnable: class Runnable { PrimerThread implements 2) La clase ha de crear un atributo (o variable local en el método start() ) de la clase Thread: Thread t.1 currentThread(). como ocurre en el ejemplo: SegundoThread es subclase de PrimerThread. Devuelve false si el thread está en el estado nuevo thread o muerto y true en caso contrario. Ambas formas de crear threads admiten un parámetro de tipo String que identifica al thread por su nombre: public Thread(String nombre). 3) Hay que redefinir el método start(): Instanciar el atributo de la clase Thread llamando a su constructor pasándole como parámetro la propia instancia de clase ( this): t = new Thread(this). 11.4 Operaciones sobre threads.4. String nombre). ambas son Thread. Devuelve el thread que se está ejecutando acutalmente. Una vez declarada la clase que implementa la interface Runnable. Thread-2.start(). Iniciar el thread: t.start(). public final boolean isAlive(). public static Thread currentThread().4. public Thread(Runnable destino. y por lo tanto. 132 . ya puede ser instanciada e iniciada como cualquier thread. … 11. la clase Thread se los asigna por defecto como Thread-1. Si no se ha asignado nombre a los threads.

4. En ambos casos se lanzará la excepción InterruptedException si se llama al método interrupt() del thread. el estado del mismo pasa de ejecutable a suspendido inmediatamente y sólo puede ser reactivado (pasado al estado ejecutable) llamando a su método resume().println("isAlive() en ejecución: "+ t. class MiThread extends Thread { public void run() { try { sleep(2000). System. // de esta forma. } catch (InterruptedException e) { } } } class Vivo { public static void main(String args[]) { MiThread t = new MiThread(). 2) Acepta un parámetro más: un número entero de nanosegundos (0 … 999999 ) que se sumaran a los milisegundos de espera.isAlive()). Llamando al método suspend() de un thread. 1) public static void sleep(long milisegundos) throws InterruptedException.4.4 suspend().out.println("isAlive() antes de iniciar: "+ t.start().3 sleep(). System. 1) Hace que el thread actual pase del estado ejecutable a dormido y permanezca en dicho estado durante los milisegundos especificados como parámetro. 2) public static void sleep(long milisegundos. try { // Hace "dormir" al thread actual Thread. Una vez que se ha cumplido el tiempo.isAlive()). 11. } } La salida correspondiente al programa es: Estado antes de iniciar: false Estado en ejecución: true Estado después de ejecución: false 11. int nanosegundos) throws InterruptedException. el thread “despierta” y pasa automáticamente al estado de ejecutable.out.isAlive()).sleep(3000). 133 .currentThread(). t.out.println("isAlive() después de ejecución: "+ t. La llamada al método resume() de un thread que está dormido no tiene ningún efecto. public final void suspend(). le da tiempo a terminar al // thread t } catch (InterruptedException e) { } System.

El método wait() es heredado de la superclase Object.start(). pero sí que está más repartida la CPU: 1:NO 2:SI 3:SI 4:NO 5:SI 6:NO 7:NO 8:SI 9:NO 10:SI 11:NO 12:NO 14:NO 13:SI 15:NO 16:SI 17:SI 18:NO 19:SI 20:NO 21:SI 22:NO 23:SI 24:SI 25:NO 26:SI 27:SI 28:NO 29:NO 30:NO 31:SI 32:NO 33:SI 34:SI 35:SI 36:NO 37:SI 38:NO 39:SI 40:NO 134 . SiNo=s. ya que puede perder la CPU antes y por consiguiente no tienen porqué salir los Síes y Noes alternativamente.print(++Contador+":"+SiNo+" "). } public void run() { int i. int nanosegundos) throws InterruptedException 1) Causa el paso al estado “esperando” del thread indefinidamente hasta que el thread sea notificado mediante notify() o notifyAll(). for (i=1.5 wait(). class UnThreadDosInstanciasAmables { public static void main(String args[] ) { SiNoThreadAmable s = new SiNoThreadAmable("SI").out. s. 3) El thread estará “esperando” hasta que sea notificado o expire el timeout (milisegundos + nanosegundos). 2) El thread estará “esperando” hasta que sea notificado o expire el timeout (milisegundos). yield(). ) el thread cede la CPU al otro thread mediante la llamada a yield(). Para cada salida por pantalla.println(++Contador+”:”SiNo+” “).start().4. Transfiere el control al siguiente Thread en el scheduler 41 (con la misma prioridad que el actual) que se encuentre en estado ejecutable. Esto no significa que el otro thread continúe su ejecución hasta llegar a su propio yield().out.i<=20. 11. i++) { System. (System. public SiNoThreadAmable(String s) { super(). public static void yield().11. 3) public final void wait(long milisegundos. de la cuál heredan todos sus métodos todas las clases creadas en Java.6 yield(). SiNoThreadAmable n = new SiNoThreadAmable("NO").4. } } } En este caso hay dos threads que se ejecutan concurrentemente. n. 2) public final void wait(long milisegundos) throws InterruptedException. } } class SiNoThreadAmable extends Thread { private String SiNo. static int Contador=0. 1) public final void wait() throws InterruptedException.

start(). En estos dos casos. i++) System. int nanoseg) throws InterruptedException. System. Hace que el thread que se está ejecutando actualmente pase al estado “esperando” indefinidamente hasta que muera el thread sobre el que se realiza el join().out.println("El thread ha terminado").join(). 135 .  class MiThread extends Thread { public void run() { int i. public final void join() throws InterruptedException. el thread de la clase Join1 no habría esperado la finalización de t y la salida por pantalla habría sido otra: 1 2 3 El thread ha terminado 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 Existen dos métodos join() más:  public final synchronized void join(long miliseg) throws InterruptedException.4. el thread actual no espera indefinidamente sino que reinicia su ejecución en el instante en que se finalice el thread sobre el que se hace el join() o pase el tiempo especificado por los parámetros miliseg (milisegundos) y opcionalmente nanoseg (nanosegundos).print(i+" "). public final synchronized void join(long miliseg.7 join(). t. } } class Join1 { public static void main (String args[]) throws InterruptedException { MiThread t = new MiThread().out. t. } } El thread de la clase Join1 espera indefinidamente hasta que finalice el thread t.join().11.i<=100. La salida por pantalla es: 1 2 3 4 5 6 7 8 9 22 23 24 25 26 27 40 41 42 43 44 45 58 59 60 61 62 63 76 77 78 79 80 81 94 95 96 97 98 99 10 11 12 13 14 15 16 17 18 28 29 30 31 32 33 34 35 36 46 47 48 49 50 51 52 53 54 64 65 66 67 68 69 70 71 72 82 83 84 85 86 87 88 89 90 100 El thread ha terminado 19 37 55 73 91 20 38 56 74 92 21 39 57 75 93 Si no se hubiera realizado el t. for (i=1.

5 Threads y sincronismo.11. si el productor genera los datos más deprisa de lo que el consumidor es capaz de tratarlos. que se ejecutaban concurrentemente.5. Existen. 11. cada uno de ellos se ejecutaba independientemente de los demás. si el consumidor es más rápido que el productor. Este flujo de datos puede ser almacenado en una zona de memoria compartida por ambos threads. la sincronización es vital. sin embargo. sino que los elimina el productor).5. El paradigma productor/consumidor consiste en la ejecución de un thread que produce un flujo de datos que deben ser consumidos por otro thread. ya que de lo contrario. En este caso. cooperando entre ellos para su correcto funcionamiento. puede encontrarse con que no hay datos que consumir o que se consuman más de una vez (si no elimina los datos consumidos.1 El paradigma productor/consumidor. En este caso. situaciones en las que es imprescindible sincronizar en cierta forma la ejecución de distintos threads que buscan un objetivo común. puede producirse un desbordamiento de la memoria asignada al efecto. por otra parte. debe existir un mecanismo que “frene” al productor o al consumidor en los casos necesarios. 11.2 Sección crítica. Se llama sección crítica a los segmentos de código dentro de un programa que acceden a zonas de memoria comunes desde distintos threads que se ejecutan concurrentemente 136 . Hasta el momento se ha estado tratando con threads asíncronos.

println("Contado hasta ahora: "+ contador.En Java. c2. las secciones críticas se marcan con la palabra reservada synchronized. Aunque está permitido marcar bloques de código más pequeños que un método como synchronized. } } class ThreadSinSync { public static void main(String arg[]) { Contable c1 .out. } } 137 .incrementa(). long aux. public Contable (Contador c) { contador=c. para seguir una buena metodología de programación. } System. for (i=1. es preferible hacerlo a nivel de método.i<=100000. aux++. } } class Contable extends Thread { Contador contador. } public void run () { int i.getValor()). public void incrementa() { long aux. class Contador { private long valor=0. aux=valor. c1. Contador c = new Contador().start().start(). c2 . valor=aux. c1 = new Contable(c). i++) { contador. } public long getValor() { return valor. c2 = new Contable(c).

ya que desde esta instrucción se accede a un objeto (contador) que es compartido por ambos threads (c1 y c2). la sección crítica es la línea: contador. aunque el efecto de haber codificado valor++ habría sido similar. 138 . Lo que ha ocurrido en realidad para que se produzca este resultado equivocado es lo siguiente Evidentemente.Para realizar el incremento en el método incrementa().incrementa(). se ha empleado una variable auxiliar intermedia (aux). La salida por pantalla es: Contado hasta ahora: 124739 Contado hasta ahora: 158049 cuando debería haber sido: en la primera línea un número comprendido entre 100000 y 200000. Simplemente cambiando la línea de código: public void incrementa() { por public synchronized void incrementa() { se habría conseguido bloquear el método incrementa. y en la segunda línea el valor 200000. a efectos didácticos. En este caso. de forma que no pudieran ejecutarlo simultáneamente dos threads sobre el mismo objeto (contador). esto mismo ha ocurrido un gran número de veces durante la ejecución de los threads.

meter(i). } } class Consumidor extends Thread { Caja c. Cuando un thread está ejecutando un método synchronized de un objeto.println("sacado el valor: "+valor). evitando que cualquier otro thread ejecute ningún otro método synchronized sobre ese mismo objeto.La salida del programa habría sido (correcta): Contado hasta ahora: 186837 Contado hasta ahora: 200000 11. } public void run() { int i. adquiriendo de nuevo el monitor (llamada a un método synchronized desde otro método synchronized).3 Monitores.out. valor=0.println("metido el valor: "+valor). i<=10. } } class Productor extends Thread { Caja c. cada objeto que posee un método synchronized posee un único monitor para ese objeto. } public synchronized void sacar() { System. for (i=1.5. Esto no impide que el propietario del monitor ejecute otro método synchronized de ese mismo objeto. public Consumidor(Caja nc) { c = nc. class Caja { private int valor. public synchronized void meter(int nv) { valor = nv. public Productor(Caja nc) { c = nc. System. i++) c. se convierte en el propietario del monitor. En Java.out. } public void run() { 139 .

sacar(): Muestra en pantalla el valor almacenado y pone ese valor a cero. 140 . i++) c. } } En este ejemplo existen dos threads que se comportan siguiendo el paradigma productor/consumidor. p. se declaran los métodos meter y sacar como synchronized.sacar(). Para asegurar la exclusión mutua en la zona crítica (la que accede a valor). ya que el productor puede almacenar varios valores antes de que el consumidor extraiga el valor o. también. Consumidor c = new Consumidor(cj). i<=10. Pero esto no es suficiente para que el programa funcione correctamente.start(). por lo que la salida por pantalla podría ser la siguiente: metido el valor: 1 sacado el valor: 1 sacado el valor: 0 sacado el valor: 0 metido el valor: 2 metido el valor: 3 sacado el valor: 3 sacado el valor: 0 sacado el valor: 0 metido el valor: 4 metido el valor: 5 sacado el valor: 5 sacado el valor: 0 metido el valor: 6 metido el valor: 7 metido el valor: 8 sacado el valor: 8 sacado el valor: 0 metido el valor: 9 metido el valor: 10 De alguna forma habría que asegurar que no se meta ningún valor si la caja está llena y que no se saque ningún valor si la caja está vacía. } } class ProdCons { public static void main(String argum[]) { Caja cj = new Caja(). Existe un objeto de la clase Caja que es capaz de almacenar un único número entero. que el consumidor intente sacar varios valores consecutivamente. Productor p = new Productor(cj). Tanto el thread productor como el consumidor comparten el mismo objeto de la clase Caja.int i.start(). for (i=1. c. Sobre esta caja se pueden realizar dos tipos de operaciones:  meter(int): Almacena el entero que se le pasa como parámetro y muestra el valor en pantalla.

disponible=false.out.start().out.println("sacado el valor: "+valor). } public void run() { int i. } } public synchronized void sacar() { if (disponible) { System. i<=10.sacar(). i++) c. Productor p = new Productor(cj). i<=10. c. valor=0. termina su ejecución. disponible=true.meter(i). i++) c. 141 . y sigue su ejecución hasta terminar el bucle. System.start(). como el consumidor ya ha terminado su ejecución no se pueden introducir más valores y el programa termina. el productor introduce el siguiente valor (el 2). el consumidor ha seguido su ejecución en el bucle y como no se mete ningún valor por el consumidor. public Productor(Caja nc) { c = nc. } } class ProdCons2 { public static void main(String argum[]) { Caja cj = new Caja(). Consumidor c = new Consumidor(cj). p. public synchronized void meter(int nv) { if (!disponible) { valor = nv. } public void run() { int i. } } Salida por pantalla: metido el valor: 1 sacado el valor: 1 metido el valor: 2 Después de sacar el valor 1. } } class Consumidor extends Thread { Caja c. private boolean disponible=false. } } } class Productor extends Thread { Caja c.class Caja { private int valor.println("metido el valor: "+valor). for (i=1. for (i=1. public Consumidor(Caja nc) { c = nc.

start().sacar(). } catch (InterruptedException e) { } } valor = nv. c. private boolean disponible=false.start(). i++) c. disponible=true. disponible=false. } public void run() { int i. Productor p = new Productor(cj). notify(). } public synchronized void sacar() { if (!disponible) { try { wait(). notify(). public Consumidor(Caja nc) { c = nc. i<=10.meter(i).out. } } class Productor extends Thread { Caja c. } public void run() { int i.println("sacado el valor: "+valor). } } class Consumidor extends Thread { Caja c. System.out. p. public synchronized void meter(int nv) { if (disponible) { try { wait(). i<=10. } } class ProdCons3 { public static void main(String argum[]) { Caja cj = new Caja(). for (i=1.println("metido el valor: "+valor). public Productor(Caja nc) { c = nc. valor=0.Lo que hace falta es un mecanismo que produzca la espera del productor si la caja tiene algún valor (disponible) y otro que frene al consumidor si la caja está vacía (no disponible): class Caja { private int valor. i++) c. Consumidor c = new Consumidor(cj). for (i=1. } } Produce el resultado deseado: metido el valor: 1 142 . } catch (InterruptedException e) { } } System.

se cambia el valor de disponible a true y se llama al método notify() el método notify() hace que el thread que está en estado de espera pase a ejecutable y tome el monitor del objeto. no se ejecuta el wait().sacado el valor: 1 metido el valor: 2 sacado el valor: 2 metido el valor: 3 sacado el valor: 3 metido el valor: 4 sacado el valor: 4 metido el valor: 5 sacado el valor: 5 metido el valor: 6 sacado el valor: 6 metido el valor: 7 sacado el valor: 7 metido el valor: 8 sacado el valor: 8 metido el valor: 9 sacado el valor: 9 metido el valor: 10 sacado el valor: 10  Si el primer thread en adquirir el monitor del objeto Caja es el Productor al ejecutar el método meter(i): la variable disponible contendrá el valor false y no se ejecutará wait(). Realiza la operación correspondiente y ejecuta el método notify() que no tiene ningún efecto. Si el primer thread en adquirir el monitor del objeto Caja es el Consumidor al ejecutar el método sacar(): La variable disponible contendrá el valor false y por lo tanto. 143 . se completa el método. se ejecuta el método wait() el método wait hace que el thread que actualmente posee el monitor lo abandone el monitor es tomado por el otro thread al llamar a meter(i) como disponible sigue siendo false.

5). Java evita esto asignando la CPU también a threads de menor prioridad aunque cada mucho menos tiempo que a los threads de mayor prioridad. t1. Además este algoritmo es explusivo.6 Prioridad de un thread. Hasta ahora se ha supuesto que todos los threads se repartían el tiempo de la CPU por igual. se le asigna directamente la CPU.start(). sin embargo esta prioridad puede ser modificada en cualquier momento llamando al método setPriority(). } } } class Prioridad1 { public static void main(String args[]) { ThreadConPrioridad t1 = new ThreadConPrioridad("1".print(nombre).start(). se reparten el tiempo mediante round-robin. 225 nombre=n. es decir. Se repartirán la CPU por igual sólo si la prioridad de los distintos thread es la misma. prioridad máxima de un thread public final static int MIN_PRIORITY = 1. public final int getPriority(). for(i=1.out. pero esto no es generalmente así. class ThreadConPrioridad extends Thread { String nombre. De todas formas.5). El algoritmo de planificación (scheduling) es el siguiente: la CPU se asigna al thread en estado ejecutable de mayor prioridad y si hay varios. Este algoritmo tiene un peligro: que un thread nunca se ejecute porque siempre existan threads de mayor prioridad. } } 144 . prioridad mínima de un thread public final static int NORM_PRIORITY = 5. éste hereda la prioridad del thread que lo creó. public final static int MAX_PRIORITY = 10. } public void run() { int i.11. t2. setPriority(pri). public ThreadConPrioridad(String n . yield(). Para conocer la prioridad de un thread se utiliza el método getPriority(). si se está ejecutando un thread y en ese momento pasa a estado ejecutable un thread de mayor prioridad. En todos los ejemplos que se han visto anteriormente los threads tenían la misma prioridad porque cuando se crea un thread.i<100. prioridad normal (por defecto) de un thread public final void setPriority(int newPriority).i++) { System. ThreadConPrioridad t2 = new ThreadConPrioridad("2". Threads. no debe confiarse la “no inanición” a la bondad del Java. int pri) { super().

Normalmente ejecuta un bucle infinito que realiza algún tipo de operación y tiene una prioridad baja (se ejecuta en background). Unicamente se diferencian de los threads normales en que. a pesar de ejecutar un bucle infinito. Si las prioridades hubieran sido otras. termina su ejecución cuando sólo quedan threads que son de tipo daemon en ejecución. los threads t1 y t2 tienen la misma prioridad (5).5). public final void setDaemon(boolean on). La salida por pantalla habría sido diferente: 111111111111111111111111111111111111111111111111111111 111111111111111111121212121212121212111111111111111111 222222222222222222222222222222222222222222222222222222 222222222222222222222222222222222222 Como puede observarse. La llamada al método setDaemon(true) hace que el thread se considere Daemon y setDaemon(false) hace que deje de serlo.Salida por pantalla: 221211122122212121212121112221212121212121212121212121 212121212121212121212122121212121212121121212121221212 121212121212121212112121212121212121212121221212211212 121212121211212121212121212121221111 En este caso. Para saber si un thread es un Daemon se utiliza el método: public final boolean isDaemon(). ThreadConPrioridad t2 = new ThreadConPrioridad("2". por lo que al llamar al método yield() se cede la ejecución al otro thread. también llamado demonio o servicio es un thread que proporciona servicios al resto de threads que se ejecutan en el mismo proceso que el daemon. Por ejemplo: ThreadConPrioridad t1 = new ThreadConPrioridad("1". la mayoría del tiempo de la CPU es acaparada por el thread de mayor prioridad.7 Threads Daemon. Cualquier thread puede ser un daemon. 145 . 11.4). Un daemon.

11. 146 .lang. Cuando se inicia la ejecución de un programa. Un grupo de threads puede contener threads.1 Creación de grupos de threads. Java crea un grupo de threads llamado main. Mediante llamadas al constructor: 1) public ThreadGroup(String nombre). Los grupos de threads sirven para manejar como una unidad a un conjunto de threads.8. y todos ellos pertenecen a un grupo raíz: main. cuando se crea un thread. String nombre).8 Grupos de threads. se añade al grupo al que pertenece el thread que lo creó. Esa es la razón por la cual todos los threads creados hasta el momento pertenecen al grupo main. 1) Crea un grupo cuyo nombre se pasa como parámetro. Hay que señalar que los grupos de threads no añaden ningún tipo de funcionalidad. Este grupo pertenecerá (subgrupo) al grupo actual (al que pertenece el thread que realiza la llamada al contructor). Para ello se utiliza la clase ThreadGroup que pertenece al paquete java. únicamente sirven para que sea más cómodo el manejo muchos threads en un programa. 2) public ThreadGroup(ThreadGroup padre. A no ser que se especifique lo contrario. pero también grupos. Todo thread creado en Java pertenece a un Grupo de threads. por ejemplo: iniciar o detener varios threads mediante una sola operación. 11.

out. Devuelve true si el grupo es un daemon y false en caso contrario. 2) Crea un grupo cuyo nombre se pasa como parámetro.currentThread().2 Operaciones sobre threads agrupados. 11. 11. public final boolean isDaemon().8. Pasan al estado “muerto” todos los threads descendientes de este grupo.Ejemplo: ThreadGroup tg = new ThreadGroup(“MiGrupo”). Runnable destino. 147 .2 Operaciones sobre un conjunto de threads.8. String nombreDelThread). Esto se realiza en la llamada al constructor del thread: public Thread(ThreadGroup grupo. public final void resume(). Ejemplo: ThreadGroup tg2 = new ThreadGroup( tg .2.2. Un grupo daemon es destruido automáticamente cuando no contiene ningún thread o grupo.println(tg. public final void stop(). Pasan al estado de “ejecutable” todos los threadsdescendientes de este grupo que estaban en estado “suspendido”. Pasan al estado de “suspendido” todos los threads descendientes de este grupo (todos los threads pertenecientes a este grupo) y se llama al método suspend() de todos los grupos pertenecientes a este grupo ( valga la redundancia).2. public Thread(ThreadGroup grupo. public final void suspend().1. System. 11. “MiGrupo2”).2. } } El método getName() devuelve un String que contiene el nombre del grupo.getName()). Convierte al grupo en daemon si el parámetro es true43.1 Operaciones sobre threads.1. aunque los threads descendientes que ya pertenecían al grupo antes de llamar al método setMaxPriority() pueden conservar su prioridad mayor que el parámetro (pri). Como se ha visto. public final void setMaxPriority(int pri).getThreadGroup(). los threads se insertan por defecto en el mismo grupo que el thread actual (el thread que lo crea) a no ser que se indique explícitamente a qué grupo debe pertenecer.8. public final void setDaemon(boolean daemon).8.2 Operaciones sobre grupos. evidentemente es: main 11.8. Es posible obtener el grupo al que pertenece un thread mediante la llamada al método getThreadGroup() de la clase Thread:  class Grupo1 { public static void main(String args[]) { ThreadGroup tg = Thread. String nombreDelThread). Establece la máxima prioridad que puede tener un thread descendiente de este grupo. La salida por pantalla. 11. Este grupo pertenecerá al grupo que se pasa como parámetro (padre).1 Asignación de un thread a un grupo.

enumerate(t). El método enumerate puede obtener un vector con los threads pertenecientes al grupo (los casos 1 y 2) o un vector con los grupos pertenecientes a un grupo (casos 3 y 4) se almacena en el parámetro lista[]. Si el grupo no está vacío. Por defecto.println("Ejecutado "+getName()). boolean recurr).out."Thread 2. MiThread t1 = new MiThread(tg. Para obtener únicamente los threads pertenecientes al grupo en cuestión es necesario pasar un nuevo parámetro de tipo bolean (recurr) con el valor false.length. 3) public int enumerate(ThreadGroup lista[]). MiThread t12 = new MiThread(tg. for (i=0. 4) public int enumerate(ThreadGroup lista[].1").i<t."Thread 1.2").println(t[i]). tg.nom). boolean recurr)."Thread 2. String nom) { super(tg.out. } } class Grupo2 { public static void main(String args[]) throws InterruptedException { ThreadGroup tg = new ThreadGroup("grupo uno")."Thread 1. MiThread t21 = new MiThread(tg2. public final boolean parentOf(ThreadGroup g). 11.  class MiThread extends Thread { public MiThread(ThreadGroup tg.2.8.1"). Este grupo debe estar vacío: no debe contener threads activos. } } 148 . } public void run() { System.2"). Thread t[] = new Thread[4]. 1) public int enumerate(Thread lista[]). Devuelve true si este grupo es padre (o es el mismo) que el grupo que se pasa como parámetro (g) y false en caso contrario. 2) public int enumerate(Thread lista[]. añadiendo los threads o grupos del grupo sobre el que se realiza la llamada y de los grupos descendientes del mismo. se obtienen listas de threads (y grupos) recursivas. int i. MiThread t22 = new MiThread(tg2. ThreadGroup tg2 = new ThreadGroup(tg.3 Obtención del contenido de un grupo. hay que llamar antes al método stop() del grupo44 para que todos los threads descendientes pasen al estado “muerto”.i++) System."grupo dos"). de lo contrario se genera una excepción de la clase IllegalThreadStateException. Destruye el grupo (pero no los threads descendientes).public final void destroy() throws IllegalThreadStateException.

grupo uno] Thread[Thread 1.1.En este caso.5.5.2.5.2. la salida por pantalla es la siguiente: Thread[Thread 1.1.grupo uno] Thread[Thread 1.grupo dos] Thread[Thread 2. la salida por pantalla habría sido: Thread[Thread 1. false).5.grupo uno] Thread[Thread 2.5.grupo uno] null null 149 .1.2.5.grupo dos] Si en lugar de enumerate(t) se hubiera utilizado la fórmula enumerate(t.

Como hemos dicho vamos a tener tres capítulos dedicados a Swing. diálogos y ventanas hasta cajas de texto. Swing es bastante extenso y aun utilizando tres capítulos no lo vamos a ver completamente. los componentes Swin utilizan las clases de los eventos incluidas en el paquete java. es decir. Lo mismo sucede con los eventos.AWT para utilizarlos. pero Swing aporta un nuevo gestor de diseño (que veremos en el siguiente capítulo.12.event. JFC y Swing JFC (Java Foundation Classes) es el nombre que recibe el conjunto de un gran número de características cuya función primordial es la de permitir la construcción de complejos interfaces de usuario. barras de progreso. El primer anuncio de JFC se realizó en la conferencia de desarrolladores JavaOne y se definió mediante las características que iba a ofrecer:  Componentes Swing: comprenden todos los componentes utilizados para interfaces de usuario desde botones. de hecho se debe importar el paquete JAVA. paneles con pestañas y listas. los componentes atómicos.swing. sería necesario un curso de la misma extensión de éste (o más) para tratar Swing de forma completa. En este primer capítulo vamos a introducir una serie de conceptos de Swing y también se va a tratar un tipo de componentes Swing. En el segundo capítulo trataremos el otro gran grupo de componentes Swing. los gestores de diseño que utilizan los componentes Swing son los mismos que los vistos en los componentes AWT.event. como pueden ser los eventos o los gestores de diseño siguen siendo válidos para los componentes Swing. aspecto y comportamiento configurables. A lo largo de este capítulo describiremos algunos de los componentes Swing.awt.swing.0 Swing Interfaces de usuario en Java: componentes Swing / contenedores Introducción Muchos de los conceptos vistos en capítulos anteriores. y además añaden nuevos eventos que se pueden encontrar en el paquete javax. así por ejemplo. Y en el último de esta serie de capítulos trataremos otras características de Swing como son el nuevo gestor de diseño que incorpora (implementado por la clase BoxLayout) y la característica Pluggable Look & Feel. no todos ya que Swing ofrece un gran número de clases agrupadas en 15 paquetes distintos. también dedicado por completo al extenso mundo de los componentes Swing) que se encuentra en el paquete javax. barras de menú. los contenedores Swing. 150 .

Así por ejemplo una misma aplicación puede presentar una apariencia y comportamiento al estilo de Java o bien tipo Windows. En muchos casos se utilizan indistintamente los términos JFC y Swing sin hacer ningún tipo de distinción. En el apartado correspondiente volveremos a retomar esta característica y la trataremos en detalle.1 (versión de Java 1.2 o como en el JDK 1.1 del lenguaje (que coincidían con las versiones de la herramienta JDK). tanto en la herramienta JDK 1.1) denominada JFC 1. en este caso. Componentes Swing frente a componentes AWT En este apartado vamos a comentar las diferencias entre los dos grupos de componentes que ofrece Java para la creación de interfaces de usuario. imágenes y texto. 151 .  API de accesibilidad: permite a tecnologías de rehabilitación tales como lectores de pantalla y displays Braille obtener información acerca del interfaz de usuario. en el tratamiento de gráficos en dos dimensiones. Los componentes AWT se utilizan principalmente en las versiones 1. Soporte para Pluggable Look and Feel: es decir. se trata de un conjunto de clases especializadas. soporte para una apariencia y comportamiento configurables.  Soporte para arrastrar y soltar (Drag and Drop): permite la posibilidad de arrastrar y soltar componentes entra aplicaciones Java y aplicaciones en otros lenguajes. El API de accesibilidad se encuentra formando parte de las características avanzadas del lenguaje Java y por lo tanto no lo vamos a tratar en este curso. como parte de la plataforma Java 2. En nuestro caso vamos a utilizar la versión que se encuentran integrada con la plataforma Java 2.  API Java 2D: al igual que ocurría con la característica o funcionalidad anterior. y como una extensión del JDK 1. La denominación swing aparece también en los paquetes correspondientes. aunque la plataforma Java 2 soporta perfectamente los componentes AWT como hemos podido comprobar en capítulos anteriores.3. Permite a cualquier programa que utilice componentes Swing definir un tipo de apariencia y comportamiento (Look and Feel). Desde Sun nos recomiendan que utilicemos si es posible los componentes Swing en lugar de los componentes AWT. Swing fue el nombre en clave que recibió el proyecto de Sun encargado de desarrollar los nuevos componentes para la construcción de interfaces de usuario.0 y 1. El API Java 2D se escapa también del alcance y pretensiones de este curso. Los componentes Swing se encuentran disponibles de dos formas distintas.0 del JDK y eran los únicos componentes que se encontraban disponibles para desarrollar interfaces de usuario.1. y el porqué de la existencia de dos grupos distintos de componentes. Los componentes AWT aparecieron en la versión 1.

por ejemplo.  arquitectura Pluggable Look & Feel. etc.AWT y los Swing en el paquete javax. más claro todavía. es que los componentes Swing se encuentran implementados sin utilizar ningún tipo de código nativo. Los componentes AWT se encuentran en el paquete JAVA.  tecnologías de rehabilitación pueden obtener información de los componentes Swing Las de forma sencilla.swing. siempre elegiremos componentes Swing. los botones pueden ser redondos. Los  posible situar bordes en torno a los componentes Swing. Vamos a comentar brevemente algunas de las razones por las que nos puede interesar utilizar componentes Swing en lugar de componentes AWT. 152 . Por lo tanto si queremos construir applets que puedan ejecutarse en cualquier navegador deberemos construir su interfaz gráfica mediante componentes AWT.  Posiblemente en un futuro se ampliarán los componentes Swing disponibles. La mayor diferencia entre los componentes AWT y los componentes Swing. Es  Los componentes Swing no tienen porque ser rectangulares. Incluso los componentes Swing más sencillos ofrecen una serie de posibilidades que los componentes AWT no recogen. es decir. la clase Button del AWT. tiene su clase correspondiente en Swing denominada JButton. elementos de menú.  rico conjunto de componentes que ofrece Swing: botones con imágenes. desgraciadamente. aspecto y comportamiento configurable La y seleccionable para los elementos del interfaz de usuario. los navegadores Web actuales. Parece hasta ahora que con los componentes Swing todo son ventajas. selectores de color. sin embargo los componentes AWT tienen el aspecto y comportamiento de la plataforma nativa sobre la que se ejecutan. Otra diferencia importante es la gran potencia y funcionalidad que ofrecen los componentes Swing. Los componentes Swing se denominan componentes ligeros (lightweight) y los componentes AWT componentes pesados (heavyweight). todavía no existen navegadores Web que soporten Swing.Los componentes Swing los podemos identificar porque los nombres de sus clases suelen ir precedidos por la letra J. ya que en la práctica no resulta tan sencillo. incluso en sus últimas versiones. no implementan la máquina virtual correspondiente a la plataforma Java 2. e incluso que ni siquiera debemos plantearnos que tipo de componentes debemos utilizar para construir interfaces de usuario. algunas de estas ventajas de los componentes Swing frente a los AWT son las que se enumeran a continuación:  botones Swing pueden mostrar imágenes y/o texto. Pero este razonamiento no es correcto. barras de El herramientas. Se debe señalar que. imágenes. Así por ejemplo. Swing nos permite especificar el aspecto y comportamiento (look and feel) del interfaz de usuario de nuestra aplicación (más adelante veremos como). Aunque se pueden generar parches que utilizaremos para que los navegadores soporten componentes Swing.

También dentro de los componentes Swing encontramos una cuarta clase denominada JWindow que representa una ventana sin controles ni título y que se encuentra siempre por encima de cualquier ventana.setOpaque(true).Contenedores de alto nivel Bajo esta nomenclatura se agrupan una serie de clases que se corresponden con componentes Swing que realizan la función de contenedores de otros componentes y que constituyen la raíz en la jerarquía de contenedores.yellow).  Cada contenedor de alto nivel posee un panel de contenido (content pane) que contiene los componentes visibles del contenedor de alto nivel del interfaz de usuario correspondiente. etiquetaAmarilla. etiquetaAmarilla. 180)).awt. Cada jerarquía de contenedores posee un contenedor de alto nivel como raíz.*.cyan). 153 . La barra de menú se sitúa en el contenedor de alto nivel. Se trata de un objeto de la clase JFrame que contiene una barra de menú (JMenuBar) de color azul y una etiqueta (JLabel) de color amarillo. Los componentes de alto nivel se basan en los siguientes principios:  Swing ofrece tres clases que representan a componentes de alto nivel: JFrame (ventana). Veamos un sencillo ejemplo que muestra un contenedor de alto nivel. pero fuera del panel de contenido.setBackground(Color. barraMenuCyan.setOpaque(true). etiquetaAmarilla. es el equivalente a la clase Window de los componentes AWT. public class ContenedorAltoNivel { public static void main(String s[]) { //se crea la ventana raíz de la jerarquía de contenedores JFrame ventana = new JFrame("Contenedor de alto nivel"). A lo largo de este capítulo iremos viendo como en los componentes Swing encontramos equivalentes de los componentes AWT.setPreferredSize(new Dimension(200.  Opcionalmente se puede añadir una barra de menú a un contenedor de alto nivel. En la Figura se puede ver el aspecto del contenedor. barraMenuCyan.*.swing. //se crea la barra de menú JMenuBar barraMenuCyan = new JMenuBar(). JDialog (diálogo) y JApplet. Y el código fuente completo de este ejemplo es : import java. //se crea la etiqueta JLabel etiquetaAmarilla = new JLabel("").  Para aparecer en pantalla todo componente de interfaz de usuario debe formar parte de una jerarquía de contenedores. import javax.setBackground(Color.

setDefaultCloseOperation(JFrame. El código fuente de este ejemplo es el que aparece en el Código fuente : import javax. public class Ventana{ public static void main(String[] args) { //se establece el Look & Feel try { UIManager. ventana.*. import java.barraMenuCyan.EXIT_ON_CLOSE). Veamos un ejemplo más para ilustrar las jerarquías de contenedores. JLabel etiqueta = new JLabel(" Soy una etiqueta"). 20)). //se muestra la ventana ventana.AWT y javax. Un  Una etiqueta (JLabel). //se añaden la etiqueta y la barra de menú a la ventana ventana. Al panel se le ha añadido un borde mediante la clase BorderFactory para mostrar el agrupamiento de forma más clara entre el botón y la etiqueta.AWT es necesario para utilizar las clases Dimension.getCrossPlatformLookAndFeelClassName()).swing. ventana. Color y BorderLayout.add(etiquetaAmarilla.swing. Un  botón (JButton).*. 154 . } catch (Exception e) { } //se crean los componentes JFrame ventana = new JFrame("Ventana").awt. También podemos comprobar la forma en la que se añade un componente a un panel de contenido de un contenedor de alto nivel como puede ser un objeto de la clase JFrame. JButton boton = new JButton("Soy un botón"). El paquete JAVA.setJMenuBar(barraMenuCyan). Se han importado los paquetes JAVA.setVisible(true). ventana.setLookAndFeel( UIManager. en este mismo apartado veremos en más detalle el código que realiza estas funciones.  panel (JPanel).pack(). Para ello nos debemos fijar en la Figura siguiente: En este ejemplo se han utilizado los siguientes componentes Swing:  Una ventana principal (JFrame). y también como añadir una barra de menú. BorderLayout. como se puede observar aunque utilicemos componentes Swing vamos a necesitar de los componentes AWT.getContentPane(). } } A la vista de este código podemos realizar los siguientes comentarios.CENTER).setPreferredSize(new Dimension(200.

esto aparece en las primeras líneas del método main() y en este caso se establece el aspecto y comportamiento de Java. 155 . ventana. //se añaden al panel el botón y la etiqueta panel.CENTER).add(etiqueta). Y por último y el botón y la etiqueta se denominan componentes atómicos.getContentPane(). Otros contenedores intermedios pueden ser paneles con pestañas (JTabbedPane) y paneles de scroll (JScrollPane). para que sea visible se le ha asignado un borde de color rojo.5)). BorderLayout.EXIT_ON_CLOSE). cómo asignar un aspecto y comportamiento (Look & Feel) determinado a nuestro interfaz de usuario.setBorder(BorderFactory. //se muestra la ventana ventana. igualmente podría tratarse de otro componente de alto nivel como podría ser un objeto de la clase JApplet o JDialog. como ocurría con los anteriores. sino que tienen entidad suficiente para presentar por sí mismos información al usuario.setDefaultCloseOperation(JFrame. ventana. Vamos a pasar a describir las funciones que presentan cada uno de los componentes Swing utilizados en el ejemplo. //se asigna un borde y un gestor de diseño al panel panel. que juegan un papel más visible e interactivo dentro del interfaz de usuario. 1)). cajas de texto (JTextField) o tablas (JTable). Swing ofrece un gran número de componentes atómicos (en este capítulo veremos algunos de ellos) como pueden ser listas desplegables (JComboBox).setVisible(true).add(boton). A menudo los componentes atómicos tienen como función obtener información del usuario.createLineBorder(Color.add(panel. panel.red. } } Este código adelanta algo que veremos en detalle en el apartado correspondiente.JPanel panel = new JPanel(). son componentes que no contienen otros componentes Swing. panel. //se añade el panel al panel de contenido de la ventana ventana. su propósito es el de simplificar la situación del botón y la etiqueta.setLayout(new GridLayout(0.pack(). El panel es un contenedor intermedio. En este ejemplo la ventana representada mediante la clase JFrame es el contenedor de alto nivel.

Para añadir un componente a un contenedor se utiliza una de las distintas formas del método add(). la aplicación presentará tres jerarquías de contenedores.CENTER). Una de las jerarquías de contenedores tiene a un objeto de la clase JFrame como raíz. aunque más adelante veremos algunos de ellos con más detalle. una barra de menú. Por defecto el panel de contenido es un contenedor intermedio que hereda de la clase JComponent y que tiene como gestor de diseño un BorderLayout.BorderLayout. Por ejemplo un applet que muestra un diálogo tiene dos jerarquías de contenedores. Cada contenedor de alto nivel indirectamente contiene un contenedor intermedio llamado panel de contenido (content pane). que devuelve un objeto de la clase Container. y por otro. Hasta ahora hemos visto un par de ejemplos que por un lado nos han mostrado como funcionan las jerarquías de contenedores. 156 . como ya vimos en el tema dedicado a los componentes AWT. además. todos los componentes visibles de la ventana del interfaz de usuario. como ya hemos dicho la raíz de esta jerarquía siempre es un contenedor de alto nivel. y por lo tanto tres contenedores de alto nivel.getContentPane(). ventana. Una vez que tenemos una referencia al panel de contenido podremos añadir los componentes que consideremos necesarios utilizando una sentencia similar a la que muestra el siguiente fuente . que se sitúan en un lugar especial fuera del panel de contenido. Un applet basado en Swing tiene al menos una jerarquía de contenedores y su raíz es un objeto de la clase JApplet. como vimos en el primer ejemplo de este apartado. en teoría. y normalmente el panel de contenido contiene. y cada una de las otras dos jerarquías un objeto de la clase JDialog como raíz. Todos los contenedores de alto nivel pueden tener. directa o indirectamente. tiene al menos una jerarquía de contenedores con un objeto de la clase JFrame como raíz de la misma. sin embargo en la práctica las barras de menú se utilizan únicamente en ventanas y en raras ocasiones en applets. nos ha mostrado como utilizar algunos de los componentes Swing. Como regla general. La excepción a esta regla son las barras de menú. y los que se encuentran en el diálogo tienen como raíz de su jerarquía de componentes un objeto de la clase JDialog. los componentes en la ventana del navegador tienen como raíz un objeto JApplet. una aplicación Java con un interfaz de usuario basado en componentes Swing.add(componente. Por ejemplo. Para obtener una referencia al panel de contenido de un componente de alto nivel debemos utilizar el método getContentPane(). Para añadir una barra de menú a un contenedor de alto nivel. si una aplicación tiene una ventana principal y dos diálogos.Como se puede observar incluso el programa Swing más sencillo presenta múltiples niveles en su jerarquía de contenedores.

157 . Se trata de una ventana que contiene una etiqueta y que al pulsar el cierre de la misma se finalizará la ejecución de la aplicación. permite organizar los componentes del interfaz de usuario en capas. un objeto de la clase JFrame representa a una ventana con bordes. es decir.setMenuBar(objMenuBar). poseen otro panel llamado panel raíz (root pane). Normalmente este panel intermedio no se suele utilizar. El panel de capas contiene directamente la barra de menú y el panel de contenido. se utiliza sobre todo para interceptar eventos de entrada que suceden sobre el contenedor de alto nivel. Estos dos contenedores son el panel de capas (layered pane) y el panel de cristal (glass pane). Todo contenedor de alto nivel además de poseer un panel de contenido. título y botones que permiten cerrar y maximizar la ventana. A continuación vamos a comentar los distintos componentes de alto nivel: JFrame. ventana. Las aplicaciones Java que poseen interfaz de usuario al menos utilizan un JFrame. JFrame Ya hemos visto este componente Swing realizando las labores de contenedor de alto nivel.crearemos un objeto de la clase JMenuBar. Este panel es útil para interceptar eventos o pintar sobre un área que ya contiene otros componentes. pasándole por parámetro el objeto JMenuBar correspondiente. su función es la de gestionar el panel de contenido y la barra de menú junto con otros dos contenedores. Veamos la utilización de la clase JFrame mediante un sencillo ejemplo. El panel de cristal suele permanecer oculto y se encuentra por encima de todos los elementos del panel raíz. Esto puede ser útil para mostrar menús de aparición súbita (popup menus) por encima de otros componentes. y además permite ordenar los componentes que se vayan añadir con detenimiento (Z-order). JDialog y JApplet. y también lo hacen a veces los applets. añadiremos los elementos de menú que se consideren necesarios y por último se lanzará sobre el contenedor de alto nivel el método setMenuBar(). En la Figura 66 se puede ver un esquema que muestra la disposición de los distintos paneles que podemos encontrar en un componente de alto nivel.

 HIDE_ON_CLOSE: es el valor por defecto. teniendo la posibilidad de mostrarse la ventana de nuevo si así lo indicamos en el programa.add(etiqueta.awt. 100)). El método pack() de un tamaño a la ventana de forma que todos sus contenidos tengan el tamaño especificado o superior.import java. BorderLayout. ventana. } }). El parámetro que se le pasa al método setDefaultCloseOperation() debe ser una de las siguientes constantes:  DO_NOTHING_ON_CLOSE: en este caso cuando se pulsa el botón de cierre de la ventana no ocurre nada.*. En las siguientes líneas se crea y añade una etiqueta (JLabel) al panel de contenido de la ventana.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. import java. Al método setVisible() se le pasa el parámetro true para que muestre la ventana en la pantalla. Por defecto cuando se pulsa el botón de cierre de la ventana.swing. public class Ventana{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana Sencilla").pack().awt.exit(0). etiqueta. otra versión de este constructor es sin argumentos.event. } } En la primera línea del método main() se utiliza el constructor de la clase JFrame que nos permite indicar el título de la ventana mediante una cadena que pasamos como parámetro. import javax.setPreferredSize(new Dimension(175. pero sigue existiendo.*. ventana.*. ventana. cuando se pulsa el botón de cierre la ventana se oculta.getContentPane(). JLabel etiqueta = new JLabel("Soy una etiqueta"). la ventana se oculta.setVisible(true). la ventana sigue visible. en este caso se implementa únicamente el método windowClosing() para finalizar la ejecución de la aplicación. 158 . para cambiar este comportamiento se puede utilizar el método setDefaultCloseOperation() o bien implementar un tratamiento de eventos similar al del ejemplo. sin la necesidad de utilizar ningún tratamiento de eventos.CENTER). A continuación se añade un oyente para los eventos de la ventana. una alternativa al método pack() es le método setSize() en el que se puede especificar de forma explícita las dimensiones de la ventana. Por último se lanzan los métodos pack() y setVisible() sobre la instancia de la clase JFrame. ventana.

en el Código se puede observar como se crea un objeto JPanel que luego va a ser el panel de contenido de una ventana. panelContenido. JPanel panelContenido=new JPanel(). que son un tipo de ventana más limitada que las ventanas representadas por la clase JFrame. Como se indica al principio de esta sección nosotros únicamente nos vamos a encargar de las clase JOptionPane y JDialog.  JMenuBar getMenuBar(): devuelve la barra de menú que tiene asignada la ventana.setContentPane(panelContenido).  ProgressMonitor: muestra un diálogo que muestra el progreso de una operación.  getDefaultCloseOperation(): devuelve la operación de cierre por defecto asignada a la int ventana.add(otroComponente.  Component getGlassPane(): devuelve el panel de cristal de la ventana.  void setContentPane(Container): asigna a la ventana un panel de contenido.   Container getContentPane(): devuelve el panel de contenido de la ventana. panelContenido. Hay varias clases que ofrecen diálogos:  JOptionPane: permiten crear sencillos diálogos estándar.Frame. pack().setLayout(new BorderLayout()). DISPOSE_ON_CLOSE: al cerrar la ventana se elimina de la memoria y de la pantalla. la clase JFrame tiene los siguientes métodos propios:  void setDefaultCloseOperation(int): asigna el tipo de operación que va a realizar la ventana cuando el usuario pulse el botón de cierre de la ventana. como pueden ser setSize().add(componente. este método se suele utilizar para una vez que tenemos una referencia al panel de contenido de la ventana añadir componentes a la misma.  JDialog: permite crear directamente diálogos completamente personalizados. setVisible() y getTitle().SOUTH). en este caso se liberan todos los recursos que estaban siendo utilizados por la ventana.BorderLayout.  JColorChooser: ofrece un diálogo estándar para la selección de colores.awt. es decir.awt. JDialog.Frame y por lo tanto hereda todos los métodos de la clase Frame. JOptionPane Vamos a pasar ahora a comentar el segundo tipo de contenedores de alto nivel. ventana.  JFileChooser: ofrece un diálogo estándar para la selección de un fichero. La clase JFrame hereda de la clase java. 159 . lo normal es utilizar un objeto de la clase JPanel para crear el panel de contenido.BorderLayout.CENTER). panelContenido. Además de los métodos de la clase java.  void setGlassPane(Component): permite asignar un panel de cristal a la ventana.  void setMenuBar(MenuBar): asigna a la ventana una barra de menú determinada representada por un objeto de la clase MenuBar. que va a ser el que contenga todos los componentes visibles del interfaz de usuario de la ventana. Ya hemos visto las posibles acciones. Este método permite utilizar nuestro propio panel de contenido. los diálogos. setTitle().

sino que se lanzaran de forma directa sobre la clase. Cuando la ventana se transforma en icono sus diálogos desaparecen de la pantalla. A continuación vamos a comentar las distintas características de la clase JOptionPane. Se puede especificar el mensaje. estos iconos son los de pregunta. Si lo que necesitamos es controlar el comportamiento del diálogo cuando se cierre o si el diálogo no debe ser modal entonces instanciaremos un objeto de la clase JOptionPane y lo añadiremos a un objeto de la clase JDialog. advertencia y error. especificar el título y texto del diálogo y los textos de los botones que aparecen. para crear un diálogo no modal se debe hacer uso de la clase JDialog que permitirá indicar si el diálogo que se crea va a ser modal o no. Como se puede observar son las mismas características que ofrecía la clase JFrame sobre la clase Frame del AWT. Los diálogos pueden ser modales. si la ventana se destruye también lo harán sus diálogos asociados. Veamos a continuación los principales métodos showXXXDialog() de la clase JOptionPane. JOptionPane ofrece soporte para mostrar diálogos estándar.Dialog. indicar los iconos. El aspecto de estos iconos variará según el Look & Feel (aspecto y comportamiento) que se aplique. Los diálogos que ofrece la clase JOptionPane son modales.awt. cuando se maximiza la ventana los diálogos vuelven a aparecer. cuando un diálogo modal se encuentra visible se bloquea la entrada del usuario en todas las demás ventanas del programa. ya que la clase JOptionPane es un contenedor que puede crear de forma automática una instancia de la clase JDialog y añadirse al panel de contenido de ese diálogo. Cuando se utiliza la clase JOptionPane en realidad también estamos haciendo uso de la clase JDialog de forma indirecta. Este conjunto de métodos son métodos estáticos y por lo tanto se lanzarán sobre una instancia concreta de la clase. En cuanto a los iconos que se muestran en el diálogo facilitado por JOptionPane. no utilizar ningún tipo de icono. Para mostrar diálogos modales sencillos se utilizará directamente uno de los métodos showXXXDialog() de la clase JOptionPane. puede ser una ventana. Object mensaje): el primer parámetro indica el componente padre del que depende.Todo diálogo es dependiente de una ventana determinada. o utilizar uno de los cuatro iconos estándar que ofrece la clase JOptionPane. un componente dentro de una ventana o nulo y el segundo el mensaje que se muestra. podemos utilizar iconos personalizados. el icono y el título que muestra el diálogo. que muestra un diálogo modal con un botón de aceptar. Este método se encuentra sobrecargado y ofrece tres versiones distintas:  void showMessageDialog(Component componentePadre. añade a la clase Dialog un panel raíz (root pane) y soporte para la operación por defecto de cierre. información. Mediante la clase JOptionPane podemos crear distintos tipos de diálogos. El primero de estos métodos es el método showMessageDialog(). La clase JDialog hereda de a clase AWT java. suele ser 160 .

En este otro caso indicamos un icono personalizado para que se muestre en el diálogo. 161 . JOptionPane."Esto es un mensaje". Otras variaciones sobre la sentencia anterior se muestran a continuación con sus correspondientes resultados. estas constantes son: PLAIN_MESSAGE (sin icono). "Título". int tipoMensaje): en este caso se especifica también el título."Esto es un mensaje". Icon icono): en esta última versión del método podemos indicar un icono personalizado para que se muestre en el diálogo. la instancia de la clase JFrame. WARNING_MESSAGE (icono de advertencia) y QUESTION_MESSAGE (icono de pregunta). JOptionPane. int tipoMensaje. En este caso se muestra el título y tipo de mensaje por defecto. Podemos añadir las distintas sentencias de creación de diálogos que vamos a ver ahora al ejemplo de la sección anterior en la que tratábamos la clase JFrame.INFORMATION_MESSAGE. Veamos algunos ejemplos con el método showMessageDialog(). Object mensaje. ImageIcon icono = new ImageIcon("icono. que será una cadena."Esto es un mensaje").showMessageDialog(ventana. String título. a nuestra clase Ventana de la sección anterior. INFORMATION_MESSAGE (icono de información). JOptionPane.una cadena de texto que podemos dividir en varias líneas utilizando el carácter de nueva línea (\n).showMessageDialog(ventana. ERROR_MESSAGE (icono de error). obtendremos el resultado que aparece en la Figura.icono).WARNING_MESSAGE).  void showMessageDialog(Component componentePadre. Object mensaje.  void showMessageDialog(Component componentePadre. String título. para ello se utilizan una serie de constantes definidas en la clase JOptionPane. Este último parámetro determinará el icono que se va a mostrar en el diálogo. llamada ventana va a ser el componente padre de los diálogos.gif").showMessageDialog(ventana."Título". y el tipo de mensaje a mostrar.JOptionPane. Si añadimos la línea que muestra el Código. JOptionPane.

no y cancelar. al igual que el anterior. Otro método de la clase JOptionPane que muestra un diálogo es el método showConfirmaDialog(). int int tipoOpción. Object mensaje. String título. String título."Esto es un mensaje". se encuentra sobrecargado y por lo tanto ofrece tres versiones distintas. String título. int int tipoOpción): en este caso podemos especificar el título del diálogo de confirmación y el tipo de opciones que se van a mostrar.JOptionPane. Object mensaje. int int tipoOpción. int tipoMensaje): en esta versión del método podemos indicar además el tipo de mensaje que se muestra en el diálogo. es decir. este entero va a recoger la selección que ha realizado el usuario. indicará el botón que ha sido pulsado. int tipoMensaje.  showConfirmDialog(Component componentePadre. para esto último utilizaremos las siguientes constantes ofrecidas por la clase JOptionPane: DEFAULT_OPTION. si pulsamos el botón etiquetado como OK. Object mensaje): este método int muestra un diálogo modal con los botones.showMessageDialog(ventana.  showConfirmDialog(Component componentePadre. el diálogo se cerrará. que pasamos a comentar a continuación. Icon icono): en esta última versión especificamos un icono personalizado que se va a mostrar en el diálogo de conformación correspondiente. El entero que devuelve este método se corresponde con uno de los valores de las siguientes constantes de la clase JOptionPane: 162 . YES_NO_OPTION. En este caso este método muestra un diálogo de confirmación. si.ERROR_MESSAGE). Object mensaje. que representan las opciones disponibles. y además con el título por defecto.  showConfirmDialog(Component componentePadre.  showConfirmDialog(Component componentePadre. YES_NO_CANCEL_OPTION y OK_CANCEL_OPTION. Como se puede comprobar en todos los ejemplos. Este método. de la misma forma que lo hacíamos en el método showMessageDialog(). para que el usuario seleccione entre los botones correspondientes. Como se puede observar en todas las versiones del método showConfirmDialog() se devuelve un entero (int)."Título". JOptionPane.

"Confirme operación".YES_OPTION.WARNING_MESSAGE). NO_OPTION."¿Desea formatear el disco?"). Este método es mucho más potente que los vistos anteriormente. Object mensaje. con este método podremos indicar los botones que queremos aparezcan en el diálogo.String título.int tipoMensaje.showConfirmDialog(ventana. int tipoOpción. JOptionPane. El método showOptionDialog() se diferencia del método showConfirmDialog() principalmente en que permite especificar las etiquetas de los botones que aparecen y además permite especificar la opción seleccionada por defecto.showConfirmDialog(ventana.JOptionPane. JOptionPane. Icon icono."¿Desea formatear el disco?". iconos. mensaje y títulos especificados para que el usuario seleccione entre las distintas opciones que se le ofrecen. En este caso se muestra el diálogo de confirmación por defecto. CANCEL_ OPTION.YES_NO_OPTION. Object valorInicial) Vamos a comentar los distintos parámetros de este nuevo método. ya que permite una mayor personalización del diálogo. Al igual que ocurría con el método anterior. El siguiente método que vamos a tratar de la clase JOptionPane va a ser el método showOptionDialog(). OK_OPTION y CLOSED_OPTION (el usuario cierra el diálogo sin pulsar ninguna de las opciones disponibles). 163 . La función de este método es la de mostrar un diálogo modal con los botones. Object[] opciones. Los tres primeros parámetros son los mismos que los vistos en el método showMessageDialog() y además tienen el mismo significado. vamos a ver ejemplos de utilización del método showConfirmDialog. La sintaxis de este método es la siguiente: int showOptionDialog(Component componentePadre. JOptionPane.

El diálogo que se muestra va a tener dos botones. es decir."Confirme operación". en nuestra ya conocida clase Ventana. Como se puede observar en la sintaxis del método showOptionDialog() se devuelve un entero (int). además es el segundo botón el que se encuentra seleccionado por defecto.showOptionDialog(ventana. opciones.YES_NO_OPTION. así como con un icono personalizado. Object[] opciones={"Vale". Ahora se va a mostrar ejemplos de uso del método showOptionDialog(). Object mensaje): muestra un diálogo con el mensaje correspondiente que requiere una entrada del usuario a través de una caja de texto. así por ejemplo un diálogo del tipo YES_NO_OPTION siempre devolverá los valores: YES_OPTION. opciones[1]). es decir. indicará el botón que ha sido pulsado.JOptionPane.En el tipo de opción se especifica el conjunto de opciones que se van a presentar al usuario. icono. 164 . Se debe indicar que aunque utilicemos etiquetas personalizadas para nuestros botones. va a recoger la selección que ha realizado el usuario. El siguiente parámetro es un array de objetos que se va a corresponder con un array de cadenas que se van a mostrar en cada uno de los botones del diálogo. y por lo tanto se corresponderán con las constantes vistas en el método showConfirmDialog(). Los dos siguientes parámetros. Estos ejemplos son únicamente unas cuentas sentencias que podemos incluir. como ocurría con los métodos anteriores. "Ni hablar"}. NO_OPTION o CLOSED_OPTION. uno de aceptar y otro de cancelar. Se muestra un diálogo con las opciones si/no pero con unas etiquetas de botones personalizadas. ImageIcon icono = new ImageIcon("icono. El último parámetro indica cual es la opción que se encuentra seleccionada por defecto. se siguen devolviendo los mismos valores de las constantes. si el usuario pulsa el botón de aceptar indicará que ha introducido una información que podemos recuperar. Este método se encuentra sobrecargado. tipo de mensaje y el icono personalizado."¿Desea formatear el disco?". JOptionPane. JOptionPane.gif"). este entero tiene la misma función que el que devolvía el método showConfirDialog(). es decir. ya sea a través de una caja de texto o a través de un una lista de opciones.WARNING_MESSAGE. tiene el mismo cometido que el método showMessageDialog(). y ofrece las siguientes versiones:  Object showInputDialog(Component componentePadre. este método va a permitir obtener información de entrada del usuario a través del diálogo. El último método que vamos a ver de la clase JOptionPane es el método showInputDialog(). podemos utilizar nuestras propias etiquetas pera mostrar en los botones.

out. int tipoMensaje): en esta caso nos permite especificar un título y un tipo de mensaje (ya conocemos las constantes correspondientes). ImageIcon icono = new ImageIcon("icono. System. int tipoMensaje.valores[2]). Object opciónSeleccionada): en este método se permite indicar un icono personalizado y un conjunto de opciones en forma de lista desplegable para que el usuario seleccione una de ellas además se permite seleccionar una opción por defecto. También se ha utilizado un icono personalizado. Object mensaje. En este caso se muestra una lista con las opciones disponibles. En este caso se va a recoger el dato facilitado por el usuario y mostrarlo en la salida estándar de la aplicación."Verde". sin utilizar ningún componente padre. Object respuesta=JOptionPane. 165 . Object showInputDialog(Component componentePadre. Object mensaje.valores. aunque de todas forma sigue bloqueando a la ventana que lo ha generado. System. por lo que el diálogo se situará en el centro de la pantalla.println("El nombre del usuario es: "+respuesta). String respuesta=JOptionPane. Object opciones.showInputDialog(ventana."Negro"."Selección de color".JOptionPane."¿Cuál es tu nombre?"). En los siguientes ejemplos se muestra la utilización del método showInputDialog()."¿Cuál es tu color favorito?". String título.showInputDialog(ventana.  String showInputDialog(Object mensaje): en este caso no se indica nada más que el mensaje que se va a mostrar al usuario. Object[] valores={"Rojo". icono.gif"). que se va a corresponder con una cadena que va a representar la información indicada por el usuario. para que el usuario seleccione la que desee."Azul". ya que en los otros casos se centra siempre con respecto al componente padre.out. Icon icono. String título. ya sea a través de una caja de texto una de una lista de opciones disponibles.  Object showInputDialog(Component componentePadre.println("El color favorito del usuario es el: "+respuesta). Como se puede comprobar siempre se devuelve un objeto de la clase String."Amarillo"}.QUESTION_MESSAGE.

a todos los contenedores de alto nivel. el icono personalizado.*. o también nos puede interesar utilizar un diálogo que no sea modal.*. como ya hemos comentado.Hasta ahora hemos visto los métodos que nos ofrece la clase JOptionPane para mostrar distintos tipos de diálogo. ventana.awt. dialogo. import java. String título): se especifica además el título que va a tener el diálogo.INFORMATION_MESSAGE. En algunos casos nos puede interesar validar la información ofrecida por el usuario en un diálogo. JOptionPane contenido=new JOptionPane("Esto es un mensaje". algunos de los constructores ofrecidos por la clase JDialog son:  JDialog(): crea un diálogo no modal.100). y que es común. las opciones disponibles y la opción seleccionada por defecto. deberemos crear el objeto JDialog que lo va a contener.swing. únicamente nos queda asignar al diálogo (JDialog) su contenido (JOptionPane). import javax. } } 166 . public class Dialogo{ public static void main(String s[]) { JFrame ventana = new JFrame("Ventana Sencilla"). En algunos casos estos diálogos nos servirán.  JDialog(Frame ventanaPropietaria.  JDialog(Frame ventanaPropietaria): se indica la ventana a la que se encuentra asociado el diálogo. Para ello necesitamos crear una instancia de la clase JOptionPane para añadirla al objeto JDialog correspondiente.  JDialog(Frame ventanaPropietaria. La clase JOptionPane presenta múltiples constructores que permiten especificar el mensaje que se va a mostrar. pero en otros casos esto puede no ser así. para ello utilizamos el método setContentPane() de la clase JDialog.pack().setLocationRelativeTo(ventana). import java."Esto es un diálogo". el tipo de opciones. JDialog dialogo=new JDialog(ventana.*. JOptionPane.setVisible(true). A continuación se muestra este proceso con un ejemplo que consiste en una sencilla aplicación Java que muestra una ventana y un diálogo asociada a la misma. el tipo de mensaje.true). boolean modal.setContentPane(contenido).setVisible(true). En estos casos en los que deseamos personalizar al máximo los diálogos utilizaremos la clase JDialog conjuntamente con la clase JOptionPane. Si ya tenemos instanciados el objeto JOptionPane y el objeto JDialog. ya que su comportamiento se puede adecuar a nuestras necesidades.YES_NO_CANCEL_OPTION). sin título definido y sin ninguna ventana propietaria. boolean modal): se indica si el diálogo va a ser modal o no.awt. dialogo. Estos diálogos tienen en común una serie de características: al pulsar alguno de los botones que contienen se cierran. dialogo. dialogo. ventana.event.JOptionPane.setSize(175. también se cierran cuando el usuario pulsa el cierre del diálogo y por último son todos modales. Una vez creado el objeto JOptionPane.

su labor principal es la de contener otros componentes. Se utilizan debido a las limitaciones del tamaño de la pantalla. La clase JApplet aporta dos características esenciales a los applets.  void setDefaultCloseOperation(int operacion): asigna una operación de cierre por defecto al diálogo. En el código se puede observar que se utiliza el método setLocationRealtiveTo(). suele contener componentes grandes o que pueden crecer. con todo lo que ello supone. Contenedores intermedios Los contenedores intermedios son contenedores Swing.  JScrollPane: ofrece una vista de scroll de un componente. si queremos que realicen alguna operación cuando se pulsen. se le puede asignar gestores de diseño y bordes. ya que la operación tiene asignada por defecto para el cierre es HIDE_ON_CLOSE. ofrece soporte para tecnologías de rehabilitación y ofrece un panel raíz. añadir componentes al panel de contenido. posibilidad de tener una barra de menú. ocultarse en el cierre.El resultado es : Como se puede comprobar la pulsación de los botones del diálogo no tiene el efecto que tenían anteriormente. que aunque no son contenedores de alto nivel.Applet. es por lo tanto la versión Swing de la clase Applet. 167 . Se utiliza normalmente para agrupar componentes. Aunque si pulsamos el cierre del diálogo éste se sigue cerrando. etc. Otros métodos de la clase JDialog son los siguientes:  Container getContentPane(): devuelve el panel de contenido del diálogo. es decir.  getDefaultCloseOperation(): devuelve la operación de cierre por defecto que tiene int asignada el diálogo. este método centra el diálogo de forma relativa al componente que le pasamos por parámetro. Esta clase hereda de la clase java. deberemos hacerlo a través de una gestión de eventos a través del código de nuestra aplicación. como ocurría con la clase JFrame. es decir.applet. Estos contenedores se siguen basando en la jerarquía de contenedores de Swing que ya hemos visto anteriormente. Los paneles de contenido de los contenedores de alto nivel suelen ser de la clase JPanel. Swing ofrece una serie de contenedores de propósito general:  JPanel: es le más flexible y utilizado de todos ellos. JApplet Este es el tercero de los contenedores de alto nivel.

de hecho se debe importar el paquete JAVA. la profundidad. como ya vimos en el apartado anterior el panel raíz esta formado por las siguientes partes: panel de capas. Además también existen los siguientes contenedores intermedios que se encuentran más especializados:  JInternalFrame: permite mostrar una ventana dentro de otra. JSplitPane: este panel agrupa dos componentes. Un ejemplo pueden ser las barras de herramientas de un procesador de textos como MS Word. Al añadir un componente a un panel de este tipo se especifica su profundidad mediante un entero. no vamos a tratar todos ya nos excederíamos en la extensión del presente curso.  JToolBar: grupa una serie de componentes (normalmente botones) en una fila o en una columna. panel de contenido. Para añadir componentes lo haremos de la misma forma que veíamos en los paneles AWT. Esta tercera dimensión se denomina también Zorder.  JRootPane: esta clase representa el panel raíz de un contenedor de alto nivel. El usuario puede ajustar la línea divisora que separa ambos componentes arrastrándola. no se debe olvidar que Swing tienen un gran número de componentes. para poder posicionar componentes de esta forma. el usuario puede ir cambiando entre los distintos conjuntos de manera sencilla. 168 . Parece una ventana y ofrece toda su funcionalidad pero debe parecer siempre dentro de otra ventana (contenedor de alto nivel) que la contiene. import java. JPanel Esta clase permite construir paneles de propósito general para contener componentes Swing. por defecto el gestor de diseño de un objeto JPanel es un FlowLayout.*.AWT para poder utilizarlos. cuanto mayor sea el entero especificado mayor será la profundidad en la que se sitúa el componente.awt. En el Código siguiente se muestra la forma de utilizar esta clase. Swing utiliza los mismos gestores de diseño que vimos para los componentes AWT. el explorador de Windows.  JLayeredPane: este panel ofrece una tercera dimensión. aunque se pueden hacer transparentes mediante el método setOpaque() pasándole el valor false por parámetro. la vista del árbol de directorios se encuentra separada de la vista de contenidos de un directorio. El aspecto es similar al que ofrece. Un ejemplo podrían ser las distintas pestañas de una hoja de propiedades. que veremos en el apartado correspondiente. por ejemplo. La clase JPanel permite asignar un gestor de diseño al panel para indicar la forma en la que se van añadiendo los distintos componentes al mismo. A continuación vamos a comentar algunos de estos paneles intermedios. La clase JPanel es la versión Swing de la clase Panel de AWT.  JTabbedPane: contiene muchos componentes pero sólo puede mostrar un conjunto de ellos a la vez. pueden permitir al usuario arrastrar la barra a distintos lugares. panel de cristal y barra de menú. también por defecto los paneles son opacos. con las distintas versiones de los métodos add(). pero se añade un nuevo gestor mediante la clase BoxLayout. uno al lado del otro. es decir. Por defecto un panel no muestra nada en pantalla a excepción de su fondo.

Para crear los distintos bordes que ofrece Swing se suele utilizar la clase BorderFactory.awt. . java.setLayout(new BorderLayout()). JLabel etiqueta1 = new JLabel("Soy una etiqueta". JPanel panel=new JPanel(). panel.*. JLabel etiqueta2 = new JLabel("Soy otra etiqueta".awt.setPreferredSize(new Dimension(175. una combinación de dos bordes. panel.CENTER). BorderLayout. ventana. elevados.add(etiqueta2.CENTER).*. Veamos un ejemplo que asigna distintos bordes a varios paneles dentro de una ventana.swing. el resultado se puede apreciar en la Figura. panel. etiqueta2.pack(). BorderLayout. con títulos. javax. ventana. etc. BorderLayout.add(panel. Esta clase ofrece un gran número de métodos que permiten crear distintos tipos de bordes: de líneas. class Panel{ static void main(String args[]) { 169 . marcados.*.event. public class Panel{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana Sencilla").SOUTH).add(etiqueta1. Los bordes no son realmente componentes.import java.NORTH). en este caso un objeto de la clase JPanel.setVisible(true).JLabel. import javax. ventana.JLabel.event. 100)).*. } } Se trata simplemente de añadir dos etiquetas a un panel (JPanel) y añadir este panel al panel de contenido de una ventana (JFrame). 100)). La clase JPanel hereda de la clase JComponent. los bordes. sino que se utilizan para delimitar visualmente una serie de componentes de otros.awt.CENTER). Cada objeto de la clase JComponent puede tener uno o más bordes.swing. Para asignar un borde a un componente.*. etiqueta1. se utiliza el método setBorder(). import import import public public java. hundidos.setPreferredSize(new Dimension(175.getContentPane(). y debido a ello permite utilizar una nueva funcionalidad ofrecida por Swing.

CENTER).getContentPane().5.JLabel.createMatteBorder(5. ventana.JLabel. JLabel etiqueta5 = new JLabel("Borde con título".5. ventana.setVisible(true). ventana.setBorder( BorderFactory.add(panel4). JPanel panel3=new JPanel(). JLabel etiqueta6 = new JLabel("Borde grabado". JLabel etiqueta7 = new JLabel("Borde compuesto".setBorder(BorderFactory.JLabel.createLineBorder(Color.getContentPane().yellow). panel6. panel2. JPanel panel6=new JPanel().CENTER). panel1.add(etiqueta2).createEtchedBorder()). panel7.createLineBorder(Color. ventana.setBorder(BorderFactory. JPanel panel7=new JPanel(). JLabel etiqueta4 = new JLabel("Borde decorado". ventana.CENTER).JLabel.setBorder(BorderFactory.CENTER).add(etiqueta4).getContentPane()).getContentPane(). ventana.1)). JPanel panel4=new JPanel(). ventana.add(etiqueta3).add(etiqueta6). } } 170 .getContentPane(). panel3. panel7. panel4. JLabel etiqueta3 = new JLabel("Borde hundido".5.setBorder(BorderFactory.CENTER). ((JPanel)ventana.black)).CENTER).pack().getContentPane().JLabel.createRaisedBevelBorder())).add(panel1).add(etiqueta5).10)).add(etiqueta1).setLayout(new GridLayout(7. panel7.getContentPane().add(panel5). panel2. JLabel etiqueta1 = new JLabel("Borde tipo línea".JLabel.red)). JPanel panel2=new JPanel().CENTER).50)). panel4.createLoweredBevelBorder()).getContentPane().add(panel2).add(etiqueta7).createRaisedBevelBorder()).createEmptyBorder(10.10.Color. ventana.JLabel. ventana. panel6.blue). panel5. JPanel panel1=new JPanel().add(panel7).createTitledBorder( BorderFactory.getContentPane().setBorder(BorderFactory.createLineBorder(Color."Título")). JLabel etiqueta2 = new JLabel("Borde elevado".createCompoundBorder( BorderFactory.setBorder(BorderFactory.add(panel3).add(panel6).setPreferredSize(new Dimension(175. panel1. BorderFactory. panel3. JPanel panel5=new JPanel().setBorder(BorderFactory. ventana.10. panel5.JFrame ventana = new JFrame("Ventana Sencilla").

Para crear un contenedor de este tipo primero debemos instanciar el objeto correspondiente de la clase JTabbedPane. luego se van creando los distintos componentes y se van añadiendo al contenedor mediante el método addTab(). este borde vacío se ha utilizado para crear un margen entre el panel de contenido y el contenedor. como se puede observar al recuperar el panel de contenido para asignarle un borde vacío se ha tenido que hacer un "cast" con la clase JPanel. El usuario puede visualizar los componentes que desea ver seleccionando la pestaña correspondiente.Comentarios del código: El primero de ellos es referente al tipo de borde utilizado en el panel de contenido. Algunos de los métodos de la clase BorderFactory se encuentran sobrecargados. para permitir una mayor personalización de los distintos tipos de bordes que queremos asignar. en este caso una instancia de la clase JFrame. compartiendo un mismo espacio. normalmente otros paneles. A cada panel se le ha asignado un borde distinto y se le ha añadido una etiqueta (JLabel) con la descripción del tipo de borde correspondiente. JTabbedPane Gracias a este contenedor intermedio podemos tener distintos componentes. Al panel de contenido de la ventana se le ha asignado un gestor de diseño GridLayout con siete filas y una única columna. 171 .

panel3. } }). panel3.*. //tratamiento de eventos para el cierre de la ventana ventana.icono. panel1.panel4. } } 172 .setBorder(BorderFactory.createLineBorder(Color.icono. ventana.pack().icono. panelTab."Soy la tercera pestaña").JLabel. JPanel panel2=new JPanel().*. import javax.200)).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.icono.exit(0). panelTab. El ejemplo consiste simplemente en un objeto JTabbedPane al que se le van añadiendo distintos paneles. panel4. JPanel panel5=new JPanel().getContentPane().add(new JButton("Botón".red)). cada uno con sus componentes.addTab("Tres".setVisible(true).HORIZONTAL. ventana. panelTab. //se le da un tamaño al contenedor de pestañas panelTab. JPanel panel4=new JPanel().CENTER)). panel2.add(new JLabel("Soy una etiqueta". JPanel panel3=new JPanel().10)).panel1.30.add(new JSlider(JSlider. //se van creando paneles con componentes y se añaden al objeto JTabbedPane JPanel panel1=new JPanel().setPreferredSize(new Dimension(400."Soy la cuarta pestaña"). //se crea una nueva pestaña con el nuevo componente panelTab.gif"). panel5.panel2.Antes de seguir con esta nueva clase vamos a verla en acción mediante un sencillo ejemplo.awt. JTabbedPane panelTab = new JTabbedPane().add(panelTab). public class PanelTab{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana Sencilla")."Soy la primera pestaña"). import java.0."Soy la segunda pestaña").add(new JLabel("Soy otra etiqueta"."Soy la última pestaña").addTab("Cuatro". import java.icono.event. panelTab. panel3.icono)). //se añade a la ventana ventana.awt.addTab("Cinco". panelTab.*.JLabel.add(new JToggleButton("Otro botón". ImageIcon icono = new ImageIcon("icono.panel5.addTab("Dos".addTab("Uno".icono)).setSelectedIndex(0).swing.CENTER)).

173 . Icon icono. mediante una constante que recibe como parámetro. Component componente): en este caso además se indica el icono que se va a mostrar en la pestaña. pero existe otro constructor que permite. Component componente. Obtenemos el resultado siguiente: Para añadir una nueva pestaña ya sabemos que debemos utilizar el método addTab(). Icon icono. este método presenta las siguientes versiones:  addTab(String texto.  addTab(String texto. Component componente): el primer argumento indica el texto que va a parecer en la pestaña y el componente que va a contener. Estas constantes se encuentran definidas en la clase JTabbedPane y son las siguientes TOP. especificar la localización de las pestañas. BOTTOM.BOTTOM).Si se prueba el ejemplo anterior se puede comprobar que no se ha escrito ningún código para realizar el tratamiento de eventos. String ayuda): en la última versión del método addTab() se permite especificar el texto que aparecerá a modo de ayuda (tooltip) cuando situemos el puntero del ratón sobre la pestaña.  addTab(String texto. En el ejemplo se ha utilizado un constructor de la clase JTabbedPane que no utiliza ningún parámetro. Así si modificamos el ejemplo anterior cambiando el constructor utilizado para el panel JTabbedPane mediante la siguiente línea de código:e JTabbedPane panelTab = new JTabbedPane(JTabbedPane. LEFT y RIGHT. la clase JTabbedPane realiza este tratamiento (mostrar los componentes de la pestaña seleccionada) de forma automática.

y la pestaña no existe se producirá una excepción.green).  removeAll(): elimina todas las pestañas."Otro texto"). Así si una vez creado el panel de nuestro ejemplo añadimos las líneas de código que se muestran en el Código fuente siguientey obtenemos el resultado que aparece en la Figura.red). Icon icono. int índice): inserta una nueva pestaña en la posición indicada por el parámetro índice.  remove(Component componente): elimina la pestaña que contenga el componente especificado como argumento. //se cambia el componente que posee la pestaña panelTab.add(new JTextArea(5.otroIcono). String ayuda.  getSelectedIndex(): devuelve el índice de la pestaña seleccionada actualmente.En el ejemplo se ha utilizado el método setSelectedIndex() para indicar la pestaña que por defecto se encuentra seleccionada. 174 .setDisabledIconAt(0.setForegroundAt(0.  removeTabAt(int índice): elimina la pestaña cuya posición coincida con la indicada. Para manipular las pestañas la clase JTabbedPane ofrece los siguientes métodos:  insertTab(String texto. también el color de fondo y el del texto de la pestaña.gif"). panelNuevo.30)).Color.setBackgroundAt(0. Curioso resultado ya que no se muestra el icono que se utiliza para indicar que la pestaña está deshabilitada. Component componente. JPanel panelNuevo=new JPanel().Color.setTitleAt(2. que será la que mostrará sus componentes. Las pestañas comienzan a numerarse en cero. //se modifica el título panelTab. ImageIcon otroIcono = new ImageIcon("icono2. int También es posible modificar la apariencia de las pestañas del panel JTabbedPane. //color del texto panelTab.que tiene como parámetro el índice de la pestaña.  indexOfTab(String texto): devuelve el índice de la pestaña que posea el texto indicado int por parámetro.setComponentAt(3. Podemos indicar el icono que va a mostrar la pestaña según se encuentre habilitada o deshabilitada. //icono que se muestra cuando la pestaña está desactivada panelTab. //color de fondo cuando no está seleccionada la pestaña panelTab. Si utilizamos cualquiera de los métodos anteriores .panelNuevo).

//se añade el separador a la barra de herramientas barra. combo.JToolBar Esta clase representa una barra de herramientas.add(boton3). //tratamiento de eventos para el cierre de la ventana ventana.gif").awt. En el Código siguiente se puede observar como se utiliza un objeto de la clase JToolBar. import javax. ImageIcon icono2=new ImageIcon("icono2. //caja de texto JTextField caja=new JTextField("caja de texto").exit(0).*.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. En nuestro caso vamos a tener una ventana (JFrame) que va a tener un panel de contenido al que se va a añadir la barra de herramientas (JToolBar) y un área de texto (JTextArea). //iconos ImageIcon icono1=new ImageIcon("icono1. no debe existir ningún componente más en el centro del contenedor.addItem("dos").addSeparator().gif"). //lista con elementos JComboBox combo=new JComboBox(). barra.swing. } }). normalmente este tipo de contenedor va a contener botones con iconos dentro de una fila o columna.*. ImageIcon icono3=new ImageIcon("icono3. //barra de herramientas JToolBar barra=new JToolBar(). combo. //botones JButton boton1=new JButton(icono1). JButton boton2=new JButton(icono2). barra.add(combo). Normalmente la barra de herramientas se añade en el norte del gestor de diseño y el componente al que afecta en el centro.event.gif").addItem("uno").add(boton1). no sólo botones.*. barra.addItem("tres"). import java. combo. public class BarraHerramientas{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con barra de herramientas"). el contenedor en el que se sitúa la barra de herramientas debe tener un gestor de diseño BorderLayout. JButton boton3=new JButton(icono3). //se añaden los botones barra. Para que este funcionamiento de arrastre de la barra sea correcto. import java. Como se puede ver la barra de herramientas puede contener otros tipos de componentes.add(boton2). Por defecto el usuario puede arrastrar la barra de herramientas y situarla en los diferentes bordes del contenedor o bien como una ventana independiente. Estos botones cumplen las mismas funciones que las opciones de menú. barra.add(caja). //se añade la barra al panel de contenido 175 .awt.

Esto mismo ocurre en nuestro ejemplo.add(scrollPane. import import import public java. } } Como se puede comprobar en el código anterior.swing. ventana.setVisible(true). La profundidad de un determinado componente se especifica mediante un entero. para añadir un separador a la barra de herramientas se utiliza el método addSeparator().*. JLayeredPane Este contenedor ofrece una tercera dimensión que permite posicionar los componentes que contiene especificando una profundidad. que veremos más adelante en el apartado dedicado al mismo. Para añadir un componente a un JLayeredPane se utiliza el método add(). la clase JToolBar utiliza el gestor de diseño BoxLayout. Vimos que los contenedores de alto nivel de Swing contienen un panel de raíz que a su vez contiene un panel de capas (layered pane).add(barra. cuanto mayor sea este entero mayor será la profundidad del componente correspondiente. Si queremos que la barra de herramientas permanezca fija se puede lanzar sobre el objeto de la clase JToolBar el método setFloatable() pasando como argumento el valor false. javax. 100)). en este método se debe indicar la profundidad del componente.CENTER).BorderLayout. //se añade a un panel de scroll JScrollPane scrollPane = new JScrollPane(areaTexto). que se sitúa un objeto de la clase JLayeredPane dentro del panel de contenido de una ventana (JFrame).getContentPane().awt. Para posicionar los distintos elementos que contiene.NORTH). class PanelCapas{ 176 .30). la capa en la que se encuentra. En el siguiente ejemplo se van añadiendo a una instancia de la clase JLayeredPane etiquetas con color de fondo a distintas profundidades. //se añade el panel de scroll al panel de contenido ventana.pack(). //se asigna un tamaño preferido a la ventana ((JPanel)ventana. //se crea un área de texto JTextArea areaTexto = new JTextArea(5. sino que se crea un objeto JLayeredPane distinto para utilizarlo dentro de otro panel. ventana.getContentPane().awt.*.ventana.setPreferredSize(new Dimension(400.getContentPane()).BorderLayout.event.*. Si los componentes que contiene el panel de capas se superponen los componentes que se encuentran a una mayor profundidad se muestran encima de los de una menor profundidad. normalmente no se suele utilizar el JLayeredPane del JRootPane. java. Veamos el Código:. es decir.

y.setOpaque(true).Point origen) { JLabel etiqueta = new JLabel(texto). Color.add(etiqueta. origen.createLineBorder(Color. //punto de origen Point origen = new Point(10.black)). origen.blue. etiqueta. i++) { JLabel etiqueta = creaEtiqueta(textosCapa[i]. 310)).magenta.x.origen). Color. //se van creando las etiquetas de color a distinta profundidad for (int i = 0. Color.y += separacion. Color. 20). public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con panel de capas"). return etiqueta. //se añade el panel creado al panel de contenido de la ventana ventana.red. i < textosCapa.TOP). etiqueta.yellow. } } 177 .setHorizontalAlignment(JLabel. "Rojo (3)". "Verde (4)" }.green }. JLayeredPane panelCapas=new JLayeredPane(). //tratamiento de eventos para el cierre de la ventana ventana. "Magenta (1)". static private Color[] coloresCapa = { Color.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. 140. 140).length.CENTER).new Integer(i)).setBorder(BorderFactory.Color color. origen.setVerticalAlignment(JLabel.setBackground(color). etiqueta. "Azul (2)". etiqueta. //se añade la etiqueta al panel de capas panelCapas. ventana.getContentPane().setBounds(origen. //separación entre etiquetas int separacion = 35. ventana.pack().exit(0).coloresCapa[i]. //se asigna un borde a la etiqueta etiqueta. //se alinea el texto en la etiqueta etiqueta. } }). } //se indica un tamaño para le panel panelCapas. private static JLabel creaEtiqueta(String texto. } //método para la creación de etiquetas con un texto y un color en un punto //de origen.setVisible(true).setPreferredSize(new Dimension(300.add(panelCapas).static private String[] textosCapa = { "Amarillo(0)".x += separacion.

se puede especificar la posición de un componente.icono. panelCapas. Si utilizamos 0 el componente se encontrará por encima del resto. una vez creadas las etiquetas en las distintas capas. a una profundidad determinada. cuanto menor es el número mayor es la profundidad del componente dentro de la capa.0).Como se puede comprobar a la vista del código se han creado dos arrays que contienen por un lado los textos de las etiquetas y por otro los colores de las etiquetas. dónde n es el número de componentes dentro de la capa. JLabel nuevaEtiqueta=new JLabel(icono). Se ha utilizado un bucle for para ir recorriendo estos arrays y crear las etiquetas mediante el método crearEtiqueta().icono. ya que los utilizamos directamente en el método main() si lanzarlos sobre una instancia de una clase.new Integer(2). El valor de esta posición va desde -1 hasta n-1.getIconHeight()).setBounds(180. para ello existe una versión del método add() que posee un tercer parámetro para indicar esta posición dentro de la capa.gif"). 178 . Si al ejemplo anterior le añadimos las líneas que muestra el Código siguiente. Utilizar -1 es equivalente a utilizar n-1.75. indica la posición más en el fondo.add(nuevaEtiqueta. Lo que se hace es añadir una nueva etiqueta con un icono en la capa 2 de modo que quede por encima de la etiqueta de color que ya existía en esa misma capa. Es posible por lo tanto definir la posición de un componente respecto al resto de componentes dentro de la misma capa. ImageIcon icono = new ImageIcon("imagen. Como se puede ver el método y los atributos utilizado son estáticos. Al contrario que las capas. nuevaEtiqueta. Dentro de una capa. es decir.getIconWidth(). El nuevo aspecto del panel de capas es el que aparece en la Figura.

y para enviarlo al fondo el método moveToBack().setLayer(nuevaEtiqueta. para ello se utiliza el método setLayer(). Así si queremos mover la etiqueta con el icono a la capa 4 escribiremos lo que indica la línea de codigo siguiente: panelCapas. ambos métodos tiene como parámetro el componente al que se quiere cambiar de posición dentro de una capa. Si utilizamos el método moveToBack() en nuestro código tendrá un nuevo aspecto del ejemplo :.moveToBack(nuevaEtiqueta).0). panelCapas. Para mover un componente dentro de una capa a la primera posición se utiliza el método moveToFront().4. El último argumento del método setLayer() es la posición del componente dentro de la nueva capa. 179 .También es posible mover un componente de una capa a otra.

 JTextField: una caja de texto en la que el usuario puede escribir. aunque es posible encontrar componentes atómicos que son la combinación de distintos componentes.  JComboBox: una lista desplegable. 180 .  JMenuBar: una barra de menú.  JCheckBoxMenuItem: un elemento de menú que contiene una casilla de verificación. una casilla de verificación.Interfaces de usuario en Java: componentes atómicos de Swing Componentes atómicos Este grupo de componentes se corresponde con aquellos componentes cuya función es presentar o recibir información.  JRadioButtonMenuItem: un elemento de menú que contiene un botón de opción. en lugar de contener otros componentes. un icono o ambos. Todos los componentes atómicos heredan de la clase JComponent. debido a esto todos ellos soportan características estándar de los componentes Swing. A lo largo de los siguientes apartados se van a mostrar algunos de estos componentes con sus respectivos ejemplos.  JSlider: permite seleccionar al usuario un valor dentro de un rango determinado.  JToggleButton: representa un botón con dos estados (pulsado/no pulsado).  JFileChooser: permite seleccionar ficheros y directorios. una caja de texto. Componentes que muestran una información estructurada o que permiten editarla:  JColorChooser: permite realizar la selección de un color determinado.  JButton: un botón común.  JTextComponent: de esta clase heredan distintas clases especializadas en el tratamiento de textos.  JMenu: una opción de menú.  JList: una lista con elementos.  JProgressBar: barra que muestra el progreso de un proceso. aunque veremos en los distintos ejemplos que nunca vamos a utilizar directamente esta clase. Componentes que existen únicamente para mostrar información:  JLabel: etiqueta que puede mostrar texto.  JTable: muestra la información en formato de tabla.  JMenuItem: un elemento de un menú.  JTree: muestra datos organizados de forma jerárquica. como pueden ser bordes y tooltips. Los componentes atómicos se subclasifican atendiendo a la labor que realizan. etc.  JRadioButton: un botón de opción que suelen utilizarse en grupos.  JToolTip: muestra una breve descripción de un componente. Un ejemplo de componente atómico podría ser un botón.  JCheckBox: una casilla de verificación. Componentes que cuya misión principal es la de obtener información relativa a la entrada del usuario.

setHorizontalTextPosition(AbstractButton.setActionCommand("desactiva").VK_D). //se da formato al texto botonIzq. private JButton botonDer.CENTER). 181 .awt.gif"). se puede indicar una imagen para que se muestre cuando el botón se encuentre deshabilitado. Por lo tanto la clase JButton posee una serie de funcionalidades que son comunes a todas las clases que heredan de la clase AbstractButton. } }). también se pueden especificar teclas de teclado alternativas.awt. botonDer. //se asigna un tooltip botonIzq.*.iconoDer). import java.setVerticalTextPosition(AbstractButton.*. Para ver la clase JButton en acción vamos a utilizar un ejemplo muy sencillo que consiste en mostrar tres botones con imágenes y ayudas (tooltips).setVerticalTextPosition(AbstractButton.gif"). //se indica el comando de acción que se utiliza cuando se pulsa el botón botonIzq. private JButton botonCentro.LEFT). public Botones (){ super("Ventana con botones").exit(0). JMenuItem o JToggleButton. private ImageIcon iconoIzq=new ImageIcon("icono3. El texto que contiene un botón se puede alinear con respecto a la imagen. private ImageIcon iconoCentro=new ImageIcon("icono2. Un botón puede contener texto o imágenes o ambos elementos. public class Botones extends JFrame implements ActionListener{ private JButton botonIzq. import java. que se indicarán mediante el subrayado de la letra del texto correspondiente. botonIzq. //se indica la tecla asociada al botón botonIzq.event. Cuando un botón se encuentra deshabilitado el Look and Feel correspondiente genera de forma automática el aspecto del botón.setMnemonic(KeyEvent. JButton Esta clase hereda de la clase AbstractButton.Componentes para obtener información Vamos a comenzar con algunos de los componentes atómicos de Swing cuya misión es la de obtener información a través de la entrada del usuario. al igual que lo hacen otras clases como pueden ser JCheckbox.swing.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.iconoIzq). botonDer=new JButton("Activa botón central".setToolTipText("Desactivo el botón central").*. private ImageIcon iconoDer=new ImageIcon("icono1. botonIzq. import javax.setEnabled(false). this. Sin embargo. la pulsación de dos de los tres botones activará o desactivará el botón central. } public void creaBotones(){ //se instancia el botón indicando la imagen botonIzq=new JButton("Desactiva botón central".CENTER).gif").

setEnabled(true). Podemos modificar el ejemplo anterior para que el botón activo por defecto sea el botón de la derecha. }else{ //se activa el botón central botonCentro. botonCentro=new JButton("Botón central". botonDer.VK_A).add(botonDer). //se registran los oyentes. ventana. } public void añadeBotones(){ //creamos un panel para añadir los botones JPanel panelContenido=new JPanel().setEnabled(true).addActionListener(this). getRootPane(). ventana.equals("desactiva")){ //se desactiva el botón central y se actualiza //el estado de los otros botones botonCentro.setEnabled(false). botonIzq. que son la misma clase. 182 . ventana.setToolTipText("No hago nada"). botonDer. botonIzq.RIGHT). además esta combinación de teclas aparece descrita en el tooltip.setEnabled(true).setVisible(true). } public void actionPerformed(ActionEvent evento){ if (evento. //establecemos este panel como panel de contenido de la ventana setContentPane(panelContenido).pack(). } } Se puede comprobar si pulsamos las teclas Alt+D o Alt+A tienen el mismo efecto que pulsar el botón correspondiente. } } public static void main(String args[]) { Botones ventana = new Botones(). panelContenido. botonDer. botonDer.iconoCentro). panelContenido.creaBotones(). Podemos indicar el botón activo por defecto de un contenedor de alto nivel mediante el método setDefaultButton() de la clase JRootPane. El botón activo por defecto aparece destacado del resto y si el usuario pulsa la tecla Enter es equivalente a pulsar este botón. botonCentro.añadeBotones(). botonDer.setEnabled(false).add(botonIzq).add(botonCentro). panelContenido. botonIzq.botonDer.setDefaultButton(botonDer).setHorizontalTextPosition(AbstractButton. botonDer.setMnemonic(KeyEvent.setEnabled(false). ventana.setActionCommand("activa"). botonCentro.getActionCommand().setToolTipText("Activo el botón central").setEnabled(false).addActionListener(this).

//el botón del que indicamos el aspecto private JButton boton.swing... Además hemos tenido que utilizar la etiqueta de subrayado de HTML (<u></u>) para indicar la tecla que se corresponde con cada botón..*. que ya hemos visto en la sección anterior con la clase JButton.. presenta una serie de características comunes a todos los tipos de botones. algunas o ninguna de ellas.. private JCheckBox chkToolTip. Así por ejemplo. una para indicar que el botón va a tener un icono. //panel del botón private JPanel panelBoton.. otra para indicar que tiene un tooltip y otra para indicar que tiene texto. si retomamos nuestro código anterior y modificamos las líneas en las que se crean los botones..event. Debido a que la clase JCheckBox hereda de la clase AbstractButton. ...*. mediante la clase JCheckBoxMenuItem. Se dispone de tres casillas de verificación. ahora el texto no aparece en color gris atenuado. tooltips..Otra característica que nos ofrece la clase JButton es la posibilidad de utilizar etiquetas HTML dentro del texto del botón. //panel de las casillas private JPanel panelCasillas. Estas características son la posibilidad de utilizar imágenes. una. botonCentro=new JButton("<html><small><i>Botón central</i></small>". 183 . etc. botonDer=new JButton("<html><font color='red' size='4'>"+ "<u>A</u>ctiva botón central</font>". Las casillas de verificación se suelen agrupar y es posible seleccionar. .gif").awt. private JCheckBox chkTexto. import javax.iconoCentro)...iconoDer)..*. teclas alternativas. private ImageIcon icono=new ImageIcon("icono2.. En el siguiente ejemplo se muestra la utilización de la clase JCheckBox para configurar el aspecto de un botón...awt. escribiendo: botonIzq=new JButton("<html><b><i><u>D</u>esactiva botón central</i><b>". JCheckbox Esta clase representa a las casillas de verificación... para ello se debe poner la etiqueta <html> al inicio del texto. y a continuación se pueden utilizar las etiquetas HTML que se consideren necesarias para dar el formato conveniente al texto. public class Casillas extends JFrame implements ItemListener{ //cada una de las casillas private JCheckBox chkIcono.iconoIzq). también se pueden utilizar estas casillas de verificación dentro de elementos de menú. import java. Como se puede apreciar aunque los botones se encuentran desactivas.. import java.

else boton.exit(0).setSelected(true). chkIcono. panelCasillas.setSelected(true). } public void creaCasillas(){ panelCasillas=new JPanel(). ventana. boton.icono). panelBoton.2)).creaBoton().setText("").setMnemonic(KeyEvent. } if (fuente==chkToolTip){ if(estado==ItemEvent.setIcon(null). panelCasillas. panelBoton.creaCasillas().setToolTipText("Soy un botón"). } } public static void main(String args[]) { Casillas ventana = new Casillas(). int estado=evento.setSelected(true). } }). chkTexto=new JCheckBox("Texto").setMnemonic(KeyEvent. } if (fuente==chkTexto){ if(estado==ItemEvent.VK_L). boton=new JButton("Soy un botón".addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.DESELECTED) boton. panelCasillas. chkTexto. } public void itemStateChanged(ItemEvent evento) { Object fuente=evento. ventana.setToolTipText("Soy un botón").VK_I). chkToolTip. else boton. chkIcono.setMnemonic(KeyEvent. getContentPane().setIcon(icono).addItemListener(this). chkTexto.setText("Soy un botón"). this. } public void creaBoton(){ panelBoton=new JPanel(). getContentPane().add(panelBoton).add(chkIcono).public Casillas (){ super("Ventana con casillas de verificación"). chkTexto.addItemListener(this).DESELECTED) boton. chkToolTip=new JCheckBox("Tooltip"). 184 .setLayout(new FlowLayout()). chkIcono=new JCheckBox("Icono").1)). panelCasillas. else boton.setLayout(new GridLayout(1.add(panelCasillas).getSource().setLayout(new GridLayout(3. getContentPane().DESELECTED) boton.addItemListener(this). chkIcono.VK_T).add(chkToolTip). chkToolTip.add(boton).getStateChange().add(chkTexto). if (fuente==chkIcono){ if(estado==ItemEvent. chkToolTip.setToolTipText("").

Nuestro ejemplo va a contener tres botones de opción agrupados para mostrar tres dibujos distintos. por ejemplo podemos indicar que un objeto JRadioButton muestre una imagen o un tooltip. la casilla que ha visto modificado su estado. import java. La clase JRadioButton también tiene como superclase o clase padre a la clase AbstractButton. public Opciones (){ super("Ventana con opciones").*. //panel de la imagen private JPanel panelImagen. private JRadioButton opConejo.event.*. y a continuación si la casilla en cuestión ha sido seleccionada o no. //imagen private JLabel imagen. private JRadioButton opCerdo.swing. ventana. Para esta clase vamos a mostrar un ejemplo que ofrecerá un dibujo de un animal distinto según el botón de opción que se encuentre seleccionado en cada momento.awt.*.setVisible(true).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. import java. En el método itemStateChanged() debemos averiguar primero la fuente del evento. this. } 185 . es decir. También podemos utilizar botones de opciones en elementos de menú mediante la clase JRadioButtonMenuItem. únicamente uno de los botones puede encontrarse seleccionado a un mismo tiempo. import javax. Para agrupar los botones se utiliza la clase ButtonGroup.pack(). JRadioButton Los botones de opción se suelen encontrar en grupos en los que.awt. public class Opciones extends JFrame implements ActionListener{ //cada una de las Opciones private JRadioButton opGato.exit(0). por convención. } } Como se puede observar la clase JButton lanza un evento del tipo ItemEvent cuando se modifica el estado de un objeto. //panel de las Opciones private JPanel panelOpciones. por lo tanto presentará el comportamiento común a todas las clases que heredan de AbstractButton.ventana.

grupo.add(opCerdo). panelOpciones.VK_J).setLayout(new BorderLayout()). grupo. opGato=new JRadioButton("Gato").setLayout(new GridLayout(3. } public void actionPerformed(ActionEvent evento){ String comando=evento.addActionListener(this).add(imagen. opConejo. ventana. opCerdo.creaImagen(). } public void creaOpciones(){ panelOpciones=new JPanel(). imagen = new JLabel(new ImageIcon("cerdo. opCerdo. imagen.add(panelImagen). ventana.setPreferredSize(new Dimension(177. } } La clase JRadioButton.getActionCommand().setVisible(true).setActionCommand("conejo. grupo. } public static void main(String args[]) { Opciones ventana = new Opciones().add(panelOpciones).creaOpciones(). panelOpciones.setMnemonic(KeyEvent. funciona igual que la clase JButton.BorderLayout. opGato. } public void creaImagen(){ panelImagen=new JPanel(). opGato.add(opConejo).add(opGato).2)). panelOpciones. panelOpciones. getContentPane(). en lo que a tratamiento de eventos se refiere.setIcon(new ImageIcon(comando)).gif").add(opConejo).addActionListener(this). imagen. opGato. ventana. panelImagen.setActionCommand("cerdo. opConejo=new JRadioButton("Conejo"). getContentPane().CENTER). opCerdo.setMnemonic(KeyEvent.pack(). ventana.setSelected(true).1)). 122)).}).gif").setLayout(new GridLayout(1.addActionListener(this). opCerdo=new JRadioButton("Cerdo").setMnemonic(KeyEvent.VK_C). opConejo.add(opGato).add(opCerdo). getContentPane(). panelImagen.VK_G). opCerdo. el botón que se pulse (seleccione) va a lanzar un evento de la clase 186 .setActionCommand("gato.gif")). //se agrupan las opciones ButtonGroup grupo=new ButtonGroup(). opConejo.gif").

el objeto JComboBox muestra un menú de elementos para elegir. para diferenciar entre los distintos botones se utiliza el ActionCommand del evento ActionEvent.setPreferredSize(new Dimension(177.BorderLayout. que puede ser editable o no. getContentPane().awt.swing.setSelectedIndex(0).CENTER). ventana. ventana.setVisible(true). public Combo(){ super("Ventana con lista desplegable"). //se cambia la imagen imagen. } } 187 .setIcon(new ImageIcon(seleccion+". import java."Cerdo".*. } }). //imagen private JLabel imagen. //se obtiene el elemento seleccionado String seleccion=(String)fuente. } public static void main(String args[]) { Combo ventana = new Combo(). import java.getSelectedItem().add(listaOpciones.ActionEvent. Para mostrar la imagen se utiliza una etiqueta (JLabel) con un icono (ImageIcon). ventana.*.BorderLayout.getSource().NORTH).event. El usuario puede escribir un valor en la caja de texto o elegir un valor del menú. } public void actionPerformed(ActionEvent evento){ JComboBox fuente=(JComboBox)evento.gif")). ventana. } public void creaCombo(){ listaOpciones=new JComboBox(opciones).creaImagen().creaCombo(). listaOpciones.exit(0). imagen.add(imagen.pack(). JComboBox Esta clase representa una lista desplegable de opciones. public class Combo extends JFrame implements ActionListener{ //lista desplegable private JComboBox listaOpciones. Cuando el usuario pulsa la lista. //opciones de la lista String[] opciones={"Gato"."Conejo"}. listaOpciones. Una lista desplegable editable es similar a una caja de texto (JTextField) con un pequeño botón.awt.*. 122)). import javax.gif")).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.addActionListener(this). this. } public void creaImagen(){ imagen = new JLabel(new ImageIcon("gato. getContentPane().

que contiene varios elementos de menú. que 188 . como muchas de las clases que hemos visto hasta ahora. es decir. A continuación se comentan cada una de estas clases. que representa las opciones que muestra la lista desplegable. JMenu Un menú permite elegir al usuario entre múltiples opciones disponibles. la jerarquía que presentan los distintos componentes Swing relacionados con la creación de menús. el mismo evento que se lanza cuando se pulsa un botón.Al seleccionar un elemento del objeto JComBox se lanza un evento ActionEvent. El constructor utilizado para instanciar un objeto de la clase JComboBox recibe como argumento un array de cadenas (String). que serán objetos de la clase JMenu. veamos en la Figura 92.  JMenu: es una opción de menú determinada. Para indicar la opción seleccionada por defecto utilizamos el método setSelectedIndex() sobre el objeto de la clase JComboBox.  JMenuBar: representa la barra de menú que va a contener los distintos elementos de menú. y para obtener la opción seleccionada y así mostrar la imagen correspondiente se utiliza el método getSelectedItem() de la clase JComboBox. Los menús parecen normalmente dentro de barras de menú o como menús contextuales (menú popup). Un elemento de menú hereda también de la clase AbstractButton.

elementoMenu=new JMenuItem(new ImageIcon("icono2. Como ocurre en estos casos primero se muestra el código fuente del ejemplo. objetos de la clase JMenu. contiene elementos de menú (JMenuItem). menu.gif")). this.KeyEvent.VK_E).new ImageIcon("icono2.setMnemonic(KeyEvent. setJMenuBar(barraMenu). ActionEvent. y también puede contener submenús. //unos cuantos elementos de menú elementoMenu=new JMenuItem("Elemento de menú de texto".addActionListener(this). //se asigna tecla de acceso rápido elementoMenu. elementoMenu.*.*.  JPopupMenu: representa un menú contextual o de aparición súbita.swing.ALT_MASK)). además se va mostrando en un área de texto (JTextArea) los distintos eventos que van generando los distintos componentes de menú junto con la fuente que ha producido dichos eventos. import java. elementoMenu. ItemListener{ JMenuBar barraMenu. } public void creaMenu(){ //Se crea la barra de menú barraMenu = new JMenuBar().addActionListener(this). elementoMenu. JMenu menu. elementoMenu=new JMenuItem("Texto e icono".addActionListener(this).  JRadioButtonMenuItem: elemento de menú que posee un botón de opción. elementoMenu. barraMenu.  JMenuItem: es un elemento de menú.setMnemonic(KeyEvent.event.gif")). JTextArea texto. public class Menus extends JFrame implements ActionListener. JScrollPane panelScroll. 189 .addSeparator(). import javax.add(elementoMenu).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. menu.getKeyStroke( KeyEvent.add(elementoMenu). menu. JCheckBoxMenuItem cbElementoMenu. es decir.serán objetos de la clase JMenuItem.VK_1.  JSeparator: elemento de menú especial que ofrece una separación entre elementos de menú de una misma opción de menú.  JCheckBoxMenuItem: elemento de menú que posee una casilla de verificación. JMenuItem elementoMenu. menu.awt. JRadioButtonMenuItem rbElementoMenu.exit(0).add(menu).add(elementoMenu).VK_T).VK_E). elementoMenu.VK_D). //se añade un separador menu.awt. submenu. public Menus(){ super("Ventana con múltiples menús"). En el Código siguiente se muestra la utilización de todas estas clases. import java.setMnemonic(KeyEvent.*. //se crea el primer menú menu = new JMenu("Un Menú"). } }).setAccelerator(KeyStroke.

} public void creaTexto(){ texto= new JTextArea(10. menu.\n" + " Fuente del evento: " + fuente.addSeparator(). panelScroll= new JScrollPane(texto).add(rbElementoMenu).getStateChange()==ItemEvent.setMnemonic(KeyEvent. texto. rbElementoMenu. rbElementoMenu.getText()+"\n" + " Nuevo estado: "+estado+"\n".addSeparator().VK_B). menu. elementoMenu. JMenuItem fuente =(JMenuItem)(evento. //un submenú menu.SELECTED) estado="Seleccionado". submenu. BorderLayout.setMnemonic(KeyEvent.add(elementoMenu).add(elementoMenu).getKeyStroke( KeyEvent.add(submenu). //Segúndo menú de la barra de menú menu = new JMenu("Otro Menú"). cbElementoMenu. getContentPane(). rbElementoMenu.add(rbElementoMenu). cbElementoMenu.VK_O).addItemListener(this). menu. cbElementoMenu=new JCheckBoxMenuItem("Casilla de verificación").addItemListener(this). String mensaje="ItemEvent detectado. rbElementoMenu. rbElementoMenu= new JRadioButtonMenuItem("Otro botón de opción").addActionListener(this).getSource()). menu. ActionEvent. menu. texto. //Un grupo de casillas de verificación menu. elementoMenu=new JMenuItem("Un elemento de menú del submenú").ALT_MASK)). barraMenu. submenu. elementoMenu. elementoMenu. if (evento.setMnemonic(KeyEvent.\n" + " Fuente del evento: " + fuente. submenu=new JMenu("Un submenú"). rbElementoMenu=new JRadioButtonMenuItem("Botón de opción").add(panelScroll.setEditable(false). else estado="No seleccionado". rbElementoMenu.addActionListener(this). } public void itemStateChanged(ItemEvent evento) { String estado="".VK_2.VK_C). submenu. String mensaje= "ActionEvent detectado.add(rbElementoMenu). } public void actionPerformed(ActionEvent evento){ JMenuItem fuente=(JMenuItem)(evento. 190 .setMnemonic(KeyEvent.CENTER).add(cbElementoMenu). cbElementoMenu=new JCheckBoxMenuItem("Otro más"). cbElementoMenu.addActionListener(this). grupo.setSelected(true).VK_S).setMnemonic(KeyEvent.setAccelerator(KeyStroke.addActionListener(this).VK_M). 50). elementoMenu= new JMenuItem("Otro elemento de menú").VK_M). ButtonGroup grupo=new ButtonGroup().add(menu).getText()+"\n".append(mensaje).add(cbElementoMenu). menu. cbElementoMenu.setMnemonic(KeyEvent. grupo.getSource()).add(rbElementoMenu).//un grupo de elementos de menú de botones de opción.

texto. y los elementos de menú del tipo JCheckBoxMenuItem lanzan eventos de la clase ItemEvent. Vamos a modificar el ejemplo anterior en el que utilizábamos la barra de menú y vamos a añadir un menú contextual (JPopupMenu) que se asociará al área de texto (JTextArea) en la que se muestran los eventos lanzados por los distintos elementos de menú. elementoMenu. public void creaPopup(){ menuPopup=new JPopupMenu(). ventana. } public static void main(String args[]) { Menus ventana = new Menus(). Un contextual o de aparición súbita (popup) se encuentra representado por la clase JPopupMenu y debe registrarse un oyente de ratón en cada componente que tenga asociado el menú popup.gif")).VK_P). El método show() recibe como parámetros el componente al que se asocia el menú y las coordenadas de la pantalla en la que se quiere mostrar el menú contextual. el oyente debe detectar que el usuario a pulsado el botón derecho del ratón para mostrar el menú contextual correspondiente.setVisible(true).pack(). El oyente que se ocupa de mostrar el menú contextual lanza el método show() sobre la instancia correspondiente de la clase JPopupMenu. El área de texto (JTextArea) encargada de ir mostrando los eventos que se producen se añade a un panel de scroll (ScrollPane). También se va a añadir un nuevo método llamado creaPopup(). Se va añadir un nuevo atributo a nuestra clase.append(mensaje). 191 . llamado menuPopup que pertenece a la clase JPopupMenu. ventana. Como se puede ver se han añadido dos teclas rápidas mediante el método setAccelerator(). ventana. elementoMenu=new JMenuItem("Segundo del popup".new ImageIcon("icono2. //se crean y añadden los distinos elementos de menú de la misma manera elementoMenu=new JMenuItem("Primer elemento del popup".KeyEvent. ventana.addActionListener(this). menuPopup.creaTexto().creaMenu(). } } Los elementos de menú lanzan eventos ActionEvent.add(elementoMenu).

elementoMenu.setMnemonic(KeyEvent.VK_S); elementoMenu.addActionListener(this); menuPopup.add(elementoMenu); menuPopup.addSeparator(); cbElementoMenu=new JCheckBoxMenuItem("Tercer elemento"); cbElementoMenu.setMnemonic(KeyEvent.VK_T); cbElementoMenu.addItemListener(this); menuPopup.add(cbElementoMenu); //se crea el oyente y se registra para el área de texto PopupListener oyente=new PopupListener(); texto.addMouseListener(oyente); }

Este método se puede lanzar una vez utilizado el método creaTexto(). Como se puede observar se crea una instancia de un objeto de la clase PopupListener, esta clase es una clase interna que hereda de la clase MouseAdapter y que va a ser el oyente de nuestro menú contextual y el que va a mostrarlo. El código de esta clase adaptadora interna es:
class PopupListener extends MouseAdapter{ public void mousePressed(MouseEvent evento){ menuPopup.show(evento.getComponent(),evento.getX(),evento.getY()); } }

Y un ejemplo de la utilización del menú contextual se puede observar en la Figura.

Como se puede comprobar a la vista de la figura anterior, seguimos recogiendo los eventos de los distintos elementos de menú, incluso del menú contextual. Pero si el lector prueba este ejemplo comprobará que el menú contextual parecerá también cuando se pulse el botón izquierdo del ratón, y no sólo cuando se pulse el botón derecho, que sería lo deseable. La clase MouseEvent ofrece el método isPopupTrigger() para averiguar si debemos mostrar el menú popup o no. El método isPopupTrigger() devolverá verdadero si la pulsación del ratón se corresponde con un evento que debe mostrar un menú contextual, en el caso de Windows se corresponde con el botón derecho del ratón. Así nuestro código fuente del adaptador del ratón quedaría como se muestra en el Código :
class PopupListener extends MouseAdapter{ public void mousePressed(MouseEvent evento){ if (evento.isPopupTrigger()){ menuPopup.show(evento.getComponent(),evento.getX(),evento.getY());
192

} } }

La sorpresa es que ahora no se muestra nunca el menú contextual, no con le botón derecho ni con el botón derecho del ratón, la verdad no he conseguido discernir porque no aparece.

JSlider
Este componente permite al usuario seleccionar un valor numérico entre un rango determinado, este componente se utiliza para restringir los valores que puede ofrecer el usuario y así evitar errores y el tratamiento de los mismos. Para mostrar el funcionamiento de este componente Swing se ha utilizado un ejemplo en el que según se indique en el selector (JSlider) se dará un tamaño determinado a un botón (JButton), el botón se redimensionará según se indique en el selector.
import java.awt.*; import java.awt.event.*; import javax.swing.*; //eventos nuevos de Swing import javax.swing.event.*; public class Selector extends JFrame implements ChangeListener{ //selector de valores private JSlider selector; private JButton boton; public Selector(){ super("Ventana con selector (JSlider)"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void creaSelector(){ selector=new JSlider(JSlider.HORIZONTAL,0,300,50); selector.addChangeListener(this); selector.setMajorTickSpacing(100); selector.setMinorTickSpacing(10); selector.setPaintTicks(true); selector.setPaintLabels(true); getContentPane().add(selector,BorderLayout.NORTH); } public void creaBoton(){ boton=new JButton("Soy un botón"); JPanel panel=new JPanel(); panel.setLayout(new FlowLayout()); panel.add(boton); getContentPane().add(panel,BorderLayout.CENTER); boton.setSize(50,50); } public void stateChanged(ChangeEvent evento){ JSlider fuente=(JSlider)evento.getSource(); if (!fuente.getValueIsAdjusting()){ boton.setSize((int)fuente.getValue(),(int)fuente.getValue()); } } public static void main(String args[]) { Selector ventana = new Selector(); ventana.creaSelector();
193

ventana.creaBoton(); ventana.setSize(310,310); ventana.setVisible(true); } }

A la vista del código se pueden hacer los siguientes comentarios y apreciaciones. El constructor utilizado para crear el objeto de la clase JSlider, posee un argumento para indicar la orientación del selector correspondiente, se corresponde con las constantes HORIZONTAL y VERTICAL de la clase JSlider. Los siguientes argumentos, especifican respectivamente, el valor mínimo, el valor máximo y el valor seleccionado inicialmente del objeto JSlider. Si no indicamos estos valores, el valor mínimo del selector será 0, el máximo 100 y el seleccionado inicialmente 50. Para configurar inicialmente el objeto de la clase JSlider, hemos utilizado una serie de métodos:  setMajorTickSpacing(int espaciado): este método nos permite indicar las separaciones mayores entre el máximo y el mínimo del selector.  setMinorTickSpacing(int espaciado); este método indica las separaciones menores entre el rango indicado para el componente Swing JSlider.  setPaintTicks(boolean): mediante este método indicamos si deseamos o no que parezcan las separaciones del objeto JSlider.  setPaintLabels(boolean): nos permite indicar si queremos que se pinten las diferentes etiquetas del rango. Para registrar el oyente del selector hemos utilizado el método addChangeListener(), ya que la clase JSlider lanza eventos de la clase ChangeEvent. Este es un nuevo tipo de evento que se incluye en el paquete javax.swing.event y se lanza cuando se modifica el valor actual de un objeto de la clase JSlider. El método que debe implementar un oyente de eventos ChangeEvent es el método stateChanged(). En el ejemplo anterior hemos visto que se ha utilizado el método getValueIsAdjusting() de la clase JSlider, este método devuelve verdadero mientras se esté
194

seleccionando el valor del objeto JSlider, de esta forma no se redimensionará el botón hasta que el usuario no haya finalizado de arrastrar el tirador del selector, es decir, cuando el usuario ha finalizado con el proceso de selección. Las etiquetas que aparecen en el selector las podemos personalizar con la ayuda del método setLabelTable() de la clase JSlider y de un objeto de la clase Hashtable. Para utilizar la clase Hashtable debemos importar el paquete Primero crearemos un objeto que representa una tabla hash y mediante el método put() vamos indicando la posición que queremos que ocupe la etiqueta y el objeto JLabel que va a mostrar el texto correspondiente. Veamos, en el Código siguiente, un sencillo ejemplo.
public void creaSelector(){ selector=new JSlider(JSlider.HORIZONTAL,0,300,50); selector.addChangeListener(this); selector.setMajorTickSpacing(100); selector.setPaintTicks(true); //tabla de etiquetas Hashtable etiquetas=new Hashtable(); etiquetas.put(new Integer(0),new JLabel("Minúsculo")); etiquetas.put(new Integer(100),new JLabel("Pequeño")); etiquetas.put(new Integer(200),new JLabel("Mediano")); etiquetas.put(new Integer(300),new JLabel("Grande")); //asignamos las etiquetas al selector selector.setLabelTable(etiquetas); selector.setPaintLabels(true); getContentPane().add(selector,BorderLayout.NORTH); }

Con la clase JSlider se da por terminado el apartado dedicado al grupo de componentes Swing cuya función es la de recoger la entrada del usuario, a continuación vamos a comentar algunos componentes atómicos cuya función es la de simplemente mostrar información al usuario, algunos de los representantes de este grupo que vamos a tratar a continuación ya los conoceremos de ejemplos anteriores, como ocurre con el componente JLabel.
195

Componentes para mostrar información
Se ofrecen distintos ejemplos de componentes Swing encargados de mostrar información.

JLabel
Ya hemos utilizado numerosas veces este útil y sencillo componente de Swing, como ya sabemos su labor es la de mostrar una información al usuario, ya sea textual o con imágenes o con ambos elementos. En el siguiente ejemplo se muestra la utilización de la clase JLabel creando cuatro objetos distintos de esta clase, se ha añadido un borde a cada etiqueta para que se distingan claramente unas de otras.
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Etiquetas extends JFrame{ private JLabel etiqueta1; private JLabel etiqueta2; private JLabel etiqueta3; private JLabel etiqueta4; private ImageIcon icono; public Etiquetas(){ super("Ventana con etiquetas"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void creaEtiquetas(){ icono=new ImageIcon("icono2.gif"); etiqueta1=new JLabel("Imagen y texto",icono,JLabel.CENTER); etiqueta1.setVerticalTextPosition(JLabel.BOTTOM); etiqueta1.setHorizontalTextPosition(JLabel.CENTER); etiqueta1.setBorder(BorderFactory.createLineBorder(Color.red)); etiqueta2=new JLabel("Sólo texto"); etiqueta2.setHorizontalAlignment(JLabel.RIGHT); etiqueta2.setVerticalAlignment(JLabel.TOP); etiqueta2.setBorder(BorderFactory.createLineBorder(Color.blue)); etiqueta3=new JLabel(icono); etiqueta3.setBorder(BorderFactory.createLineBorder(Color.green)); etiqueta4=new JLabel("Imagen y texto",icono,JLabel.CENTER); etiqueta4.setVerticalTextPosition(JLabel.TOP); etiqueta4.setHorizontalTextPosition(JLabel.CENTER); etiqueta4.setBorder(BorderFactory.createLineBorder(Color.pink)); } public void añadeEtiquetas(){ getContentPane().setLayout(new GridLayout(1,4,5,5)); getContentPane().add(etiqueta1); getContentPane().add(etiqueta2); getContentPane().add(etiqueta3); getContentPane().add(etiqueta4); } public static void main(String args[]) { Etiquetas ventana = new Etiquetas(); ventana.creaEtiquetas(); ventana.añadeEtiquetas(); ventana.pack(); ventana.setVisible(true); }}
196

CENTER).add(etiqueta1).setHorizontalTextPosition(JLabel.JLabel.awt. etiqueta1.TOP).setBorder(BorderFactory.15)).gif"). etiqueta4. y mediante las constantes LEFT.setVerticalTextPosition(JLabel.*. TOP y BOTTOM. import java.1.event. getContentPane(). public Etiquetas(){ super("Ventana con etiquetas"). etiqueta2. etiqueta1=new JLabel("<html><font size='4' color='red'><b><i>"+ "Imagen y texto</b></i></font>".*. RIGHT. public class Etiquetas extends JFrame{ private JLabel etiqueta1.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.setVerticalTextPosition(JLabel. JLabel. this. icono.pink)). etiqueta4=new JLabel("<html><h2><i>Imagen y texto</i></h2><hr>".add(etiqueta3).createLineBorder(Color. etiqueta3=new JLabel("<html><table border='1'><tr><td>Celda 1</td>"+ "<td>Celda2</td></tr><tr><td align='center' colspan='2'>Celda 3</td>"+" </tr></table>".swing.CENTER). import javax.setHorizontalTextPosition(JLabel.setBorder(BorderFactory.red)). } public void creaEtiquetas(){ icono=new ImageIcon("icono2. private JLabel etiqueta2. getContentPane().createLineBorder(Color.createLineBorder(Color.add(etiqueta4).setBorder(BorderFactory. con los componentes JLabel podemos utilizar código HTML para indicar el formato del texto que se va a mostrar. getContentPane().Como se puede observar en el ejemplo anterior es posible especificar la alineación del texto respecto a la imagen que contiene la etiqueta utilizando el método setVerticalTextPosition() y setHorizontalTextPostion(). etiqueta4.icono. etiqueta4. } }). Veamos un ejemplo:l import java. CENTER.setLayout(new GridLayout(4.CENTER).exit(0).createLineBorder(Color.CENTER). } public void añadeEtiquetas(){ getContentPane().BOTTOM). El valor por defecto es centrado (CENTER). También se puede indicar la alineación de los componentes dentro de la etiqueta con los métodos setHorizontalAlignment() y setVerticalAlignment().CENTER). Al igual que sucedía con la clase JButton. private JLabel etiqueta3. etiqueta2=new JLabel("<html><ul><li>Elemento 1<li>Elemento2</ul>"). getContentPane().blue)). } public static void main(String args[]) { 197 . private JLabel etiqueta4.green)).15. etiqueta3.setBorder(BorderFactory.JLabel.awt.add(etiqueta2). etiqueta1. private ImageIcon icono. etiqueta1.*.

sino que utilizaremos los métodos setToolTipText() y getTootTipText() de la clase JComponent. Aunque realmente no vamos a utilizar nunca directamente la clase JToolTip.setSize(300.añadeEtiquetas(). ventana.Etiquetas ventana = new Etiquetas(). Al crear una instancia de la clase JProgressBar podemos indicar la orientación que va a tener la barra de progreso. para ello se utilizan las constantes HORIZONTAL y 198 . ventana. esta clase representa las pequeñas ayudas que se muestran en forma de pequeño texto explicativo (tooltip) cuando nos situamos sobre un componente determinado.creaEtiquetas(). también podemos encontrar la clase JToolTip. JProgressBar Este componente Swing muestra gráficamente el progreso de una operación determinada.setVisible(true). ya hemos visto la utilización de estos métodos en ejemplos anteriores. la barra de progreso va mostrando el porcentaje de tarea que se ha realizado.450). ventana. con el primero asignamos un tooltip a un componente Swing y con el segundo obtenemos el tooltip que tiene asignando un componente Swing determinado. ventana. } } JToolTip Dentro del grupo de componentes atómicos de Swing encargados exclusivamente de mostrar información. nos va informando de la evolución de un proceso.

setLayout(new FlowLayout()).getMaximum()) //se emite un pitido al llegar al máximo Toolkit.setValue(valor). valor=barra.*. disponemos del método setValue(). this.100). panel.BorderLayout.add(panel.exit(0). //valor que se va incrementando private int valor. Los máximos y mínimos los podemos manipular con los métodos getMinumum()/setMinimum() y getMaximum()/setMaximum().VERTICAL de la clase JProgressBar.setStringPainted(true).BorderLayout. if(valor==barra. getContentPane().event.getMinimum()). boton. Al llegar al máximo se emitirá un sonido y después se volverá la barra de progreso a su estado inicial.getMinimum(). } }).awt.setValue(barra. import java.getMaximum()){ //hemos sobrepasado el máximo de la barra de progreso barra.0. } else{ barra.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. } public void actionPerformed(ActionEvent event){ //se incrementa el valor valor=valor+10. //indicamos que aparecen las etiquetas del progreso barra.setValue(0). this.add(barra. panel. import javax. } public void creaBoton(){ boton=new JButton("Incrementar").NORTH).beep(). También podemos indicar el máximo y el mínimo de la barra de progreso. que se corresponde con el proceso actual.CENTER).add(boton).addActionListener(this). public BarraProgreso(){ super("Ventana con barra de progreso").getDefaultToolkit(). private JButton boton. JPanel panel=new JPanel(). import java.HORIZONTAL.valor=0. public class BarraProgreso extends JFrame implements ActionListener{ private JProgressBar barra. //valor inicial barra. } public void creaBarra(){ //una barra de mínimo 0 y máximo 100 barra=new JProgressBar(JProgressBar.swing. } } public static void main(String args[]) { 199 .*.awt.*. Para incrementar el valor actual de la barra de progreso. getContentPane(). if (valor>barra. A continuación se ofrece un sencillo ejemplo que consiste en ir pulsando un botón que incrementará por cada pulsación el valor actual de la barra de progreso.

} } Como se puede comprobar en el ejemplo. Además este componente permite mostrar de forma sencilla un diálogo que permite seleccionar también un color. la barra de progreso muestra el tanto por ciento (%) de la operación realizada. como pueden ser los distintos colores. Componentes que muestran información estructurada En este último apartado se van a tratar dos componentes JColorChooser y JFileChooser que permiten seleccionar un color determinado y un fichero del sistema de ficheros. este tanto por ciento lo calcula teniendo en cuenta el valor actual y sus valores máximo y mínimo. 200 . respectivamente.setSize(200. Para que se muestre el etiqueta del tanto por ciento se ha utilizado el método setStringPainted() pasándole como argumento el valor true. además en algunos casos permiten editar esta información.200). Podemos mostrar en la barra de progreso cualquier texto mediante el método setString() de la clase JProgressBar y así variar el comportamiento por defecto de la barra de progreso. ventana. JColorChooser Este componente Swing además de ofrecer una información estructurada. Para obtener el tanto por ciento de la tarea realizada (completada) representada por la barra de progreso disponemos del método getPercentComplete(). ventana. Este es el último de los componentes Swing pertenecientes al grupo de componentes encargados de mostrar información.creaBoton(). ventana. Veremos dos ejemplos de las dos formas que podemos utilizar el componente JColorChooser: como si se tratara de otro componente más o como un diálogo. los siguientes componentes pertenecen al grupo de los componentes atómicos que muestran también una información pero de una forma más compleja y estructurada.setVisible(true). La clase JColorChooser representa un componente Swing atómico. nos permite seleccionar un elemento determinado de esa información.creaBarra(). ventana. pero bastante complejo y completo que permite seleccionar colores de distintas formas.BarraProgreso ventana = new BarraProgreso().

setForeground(Color.event. cada una de ellas permite una forma distinta de seleccionar los colores. etiqueta.colorchooser. El panel de muestra se encuentra en la parte inferior y va mostrando el color seleccionado en cada momento del panel de selección. import javax.*. } }). etiqueta.*. lanza un evento de la clase ChangeEvent (este evento vimos que también era lanzado por el componente JSlider) cada vez que se cambia la selección del color en el selector de color (JColorChooser). El modelo de selección de color (instancia de la clase ColorSelectionModel). un panel con pestañas (JTabbedPane) y un panel con la muestra de la selección (preview). etiqueta.swing. sino sobre su ColorSelectionModel.colorchooser. Si queremos detectar los cambios de selección de color del componente JColorChooser debemos registrar el oyente correspondiente al evento ChageEvent. Pasemos ahora a ver un código de ejemplo que utiliza un objeto de la clase JColorChooser para configurar el color del texto de una etiqueta.awt.swing.white).event. etiqueta.swing. } public void creaEtiqueta(){ //Configuramos la etiqueta sobre la que se aplica la selección de color etiqueta= new JLabel("La Plataforma Java 2". Para poder tratar la selección actual el componente JColorChooser hace uso de una clase llamada ColorSelectionModel que se encuentra en el subpaquete de Swing denominado javax.green).setBackground(Color.awt.*. El panel de selección con pestañas encuentra en la parte superior y presenta tres pestañas. private JColorChooser selectColor. this. Font.setFont(new Font("SansSerif". debemos lanzar sobre el objeto JColorChooser el método getSelectionModel().En el Look & Feel de Java (en el apartado correspondiente hablaremos de los distintos Look & Feel y como establecerlos) una instancia de la clase JColorChooser muestra el siguiente aspecto: se encuentra dividido en dos partes.setOpaque(true). import javax.*.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. import javax. public SelectorColor() { super("Selector de color"). import java. Para obtener la instancia de la clase ColorSelectionModel correspondiente a un objeto de la clase JColorChooser.swing.*. 24)).exit(0). 201 .JLabel. pero no se debe hacer directamente sobre el componente JColorChooser.BOLD. import java.CENTER). public class SelectorColor extends JFrame implements ChangeListener{ private JLabel etiqueta.

45)). selectColor.creaEtiqueta(). } } 202 .add(etiquetaPanel. //panel con borde que va a contener la etiqueta JPanel etiquetaPanel = new JPanel(new BorderLayout()).etiqueta. } public static void main(String[] args) { SelectorColor ventana = new SelectorColor(). ventana.setPreferredSize(new Dimension(80. } public void creaSelectorColor(){ selectColor= new JColorChooser(etiqueta. //se obtiene el modelo de seleción de color para registrar el oyente //de los eventos ChangeEvent selectColor.setForeground(selectColor.add(etiqueta.getForeground()).getColor()). etiquetaPanel.setVisible(true).setBorder(BorderFactory.getSelectionModel().add(selectColor. } public void stateChanged(ChangeEvent e) { etiqueta.SOUTH). ventana. getContentPane().BorderLayout.createTitledBorder("etiqueta")). BorderLayout. ventana.createTitledBorder ("Selecciona el color del texto")).addChangeListener(this). etiquetaPanel.setBorder(BorderFactory.CENTER).creaSelectorColor(). getContentPane(). BorderLayout. ventana.CENTER).pack().

en la Figura 102 se puede ver otra selección distinta. En nuestro caso le hemos indicado el color de la letra de la etiqueta sobre la que se va a aplicar las distintas selecciones de color. El método stateChanged(). añadiéndolo al panel de contenido de la ventana. En este caso el componente JColorChooser lo hemos tratado como otro componente atómico más. La sintaxis de este método es: JColorChooser. utilizando el formato de color RGB. Color color) 203 . que se lanzará cada vez que se cambie la selección de color del selector de color.Como se puede comprobar en el ejemplo el constructor utilizado de la clase JColorChooser recibe como parámetro un color. este es el color seleccionado inicialmente dentro del selector de color. En la ejecución del ejemplo se puede observar las tres formas distintas de seleccionar el color que permite el componente JColorChooser.showDialog(Component padre. y se lo aplica al texto de la etiqueta mediante el método setForeground(). String título. para ello podemos utilizar el método estático showDialog() de la clase JColorChooser. pero también podemos mostrarlo como un diálogo. recupera el color actual mediante el método getColor() de la clase JColorChooser.

private JButton boton.setBorder(BorderFactory.setForeground(Color. Ahora vamos a modificar el ejemplo anterior para realizar una función similar pero utilizando el selector de colores como un diálogo modal. 204 . getContentPane().setFont(new Font("SansSerif".JLabel. public DialogoSelectorColor() { super("Selector de color con diálogo").45)).swing. getContentPane(). etiqueta.*. Para mostrar el diálogo vamos a utilizar un botón (JButton) y el evento ActionEvent. //panel con borde que va a contener la etiqueta JPanel etiquetaPanel = new JPanel(new BorderLayout()).addActionListener(this).setOpaque(true).*.creaBoton().add(panel.CENTER). } public void creaBoton(){ JPanel panel=new JPanel(). import javax.add(etiquetaPanel. sino que el color seleccionado lo obtenemos directamente cuando el usuario pulse el botón de OK del diálogo.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.event. } public void creaEtiqueta(){ //Configuramos la etiqueta sobre la que se aplica la selección de color etiqueta= new JLabel("La Plataforma Java 2". En este nuevo supuesto no se utiliza la clase ColorSelectionModel.exit(0).*. BorderLayout.add(etiqueta. boton=new JButton("Selección de color").180). etiqueta. panel.setSize(400.setForeground(color). el segundo el título del diálogo y el tercero el color seleccionado por defecto en el diálogo de selección de color. etiqueta.setLayout(new FlowLayout()).El primer argumento de este método es el componente padre del diálogo (el componente del que depende). etiqueta.white). panel. ventana. ventana. etiquetaPanel.CENTER).showDialog(this."Selecciona un color".CENTER). import java. this. } }).BorderLayout. if (color!=null) etiqueta. boton.green). ventana.getForeground()).awt.setBackground(Color.creaEtiqueta(). public class DialogoSelectorColor extends JFrame implements ActionListener{ private JLabel etiqueta. etiqueta. Font.BOLD. 24)). } public void actionPerformed(ActionEvent evento) { Color color=JColorChooser.awt. Esto se ve mucho más claro en el código fuente del ejemplo import java.add(boton). } public static void main(String[] args) { DialogoSelectorColor ventana = new DialogoSelectorColor(). etiqueta. BorderLayout.SOUTH).createTitledBorder("etiqueta")). etiquetaPanel.setPreferredSize(new Dimension(80.

Al pulsar el botón selección de color aparece: JFileChooser Este es el último componente atómico de Swing que vamos a ver.ventana. sino que se devolverá el valor null (nulo).setVisible(true). El componente JFileChooser es similar al visto anteriormente. } } Si el usuario cancela la selección de color. ya sea cerrando el diálogo o pulsando el botón de cancelación. 205 . no se devolverá ningún color. podemos crearlo como un componente más y añadirlo a un panel o bien mostrarlo como un diálogo modal.

addActionListener(this). private JButton botonGuardar. botonGuardar. import java. public class DialogoSelectorFichero extends JFrame implements ActionListener{ private JTextArea resultado. El aspecto que muestra el diálogo para la apertura de fichero es muy similar al del diálogo para guardar ficheros. } public void creaResultado(){ 206 .Este componente nos permite navegar por el sistema de ficheros y seleccionar un fichero o directorio. botonAbrir=new JButton("Abrir un fichero. ambas constantes de encuentran definidas en la clase JFileChooser. Estos métodos no son estáticos como ocurría con el componente ColorChooser.add(botonAbrir). Tanto el método showOpenDialog() como showSaveDialog() devuelven un valor entero que se corresponde con las constantes que indican el resultado de la selección del usuario. } public void creaBotones(){ ImageIcon iconoAbrir = new ImageIcon("abrir. import java.addActionListener(this).io.exit(0). public DialogoSelectorFichero() { super("Diálogo para la selección de ficheros"). this. estos métodos son showOpenDialog() y showSaveDialog(). A continuación vamos a mostrar un sencillo ejemplo que posee dos botones y un área de texto (JTextArea). Pero la clase JFileChooser únicamente muestra el interfaz que nos permite seleccionar los ficheros.*. es decir. según el botón que se pulse se mostrará un diálogo de selección de ficheros distinto. selectorFichero=new JFileChooser().addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. } }).gif"). pero el tratamiento de los mismos corre de nuestra cuenta.*. JPanel panelBotones=new JPanel().gif").*. private JFileChooser selectorFichero. el tratamiento de los ficheros debemos implementarlo en nuestra aplicación. panelBotones. import javax.NORTH). ImageIcon iconoGuardar = new ImageIcon("guardar.BorderLayout. el que se utiliza para abrir ficheros y el que se utiliza para grabar ficheros. indican si el usuario a pulsado el botón de cancelación (CANCEL_OPTION) o no (APPROVE_OPTION). iconoGuardar). para abrir ficheros y para guardar ficheros. panelBotones. Normalmente se utilizan estos componentes como diálogos modales...add(panelBotones.add(botonGuardar).swing. iconoAbrir). private JButton botonAbrir. botonAbrir.". En el área de texto se irán mostrando las selecciones de ficheros o cancelaciones realizadas por el usuario.. Ambos métodos reciben como argumento un objeto Component que representa el padre del diálogo de selección de ficheros.awt.".*. getContentPane(). import java.awt. La clase JFileChooser ofrece dos métodos para mostrar los dos tipos de selectores de ficheros distintos. botonGuardar=new JButton("Guardar un fichero. sino que se deben lanzar sobre una instancia de la clase JFileChooser..event.

APPROVE_OPTION) { File fichero = selectorFichero. if (valorDevuelto== JFileChooser.add(panelResultado.resultado = new JTextArea(5.setEditable(false). } else resultado. } public void actionPerformed(ActionEvent evento) { if (evento.CENTER). } } Y la del diálogo de selección de ficheros para su apertura.20).append("Apertura cancelada por el usuario\n").5.append("Abierto: " + fichero.getSelectedFile().5.getName()+"\n"). resultado.setMargin(new Insets(5.append("Guardado: " + fichero. resultado.BorderLayout.getSource()==botonAbrir){ int valorDevuelto= selectorFichero. ventana. }else{ int valorDevuelto= selectorFichero. } else resultado. ventana.setVisible(true). if (valorDevuelto== JFileChooser.pack().APPROVE_OPTION) { File fichero = selectorFichero. resultado.creaResultado(). ventana.showOpenDialog(this). JScrollPane panelResultado = new JScrollPane(resultado).append("Operación de grabado cancelada"+ "por el usuario\n"). ventana.showSaveDialog(this).creaBotones().5)). resultado. } } public static void main(String[] args) { DialogoSelectorFichero ventana = new DialogoSelectorFichero(). es: 207 .getName()+"\n"). getContentPane().getSelectedFile().

Como se puede comprobar en el ejemplo. El constructor de la clase JFileChooser puede recibir como argumento un objeto File o String para indicar el directorio inicial. es decir. en el siguiente capítulo trataremos el nuevo gestor de diseño de Swing y la característica Pluggable Look & Feel. que devuelve un objeto de la clase File. representado por la clase BoxLayout y la característica especial que ofrece Swing denominada Pluggable Look & Feel. para obtener el fichero que se ha seleccionado se utiliza el método getSelectedFile(). Este ha sido el componente Swing atómico que cierra este capítulo. A través de este objeto podemos manipular ficheros. va recordando las rutas de las selecciones anteriores. Cada vez que se muestra el diálogo para la selección de ficheros guarda el directorio actual de la selección anterior. el nuevo gestor de diseño de Swing. Interfaces de usuario en Java: otras características de Swing Introducción Este capítulo cierra el ciclo de capítulos dedicado a Swing. 208 . en una aplicación real se utilizaría para guardar o abrir ficheros. este capítulo no va a ser tan extenso como los anteriores ya que trataremos dos aspectos muy determinados. El directorio inicial también se puede especificar mediante el método setCurrentDirectory() al que se le pasa como argumento un objeto de la clase File. Además permite la creación de nuevos directorios.

Y_AXIS)). panelContenido. Este gestor de diseño organiza los componentes en una pila. } }).addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.add(new JButton("Otro botón")).El gestor de diseño BoxLayout La clase BoxLayout.  Y_AXIS: los componentes se distribuyen de arriba a abajo.add(new JButton("Soy un botón")).swing. panelContenido.Y_AXIS por BoxLayout. vamos a ver con un sencillo ejemplo la forma en la que distribuye los componentes en el panel al que se aplica.swing. ventana. import java.setLayout(new BoxLayout(panelContenido. Antes de seguir comentando este gestor de diseño ofrecido por Swing. el panel (JPanel) sobre el que se va a aplicar el gestor de diseño y la orientación en la que se van a distribuir los componentes dentro de dicho panel.BoxLayout. El constructor de la clase BoxLayout posee dos argumentos.X_AXIS. ventana.*.setContentPane(panelContenido).exit(0).setVisible(true).pack(). Este último parámetro es un entero que se corresponde con las siguientes constantes definidas en la clase BoxLayout:  X_AXIS: los componentes se distribuyen de izquierda a derecha. representa a un nuevo gestor de diseño ofrecido por Swing. Si retomamos el ejemplo anterior y cambiamos la constante BoxLayout.awt.add(new JButton("Soy un botón más")). JPanel panelContenido=new JPanel(). } } En el ejemplo anterior podemos comprobar la forma de crear un gestor de diseño para distribuir los componentes de arriba a abajo. se obtiene el resultado que muestra continuación: 209 . Se puede decir que es una versión ampliada del gestor de diseño FlowLayout que ofrece AWT. ventana.event. uno encima del otro y también de izquierda a derecha uno al lado del otro. que podemos encontrar en el paquete javax. import javax. public class BoxLayoutSencillo{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout"). ventana. panelContenido. panelContenido. panelContenido.add(new JButton("Soy el último")).*.

0))).BoxLayout. ventana.createLineBorder(Color. panelInferior. 210 .CENTER). public class DosBoxLayout{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout").BoxLayout. panelInferior.30)). panelSuperior. JPanel panelSuperior=new JPanel().add(panelSuperior. } } El interfaz que genera este código es: A la vista del código se puede decir que este interfaz está compuesto por dos paneles los que se han aplicado un gestor de diseño BoxLayout distinto.event.setLayout(new BoxLayout(panelSuperior.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.getContentPane(). se suele utilizar la clase Box.*.awt.BorderLayout.add(new JButton("Botón 2")).add(new JTextArea(5.Conjuntamente con la clase BoxLayout. panelInferior.add(Box. panelInferior. esta clase ofrece una serie de métodos para controlar de una forma más precisa la forma en la que se distribuyen los componentes dentro de un panel al que se le ha aplicado este gestor de diseño BoxLayout.setBorder(BorderFactory.setVisible(true). ventana. uno de arriba a abajo y otro de izquierda a derecha.add(panelInferior.add(Box.red)).add(new JLabel("Esto es una etiqueta")).add(Box. JPanel panelInferior=new JPanel(). import java. panelSuperior.getContentPane(). panelInferior. panelInferior.awt. panelSuperior.*.swing.green)).pack(). ventana. } }). import javax.exit(0).X_AXIS)).createHorizontalGlue()).5))).createLineBorder(Color.NORTH).createRigidArea(new Dimension(0. ventana.*. panelSuperior.BorderLayout.setBorder(BorderFactory. ventana. import java.createRigidArea(new Dimension(10. panelSuperior.setLayout(new BoxLayout(panelInferior.add(new JButton("Botón 1")).Y_AXIS)).

el resultado hubiera sido la Figura siguiente: A la vista de la imagen se puede decir que el área se ha extendido entre los dos botones. 211 . Si modificamos el primer ejemplo visto en este apartado tenemos: import java.CENTER_ALIGNMENT).exit(0). La clase Box ofrece también el método createVerticalGlue().RIGHT_ALIGNMENT). aunque para que no existan problemas de alineación todos los componentes deben tener la misma. JButton boton4=new JButton("Soy el último"). boton3.event. JButton boton2=new JButton("Soy un botón más"). Si la llamada al método createHorizontalGlue() la hubiéramos realizado en el lugar en la que se encuentra la llamada al método createRigidArea().addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. En este panel inferior también se utiliza el método createRigidArea() para separar los dos botones diez pixels. JButton boton1=new JButton("Soy un botón"). en este caso el área invisible se extiende de forma vertical enviando los componentes dentro del panel hacia la zona inferior.setAlignmentX(Component. import java. en este caso se ha utilizado un área sólo con componente horizontal. es decir. El método createHorizontalGlue() crea un área invisible que crece horizontalmente para rellenar todo el espacio libre disponible dentro del contenedor. En este caso se ha indicado una separación vertical de cinco pixels. En el segundo panel se utiliza otro método de la clase Box. public class BoxLayoutSencillo{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout").setAlignmentX(Component. JPanel panelContenido=new JPanel(). boton1. ventana.Se ha aplicado un borde a cada uno de estos dos paneles para distinguirlos más claramente. enviando al segundo botón a la derecha del todo.*. JButton boton3=new JButton("Otro botón"). En el primer panel se ha utilizado el método createRigidArea() de la clase Box para crear una separación fija (área rígida) invisible entre la etiqueta (JLabel) y el área de texto (JTextArea).awt. este método rellena el espacio sobrante y desplaza a los componentes hacia la derecha.*.awt. este método provoca que los dos botones que se añadan a continuación se desplacen hacia la derecha. El gestor de diseño BoxLayout respeta el tamaño máximo de los componentes que contiene y también la alineación establecida por los mismos. el método createHorizontalGlue(). } }).

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. JButton boton4=new JButton("Soy el último").boton4. import java. JButton boton3=new JButton("Otro botón"). panelContenido.Y_AXIS)).CENTER_ALIGNMENT).setAlignmentX(Component. boton2. panelContenido. panelContenido. ventana.setVisible(true).setContentPane(panelContenido). } }). panelContenido. ventana.setLayout(new BoxLayout(panelContenido. ventana.setLayout(new BoxLayout(panelContenido.add(boton3). boton1. JButton boton2=new JButton("Soy un botón más").*.CENTER_ALIGNMENT). panelContenido.awt.pack().BoxLayout.pack(). panelContenido. public class BoxLayoutSencillo{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout").setAlignmentX(Component.exit(0).setAlignmentX(Component.setVisible(true).setAlignmentX(Component.CENTER_ALIGNMENT). } } 212 .*.CENTER_ALIGNMENT). panelContenido. panelContenido. ventana.swing. import javax. ventana.awt.add(boton1).setAlignmentX(Component. ventana.add(boton4).add(boton4).event. JButton boton1=new JButton("Soy un botón"). panelContenido.BoxLayout. } } La alineación se respetará en este otro ejemplo. ventana.CENTER_ALIGNMENT).add(boton1). import java.*.setContentPane(panelContenido). boton4.add(boton3). JPanel panelContenido=new JPanel(). panelContenido.add(boton2). boton3.Y_AXIS)).add(boton2).

La clase UIManager ofrece un método estático llamado setLookAndFeel(). Al igual que ocurría con el Look & Feel de Windows. Se pueden distinguir cuatro Look & Feel estándar distintos:  Java (Metal): se trata del Look & Feel por defecto y es el que se ha estado utilizando en todos los ejemplos de los componentes Swing.swing. éste únicamente puede ser utilizado en plataformas Windows. tienen la característica común que todas ellas heredan de la clase abstracta javax. Para indicar un Look & Feel determinado en una aplicación Java utilizaremos la clase UIManager (gestor de interfaz gráfico) que se encuentra en el paquete javax.MotifLookAndFeel. que es el Look & Feel de Java. este Look & Feel está restringido a una plataforma específica.motif. A diferencia del anterior Look & Feel.plaf.MacLookAndFeel.plaf.windows. Se corresponde con la implementación de la clase javax. a nuestra aplicación Java le podemos asignar un aspecto específico. ya que en nuestros ejemplos no hemos especificado ningún Look & Feel. Este Look & Feel es implementado por la clase com. Este Look & Feel lo podemos utilizar en cualquier plataforma.java.swing.  Mac: este último Look & Feel es el correspondiente a los sistemas Macintosh. esta plataforma es la plataforma Mac OS. Todas estas clases que implementan un Look & Feel determinado.metal.LookAndFeel. que es el aspecto que tienen las plataformas de Sun.WindowsLookAndFeel.Estableciendo el Look & Feel En el capítulo anterior comentábamos que una característica que ofrece Swing es el aspecto y comportamiento configurable de sus componentes. 213 .java. Cuando no se indica ningún Look & Feel determinado Swing utiliza el Look & Feel por defecto. como veremos un poco más adelante.swing.swing. es decir.plaf. que recibe como parámetro una cadena que especifica la clase que se corresponde con el Look & Feel que deseamos asignar a nuestra aplicación Java. Se encuentra en al clase javax.  Motif: representa el aspecto CDE/Motif. y al igual que el Look & Feel de Java puede ser utilizado en cualquier plataforma.mac.MetalLookAndFeel.  Windows: es aspecto que presentan los sistemas Windows y lo encontramos implementado en la clase com. Incluso. podemos establecer y cambiar en tiempo de ejecución de nuestra aplicación su Look & Feel.sun.swing. también denominado Metal (fue el código que se le dio al proyecto que lo desarrolló). lo que se denomina Pluggable Look & Feel.sun.plaf.swing.

out. para que se redimensionen todos los componentes según su nuevo Look & Feel. y el segundo caso se corresponde con el nombre de la clase que ofrece el Look & Feel de Java. En este caso además de utilizar el método setLookAndFeel() de la clase UIManager. try { UIManager.updateComponentTreeUI(contenedor). presente también en el paquete javax.setLookAndFeel(UIManager. conjuntamente con el método setLookAndFee() se puede ver en el Código siguiente. La utilización de este método. Por lo tanto estos dos métodos se pueden utilizar como argumento para el método setLookAndFeel(). utilizaríamos el Código: try { UIManager. para que de esta forma todos actualicen su Look & Feel en tiempo de ejecución. podemos establecer el Look & Feel de la aplicación en tiempo de ejecución. cuando el Look & Feel que queremos utilizar no es soportado por la plataforma actual. además del método setLookAndFeel(). } catch (Exception e) { } new AplicacionSwing().sun.motif.println("No se pudo asignar el Look & Feel"). } catch (Exception e) { } 214 . que es el Look & Feel que se garantiza funcionará correctamente para todas las plataformas. El método updateComponentTreeUI() de la clase SwingUtilities debe utilizarse para cada uno de los contenedores de alto nivel del interfaz de usuario de la aplicación.El método setLookAndFeel() de la clase UIManager lanza una excepción de la clase UnsupportedLookAndFeelException. this.swing. try { UIManager.java. De esta forma si queremos que nuestra aplicación posea el Look & Feel de Motif deberemos incluir el siguiente código dentro del método main() de la aplicación. Ambos métodos devuelven una cadena.MotifLookAndFeel"). como ya hemos adelantado al comienzo de este apartado.pack(contenedor). estos métodos son getSystemLookAndFeelClassName() y getCrossPlatformLooAndFeelClassName().plaf.setLookAndFeel(lf). que se encuentra también dentro del paquete javax. La clase UIManager.setLookAndFeel("com.swing. se puede establecer una vez que la aplicación ya se ha iniciado y el interfaz de usuario es visible. es decir. así por ejemplo si deseamos aplicar el Look & Feel de la plataforma sobre la que se ejecuta la aplicación. deberemos atrapar por lo tanto esta excepción cuando invoquemos el método setLookAndFeel(). } En este caso se supone que sólo existe un contenedor de alto nivel.getSystemLookAndFeelClassName()). nos ofrece otros dos métodos que pueden resultar de utilidad.swing. } catch (Exception excepcion) { System. Pero el Look & Feel. SwingUtilities. deberemos utilizar el método estático updateComponentTreeUI() de la clase SwingUtilities. El método updateComponentTreeUI() recibe como argumento un objeto de la clase Component que representa el contenedor de alto nivel sobre el que se quiere actualizar su Look & Feel. Además es recomendable lanzar el método pack() sobre cada uno de los contenedores de alto nivel del interfaz de usuario. en el primer caso se corresponde con el nombre de la clase del Look & Feel de la plataforma sobre la que se está ejecutando la aplicación.

Para mostrar la característica Pluggable Look & Feel de Swing se va a utilizar un sencillo ejemplo que consiste una aplicación con una ventana (JFrame) que permite especificar el Look & Feel en tiempo de ejecución. además de contener diversos componentes Swing.setLayout(new BoxLayout(getContentPane(). El código fuente perteneciente al constructor de nuestra clase se puede observar : public LF(){ super("Pluggable Look & Feel"). Al ejecutar la aplicación el aspecto que muestra es el de la Figura. this. debido a esto al arrancar la aplicación comienza a ejecutarse utilizando el Look & Feel de Java. } catch (Exception e) { } getContentPane(). LA ventana de la aplicación del ejemplo. cuatro de ellos para cada uno de los distintos Look & Feel (Java. Antes de seguir comentando más detalles de esta aplicación de ejemplo. existen cinco botones de opción. vamos a mostrar el aspecto que tendría esta aplicación. Windows. Es decir. y que al seleccionar cada uno de ellos se aplicará sobre la aplicación el Look & Feel que representa cada opción.exit(0). Al iniciarse su ejecución dentro del constructor de la aplicación.Y_AXIS)).BoxLayout. } En el constructor además de establecer el Look & Feel de Java se establece el gestor de diseño que va a utilizar el panel de contenido de la ventana. se establece el Look & Feel mediante el nombre de la clase devuelto por el método getCrossPlatformLookAndFeelClassName() de la clase UIManager. Motif y Mac) y otro para seleccionar el Look & Feel de la plataforma sobre la que se ejecuta la aplicación.getCrossPlatformLookAndFeelClassName()). y se corresponde con el Look & Feel de Java.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. contiene cinco botones de opción (JOptionButton) agrupados.setLookAndFeel(UIManager. El gestor de diseño que se 215 . } }). try { UIManager.

ya que el código fuente de la aplicación de ejemplo es bastante sencillo y se utilizan componentes Swing vistos en los capítulos anteriores. en su variante de distribución de componentes de arriba abajo (BoxLayout. y además en mi caso particular el Look & Feel del sistema (Look & Feel de la plataforma actual) será por lo tanto el de Windows. ya que he utilizado una plataforma Windows para ejecutar la aplicación de ejemplo. cada una con otro nuevo Look & Feel. De la figura anterior también se puede comprobar que la opción seleccionada por defecto se corresponde lógicamente con el Look & Feel que presenta la aplicación inicialmente. en los que se ha ofrecido el código completo del ejemplo. La primera corresponde al Look & Feel de Windows y la segunda al Look & Feel de Motif.utiliza es BoxLayout. descrito en el apartado anterior. No vamos hacer como en otros ejemplos de este curso. Podemos ir asignando a la aplicación los distintos Look & Feel seleccionando la opción correspondiente. En mi caso no he podido utilizar el Look & Feel de Mac. sólo vamos a mostrar y comentar aquellos fragmentos que resultan más interesantes (sobre todo desde el punto de vista de la característica Pluggable Look & Feel).Y_AXIS). por lo tanto éste Look & Feel no estará disponible. 216 . A continuación se muestran otras dos figuras.

grupo. opSistema.java. else if(fuente==opMotif) lf="com. Será en este método dónde se establezca el Look & Feel seleccionado a través de los distintos botones de opción. opMac.add(panelOpciones).addActionListener(this). grupo.5)).swing. conjuntamente con el constructor de la clase.windows.VK_J). es dónde utilizamos métodos y clases relacionados directamente con el mecanismo Pluggable Look & Feel.WindowsLookAndFeel".add(opWindows).VK_M). opMotif.VK_W).plaf.add(opJava). opMotif. if (fuente==opWindows) lf="com. cuyo código veremos: public void creaOpciones(){ panelOpciones=new JPanel().addActionListener(this).plaf. opSistema=new JRadioButton("Sistema"). opJava. panelOpciones. opWindows. opJava. opMac.5. //se agrupan las opciones ButtonGroup grupo=new ButtonGroup().MetalLookAndFeel".setBorder(BorderFactory. panelOpciones.setLayout(new GridLayout(1. opMotif=new JRadioButton("Motif").createLoweredBevelBorder()). panelOpciones. else if(fuente==opJava) lf="javax.addActionListener(this).swing. opSistema. opWindows=new JRadioButton("Windows"). pero si que es interesante mostrar como se crean las opciones que permiten seleccionar el Look & Feel de la aplicación.setMnemonic(KeyEvent. panelOpciones. getContentPane(). opMac=new JRadioButton("Mac"). grupo.java.MotifLookAndFeel".add(opMac).swing.addActionListener(this). opWindows.setSelected(true).setMnemonic(KeyEvent.add(opSistema).getSource().public class LF extends JFrame implements ActionListener{ Como se puede ver es una sencilla ventana que va a contener una serie de componentes Swing. No vamos a detenernos en la creación de los distintos componentes del interfaz de usuario. Para crear las opciones que representan los distintos LooK & Feel se ha utilizado el método creaOpciones().VK_S).add(opSistema).add(opWindows).add(opMotif).VK_C).5.setMnemonic(KeyEvent.setMnemonic(KeyEvent. opJava. panelOpciones.add(opMac).addActionListener(this).add(opJava). 217 . } La pulsación de cada opción será tratada dentro del método actionPerformed() que realmente.sun. grupo. opJava=new JRadioButton("Java/Metal"). public void actionPerformed(ActionEvent evento){ Object fuente=evento. grupo. A continuación se ofrece el código fuente perteneciente al método actionPerformed().setMnemonic(KeyEvent.sun. panelOpciones. String lf="".plaf. panelOpciones.metal.motif.add(opMotif).

utilizando una plataforma Windows. 218 .swing. } catch(IllegalAccessException e){ texto.pack().\n"+excepcion+"\n").\n"+excepcion+"\n").getSystemLookAndFeelClassName().\n"+e+"\n"). se decidimos atrapar la excepción UnsupportedLookAndFeelException. Si en mi caso particular. else if(fuente==opSistema) lf=UIManager.mac.MacLookAndFeel". } catch (InstantiationException excepcion){ texto. el código de este método es bastante sencillo.setLookAndFeel(lf).append("Excepción de instanciación. obtendré una excepción lanzada por el método setLooAndFeel(). lo único que se hace es establecer el Look & Feel que se corresponde con la opción pulsada.append("Excepción de acceso.append("Clase no encontrada. Si ocurre una excepción se muestra en el área de texto (JTextArea) de la aplicación. selecciono la opción correspondiente al Look & Feel de Mac. } catch (UnsupportedLookAndFeelException excepcion) { texto. this. se nos obligará a atrapar tres excepciones más. try { UIManager.append("Look & Feel no soportado.\n"+excepcion+"\n").updateComponentTreeUI(this). } } Como se puede comprobar a la vista del código anterior. SwingUtilities. } catch (ClassNotFoundException excepcion){ texto.else if(fuente==opMac) lf="javax. Por lo demás.plaf. esto se puede observar en la Figura. si se tiene en cuenta lo explicado hasta el momento.

save.getItem(). public void init() { Container cp = getContentPane().addItemListener(this). cp.*.*.gif")). public class CampoTexto extends JApplet { JPasswordField jtf. cp.add(jl).event. import javax.swing.setEchoChar('*').awt.*. 219 .add(jtf).*. jl.*.addItem("open").gif")).*.swing. import java.awt. import javax. import java. import javax.setLayout(new FlowLayout()).add(jc). public class BotoneImagen extends JApplet implements ActionListener { JTextField jtf. } public void itemStateChanged(ItemEvent ie) { String s = (String)ie. cp. jtf. cp. jc.*. } } JcomboBox (Combos) import java.swing. } } Jbutttton (Botones) import java. //import java. public class ComboImagen extends JApplet implements ItemListener { JLabel jl.*. public void init() { Container cp = getContentPane().addItem("save"). JComboBox jc = new JComboBox(). cp. delete. ImageIcon open. jtf = new JPasswordField(15). import java.awt. jl = new JLabel(new ImageIcon("open. jc.Ejemplos de Swing Campos de Texto.awt. jc.*.setLayout(new FlowLayout()).event. jc.text.awt. public void init() { Container cp = getContentPane().addItem("delete").swing.setIcon(new ImageIcon(s + ".

getActionCommand()). } } Componentes ficha (Tabbed Pane) import javax. jb. } } class Ciudades extends JPanel { public Ciudades() { JButton b1 = new JButton("San Vicente").addTab("Savor".cp. jb. } public void actionPerformed(ActionEvent ae) { jtf. cp.add(jtf).setActionCommand("salvar").add(jtp).setLayout(new FlowLayout()).addTab("Ciudad". jtp. public class JTabbedPaneEjemplo extends JApplet { public void init() { JTabbedPane jtp = new JTabbedPane().setText(ae.setActionCommand("borrar").gif"). add(b3).addActionListener(this).add(jb).gif").addActionListener(this). } } class Colores extends JPanel { public Colores() { 220 . jtp. jb = new JButton(borrar). jb. add(b4). ImageIcon salvar = new ImageIcon("save. JButton b4 = new JButton("San Miguel"). new Ciudades()). jb. cp.addTab("Color". ImageIcon borrar = new ImageIcon("delete. add(b1). JButton b3 = new JButton("Santa Ana"). JButton jb = new JButton(abrir). jb. JButton b2 = new JButton("San Salvador"). getContentPane().add(jb). ImageIcon abrir = new ImageIcon("open.*. add(b2). jb = new JButton(salvar). cp.setActionCommand("abrir"). jtf = new JTextField(15).swing. new Colores()). jb. new Savores()).addActionListener(this). cp.add(jb). jtp.gif").

221 .tree.add(a2).awt. // Creando el nodo raiz DefaultMutableTreeNode tope = new DefaultMutableTreeNode("Opciones"). // Creando el subarbol "A" DefaultMutableTreeNode a = new DefaultMutableTreeNode("A"). DefaultMutableTreeNode a2 = new DefaultMutableTreeNode("A2"). jcb.addItem("Vainilla").swing. a. JCheckBox cb2 = new JCheckBox("Verde"). tope. public void init() { // Obtener el content pane Container contentPane = getContentPane().swing. a.add(a). jcb. /* <applet code="Arboles" width=400 height=200> </applet> */ public class Arboles extends JApplet { JTree arbol.*.JCheckBox cb1 = new JCheckBox("Rojo"). import javax.*.event. } } Arboles (Trees) import java.addItem("Chocolate").awt.add(a1). DefaultMutableTreeNode a1 = new DefaultMutableTreeNode("A1"). } } class Savores extends JPanel { public Savores() { JComboBox jcb = new JComboBox().setLayout(new BorderLayout()). add(cb3). add(cb1).*. JTextField jtf. import java. // Creando el subarbol "B" DefaultMutableTreeNode b = new DefaultMutableTreeNode("B"). import javax.addItem("Fresa"). // Configurando el layout contentPane.*. tope. JCheckBox cb3 = new JCheckBox("Azul"). jcb.add(b). add(cb2). add(jcb).

*.swing. import javax. // implementar la clase interna para eventos de raton arbol.*. { "Roberto". contentPane. "25". // Inicializando los datos final Object[][] datos = { { "Luis". // agregando text field to applet jtf = new JTextField("".add(jsp. if(tp != null) jtf.DefaultMutableTreeNode b1 = new DefaultMutableTreeNode("B1").getPathForLocation(me. "24". // agregando al scroll pane int v = ScrollPaneConstants. // Manejador layout contentPane.CENTER). } } Tablas(Tables) import java. "M" }. b. h).awt. DefaultMutableTreeNode b3 = new DefaultMutableTreeNode("B3"). else jtf.toString()).getX(). v. } }).HORIZONTAL_SCROLLBAR_AS_NEEDED. BorderLayout.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent me) { doMouseClicked(me). "M" }.SOUTH).VERTICAL_SCROLLBAR_AS_NEEDED. "F" }. // agregando el scroll pane al content pane contentPane. public class Tablas extends JApplet { public void init() { Container contentPane = getContentPane().add(b3). "Sexo" }. // Creando el arbol arbol = new JTree(tope). int h = ScrollPaneConstants.add(b2). JScrollPane jsp = new JScrollPane(arbol.setText(""). } void doMouseClicked(MouseEvent me) { TreePath tp = arbol.getY()). BorderLayout. b. b.add(jtf. DefaultMutableTreeNode b2 = new DefaultMutableTreeNode("B2").add(b1). { "Maria". "28". 20).setLayout(new BorderLayout()). 222 .setText(tp. "Edad". me. // Inicializando las columnas final String[] cabecera = { "Nombre".

JScrollPane jsp = new JScrollPane(tabla. h). contentpane. import java. de JComponent. JButton boton2 = new JButton("Salir").setVisible(true). 223 . // Crear la tabla JTable tabla = new JTable(datos.getContentPane(). "F" }.*.addActionListener(this).CENTER).*. "20". contentpane. Lo primero es hacerse con el objeto gráfico del componente sobre el cual queremos dibujar. Si deseamos dibujar algo lo que más normal es acudir a la documentación de las librería y buscar en ella los métodos que necesitemos. boton2. { "Laura".400).SOUTH). public class Dibujar1 extends JFrame implements ActionListener{ public Dibujar1(){ setSize(400. JPanel p =new JPanel(). { "Elena".awt. Veamos un ejemplo de esto. Graphics g = Componente.CENTER). x2) es el punto de inicio de la línea y (x3. int h = ScrollPaneConstants. "24". } } Empezando a dibujar con Swing A continuación vamos a ver qué tenemos que hacer para dibujar en Swing. import java. import javax. BorderLayout. contentpane. boton. El objeto gráfico es un objeto que posee toda la información que un componente necesita para dibujarse en pantalla. boton2. A modo de ejemplo. por lo que no haremos aquí una revisión de ellos.HORIZONTAL_SCROLLBAR_AS_NEEDED.*.swing. p. Estos métodos son tan intuitivos como numerosos.getGraphics() Una vez obtenido dicho objeto gráfico procedemos a dibujar empleando los métodos que dicho objeto nos proporciona. setTitle("Dibujo").setActionCommand("Dibujar"). BorderLayout.setActionCommand("Salir"). Ejemplo 1. BorderLayout.{ "Cesar".add(boton). x4) el fin de la línea.addActionListener(this). Container contentpane = this. "M" }. boton.event. p. JButton boton = new JButton("Dibujar").awt.add(jsp.setLayout (new BorderLayout()).add(panel. // agregando scroll pane int v = ScrollPaneConstants. int x2. "F" } }. cabecera). this.add(boton2). int x3 int x4) en el cual (x1.add(p. Para obtener el objeto gráfico empleamos el método getGraphics(). // agregando al content pane contentPane. "19". si queremos dibujar una línea y vamos a la documentación de la clase Graphics encontraremos un método drawLine(int x1.VERTICAL_SCROLLBAR_AS_NEEDED. v.

getGraphics(). boton. 150. 80. 150). 200.drawRect(100. contentpane.add(boton).drawLine(150. setTitle("Dibujo"). Además el componente se dibujará cuando se crea y cuando se invoque el método repaint(). g. import java. import javax. contentpane. Este es el motivo por el cual en nuestro ejemplo anterior al minimizar y luego maximizar la pantalla dejamos de ver lo que habíamos dibujado. public class Dibujar2 extends JFrame implements ActionListener{ public Dibujar2(){ setSize(400. 90. p.exit(0). Si queremos que siempre que el componente se redibuje apareciesen nuestros dibujos hemos de sobrescribir el método paintComponent y escribir en el código necesario para realizar estos dibujos.getWidth(). En este método se halla toda la información que se necesita para dibujar el componente en pantalla. g.swing.getHeight()).*.setColor(Color.event. g. } JPanel panel = new JPanel().add(p.getSize()). BorderLayout.equals("Salir")){ System. public static void main(String[] args){ new Dibujar1(). g.*. Cuando este método es invocado lo único que aparecerá en el componente es lo que se dibuje desde el. 200).drawLine(0. JButton boton = new JButton("Dibujar"). 100).0.getSize()).} public void actionPerformed(ActionEvent e){ String comando = e.400).addActionListener(this). JPanel p =new JPanel().fillRect(110.SOUTH). Container contentpane = this. 224 .setLayout (new BorderLayout()).awt. 100. } Graphics g = panel.*.awt. Veamos como haríamos esto sobre el ejemplo Dibujar1: Ejemplo 2. import java. g. JButton boton2 = new JButton("Salir").getActionCommand().red).blue). Causas externas a un componente que fuerzan que este se “redibuje” son que la ventana en la que está se minimiza y luego se maximiza o que otra ventana se ponga encima de la ventana que lo contiene. } } El método paintComponent Cuando cualquier componente de las librerías Swing por cualquier razón necesita “redibujarse” en pantalla llama al método paintComponent. 150. g.(int) (this.setColor(Color.getContentPane().(int)(this. if(comando.setActionCommand("Dibujar"). boton. todo lo demás es “borrado”.

BorderLayout.0. panel. contentpane. 100). boton2.add(boton2). g.getGraphics(). 100. this.boton2. }} class MyPanel extends JPanel{ public void paintComponent(Graphics g){ g.paintComponent(g). p. } public void actionPerformed(ActionEvent e){ String comando = e.CENTER).blue). public static void main(String[] args){ new Dibujar2(). 80.getHeight()). }} 225 .equals("Salir")){ System.drawLine(0.setVisible(true).setColor(Color. 90. 200.addActionListener(this). 150).setColor(Color.(int)(this.setActionCommand("Salir"). 150. g.getSize()). 150.(int) (this. if(comando. } Graphics g = panel. g.exit(0). } MyPanel panel = new MyPanel().drawLine(150.getSize()). g.getActionCommand().drawRect(100. 200). g.getWidth().fillRect(110.red).add(panel.

226 .

y descargable automáticamente desde la red. fácil de usar. seguro. JDBC suministra un API estándar para los desarrolladores y hace posible escribir aplicaciones de base de datos usando un API puro Java. 1. siendo robusto. Dependiendo de varios factores. Un único programa escrito usando el API JDBC y el programa será capaz de enviar sentencias SQL a la base de datos apropiada. es un lenguaje base excelente para aplicaciones de base de datos. tampoco es necesario escribir diferentes aplicaciones para ejecutar en diferentes plataformas. En otras palabras. Java. 227 . Y. otro para acceder a Oracle y otro para acceder a Informix. no es necesario escribir un programa que acceda a una base de datos Sybase. o ser una mezcla de Java y métodos nativos JNI (Java Native Interface). fácil de entender.. INTRODUCCION JDBC Java Database Connectivity (JDBC) es una interfase de acceso a bases de datos estándar SQL que proporciona un acceso uniforme a una gran variedad de bases de datos relacionales. 1.1 ¿Qué es JDBC? JDBC es el API para la ejecución de sentencias SQL. Consiste en un conjunto de clases e interfases escritas en el lenguaje de programación Java. La combinación de Java y JDBC permite al programador escribir una sola vez y ejecutarlo en cualquier entorno. es necesario disponer del driver JDBC apropiado que haga de intermediario entre ésta y JDBC. no obstante a menudo es conocido como “Java Database Connectivity”). (Como punto de interés JDBC es una marca registrada y no un acrónimo. Drivers JDBC Para usar JDBC con un sistema gestor de base de datos en particular. este driver puede estar escrito en Java puro. JDBC también proporciona una base común para la construcción de herramientas y utilidades de alto nivel. con el API JDBC. Usando JDBC es fácil enviar sentencias SQL virtualmente a cualquier sistema de base de datos. con una aplicación escrita en el lenguaje de programación Java.

getString("b"). la necesidad de acceso fácil a base de datos desde Java continúa creciendo. while (rs. "login". con Java y JDBC API. } 1.1. c FROM Table1").2 JDBC es un API de bajo nivel y una base para API’s de alto nivel. 1. pero está diseñado de forma que también sea la base sobre la cual construir interfaces y herramientas de alto nivel. Con cada vez más y más programadores desarrollando en lenguaje Java. es posible publicar una página web que contenga un applet que usa información obtenida de una base de datos remota. Por ejemplo. En esta función trabaja muy bien y es más fácil de usar que otros API‟s de conexión a bases de datos. Macintosh y UNIX) a una base de datos interna vía intranet.1 ¿Qué hace JDBC? Simplemente JDBC hace posible estas tres cosas:    Establece una conexión con la base de datos. Statement stmt = con. O una empresa puede usar JDBC para conectar a todos sus empleados (incluso si usan un conglomerado de máquinas Windows.executeQuery("SELECT a.next()) { int x = rs. String s = rs. Una interfase de alto nivel es „amigable‟.1. lo que quiere decir que se usa para „invocar‟ o llamar a comandos SQL directamente. b.getFloat("c"). Envía sentencias SQL Procesa los resultados. "password").createStatement(). ResultSet rs = stmt. float f = rs.JDBC expande las posibilidades de Java. 228 . usa un API mas entendible o más conveniente que luego se traduce en la interfase de bajo nivel tal como JDBC.getInt("a").getConnection ( "jdbc:odbc:wombat". JDBC es una interfase de bajo nivel. El siguiente fragmento de código nos muestra un ejemplo básico de estas tres cosas: Connection con = DriverManager.

. Cuando se usa ODBC. entonces. de hecho. Como el driver JDBC esta completamente escrito en Java. ha sido diseñado para mantener las cosas sencillas mientras que permite las características avanzadas cuando éstas son necesarias. la robustez y en la portabilidad automática de las aplicaciones. ODBC es difícil de aprender. La respuesta es que se puede usar ODBC desde Java.ODBC no es apropiado para su uso directo con Java porque usa una interface C. Mezcla características simples y avanzadas juntas.1. JDBC por otro lado. ODBC. Por ejemplo. Más recientemente Microsoft ha introducido nuevas API detrás de ODBC. 2. pero es preferible hacerlo con la ayuda de JDBC mediante el puente JDBC-ODBC. Ofrece la posibilidad de conectar a la mayoría de las bases de datos en casi todas las plataformas.3 JDBC frente a ODBC y otros API’s En este punto. Las llamadas desde Java a código nativo C tienen un número de inconvenientes en la seguridad. la implementación. portable y seguro en todas las plataformas Java. En resumen. 229 . Se puede pensar en JDBC como un ODBC traducido a una interfase orientada a objeto que es el natural para programadores Java. La pregunta es ahora ¿por qué necesito JDBC?. ambos interfaces están basados en el X/Open SQL CLI (Call Level Interface). el ODBC de Microsoft (Open Database Connectvity). RDO. puesto que se les da una orientación a objeto basándose en clases que se implementan sobre ODBC.. desde Java?. el código JDBC es automáticamente instalable. Un API Java como JDBC es necesario en orden a permitir una solución Java “pura”. el gestor de drivers de ODBC y los drivers deben instalarse manualmente en cada máquina cliente. el API JDBC es el interfase natural de Java para las abstracciones y conceptos básicos de SQL. Hay varias respuestas a estas preguntas: 1.1. y sus opciones son complejas para „querys‟ simples. 4. Estos diseños se mueven en la misma dirección que JDBC en muchas maneras. 3. ADO y OLE DB. Java no tiene punteros. es probablemente el API más extendido para el acceso a bases de datos relacionales. JDBC retiene las características básicas de diseño de ODBC. ¿Por qué no usar.Una traducción literal del API C de ODBC en el API Java podría no ser deseable. incluyendo el notoriamente propenso a errores “void * “. y ODBC hace un uso copioso de ellos.

Esta es una configuración Cliente/Servidor en la que la máquina del usuario es el cliente y la máquina que hospeda a la base de datos es el servidor. Otra ventaja es que el usuario puede emplear un API de alto nivel más sencillo que es traducido por el „piso intermedio‟ en las llamadas de bajo nivel apropiadas. que ofrecen un rendimiento más rápido. La red puede ser una intranet. En el modelo de tres-pisos. o puede ser Internet. que envía las sentencias SQL a la base de datos. En el modelo de dos-pisos. Finalmente en muchos casos la arquitectura de tres niveles puede proporcionar ventajas de rendimiento. El API JDBC soporta los modelos en dos y tres pisos de acceso a base de datos. Los directores de IS encuentran este modelo muy atractivo por que el „piso intermedio‟ hace posible mantener el control sobre los datos y los tipos de actualizaciones que pueden hacerse en los datos corporativos.4 Modelos en dos y tres pisos. La base de datos procesa las sentencias SQL y devuelve los resultados a el „piso intermedio‟. La base de datos puede estar localizada en otra máquina a la que el usuario se conecta mediante la red. y el resultado de estas sentencias se envían al usuario. Aplicacion Java Máquina cliente JDBC Protocolo propietario DBMS DBMS Servidor de BD. De cualquier modo. este nivel intermedio ha sido escrito en lenguajes como C ó C++. se está convirtiendo en práctico desarrollar este nivel intermedio en Java.1. que conecta a los empleados dentro de la corporación. 230 . con la introducción de compiladores optimizadores que traducen el bytecode en código máquina eficiente. Esto requiere un driver JDBC que pueda comunicar con el gestor de base de datos particular al que se pretende acceder. los comandos se envían a un „piso intermedio‟ de servicios.1. Hasta ahora. que a su vez lo envía al usuario. un applet Java o una aplicación habla directamente con la base de datos. por ejemplo. Las sentencias SQL de usuario se envían a la base de datos.

pero se corre el riesgo de recibir un error en el DBMS. Aplicacion Java Máquina cliente llamadas HTTP. RML ó CORBA Aplicacion Servidora (Java) JDBC Servidor (Lógica de negocio) Protocolo propietario del DBMS DBMS Servidor de BD. o puede ser una derivación especializada de SQL 231 . Por ejemplo. De hecho una consulta de una aplicación incluso no tiene por que ser SQL. Una de las áreas de dificultad es que aunque muchas DBMS‟s (Data Base Management Systems) usan un formato estándar de SQL para la funcionalidad básica. multiproceso y seguridad de Java. Es de esperar que la porción de SQL que es verdaderamente estándar se expandirá para incluir más y más funcionalidad. Una forma en que el API JDBC trata este problema es permitir que cualquier cadena de búsqueda se pase al driver subyacente del DBMS. 1. el API de JDBC debe soportar SQL tal como es. estos no conforman la sintaxis más recientemente definidas o semánticas para funcionalidades más avanzadas. Entretanto.Esta es una gran ventaja al hacer posible aprovechar las características de robustez.5 SQL Conforme SQL es el lenguaje estándar para el acceso a las bases de datos relacionales. y aquellas que lo hacen no son consistentes con otras. no todas las bases de datos soportan procedimientos almacenados o joins de salida. Esto quiere decir que una aplicación es libre de usar la sentencia SQL tal como quiera.1. de cualquier modo.

La sintaxis de escape provee una sintaxis JDBC estándar para varias de las áreas más comunes de divergencia SQL. Estas pruebas de conformidad chequean la existencia de todas las clases y métodos definidos en el API JDBC. Los desarrolladores de drivers pueden cerciorarse que sus drivers cumplan estas especificaciones mediante la suite de test disponible en el API JDBC.sun. Para aplicaciones complejas. http://java.com/products/jdbc 232 . Por supuesto la información de este apartado será rápidamente obsoleta. 1. ”Sintaxis de escape en Sentencias Objetos”. de servicios de Internet y desarrolladores. Por ejemplo.5. Con la mayor aceptación de JDBC por parte de vendedores de bases de datos. ahí escapes para literales de fecha o procedimientos almacenados. Y es proveer información descriptiva sobre el DBMS por medio de la interfase DatabaseMetaData por la que las aplicaciones pueden adaptarse a los requerimientos y posibilidades de cada DBMS: Como el API JDBC se usará como base para el desarrollo de herramientas de acceso y API‟s de alto nivel . direccionará el problema de la conformidad a cualquiera de estas. y chequean tanto como es posible que la funcionalidad SQL Entry Level esté disponible. Una segunda forma en que JDBC trata este problema es proveer cláusulas de escape al estilo de ODBC . un driver debe soportar al menos el nivel de entrada ANSI SQL-2 Entry Level.1. En orden a usar esta designación. JDBC se está convirtiendo en el estándar de acceso a bases de datos.2 Productos JDBC. que se discutirán en el 4. La designación “JDBC COMPLIANT” se creó para situar un nivel estándar de funcionalidad JDBC en la que los usuarios puedan confiar. La designación “JDBC COMPLIANT” indica que la implementación JDBC de un vendedor ha pasado los tests de conformidad suministrados por JavaSoft. por supuesto. pero esta definición de compliance tiene algún grado de seguridad en una implementación JDBC. Existen una serie de productos basados en JDBC que ya han sido desarrollados. y JavaSoft no esta distribuyendo implementaciones de vendedores. Tales tests no son exhaustivos. JDBC trata la conformidad SQL de una tercera manera.diseñada para especificas DBMS (para consultas a imágenes o documentos por ejemplo).

La suite de testeo JDBXC suministra seguridad y confianza en los drivers JDBC que se ejecutarán en el programa. Actualmente es bastante pequeña y simple. 233 . El puente JDBC-ODBC permite a los drivers ODBC usarse como drivers JDBC.1. Fue implementado como una forma de llegar rápidamente al fondo de JDBC y para proveer de acceso a los DBMS menos populares si no existen drivers JDBC para ellos.2.1 JavaSoft Framework JavaSoft suministra tres componentes JDBC como parte del JDK    El gestor de drivers JDBC La suite de testeo de drivers JDBC El puente JDBC-ODBC El gestor de drivers es la espina dorsal de la arquitectura JDBC. su función principal es conectar las aplicaciones Java al driver JDBC correcto y después soltarlo. Solo los drivers que pasan el test pueden ser designados JDBC COMPLIANT.

Este tipo de driver convierte llamadas JDBC en el protocolo de la red usado por DBMS directamente. debe cargarse en cada máquina cliente que use este driver. Dado que muchos de estos protocolos son propietarios. 1.driver Java nativo JDBC-Net. Nótese que como el driver puente. 4. los fabricantes de bases de datos serán los principales suministradores. este tipo de driver es el más apropiado en un red corporativa donde las instalaciones clientes no son un problema mayor. Este driver traduce llamadas JDBC al protocolo de red independiente del DBMS que después es traducido en el protocolo DBMS por el servidor. Sybase. Este tipo de driver convierte llamadas JDBC en llamadas del API cliente para Oracle. DB2 y otros DBMS.driver Java parcialmente Nativo. este estilo de driver requiere que cierto código binario sea cargado en cada máquina cliente. Esto permite llamadas directas desde la máquina cliente al servidor DBMS y es la solución más práctica para accesos en intranets. 2.. y en muchos casos el código cliente de base de datos. Esperamos que las alternativas 3 y 4 sean las formas preferidas de acceder a las bases de datos desde JDBC. Nótese que el código binario ODBC.. 3..puente JDBC-ODBC más driver ODBC: El producto de JavaSoft suministra acceso vía drivers ODBC. Informix. Como resultado. Este middleware en el servidor de red es capaz de conectar a los clientes puros Java a muchas bases de datos diferentes.. En general esta es la alternativa más flexible.2 Tipos de drivers JDBC Los drivers que son susceptibles de clasificarse en una de estas cuatro categorías. Las categorías 1 y 2 son soluciones interinas cuando no están disponibles drivers directos puros Java. o para una aplicación en el servidor escrito en Java en una arquitectura en tres-niveles.2.. El protocolo específico usado dependerá del vendedor.driver puro Java y nativo-protocolo. 234 .1.

Connection con = DriverManager. daremos primero una breve explicación de URL en general y luego entraremos en una discusión sobre URL‟s de JDBC. 2.getConnection.1. Este método toma una cadena que contiene una URL. o puede tener varias conexiones con varias bases de datos diferentes. Puede pensarse en ella como una dirección. "12Java"). 2. La clase DriverManager.1 Vista Preliminar Un objeto Connection representa una conexión con una base de datos. es mucho más fácil dejar que la clase DriverManager maneje la apertura de la conexión. El método connect de Driver usa esta URL para establecer la conexión.2. Un usuario puede evitar la capa de gestión de JDBC y llamar a los métodos de Driver directamente.1 Apertura de una conexión La forma estándar de establecer una conexión a la base de datos es mediante la llamada al método DriverManager.2 Uso general de URL’s Dado que URL‟s causan a menudo cierta confusión. "oboy".getConnection(url. 235 . Normalmente. intenta localizar un driver que pueda conectar con la base de datos representada por la URL. Una sesión de conexión incluye las sentencias SQL que se ejecutan y los resultados que son devueltos después de la conexión. se chequea con cada driver de la lista hasta que encuentra uno que pueda conectar con la base de datos especificada en la URL. Esto puede ser útil en el caso raro que dos drivers puedan conectar con la base de datos y el usuario quiera seleccionar uno explícitamente. Una URL (Uniform Resource Locator) da información para localizar un recurso en Internet. String url = "jdbc:odbc:wombat". CONEXIÓN 2. El siguiente código muestra como ejemplo una conexión a la base de datos localizada en la URL “jdbc:odbc:wombat” con un user ID de “oboy” y password “12java”. referida como la capa de gestión JDBC. de cualquier modo.1. Una única aplicación puede tener una o más conexiones con una única base de datos. La clase DriverManager mantiene una lista de clases Driver registradas y cuando se llama al método getConnection.

las URL‟s JDBC permiten un nivel de indirección. da información sobre donde se encuentra la fuente de los datos. permite que las URL contengan valores de atributos (pero no los requieren).3 JDBC y URL’s Una URL JDBC suministra una forma de identificar una base de datos para que el driver apropiado pueda reconocerla y establecer la conexión con ella. Los usuarios no tienen por que preocuparse sobre como se forma una URL JDBC. Esto quiere decir que la URL JDBC puede referirse a una base de datos lógica o un host lógico que se traduce dinámicamente al nombre actual por el sistema de nombramiento de la red. el resto de la URL es el path al fichero. el resto de la URL identifica el host y puede opcionalmente dar un path más específico al sitio. las convenciones son necesariamente muy flexibles. por ejemplo. para un applet que quiera hablar con una base de datos dada el abrir la conexión sin necesitar que el usuario realice ninguna tarea de administración de sistemas. Los desarrolladores de drivers son los que determinan actualmente que JDBC URL identifica su driver particular. el siguiente es la URL para la home page de JavaSoft.com/products/jdk/CurrentRelease file:/home/haroldw/docs/books/tutorial/summary. 236 . Tercero. Para los protocolos ftp y http.zip http://java.La primera parte de una URL especifica el protocolo usado para acceder a la información y va siempre seguida por dos puntos.1.sun.html El resto de la URL. Esta URL identifica solo al host: http://java. Si el protocolo es “file” indica que el recurso está en un sistema de ficheros local mejor que en Internet : veamos unos ejemplos: ftp://javasoft. que especifica “file transfer protocol” y http que especifica “hypertext transfer protocol”. por ejemplo. Segundo.com 2. Por ejemplo. las URL‟s JDBC permiten a los desarrolladores de drivers codificar toda la información de la conexión dentro de ella. EL subprotocolo odbc. Esto hace posible. El rol de JDBC es recomendar algunas convenciones a los fabricantes de drivers para su uso. ellos simplemente usan la URL suministrada con el driver que usan. permiten a diferentes drivers usar diferentes esquemas para nombrar las bases de datos.sun. Si el protocolo es file. Primero. Dado que los JDBC URL se usan con varios tipos de drivers. Algunos protocolos comunes son ftp.com/docs/JDK-1_apidocs. todo después de los dos puntos.

y puede tener un subnombre con cualquier sintaxis interna que el fabricante del driver haya escogido. el servicio de nombre puede ser el subprotocolo. para el ejemplo. Un ejemplo sobresaliente de un subprotocolo es “odbc”. la URL especifica que el servicio local DCE resolverá el nombre de la base de datos “accounts-payable” para poder conectar con la base de datos real. El protocolo en una URL JDBC es siempre jdbc . que puede estar soportado por uno o más drivers. el subprotocolo es “odbc” y el subnombre “fred” es el nombre de la fuente de datos ODBC local. El subnombre puede variar dependiendo del subprotocolo. la dirección de red debería incluirse en la URL JDBC como parte del 237 .Esto permite a los administradores de sistemas evitar dar especificaciones de sus hosts como parte del nombre JDBC. y no hay restricción acerca de cual usar. que ha sido reservado para URL‟s que especifican nombres de fuentes de datos estilo ODBC. Si se quiere usar un servicio de nombre de la red (ya que el nombre de la base de datos en la URL JDBC no tiene por que ser su nombre actúal). Por ejemplo para acceder a la base de datos a través del puente JDBC-ODBC.<subprotocol> . La sintaxis para las URL‟s JDBC que se muestra a continuación tiene tres partes separadas por dos puntos: jdbc:<subprotocol>:<subname> Las tres partes se descomponen como sigue: 1 2 jdbc – el protocolo. podría tener una URL como : jdbc:dcenaming:accounts-payable En este ejemplo. Si la base de datos va a ser accesible a través de Internet. por ejemplo. NIS y DCE). En el ejemplo anterior “fred” es suficiente porque ODBC suministra la información restante.el nombre del driver o el nombre del mecanismo de conectividad con la base de datos. Hay una variedad de servicios de nomenclatura de red diferentes (tales como DNS. 3 <subname> . Por tanto. Una base de datos en un servidor remoto requiere más información.una forma de identificar la base de datos. la URL a usar podría ser algo así como lo siguiente: jdbc:odbc:fred En este ejemplo. El punto de un subnombre es para dar información suficiente para localizar la base de datos.

y quisiera registrar “miracle” como el subprotocolo para el driver JDBC que conecte a su DBMS Miracle no tiene que usar sino ese nombre. por poner otro ejemplo. Miracle Corporation.PWD=fooey 2. //hostname:port/subsubname Suponiendo que “dbnet” es un protocolo para conectar a un host.UID=kgh. Por ejemplo.1.1. JDBC no pone ninguna restricción sobre los tipos de sentencias que pueden enviarse: esto da un alto grado de flexibilidad.1.ExtensionCase=LOWER jdbc:odbc:qeora.5 Registro de subprotocolos Un desarrollador de drivers puede reservar un nombre para usar como el subprotocolo en una URL JDBC. JDBC requiere que un driver cumpla al menos ANSI SQL-2 Entry 238 .CacheSize=20. Se requiere de cualquier modo.6 Envío de Sentencias SQL Una vez que la conexión se haya establecido. que el usuario sea responsable de asegurarse que la base de datos subyacente sea capaz de procesar las sentencias SQL que le están siendo enviadas y soportar las consecuencias si no es así. Cuando la clase DriverManager presenta este nombre a su lista de drivers registrados. la URL JDBC debería parecerse a algo como: jdbc:dbnet://wombat:356/fred 2. Ha sido reservado para URL‟s que especifican el estilo ODBC de nombres de fuentes de datos y que tiene la característica de permitir especificar cualquier número de valores de atributos después del subnombre (el nombre de la fuente de datos) La sintaxis completa para el protocolo “odbc” es: jdbc:odbc:<data-source-name>[.4 El subprotocolo “odbc” El subprotocolo “odbc” es un caso especial. una aplicación que intenta enviar una llamada a un procedimiento almacenado a una DBMS que no soporta procedimientos almacenados no tendrá éxito y generará una excepción. 2.subnombre y debería seguir a la convención estándar de nomenclatura de URL. Si fuera. Por ejemplo odbc está reservado para el puente JDBC-ODBC. permitiendo el uso de sentencias específicas de la base de datos o incluso sentencias no SQL. el driver para el que este nombre está reservado debería reconocerlo y establecer una conexión a la base de datos que lo identifica.<attribute-name>=<attribute-value>]* Todos los siguientes son nombres válidos jdbc:odbc jdbc:odbc:qeor7 jdbc:odbc:wombat jdbc:odbc:wombat. se usa para pasar sentencias SQL a la base de datos subyacente.

Un objeto PreparedStatement se usa para sentencias SQL que toman uno o más parámetros como argumentos de entrada (parámetros IN). 239 . Esto significa que los usuarios pueden contar al menos con este nivel de funcionalidad. Un objeto PreparedStatement es potencialmente más eficiente que un objeto Statement porque este ha sido precompilado y almacenado para su uso futuro. 3.1. PreparedStatement tiene un grupo de métodos que fijan los valores de los parámetros IN.. La lista siguiente da una forma rápida de determinar que método Connection es el apropiado para crear los diferentes tipos de sentencias SQL.PreparedStatement – creada por el método prepareStatement. completas y. Instancias de PreparedStatement extienden Statement y por tanto heredan los métodos de Statement. y añade métodos para el manejo de los parámetros OUT e INOUT. los cuales son enviados a la base de datos cuando se procesa la sentencia SQL.7 Transacciones Una transacción consiste en una o más sentencias que han sido ejecutadas. El método createStatement se usa para:  Sentencias SQL simples (sin parámetros). o bien se ha hecho commit o bien roll-back.Level para ser designado JDBC COMPLIANT. Los objetos CallableStatement se usan para ejecutar procedimientos almacenados SQL – un grupo de sentencias SQL que son llamados mediante un nombre. Cuando se llama al método commit o rollback .CallableStatement – creado por el método prepareCall. la transacción actúal finaliza y comienza otra. 2.Statement – creada por el método createStatement. El método prepareStatement se usa para:   Sentencias SQL con uno ó más parámetros IN Sentencias SQL simples que se ejecutan frecuentemente El método prepareCall se usa para:  Llamar a procedimientos almacenados. Estas clases y métodos son los siguientes: 1. JDBC suministra tres clases para el envío de sentencias SQL y tres métodos en la interfaz Connection para crear instancias de estas tres clases. algo parecido a una función ... Un objeto Statement se usa para enviar sentencias SQL simples 2.. Un objeto CallableStatement hereda métodos para el manejo de los parámetros IN de PreparedStatement.

setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED). restaurando los valores existentes l inicio de la transacción. En este caso. A veces un usuario no quiere que tenga efecto un determinado cambio a menos que se efectué otro. Si el modo auto-commit es desactivado. Muchos drivers JDBC soportan transacciones. El método rollback descarta estos cambios. cada sentencia es „commitada‟ individualmente. Normalmente. Un usuario JDBC puede instruir a la DBMS para que un valor que ha sido leído antes del „commit‟ (“dirty reads”) con el siguiente código donde con es el objeto de la actual conexión: con. Por ejemplo. El método commit hace permanente cualquier cambio que una sentencia SQL realiza en la base de datos. si uno o los dos fallan. el nivel de transacción más alto es el más lento en la ejecución de la aplicación. 2. El usuario puede especificar un nivel de aislamiento para indicar que nivel de precaución debería ejercitar el DBMS para la resolución de estos conflictos. Esto puede hacerse desactivando el modo auto-commit y agrupando ambas actualizaciones en una transacción. ¿Debería permitirse. dado que el valor cambiado leído por la segunda transacción será invalido si la primera transacción ha hecho rollback?. La interfase Connection define cinco niveles de aislamiento con el nivel más bajo que especifica que no soporte transacciones hasta el más alto que especifica que mientras una transacción esté abierta ninguna otra transacción puede realizar cambios en los datos leídos por esa transacción. se llama al método rollback. un driver JDBC-compliant debe soportar transacciones. por tanto una transacción se compone de una única sentencia.1.8 Niveles de aislamiento de transacciones Si un DBMS soporta el proceso de transacciones. y libera cualquier bloqueo mantenido por la transacción. DatabaseMetaData suministra información que describe el nivel de transacción soportado por el DBMS. por lo tanto incluirá todas las sentencias que han sido ejecutadas desde la última invocación a uno de los métodos commit o rollback. y esto significa que cuando se completa se llama automáticamente al método commit. tendrá que manejar de alguna forma los potenciales conflictos que puedan surgir cuando dos transacciones están operando sobre una base de datos concurrentemente. ¿que ocurrirá cuando una transacción cambia un valor y una segunda transacción lee el valor antes de que el cambio haya sido „commitado‟ o descartado?. Si ambas actualizaciones tienen éxito se llama al método commit haciendo estos cambios permanentes. El nivel de aislamiento más alto. todas las sentencias de la transacción son “commitadas‟ o deshechas en grupo. En este segundo caso. De hecho. la transacción no terminará hasta que se llame al método commit o al método rollback explícitamente.(debido a que 240 . el que más cuidado toma para evitar conflictos.Una conexión nueva se abre por defecto en modo auto-commit.

el único método en esta clase que necesita un programador general para su uso directamente es DriverManager. Todas las clases Driver deben escribirse con una sección estática que cree una instancia de la clase y luego la registre en la clase DriverManager cuando se cargue. El desarrollador debe balancear la necesidad de rendimiento con la necesidad de la consistencia de los datos al tomar la decisión del nivel de aislamiento a usar. 3. Como su nombre indica. getDrivers y registerDriver así como al método de Driver connect. La clase DriverManager mantiene una lista de clases disponibles que han sido registrados mediante el método DriverManager. este método establece una conexión con la base de datos. 3. No se recomienda cambiar el nivel de aislamiento de transacción en medio de una puesto que lanzará una llamada inmediata al método commit. debería llamarse 241 . pero en la mayoría de los casos es preferible dejar que la clase DriverManager gestione los detalles al establecer la conexión. Además el usuario normalmente no debería llamar a DriverManager. y este nuevo nivel estará efectivo durante la sesión de conexión. su nivel de aislamiento depende del driver.registerDriver directamente. y trabaja como intermediaria entre el usuario y los drivers. LA CLASE DriverManager 3.1 Mantenimiento de la lista de drivers disponibles. Cuando se crea un nuevo objeto Connection. JDBC permite al usuario llamar a los métodos de DriverManager getDriver. es necesario fijar este antes de la transacción comience y volverlo a situar en su valor anterior una vez que la transacción haya terminado. Un usuario puede llamar al método setIsolationLevel para cambiar el nivel de aislamiento de la transacción.1 Vista preliminar La clase DriverManager implementa la capa de gestión de JDBC. Además la clase DriverManager se ocupa de cosas cómo gestionar los límites de tiempo de „login‟ en el driver y de la salida de los mensajes de traza y log. el nivel de aislamiento que pueda soportarse depende de las posibilidades de la base de datos subyacente. Por supuesto. Guarda la lista de los drivers que están disponibles y establece la conexión entre la base de datos y el driver apropiado. provocando que los cambios hasta ese punto se hagan permanentes en la base de datos. pero normalmente por defecto es el de la DBMS subyacente. Para aplicaciones simples.1. Para cambiar el nivel de aislamiento solo para una transacción.getConnection.se incrementan los bloqueos y se disminuye la concurrencia de los usuarios).registerDriver.

Como se ha mencionado anteriormente. El siguiente código ilutsra como un programador debería introducir estas tres clases en ~/. esta forma de cargar drivers es la recomendada.db.Driver").drivers.db. Este es también el método que se usa para traer un driver particular puesto que una vez que la clase DriverManager ha sido inicializada no chequeará la lista de propiedades jdbc.drivers=foo. 2 Mediante la adición del driver a la propiedad jdbc. El siguiente código carga la clase acme.sql.bah.registerDriver. Una clase Driver se carga.test. Entonces cuando la clase DriverManager abre una conexión solo usará los drivers que vienen desde el sistema de ficheros local o desde las mismas clases cargadoras como el código que solicita la conexión.hotjava/properties jdbc.. En ambos casos. Notese que en esta segunda manera de cargar los drivers es necesario una preparación del entorno que es persistente.Driver:bad.automáticamente por el driver cuando esté se carga. la clase DriverManager intenta cargarlos.Driver:wombat.forName("acme.forName.Driver se ha escrito para que al cargar produzca una instancia y llame al método DriverManager. 242 .registerDriver con esta instancia como argumento (es lo que debería hacer). La primera llamada a el método DriverManager hará que estos drivers se carguen automáticamente. Si acme.lang.db. la capa de gestión de JDBC guardará traza de que clases de cargadores provee cada driver. Por razones de seguridad. y si el usuario ha introducido uno o más drivers.drivers. de dos formas diferentes: 1 Mediante una llamada al método Class. esto debería hacerse automáticamente al cargar la clase.drivers de java. entonces este estará en la lista de drivers disponibles para efectuar la conexión.ourDriver. Si existe alguna duda sobre esto es preferible y más seguro llamar al método Class. Cuando la clase DriverManager se inicializa. mira en la propiedad jdbc.System. separadas por dos puntos.Esta es una lista de nombres de clases de drivers.forName para cargar explicitamente cada driver. Este carga explícitamente la clase driver. y por tanto se registra. Dado que no depende de ningún „setup‟ externo.Driver: Class. es responsabilidad de la clase Driver recién cargada registrarse a si misma mediante una llamada a DriverManager. que es la que carga la clase DriverManager.

todos los cuales actúan como contenedores para la ejecución de sentencias en una conexión dada: Statement. el orden en que los driver son testeados es significante porque DriverManager usará el primer driver que encuentre que pueda conectar con éxito a la base de datos. A veces puede darse el caso de que más de un driver JDBC pueda establecer la conexión para una URL dada.1. Primero DriverManager intenta usar cada driver en el orden en que ha sido registrado ( los drivers listados en la propiedad jdbc.drivers son siempre los registrados primero).jdbc.getConnection. a menos que se cargue desde el mismo código fuente que el código que intenta abrir la conexión. 4. cuando conectamos con una base de datos remota.getConnection.odbc. 243 . podría ser posible usar un driver puente JDBC-ODBC. Por ejemplo. se está en condiciones de establecer la conexión con la base de datos. El siguiente código es un ejemplo de todo lo necesario normalmente para establecer una conexión con un driver puente JDBC-ODBC: Class. DriverManager. //loads the driver String url = "jdbc:odbc:fred". Actualmente hay tres tipos de objetos Statement. pasándole como argumento la URL que el usuario ha pasado originalmente al método DriverManager. Una primera ojeda puede parecer insuficiente.connect cada uno por turno. La solicitud de la conexión se realiza mediante una llamada al método DriverManager. "passwd").JdbcOdbcDriver"). El primer driver que reconozca la URL realiza la conexión.1 Vista Preliminar Un objeto Statement se usa para enviar sentencias SQL a la base de datos. "userID".getConnection(url. y DriverManager testea los drivers regsitrados para ver si puede establecer la conexión. pero son necesarias solo unas pocas llamadas a procedimientos y comparaciones de cadena por conexión puesto que no es probable que haya docenas de drivers se carguen concurrentemente. LA CLASE Statement 4.3. o un driver suministrado por el vendedor. Saltará cualquier driver con código „untrusted‟.forName("sun. Testea los drivers mediante la llamada al método Driver. En tales casos.2 Establecer una conexión Una vez que la clase Driver ha sido cargada y registrada con la clase DriverManager. o un driver JDBC de protocolo genérico de red.

244 .executeQuery("SELECT a. y un objeto CallableStatement se usa para ejecutar un procedimieno de base de datos almacenado. UPDATE o DELETE es una modificación de una o más columnas en cero o más filas de una tabla. UPDATE ó DELETE así como sentencias SQL DDL (Data Definition Language) como CREATE TABLE o DROP TABLE. El efecto de una sentencia INSERT. "").getConnection(url. executeQuery. como podemos ver en el siguiente fragmento de código. le valor devuelto por executeUpdate es siempre cero. y la interfase CallableStatement añade métodos para trabajar con parameters OUT. Statement stmt = con. esta conexión puede usarse para enviar sentencias SQL. "sunny". Estas estàn especializadas para enviar tipos particulares de sentencias SQL.1.2 Ejecución de sentencias usando objetos Statement. La interfase Statement nos suministra tres métodos diferentes para ejecutar sentencias SQL. executeUpdate y execute. El método executeUpdate se usa para ejecutar sentencias INSERT. Por ejemplo: ResultSet rs = stmt. 4. Un objeto Statement se usa para ejecutar una sentencia SQL simple sin parámetros. c FROM Table2"). La interfase PreparedStatement añade métodos para trabajat con los parámetros IN. El valor devuelto de executeUpdate es un entero que indica el número de filas que han sido afectadas (referido como update count).PreparedStatement que hereda de Statement y CallableStatement que hereda de PreparedStatement. que no operan sobre filas. Un objeto PreparedStatement se usa para ejecutar sentencias SQL precompiladas con o sin parámetros IN. La sentencia SQL que será enviada a la base de datos es alimentada como un argumento a uno de los métodos de ejecución del objeto Statement.createStatement(). 4. Un objeto Statement se crea mediante el método de Connection createStatement. b. La interfase Statement suminstra métodos básicos para ejecutar sentencias y devolver resultados.1. Para sentencias tales como CREATE TABLE o DROP TABLE.1 Creación de objetos Statement Una vez establecida la conexión con una base de datos particular. Connection con = DriverManager. El método a usar esta determinado por el producto de la sentencia SQL El método executeQuery esta diseñado para sentencias que producen como resultado un único result set tal como las sentencias SELECT.

executeUpdate y execute. de cualquier modo.1. Un sentencia se considera completa cuando ha sido ejecutada y se han devuelto todos los resultados. más que un update count o una combinación de ambos. 4. En el primer caso. 4. no se completa hasta que los result sets o update counts que se generan han sido devueltos. la sentencia se completa cuando todas las filas del objeto ResultSet se han devuelto.4 Cerrar objetos Statement.1.3 Realización de Statement Cuando una conexión está en modo auto-commit. Los objetos CallableStatement heredan las formas de estos métodos de PreparedStatement. Debe notarse que la interfase PreparedStatement. que devuelve un único result set..execute. Esta diferencia se convierte en importante cuando está activo el modo auto-commit porque afecta cuando se llama al método commit. Pare el método executeQuery. Todos los métodos que ejecutan sentencias cierran los objetos Resultset abiertos como resultado de las llamadas a Statement. Los objetos PreparedStatement no suministran una sentencia SQL como argumento a estos métodos puesto que ya tienen la sentencia precompilada. por tanto debe suministrarse como un argumento a los métodos Statement. No obstante se recomienda como una buena práctica de programación que se cierren explicitamente cuando no sean ya necesarios. Otros tratan el procedimiento entero como una sentencia compuesta. que hereda los métodos de la interfase Statement. En el segundo. Los objetos Statement en si mismos no contienen una sentencia SQL. un sentencia se completa cuando se ejecuta. tiene sus propias versiones de los métodos executeQuery. Esto 245 . En los raros casos en que se llama al método execute. Esto quiere decir que es necesario completar el proceso con el actual objeto Resulset antes de reejecutar una sentencia Statement. Para el método executeUpdate. las sentencias ejecutadas son „comitadas‟ o rechazadas cuando se completan. Usar un parametro de query con las versiones de los métodos de PreparedStatement o CallableStatement producirái una SQLException. Como es esta una característica avanzada que muchos programadores no necesitarñan nunca se verá en su propia sección.El método execute se usa para ejecutar sentencias que devuelven más de un result set. Los objetos Statement se cerrarán automáticamente por el colector de basura de Java (garbage collector). cada sentencia individual es commitada. se commiten todas juntas. Algunos DBMS tratan cada sentencia en un procedimiento almacenado como sentencias separadas.

Recuperar Valores desde una Hoja de Resultados Ahora veremos como enviar la sentencia SELECT de la página anterior desde un programa escrito en Java y como obtener los resultados que hemos mostrado. JDBC devuelve los resultados en un objeto ResultSet. se puede mover el cursor hacia atrás. pero requiere permisos especiales y normalmente lo hace un administrador de bases de datos). y el método para recuperar valores de ese tipo es getFloat. por eso necesitamos declarar un ejemplar de la clase ResultSet para contener los resultados. El siguiente código presenta el objeto ResultSet: rs y le asigna el resultado de una consulta anterior.libera recursos DBMS inmediatamente y ayuda a evitar potenciales problemas de memoria. La segunda columna de cada fila almacena un valor del tipo FLOAT de SQL. Sin embargo. que es un ejemplar de ResultSet. Por ejemplo. Este código ha sido probado en la mayoría de los controladores de base de datos. hacia posiciones específicas y a posiciones relativas a la fila actual además de mover el cursor hacia adelante. contiene las filas de cafés y sus precios mostrados en el juego de resultados de la página anterior. que almacena un valor del tipo VARCHAR de SQL. demostraremos algún código SQL. El método para recuperar un valor VARCHAR es getString.0. veremos lo sencillo que es utilizar JDBC para pasar esas sentencias SQL a nuestro controlador de bases de datos y procesar los resultados devueltos. y luego. Sucesivas invocaciones del método next moverán el cursor de línea en línea de arriba a abajo. 5. cubierto en la siguiente sección. Utilizar los métodos getXXX Los métodos getXXX del tipo apropiado se utilizan para recuperar el valor de cada columna. ya que JDBC puede enviar codigo SQL a nuestro controlador. la primera columna de cada fila de rs es COF_NAME. podríamos encontrar algunos problemas de compatibilidad su utilizamos antiguos drivers ODB con el puente JDBC.ODBC. Después. El siguiente 246 . Para ser un poco manejable se tendrá un número pequeño de tablas. Primero veremos como abrir una conexión con nuestro controlador de base de datos. Observa que con el JDBC 2. El método next mueve algo llamado cursor a la siguiente fila y hace que esa fila (llamada fila actual) sea con la que podamos operar. primero debemos llamar al método next para mover el cursor a la primera fila y convertirla en la fila actual. (crear una base de datos no es nada díficil. Como el cursor inicialmente se posiciona justo encima de la primera fila de un objeto ResultSet.0 CONEXIONES A BASES DE DATOS CON JAVA Seleccionar una Base de Datos A lo largo de la sección asumiremos que la base de datos COFFEES ya existe. PRICE FROM COFFEES"). Para acceder a los nombres y los precios.executeQuery("SELECT COF_NAME. Utilizar el Método next La variable rs. iremos a la fila y recuperaremos los valores de acuerdo con sus tipos. ResultSet rs = stmt.

Utilizar el número de columna es un poco más eficiente. while (rs.getString("COF_NAME"). ResultSet rs = stmt. La primera línea de código obtiene el valor de la primera columna de la fila actual de rs (columna COF_NAME). 247 . etc. y hay algunos casos donde es necesario utilizarlo. Observa que utilizamos la variable s en la expresión println mostrada arriba.99 Veamos cómo funcionan los métodos getXXX examinando las dos sentencias getXXX de este código. Float n = rs. La segunda línea de código obtiene el valor de la segunda columna de la fila actual de rs. y lo convierte a un float de Java antes de asignarlo a la variable n. convirtiéndolo a un objeto String de Java y asignándolo a s. Cada vez que se llama al método next. Una forma es dar el nombre de la columna. con un 1 significando la primera columna.99 French_Roast_Decaf 9. En suma. y el bucle continúa hasta que no haya más filas en rs. Primero examinaremos getString.executeQuery(query). JDBC permite utilizar tanto el nombre cómo el número de la columna como argumento a un método getXXX.getFloat(2).getString("COF_NAME"). por eso getString recuperará (obtendrá) el valor almacenado en la columna COF_NAME de la fila actual de rs. } La salida se parecerá a esto. El método getString es invocado sobre el objeto ResultSet: rs.println(s + " " + n). System.getFloat("PRICE"). String s = rs.next()) { String s = rs.getString(1). Si utilizáramos el número de columna en vez del nombre de columna el código anterior se podría parecer a esto.99 Colombian_Decaf 8. Colombian 7. El valor recuperado por getString se ha convertido desde un VARCHAR de SQL a un String de Java y se ha asignado al objeto String s. Recuerda que el número de columna se refiere al número de columna en la hoja de resultados no en la tabla original. String s = rs. String query = "SELECT COF_NAME.out.99 French_Roast 8. que es un FLOAT de SQL. JDBC ofrece dos formas para identificar la columna de la que un método getXXX obtiene un valor. un 2 para la segunda. La segunda forma es dar el índice de la columna (el número de columna). float n = rs.99 Espresso 9. como se ha hecho arriba. lo convierte a un float de Java y lo asigna a n.código accede a los valores almacenados en la fila actual de rs e imprime una línea con el nombre seguido por tres espacios y el precio. PRICE FROM COFFEES". la siguiente fila se convierte en la actual. de esta forma: println(s + " " + n) La situación es similar con el método getFloat excepto en que recupera el valor almacenado en la columna PRICE.

el método getInt puede ser utilizado para recuperar cualquier tipo numérico de caracteres. Uitlizando el objeto stmt. Explicaremos el SQL3 más adelante). este código JDBC ejecuta la sentencia SQL contenida en updateString. COF_NAME Colombian French_Roast Espresso Colombian_Decaf French_Roast_Decaf SUP_ID 101 49 150 101 49 248 PRICE 7. String updateString = "UPDATE COFFEES " + "SET SALES = 75 " + "WHERE COF_NAME LIKE 'Colombian'". (Sin embargo.99 8.99 8. y ambos son intercambiables. Actualizar Tablas Supongamos que después de una primera semana exitosa. Métodos para Recuperar Tipos SQL muestra qué métodos pueden utilizarse legalmente para recuperar tipos SQL. La sentencia SQL para actualizar una columna se podría parecer a esto.executeUpdate(updateString). pero tiene sus limitaciones. Una "X" indica que el método getXXX está recomendado para recuperar el tipo JDBC dado.99 9. Por ejemplo. LONGVARBINARY. y el valor tendrá que ser convertido de nuevo a número antes de poder operar con él. y más importante. Utilizar los métodos de ResultSet.JDBC permite muchas lateralidades para utilizar los métodos getXXX para obtener diferentes tipos de datos SQL. si se está utilizando para recuperar un tipo numérico. no puede utilizarse con los tipos BINARY." Ambos términos se refieren a los tipos genéricos de SQL definidos en java. Observa que esta tabla utiliza el término "JDBC type" en lugar de "SQL type. Los datos recuperados serán convertidos a un int.99 SALES 75 0 0 0 0 TOTAL 0 0 0 0 0 . es posible recuperar cualquier tipo básico SQL con él. o TIMESTAMP de SQL. Obtener un valor con getString puede ser muy útil. VARBINARY.sql. DATE. sin embargo.99 9. no se pueden recuperar los nuevos tipos de datoas del SQL3. si el tipo SQL es VARCHAR.getXXX para Recuperar tipos JDBC Una "x" indica que el método getXXX se puede utilizar legalmente para recuperar el tipo JDBC dado. esto es. el propietario de "The Coffee Break" quiere actualizar la columna SALES de la tabla COFFEES introduciendo el número de libras vendidas de cada tipo de café. JDBC intentará convertirlo en un entero. Por ejemplo. TIME. Se recomienda utilizar el método getInt sólo para recuperar INTEGER de SQL. getString lo convertirá en un String de Java. La tablaCOFFEES ahora se parecerá a esto. qué métodos están recomendados para recuperar los distintos tipos SQL. stmt. Utilizar el método getString Aunque el metodo getString está recomendado para recuperar tipos CHAR y VARCHAR de SQL.Types.

necesitamos utilizar el método next para acceder a ella. nunca se accedería a ella.out. TOTAL es la quinta columna en la tabla COFFEES pero es la segunda columna en la hoja de resultados generada por la petición del ejemplo anterior. y el índice 2 a getInt (la segunda columna de la hoja de resultados es TOTAL).println(n + " pounds of " + s + " sold to date. int n = rs. y por eso tiene valor 0. int n = rs. e imprimiendo esos valores. utilizamos el índice de columna en vez del nombre de columna. ResultSet rs = stmt. Por ejemplo. si sucediera que existiera una línea. y luego imprimiremos el número de libras vendidas hasta la fecha. int n = rs.out.getInt(2). String query = "SELECT COF_NAME.println(n + " pounds of " + s + " sold this week.") } Esto imprimira lo siguiente.") } Observa que en este ejemplo.next()) { String s = rs.out. Ahora seleccionaremos la fila que hemos actualizado. rs.getInt(2). Ahora actualizaremos la columna TOTAL añadiendo la cantidad vendida durante la semana a la cantidad total existente.getString(1).getString(1).println(n + " pounds of " + s + " sold this week.next(). while (rs.next()) { String s = rs. System. Un objeto ResultSet se crea con un cursor apuntando por encima de la primera fila. String s = rs. while (rs. stmt.") Aunque hay una sóla línea en la hoja de resultados.executeQuery(query). TOTAL FROM COFFEES " + "WHERE COF_NAME LIKE 'Colombian'". String updateString = "UPDATE COFFEES " + "SET TOTAL = TOTAL + 75 " + "WHERE COF_NAME LIKE 'Colombian'". System. SALES FROM COFFEES " + "WHERE COF_NAME LIKE 'Colombian'". la única) de rs. ResultSet rs = stmt. System. Es importante distinguir entre un índice de columna en la tabla de la base de datos como opuesto al índice en la tabla de la hoja de resultados.Observa que todavía no hemos actualizado la columna TOTAL. En este código. suministrando el índice 1 a getString (la primera columna de la hoja de resultados es COF_NAME). 75 pounds of Colombian sold this week. sólo hay una línea en la ResultSet: rs y una línea en la salida. String query = "SELECT COF_NAME. Por lo tanto. Cómo la claúsula WHERE límita la selección a una sóla línea.getInt("SALES").executeUpdate(updateString). 249 .getString("COF_NAME"). La primera llamada al método next posiciona el cursor en la primera fila (y en este caso. sería posible escribir el código sin un bucle while.executeQuery(query). recuperando los valores de las columnas COF_NAME y SALES. sólo se llama una vez a next.

y ha sido precompilado. Aunque los objetos PreparedStatement se pueden utilizar con sentencias SQL sin parámetros. que también ha sido. Este tipo especial de sentencias se deriva de una clase más general. enviada al controlador de la base de datos. Si el valor que queremos sustituir es un String de Java. La ventaja de esto es que en la mayoría de los casos. probablemente nosotros utilizaremos más frecuentemente sentencias con parámetros. Veremos un ejemplo de esto en las página siguientes. si hay alguno. "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?". La ventajA de utilizar sentencias SQL que utilizan parámetros es que podemos utilizar la misma sentencia y suministrar distintos valores cada vez que la ejecutemos. etc. La caracterísitca principal de un objeto PreparedStatement es que. donde será compilado. al contrario que un objeto Statement. Como resultado. hay un método setXXX para cada tipo Java. esta sentencia SQL se enviará al controlador de la base de datos inmediatamente. podríamos escribir lo siguiente para crear un objeto PreparedStatement que tome dos parámetros de entrada. podemos llamar al método setString.Utilizar Sentencias Preparadas Algunas veces es más conveniente o eficiente utilizar objetos PreparedStatement para enviar sentencias SQL a la base de datos. Suministrar Valores para los Parámetros de un PreparedStatement Necesitamos suministrar los valores que se utilizarán en los luegares donde están las marcas de interrogación. 75). updateSales. reduciremos el tiempo de ejecución si utilizamos un objeto PreparedStatement. creamos un objeto PreparedStatement con un objeto Connection. En general. el controlador de base de datos puede ejecutarla sin tener que compilarla primero. PreparedStatement updateSales = con. antes de ejecutar un objeto PreparedStatement. Crear un Objeto PreparedStatement Al igual que los objetos Statement. Utilizando el objeto updateSales del ejemplo anterior. en la mayoría de los casos.prepareStatement( "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?"). sino una sentencia SQL que ha sido precompilada. que ya conocemos.setInt(1. en su lugar. Podemos hacer esto llamado a uno de los métodos setXXX definidos en la clase PreparedStatement. Cuándo utilizar un Objeto PreparedStatement Si queremos ejecutar muchas veces un objeto Statement. con un valor de 75. podemos llamar al método setInt. La variable updateSales contiene la sentencia SQL. se le entrega una sentencia SQL cuando se crea. 250 . el objeto PreparedStatement no sólo contiene una sentencia SQL. Si el valor que queremos sustituir por una marca de interrogación es un int de Java. la siguiente línea de código selecciona la primera marca de interrogación para un int de Java. Statement. Esto significa que cuando se ejecuta la PreparedStatement. Utilizando nuestra conexión con abierta en ejemplos anteriores.

la sentencia SQL de updateSales será equivalente a la sentencia SQL que hay en string updateString que utilizando en el ejemplo anterior. updateSales. // changes SALES column of Espresso row to 100 (the first // parameter stayed 100. updateSales. Una vez que a un parámetro se ha asignado un valor. Si actualizáramos la columna SALES sólo una o dos veces. Si por otro lado. updateSales. and the second parameter was reset // to "Espresso") 251 . Código 2. el valor permanece hasta que lo resetee otro valor o se llame al método clearParameters. updateSales. Después de que estos valores hayan sido asignados para sus dos parámetros.executeUpdate(). // changes SALES column of French Roast row to 100 updateSales. El siguiente ejemplo selecciona la segunda marca de interrogación con el string "Colombian".setString(2. que no se suministran argumentos a executeUpdate cuando se utiliza para ejecutar updateSales.setString(2. updateSales. 100). Esto es cierto porque updateSales ya contiene la sentencia SQL a ejecutar. "French_Roast"). tuvieramos que actualizarla frecuentemente. String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE 'Colombian'". los dos fragmentos de código siguientes consiguen la misma cosa.setString(2. stmt. updateSales. dejando el otro igual. Observa. updateSales.setInt(1. "Colombian").prepareStatement( "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? "). el siguiente fragmento de código reutiliza una sentencia prepared después de resetar el valor de uno de sus parámetros.executeUpdate(). PreparedStatement updateSales = con. especialmente en situaciones cuando la utilizamos con un bucle while para seleccionar un parámetro a una sucesión de valores. el primer argumento de un método setXXX indica la marca de interrogación que queremos seleccionar. 75). Por lo tanto. "Espresso"). Utilizamos el método executeUpdate para ejecutar ambas sentencias stmt updateSales.executeUpdate(). no sería necesario utilizar una sentencia SQL con parámetros. ya que la sentencia simple implica menos pasos. y el segundo argumento el valor que queremos ponerle. podría ser más fácil utilizar un objeto PreparedStatement. Veremos este ejemplo más adelante en esta sección.executeUpdate(updateString).setString(2. updateSales. Mirando esto ejemplos podríamos preguntarnos por qué utilizar un objeto PreparedStatement con parámetros en vez de una simple sentencia.setInt(1. "Colombian"). sin embargo. Utilizando el objeto PreparedStatement: updateSales. Código 1.Cómo podríamos asumir a partir de este ejemplo.

Este fragmento de código demuestra la actualización de la columna SALES para todos los cafés de la tabla COFFEES PreparedStatement updateSales.length. 155. int n = updateSales. Consecuentemente. etc. por eso no necesitan cambiarse.setInt(1.setString(2. i < len. puede utilizar el mismo código como una plantilla. por eso la primera cantidad de salesForWeek (175) se aplica al primer nombre de café de coffees ("Colombian"). 60. updateSales. 150.setString(2. int len = coffees. Estas cantidades corresponden con los nombres de los cafés listados en el array coffees. salesForWeek[i]). Todo lo que tiene que haces es introducir las nuevas cantidades en el orden apropiado en el array salesForWeek. "Colombian_Decaf". como la creación de una tabla.executeUpdate(). String [] coffees = {"Colombian". updateSales. El siguiente fragmento de código demuestra la utilización de un bucle for para asignar los parámetros en un objeto PreparedStatement: updateSales. el valor devuelto por executeUpdate es un int que indica cuántas líneas de la tabla fueron actualizadas. n tendrá el valor 0. Los nombres de cafés del array coffees permanecen constantes. "French_Roast". updateSales.int [] salesForWeek = {175. los valores probablemente serían introducidos por el usuario en vez de desde un array inicializado). devuelve el int: 0. por eso n es igual a 1. Por ejemplo. Cuando el método executeUpdate es utilizado para ejecutar una sentecia DDL. 50). el siguiente código muestra el valor de retorno de executeUpdate asignado a la variable n. 90}. } Cuando el propietario quiera actualizar las ventas de la semana siguiente. String updateString = "update COFFEES " + "set SALES = ? where COF_NAME like ?".setInt(1. updateSales = con. "Espresso". La actualización afecta sólo a una línea de la tabla. coffees[i]). updateSales. "French_Roast_Decaf"}. i++) { updateSales. en el siguiente fragmento de código. "Espresso").Utilizar una Bucle para asignar Valores Normalmente se codifica más sencillo utilizando un bucle for o while para asignar valores de los parámetros de entrada. la segunda cantidad de salesForWeek (150) se aplica al segundo nombre de café en coffees ("French_Roast"). for(int i = 0. (En una aplicación real. El array salesForWeek contiene las cantidades vendidas semanalmente. Valores de retorno del método executeUpdate Siempre que executeQuery devuelve un objeto ResultSet que contiene los resultados de una petición al controlador de la base datos.executeUpdate(). int n = executeUpdate(createTableCoffees). // n = 0 252 .prepareStatement(updateString). que ejecuta la sentencia DDL utilizada pra crear la tabla COFFEES. // n = 1 because one row had a change in it La tabla COFFEES se ha actualziado poniendo el valor 50 en la columna SALES de la fila correspondiente a Espresso.

"COFFEES. ResultSet rs = stmt.SUP_ID". ZIP CHAR(5))". supongamos que el propietario del "The Coffee Break" quiere una lista de los cafés que le compra a Acme. stmt.println(" " + coffeeName). Esto se hace precediendo el nombre de la columna con el nombre de la tabla.'" + "and SUPPLIERS.executeUpdate("insert into SUPPLIERS values (101. Inc. SUP_NAME VARCHAR(40). '1 Party Place'.SUP_NAME LIKE 'Acme. podemos utilizar esta columna en una unión.. " + "'CA'. En nuestro ejemplo.executeUpdate("Insert into SUPPLIERS values (150.COF_NAME " + "FROM COFFEES. while (rs.'. podremos proceder con el escenario en que el propietario quería una lista de los cafés comprados a un suministrador particular. String createSUPPLIERS = "create table SUPPLIERS " + "(SUP_ID INTEGER. ResultSet rs = stmt. String query = " SELECT COFFEES. necesitamos crear la tabla SUPPLIERS y rellenarla con valores. System. Este es el caso en que se necesitan los "joins" (unión). seleccionamos los cafés comprados a Acme. o (2) la sentencia ejecutada fue una sentencia DDL. Inc. Lo siguiente que necesitamos es la forma de distinguir la columna SUP_ID a la que nos referimos. stmt. '99 Market Street'. En el siguiente código. stmt. '100 Coffee Lane'. las tablas COFFEES y SUPPLIERS tienen la columna SUP_ID." + "'Superior Coffee'. 'Groundsville'. Antes de ir más allá. Inc. '95199'"). Utilizar Uniones Algunas veces necesitamos utilizar una o más tablas para obtener los datos que queremos. Una unión es una operación de base de datos que relaciona dos o más tablas por medio de los valores que comparten. 'Meadows'. " + "'95460'"). stmt.out. SUPPLIERS " + "WHERE SUPPLIERS.executeUpdate(createSUPPLIERS). y los nombres de los cafés en la tabla COFFEES.: "). " + "STATE CHAR(2). El siguiente código crea la tabla SUPPLIERS. " + "'The High Ground'. CITY VARCHAR(20). El siguiente código inserta filas para tres suministradores dentro de SUPPLIERS. Por ejemplo. Ahora que tenemos las tablas COFFEES y SUPPLIERS. " + "'93966'").SUP_ID = COFFEES. donde stmt es un objeto Statement. que puede ser utilizada para unirlas. Los nombres de los suminstradores están en la tabla SUPPLIERS. " + "'Acme. 'CA'. System. 'Mendocino'. Como ambas tablas tienen la columna SUP_ID. Esto implica información de la tabla COFFEES y también de la que vamos a crear SUPPLIERS.executeUpdate("Insert into SUPPLIERS values (49.Observa que cuando el valor devuelto por executeUpdate sea 0.executeQuery(query).executeQuery("select * from SUPPLIERS"). } 253 . " + "STREET VARCHAR(40). Inc.out.next()) { String coffeeName = getString("COF_NAME").SUP_ID" para indicar que queremos referirnos a la columna SUP_ID de la tabla COFFEES.println("Coffees bought from Acme. Inc. El siguiente código selecciona la tabla y nos permite verla. 'CA'. puede significar dos cosas: (1) la sentencia ejecutada no ha actualizado ninguna fila.

" más el nombre de la clase delante de todos los campos o métodos JDBC que utilicemos cada vez que los utilicemos. y el cuarto la rellena con valores. Por eso si tenemos una clase llamada MySQLStatement. que se hace visible cuando la siguiente línea de código precede a la definición de clase. Más adelante veremos programas de ejemplo que son aplicaciones completas que podremos ejecutar. Cualquier línea que importe clases aparece en la parte superior de los ejemplos de código.. El asterisco (*) indica que todas las clases del paquete java. Coffees bought from Acme.java Importar Clases para Hacerlas Visibles Lo primero es importar los paquetes o clases que se van a utilizar en la nueva clase. que es donde deben estar para hacer visibles las clases importadas a la clase que está siendo definida. Poner Código en una Definición de Clase En el lenguaje Java. import java. La definición real de la clase sigue a cualquier línea que importe clases. Como son aplicaciones completas.*. el segundo inserta valores en la tabla e imprime los resultados de una petición. 254 . El sexto ejemplo de código es una aplicación que demuestra una transación y también muestra como configurar las posiciones de los parámetros en un objeto PreparedStatement utilizando un bucle for. Utilizar el Método main() Si una clase se va a ejecutar. Colombian Colombian_Decaf Crear Aplicaciones JDBC Completas Hasta ahora sólo hemos visto fragmentos de código. Si no incluimos "import java.java.sql. incluyen algunos elementos del lenguaje Java que no hemos visto en los fragmentos anteriores. debe contener un método static public main. Importar una clase la hace visible y significa que no tendremos que escribir su nombre totalmente cualificado cuando utilicemos un método o un campo de esa clase." en nuestro código. La terecera aplicación crea la tabla SUPPLIERS.sql serán importadas. Este método viene justo después de la línea que declara la clase y llama a los otros métodos de la clase. Aquí explicaremos estos elementos brevemente. Todas las clases de nuestros ejemplos utilizan el paquete java. como en el quinto código de ejemplo. Después de haber ejecutado este código.Esto producirá la siguiente salida. Observa que también podemos importar clases individuales selectivamente en vez de importar un paquete completo. El primer código de ejemplo crea la tabla COFFEES.sql (el API JDBC). su definición debería estar en un fichero llamado MySQLStatement. tendríamos que escribir "java. Inc. cualquier código que querramos ejecutar debe estar dentro de una definición de clase.*. Java no requiere que importemos clases o paquetes.sql. podemos intentar una petición que una las tablas COFFEES y SUPPLIERS.sql. Tecleamos la definición de clase en un fichero y a éste le damos el nombre de la clase con la extensión . pero al hacerlo el código se hace mucho más conveniente.

getMessage()). Primero.err. Este método lanza una ClassNotFoundException. El primer bloque try contiene el método Class.err. podemos imprimirlos todos. // Si se genera una excepción. } catch(SQLException ex) { System. obtendríamos un mensaje de error similar a éste. las aplicaciones de ejemplo de este capítulo incluyen un método main. SQLException: There is already an object named 'COFFEES' in the database. los dos bloques catch del siguiente código de ejemplo imprimen un mensaje explicando la excepción. lo que es suficiente para la mayoría de las situaciones. Por ejemplo. Java requiere que cuando un método lanza un excepción exista un mecanismo que la maneje. El siguiente fragmento de código muestra un bloque catch que se ha completado de dos formas. Recuperar Excepciones JDBC permite ver los avisos y excepciones generados por nuestro controlador de base de datos y por el compilador Java. La palabra clave public significa que los miembros de cualquier clase pueden acceder a este método. utilizamos dos bloques try y dos bloques catch.ClassNotFoundException e) { System. Sin embargo. Line 1 Este ejemplo ilustra la impresión del componente mensaje de un objeto SQLException. Utilizar bloques try y catch Algo que también incluyen todas las aplicaciones de ejemplo son los bloques try y catch. Para ver las excepciones. En el código de ejemplo.lang.La palabra clave static indica que este método opera a nivel de clase en vez sobre ejemplares individuales de la clase. por eso el bloque catch del final de la aplicación puede manejar el resto de las excepciones que podrían lanzarse ya que todas serían objetos SQLException. El segundo bloque try contiene métodos JDBC.println("SQLException: " + ex.forName("myDriverClassName"). try { // Aquí va el código que podría generar la excepción. Generalmente un bloque catch capturará la excepción y especificará lo que sucederá (que podría ser no hacer nada). Severity 16.java dos veces.lang. } catch(java. System.println(e.forName.getMessage()). y para ser completos.err. Este es un mecanismo del lenguaje Java para manejar excepciones. el bloque catch imprimirá // información sobre ella. del paquete java. State 1. por eso el bloque catch que le sigue maneja esa excepción. podemos tener un bloque catch que las imprima. todos ellos lanzan SQLException. } try { Class. } Si ejecutarámos CreateCOFFEES.print("ClassNotFoundException: "). imprime las tres partes de un objeto SQLException: el 255 . Como no estamos definiendo clases sólo para ser ejecutadas por otras clases sino que queremos ejecutarlas. realmente existen tres componentes.

Un aviso puede reportarse sobre un objeto Connection.No suitable driver HY011 -. try { // Aquí va el código que podría generar la excepción. sería encadenada a ex.Operation invalid at this time El código de error del vendedor es específico de cada driver. Line 1 SQLState: 42501 ErrorCode: 2714 SQLState es un código definido en X/Open y ANSI-92 que identifica la excepción. el bucle while continúa e imprime el mensaje de la siguiente excecpción.out. ex = ex.out.getNextException para ver si hay más excepciones. while (ex != null) { System. Si hay una segunda excepción.getSQLState ()). como las excepciones. // Si se genera una excepción. } catch(SQLException ex) { System. Severity 16. System. y getErrorCode. Por ejemplo.out. un objeto Statement (incluyendo objetios PreparedStatement y CallableStatement).SQLException caught ---\n").getNextException().println("\n--. el SQLState (un string que identifica el error de acuerdo a los convenciones X/Open de SQLState). y un código de error del vendedor (un número que es el código de error del vendedor del driver). y el código de error del vendedor.getMessage ()). O un aviso podría decirnos que ha ocurrido algún error durante una petición de desconexión. obtendríamos la siguiente información. El objeto SQLException.println("SQLState: " + ex. System.mensaje (un string que describe el error). el bloque catch imprimirá // información sobre ella. 08001 -. ex es capturado y se accede a sus tres componentes con los métodos getMessage.out. State 1. por lo que debemos revisar la documentación del driver buscando una lista con el significado de estos códigos de error. Si las hay.out.println(""). por eso se llama a ex. } } Si hubieramos sustituido el bloque catch anterior en el Código de ejemplo 1 (CreateCoffees) y lo hubieramos ejecutado después de que la tabla COFFEES ya se hubiera creado.getErrorCode ()). simplemente alertan al usuario de que algo no ha salido como se esperaba. Los Avisos no detienen la ejecución de una aplicación. Cada una de 256 . --. Recuperar Avisos Los objetos SQLWarning son una subclase de SQLException que trata los avisos de accesos a bases de datos. La segunda forma del siguiente bloque catch completo obtiene todas las exepciones que podrían haber sido lanzada. un aviso podría hacernos saber que un privilegio que queriamos revocar no ha fue revocado.println("Message: " + ex.SQLException caught --Message: There is already an object named 'COFFEES' in the database. el SQLState.println("ErrorCode: " + ex. Esto continúa hasta que no haya más excepciones. Aquí podemos ver dos ejemplos de códigos SQLState. o un objeto ResultSet. System. getSQLState.

warning = warning.0) incluye muchas nuevas características no incluidas en el paquete java.out. System. } } SQLWarning warn = rs.out. indicando que ha habido un problema al leer o escribir datos.out. Los métodos de DataTruncation permiten encontrar en que columna o parámetro se truncaron los datos.out. por eso no se apilan.sql que está incluido en la versión JDK 1.getMessage()). System.. Sin embargo. el aviso más común es un DataTruncation.println(warning. System.println("Message: " + warning.println("SQLState: " + warning.out.createStatement(). while (rs.getWarnings().println("Message: " + warn.getString("COF_NAME").println(" " + coffeeName).println("SQLState: " + warn. al que debemos llamar para ver el primer aviso reportado en la llamada al objeto.out.next()) { String coffeeName = rs.1 (referenciado como el API JDBC 1. podemos llamar al método getNextWarning de SQLWarning para obtener avisos adicionales. Todos los objetos DataTruncation tienen un SQLState 01004.println("").print("Vendor error code: "). System. esto significa que si queremos recuperar los avisos reportados por una sentencia.getErrorCode()). warn = warn.out. System. rs.getSQLState()). stmt y también por el objeto ResultSet. 257 .getMessage()).println("").out.out.2 (conocido como el API JDBC 2. cuántos bytes deberían haber sido transmitidos. System.getErrorCode()). System. System.out. while (warning != null) { System. } } } Los avisos no son muy comunes.println("\n---Warning---\n"). Al ejecutar una sentencia se borran automáticamente los avisos de la sentencia anterior. System. y cuántos bytes se transmitieron realmente. El API de JDBC 2. una subclase de SQLWarning.println("\n---Warning---\n"). if (warning != null) { System.out. if (warn != null) { System.out.out.0 El paquete java. while (warn != null) { System.getWarnings().println("Coffees available at the Coffee Break: "). si la ruptura se produjo en una operación de lectura o de escritura.sql que forma parte de la versión JDK 1.0).executeQuery("select COF_NAME from COFFEES"). Statement stmt = con. Si getWarnings devuelve un aviso.out. debemos hacerlo antes de ejecutar otra sentencia. El siguiente fragmento de código ilustra como obtener información completa sobre los avisos reportados por el objeto Statement.getNextWarning().getSQLState()).print("Vendor error code: "). SQLWarning warning = stmt.println(warn. ResultSet rs = stmt.esas clases tiene un método getWarnings. De aquellos que son reportados. System.getNextWarning().

Con el API JDBC 2.2 siguiendo las instrucciones de descarga 2. pero no se asegura que éstos funcionen. Acceder a un controlador de base de datos que implemente las características del JDBC utilizadas en el código. necesitamos hacer lo siguiente. ResultSet. Mover el Cursor por una Hoja de Resultados Una de las nuevas características del API JDBC 2. también debemos especificar si es de sólo lectura o actualizable. 258 . y como ambos parámetros son int. pero hay muchos en desarrollo. lo que probablemente será uno de los principales usos de esta característica. El primer argumento es una de las tres constantes añadidas al API ResultSet para indicar el tipo de un objeto ResultSet: TYPE_FORWARD_ONLY. Otro uso será movernos a una fila para actualizarla. También. Inicialización para Utilizar JDBC 2. Este código es similar al utilizado anteriormente. no es posible probar el código de desmostración de las características del JDBC 2.0. debemos especificar primero el tipo. 1. PRICE FROM COFFEES").  Uitlizar los nuevos tipos de datos SQL3 como valores de columnas. no se había implementado ningún driver que soportara las nuevas características. Statement stmt = con. podremos hacer las siguientes cosas: Ir hacia adelante o hacia atrás en una hoja de resultados o movernos a un fila específica. Descargar el JDK 1.0. 3. necesitamos crear un objeto ResultSet Scrollable. Instalar un Driver JDBC que implemente las características del JDBC 2. o batch. TYPE_SCROLL_INSENSITIVE. La hoja de resultados Scrollable hace posible crear una herramienta GUI (Interface Gráfico de Usuario) para navegar a través de ella. Antes de poder aprovechar estas ventajas.0 utilizadas en el código. excepto en que añade dos argumentos al método createStatement.  Hacer actualizaciones de las tablas de la base datos utilizando métodos Java en lugar de utilizar comandos SQL. Podemos aprender de los ejemplos. El segundo argumento es una de las dos constantes de ResultSet para especificar si la hoja de resultados es de sólo lectura o actualizable:CONCUR_READ_ONLY y CONCUR_UPDATABLE.0 Si queremos ejecutar código que emplee alguna de las características del JDBC 2. el compilador no comprobará si los hemos intercambiado.createStatement(ResultSet.executeQuery("SELECT COF_NAME. En el momento de escribir esto. Enviar múltiples secuencias SQL a la base de datos como una unidad.0 es la habilidad de mover el cursor en una hoja de resultados tanto hacia atrás como hacia adelante.CONCUR_READ_ONLY).TYPE_SCROLL_SENSITIVE. y TYPE_SCROLL_SENSITIVE. ResultSet srs = stmt. Lo que debemos recordar aquí es que si especificamos un tipo.0. Como consecuencia. También hay métodos que nos permiten mover el cursor a una fila particular y comprobar la posición del cursor.

srs en el ejemplo anterior. entraremos en más detalle más adelante. System.createStatement(ResultSet. ResultSet srs = stmt. Incluso aunque una hoja de resultados se seleccione desplazable. que mueve el cursor una fila hacia delante (hacia el final de la hoja de resultados). aquí tenemos un ejemplo que mueve el cursor a la primera fila y luego a la siguiente cada vez que pasa por el bucle while.getString("COF_NAME").TYPE_SCROLL_SENSITIVE. es decir. lo que hace posible utilizarlos en un bucle while. PRICE FROM COFFEES").out. Aunque deberíamos tener en mente el hecho de que no importa el tipo de hoja de resultados que especifiquemos.99 259 . El bucle termina cuando alcanza la última fila. Si no se especifican constantes para el tipo y actualización de un objeto ResultSet. yendo de la primera fila a la última.executeQuery("SELECT COF_NAME. Una vez que tengamos un objeto ResultSet desplazable. haciendo que el método next devuelva false. } La salida se podría parecer a esto.0). ResultSet. Recuerda que cuando creabamos un objeto ResultSet anteriormente.getFloat("PRICE"). podemos utilizarlo para mover el cursor sobre la hoja de resultados. Ambos métodos devuelven false cuando el cursor se sale de la hoja de resultados (posición antes de la primera o después de la última fila). con cinco espacios en blanco entre el nombre y el precio. pero ahora tenemos muchas más formas para mover el cursor. El siguiente fragmento de código imprime los valores de cada fila de srs. obtendremos automáticamente una TYPE_FORWARD_ONLY y CONCUR_READ_ONLY (exactamente igual que en el API del JDBC 1. es el nuevo método previous. pero para refrescar la memoria. tenía el cursor posicionado antes de la primera fila. La contrapartida del método next. que mueve el cursor una fila hacia atrás (hacia el inicio de la hoja de resultados). Ye hemos utilizado un método next en un bucle while. En el API JDBC 1.println(name + " " + price).99 French_Roast 8.Especificando la constante TYPE_FORWARD_ONLY se crea una hoja de resultados no desplazable. una hoja en la que el cursor sólo se mueve hacia adelante. la única forma de mover el cursor era llamar al método next. La diferencia entre estas dos es si la hoja de resultados refleja los cambios que se han hecho mientras estaba abierta y si se puede llamar a ciertos métodos para detectar estos cambios. En este momento. una hoja de resultados TYPE_SCROLL_INSENSITIVE no refleja los cambios hechos mientras estaba abierta y en una hoja TYPE_SCROLL_SENSITIVE si se reflejan. Este método todavía es apropiado si queremos acceder a las filas una a una.0.CONCUR_READ_ONLY). while (srs.next()) { String name = srs. Obtendremos un objeto ResultSet desplazable si utilizamos una de estas constantes:TYPE_SCROLL_INSENSITIVE o TYPE_SCROLL_SENSITIVE. Generalmente hablando. float price = srs. el cursor también se posiciona inicialmente delante de la primera fila. siempre estaremos limitados por nuestro controlador de base de datos y el driver utilizados. Statement stmt = con. Los tres tipos de hojas de resultados harán visibles los resultados si se cierran y se vuelve a abrir. no necesitamos preocuparnos de los puntos delicados de las capacidades de un objeto ResultSet. Colombian 7.

por eso llamar a absolute(1) pone el cursor en la primera fila. Como hemos podido ver.Espresso 9.absolute(4). el cursor debe estar detrás de la última fila.relative(2).TYPE_SCROLL_INSENSITIVE. . la siguiente línea de código movería el cursor a la fila 497.relative(-3). last.createStatement(ResultSet.absolute(-4).99 French_Roast 8.99 French_Roast_Decaf 9. El bucle termina cuando el cursor alcanza la posición anterior a la primera fila.getString("COF_NAME"). srs. y luego a la fila anterior en cada iteracción del bucle while. srs. PRICE FROM COFFEES"). Por ejemplo. luego a la primera y por último a la tercera. por eso llamar a absolute(-1) pone el cursor en la última fila.getFloat("PRICE"). Si el número es negativo.executeQuery("SELECT COF_NAME. ResultSet srs = stmt. mueve el cursor al número dado desde el final. y afterLast mueven el cursor a la fila indicada en sus nombres. Un número positivo mueve el cursor hacia adelante el número de filas dado. Si srs tuviera 500 filas.99 Colombian 7. en el siguiente fragmente de código. el método next mueve el cursor a la fila siguiente.99 Colombian_Decaf 8. . el cursor se mueve al número dado desde el principio. El método absolute moverá el cursor al número de fila indicado en su argumento. pero para hacer esto. beforeFirst. } La salida se podría parecer a esto. Los métodos first. while (srs. Se puede mover el cursor explícitamente a esa posicón con el método afterLast. // cursor está en la tercera fila 260 . Tres métodos mueven el cursor a una posición relativa a su posición actual. podemos procesar todas las filas de srs hacia atrás. cuando el método previous devuelve false. pero las filas están en orden inverso.99 Al igual que en el fragmento anterior. // cursor está en la primera fila . un número negativo mueve el cursor hacia atrás el número de filas dado. Luego el método previous mueve el cursor desde la posicón detrás de la última fila a la última fila.afterLast(). srs.99 Colombian_Decaf 8. srs. las dos salidas tienen los mismos valores. System. y el método previous lo mueve a la fila anterior.previous()) { String name = srs. .absolute(4). srs. Statement stmt = con. French_Roast_Decaf 9.99 Como se puede ver. se puede especificar cuántas filas se moverá desde la fila actual y también la dirección en la que se moverá. el cursor se mueve a la cuarta fila. // cursor está en la cuarta fila . La siguiente línea de código mueve el cursor a la cuarta fila de srs. .99 Espresso 9.println(name + " " + price). srs. float price = srs. Se puede mover el cursor a una fila particular en un objeto ResultSet. Con el método relative.CONCUR_READ_ONLY).out. Si el número es positivo. ResultSet.

int rowNum = srs. srs. // rowNum debería ser 3 Existen cuatro métodos adicionales que permiten verificar si el cursor se encuentra en una posición particular. pero cuando se hacen cambios en una hoja de resultados.println(name + " " + price).out. y si el tipo es TYPE_SCROLL_SENSITIVE.getRow(). Un objeto ResultSet actualizable no tiene porque ser desplazable. int rowNum = srs. El objeto Statement creado producirá un objeto ResultSet actualizable cada vez que se ejecute una petición. 261 . isAfterLast. float price = srs. Todos estos métodos devuelven un boolean y por lo tanto pueden ser utilizados en una sentencia condicional. moveToInsertRow y moveToCurrentRow. Por ejemplo. Con una hoja de resultados desplazable. Observa que el código también lo hace desplazable. Si el método isAfterLast devuelve false. // rowNum debería ser 4 srs. el cursor no estará después de la última fila. La posición se indica en sus nombres:isFirst.isAfterLast() == false) { srs. podemos obtener el nuevo valor de una fila después de haberlo cambiado. suministramos la constante CONCUR_UPDATABLE de ResulSet al método createStatement. Pero antes de poder aprovechar esta capacidad. el siguiente fragmento de código comprueba si el cursor está después de la última fila antes de llamar al método previous en un bucle while. uprs. Hacer Actualizaciones en una Hoja de Resultados Otra nueva característica del API JDBC 2. podemos movernos a las filas que queremos cambiar. } while (srs.getString("COF_NAME"). También veremos ejemplos que ilustran por qué podríamos querer mover el cursor a ciertas posiciones. if (srs. Por ejemplo. } En la siguiente página. como se ha visto en ejemplos anteriores. generalmente queremos poder movernos por ella. Para hacer esto. Statement stmt = con.createStatement(ResultSet.relative(2).getConnection("jdbc:mySubprotocol:mySubName").TYPE_SCROLL_SENSITIVE. veremos cómo utilizar otros dos métodos de ResultSet para mover el cursor.CONCUR_UPDATABLE).afterLast(). se puede utilizar getRow para verificar la posición actual del cursor en el ejemplo anterior.0 es la habilidad de actualizar filas en una hoja de resultados utilizando métodos Java en vez de tener que enviar comandos SQL. System.absolute(4).getRow(). Esto garantiza que el cursor estára después de la última fila antes de utilizar el método previous en el bucle while para cubrir todas las filas de srs. El siguiente fragmento de código ilustra la creacción de un objeto ResultSet actualizable.El método getRow permite comprobar el número de fila donde está el cursor.relative(-3). // rowNum debería ser 1 srs.previous()) { String name = srs. por eso se llama al método afterLast. int rowNum = srs. necesitamos crear un objeto ResultSet actualizable. isLast. Connection con = DriverManager.getFloat("PRICE"). isBeforeFirst.getRow(). ResultSet.

debemos llamar al método updateRow de ResultSet. utilizando el API JDBC 1. El siguiente fragmento de código muesta otra forma de realizar la actualización. Una vez situado el cursor.executeUpdate("UPDATE COFFEES SET PRICE = 10.99 llamando al método updateFloat. updateBigDecimal.last().0.. uprs. 10. Las operaciones de actualización en el API JDBC 2. Para que la actualización tenga efecto en la base de datos y no sólo en la hoja de resultados. El objeto ResultSet.99). por eso en le primera línea se llama al método last para mover el cursor a la última fila (la fila donde la columna COF_NAME tiene el valor FRENCH_ROAST_DECAF). 262 . el precio en uprs para "French Roast Decaf" será 10.99 French_Roast_Decaf 9.0 afectan a los valores de columna de la fila en la que se encuentra el cursor. Existe un método updateXXX diferente para cada tipo (updateString.99 Colombian_Decaf 8. Los métodos updateXXX de ResultSet toman dos parámetros: la columna a actualizar y el nuevo valor a colocar en ella. updateInt. la actualización podría ser algo como esto. Actualizar una Hoja de Resultados Programáticamente Una actualización es la modificación del valor de una columna de la fila actual. stmt.0. o modificar un valor de una columna de uprs.99.executeQuery("SELECT COF_NAME.updateRow().0 en el interface ResultSet para insertar una nueva fila en uprs.last(). pero el precio en la tabla COFFEES de la base de datos será todavía 9.99. Al igual que en los métodos getXXX de ResultSet. etc. todos los métodos de actualización que llamemos operarán sobre esa fila hasta que movamos el cursor a otra fila.) En este punto.99.ResultSet uprs = stmt.updateFloat("PRICE". esta vez utilizando el API JDBC 2.99 Espresso 9. uprs resultante se podría parecer a esto. COF_NAME PRICE -----------------. el parámetro que designa la columna podría ser el nombre de la columna o el número de la columna.99 French_Roast 8. uprs. Se utiliza este método porque el valor de la columna que queremos actualizar es un float Java.updateFloat("PRICE". borrar una fila de uprs.99 Podemos utilizar los nuevos métodos del JDBC 2. Aquí está el código para actualizar tanto uprs como COFFEES. Supongamos que queremos aumentar el precio del café "French Roast Decaf" a 10. uprs. PRICE FROM COFFEES"). La segunda línea de código cambia el valor de la columna PRICE a 10. 10.----Colombian 7. uprs.99" + "WHERE COF_NAME = FRENCH_ROAST_DECAF"). uprs.99).

pero podemos llamar a un método updateXXX apropiado para cada una de las columnas de la fila. Si también queremos actualizar el precio de COLOMBIAN_DECAF. 9. Todos los movimientos de cursor se refieren a filas del objeto ResultSet. uprs. nos damos cuenta de que el precio debería haber sido 10. uprs.Si hubiéramos movido el cursor a una fila diferente antes de llamar al método updateRow. 10.79 en vez de 10. uprs. uprs. sólo se hace una llamada al método updateRow para actualizar la base de datos con todos los cambios realizados en la fila actual. uprs.updateFloat("PRICE". sólo se había actualizado una columna. uprs.79 tanto en la hoja de resultados como en la base de datos. El siguiente fragmento de código primero cancela el precio 10.79).updateRow(). llamar a cancelRowUpdates no hará nada. la actualización se habría perdido.99 y luego lo actualiza a 10. Tenemos que llamar al método cancelRowUpdates antes de llamar al método updateRow. El siguiente fragmento de código cambia el precio de esa fila a 9. En este ejemplo. Si. si había muchas llamadas a método updateXXX en la misma fila.updateRow(). podemos llamar al método previous para posicionar el cursor en la fila de COLOMBIAN_DECAF.last().79).updateFloat("PRICE".79. no a filas de la 263 .cancelRowUpdates().99 podríamos haber cancelado la actualización llamando al método cancelRowUpdates. Incluso si hay muchas llamadas a métodos updateXXX. Cómo la fila de COLOMBIAN_DECAF precede inmediatamente a la fila de FRENCH_ROAST_DECAF. tenemos que mover el cursor a la fila que contiene ese café. uprs. una vez que se llama a updateRow.previous(). por eso.99). El concepto a recordar es que las actualizaciones y las operaciones relacionadas se aplican sobre la fila en la que se encuentra el cursor.updateFloat("PRICE". no podemos cancelar sólo una de ellas. uprs. Observa que cancelRowUpdates cancela todas las actualizaciones en una fila. por el contrario. 10.

Este único método inserta la fila simultáneamente tanto en el objeto ResultSet como en la tabla de la base de datos de la que la hoja de datos fue seleccionada. 10. podemos llamar al método insertRow para insertar la fila que hemos rellenado en la hoja de resultados. podemos constuir una nueva fila insertándola tanto en la hoja de resultados como en la tabla COFFEES en un sólo paso. El controlador de la base de datos sigue la pista de las filas seleccionadas. El "High Ground". 0)"). etc.tabla de la base de datos. Se construye una nueva fila en una llamada "fila de inserción".executeUpdate("INSERT INTO COFFEES " + "VALUES ('Kona'. en una hoja de resultados con cinco filas. Finalmente.0 en vez de utilizar comandos SQL. Si una petición selecciona cinco filas de la tabla de la base de datos. el orden de las filas en la tabla de la base de datos es indeterminado. Hacemos esto llamando a los métodos updateXXX apropiados para cada valor. La fila 1 puede ser identificada como la primera. . en el que stmt es un objeto Statement. El orden de las filas en la hoja de resultados no tiene nada que ver con el orden de las filas en la tablas de la base de datos. El primer paso será mover el cursor a la fila de inserción. Cuando se inserta una fila. muestra esta aproximación. Básicamente. y quiere añadirlo a su base de datos. y hace las actualizaciones en la fila apropiada. Supongamos que nuestro propietario del café ha obtenido una nueva variedad de café de uno de sus suministradores. 0. la fila 5 será la última. Esta fila realmente no forma parte de la hoja de resultados. El siguiente paso será seleccionar un valor para cada columna de la fila. habrá cinco filas en la hoja de resultados. Utilizando el API JDBC 1. Con el API JDBC 2. con la primera fila siendo la fila 1. stmt.0. por ejemplo. De hecho. no hay forma de saber donde será insertada dentro de la tabla. Insertar y Borrar filas Programáticamente En la sección anterior hemos visto cómo modificar el valor de una columna utilizando métodos del API JDBC 2. que contiene todas las filas y columnas de la tabla COFFEES.99. pero podrían estar localizadas en cualquier lugar de la tabla.0 podría escribir el código que pasa una sentencia insert de SQL al controlador de la báse de datos. una fila especial asociada con cada objeto ResultSet. El siguiente fragmento de código. lo que podemos hacer llamando al método moveToInsertRow. podemos pensar en ella como un buffer separado en el que componer una nueva fila. la sengunda siendo la fila 2.0 también podemos insertar una fila en una tabla o borrar una fila existente programáticamente. después de tener un objeto ResultSet con los resultados de la tabla COFFEES. uprs. Se puede hacer esto mismo sin comandos SQL utilizando los métodos de ResultSet del API JDBC 2. 150. El siguiente fragmento de código crea un objeto ResultSet actualizable y desplazable. Observa que estos son los mismos métodos updateXXX utilizados en la página anterior para cambiar el valor de una columna. y.

Cuando el cursor está sobre la fila de inserción. selecciona los cinco valores de columna e inserta la fila dentro de uprs y COFFEES. Si no suministramos valores para una columna que estaba definida para aceptar valores NULL de SQL. 265 . 10. En aquellos ejemplos. 150). el método insertRow inserta la nueva fila en la hoja de resultados y en la base de datos al mismo tiempo. En el ejemplo anterior.updateInt("SUP_ID".updateString(1.getConnection("jdbc:mySubprotocol:mySubName").updateInt("SALES". uprs. uprs. uprs. Esto también es cierto si falta una columna de la tabla en nuestro objeto ResultSet.99).updateFloat("PRICE". ResultSet. Tanto en actualizaciones como en inserciones.updateInt(2. Si la columna no acepta valores null. Se debe llamar al método updateRow para hacer que las actualizaciones ocurran en la base de datos. nuestra petición no tiene porque seleccionar todas las filas.executeQuery("SELECT * FROM COFFEES"). uprs. Podríamos preguntarnos que sucedería si insertáramos una fila pero sin suministrar los valores para cada columna. Podríamos habernos preguntado por qué los métodos updateXXX parecen tener un comportamiento distinto a como lo hacían en los ejemplos de actualización.99). 0).Connection con = DriverManager. ResultSet uprs = stmt. 0).moveToInsertRow(). obtendremos una SQLException. lo que producía una hoja de resultados con todas las columnas y todas las filas. uprs. uprs. Cuando queremos insertar una o más filas. 0). pero lo es en la fila de inserción y no en la propia hoja de resultados. llamar a los métodos updateXXX no afectan a la tabla de la base de datos. el valor seleccionado con un método updateXXX también es automáticamente seleccionado. uprs. uprs.updateInt(5.updateInt(4.updateFloat(3. pero sí todas las columnas. "Kona"). 0).insertRow(). Como podemos utilizar el nombre o el número de la columna para indicar la columna seleccionada. mostrada en el ejemplo SQL. el valor asignado a esa columna es NULL.CONCUR_UPDATABLE).createStatement(ResultSet. Para el inserciones. Statement stmt = con. querremos utilizar una claúsula WHERE para límitar el número de filas devueltas por la sentencia SELECT. Especialmente si nuestra tabla tiene cientos o miles de filas.updateString("COF_NAME". uprs. uprs. uprs para insertar la fila para "kona". El siguiente fragmento de código utiliza el objeto ResultSet. 150). la petición era SELECT * FROM COFFEES. Esto era porque el cursor estaba sobre una fila de la hoja de resultados. Mueve el cursor a la fila de inserción. uprs.updateInt("TOTAL". 10.TYPE_SCROLL_SENSITIVE. el valor seleccionado con un método updateXXX reemplazaba inmediatamente el valor de la columna en la hoja de resultados. nuestro código para seleccionar los valores de columna se podría parecer a esto. "Kona"). uprs.

stmt = con.updateString("COF_NAME". Connection con.99f).updateInt("SUP_ID".updateFloat("PRICE". uprs.updateInt("TOTAL". uprs. Luego. o podemos mover el cursor de nuevo a la hoja de resultados. 1. que por definición es la fila actual.moveToInsertRow().ClassNotFoundException e) { System. afterLast. Por ejemplo. llamar a cualquier método que ponga el cursor en una fila específica. el código inserta la fila en la hoja de resultados y en la base de datos con el método insertRow.sql. uprs. Insertar una Fila El siguiente ejemplo de código es un programa completo que debería funcionar si tenemos un driver JDBC 2.createStatement(ResultSet.forName("myDriver. "myLogin".err. desplazable y sensible a los cambios hechos por ella y por otros. ResultSet uprs = stmt. El objeto ResultSet. la hoja de resultados graba la fila en la que se encontraba el cursor.updateInt("SALES". Statement stmt.lang. podemos.0 que implemente una hoja de resultados desplazable. Esto también explica porque podemos utilizar los métodos previous y relative.print("ClassNotFoundException: "). el método moveToCurrentRow puede mover el cursor desde la fila de inserción a la fila en la que se encontraba anteriormente. } try { con = DriverManager. como first. y absolute. beforeFirst. Observa que sólo podemos llamar a moveToCurrentRow cuando el cursor está en la fila de inserción. Aunque es TYPE_SCROLL_SENSITIVE. 10. estándo todavía en la "fila de inserción". También podemos utilizar los métodos previous.getConnection(url. selecciona valores para otra nueva fila.getMessage()). 0). relative. try { Class. import java. System. "myPassword"). uprs. last. uprs. ResultSet.err. Como consecuencia. 0). uprs. podemos construir otra fila. "Kona"). 266 .executeQuery("SELECT * FROM COFFEES"). Hay métodos en el interface DatabaseMetaData que nos dirán qué es visible y qué será detectado en los diferentes tipos de hojas de resultados para nuestro driver y nuestro controlador de base de datos.Después de haber llamado al método insertRow.*.CONCUR_UPDATABLE). 2. public class InsertRows { public static void main(String args[]) { String url = "jdbc:mySubprotocol:myDataSource".TYPE_SCROLL_SENSITIVE. } catch(java. Hay algunas cosas que podríamos observar sobre el código. Después de haber introducido los valores de una fila con los métodos updateXXX. y moveToCurrentRow. 150). Cuando llamamos al método moveToInsertRow.println(e.ClassName"). que requieren movimientos relativos a la fila actual. uprs es actualizable. es posible que los métodos getXXX llamados después de las inserciones no recuperen los valores de la nuevas filas.

porque el número de filas en la hoja de resultados no ha cambiado.getInt("TOTAL"). nuestro código se parecería a esto. System.updateString("COF_NAME". uprs. En otras palabras. Por ejemplo. Todo lo que tenemos que hacer es mover el cursor a la fila que queremos borrar y luego llamar al método deleteRow. Algunos drives JDBC utilizan una fila en blanco en su lugar pone (un "hole") donde la fila borrada fuera utilizada. uprs. Ver los cambios en una Hoja de Resultados Si modificamos los datos en un objeto ResultSet. 0). no deberíamos escribir código que dependiera de si hay una fila vacía en la hoja de resultados. Con algunos driver JDBC. float price = uprs.getFloat("PRICE"). uprs. 267 .println(" " + sales + " " + total). uprs.getInt("SUP_ID"). int total = uprs. los cambios se harán visibles si lo cerramos y lo abrimos de nuevo. si escribimos una aplicación para ejecutarse con diferentes bases de datos. uprs.uprs.out.99f).getInt("SALES"). } } Borrar una Fila Hasta ahora. uprs. System.out. 11.close(). System. se puede utilizar el método absolute con la posición original de la fila para mover el cursor.println("Table COFFEES after insertion:"). una línea borrada es eliminada y ya no es visible en una hoja de resultados. deberíamos recordar que los drivers JDBC manejan las eliminaciones de forma diferente.updateInt("SUP_ID". hemos visto cómo actualizar un valor y cómo insertar una nueva fila. y es la más simple.getString("COF_NAME").out. 150). En cualquier caso. } catch(SQLException ex) { System. } uprs.beforeFirst(). "Kona_Decaf").deleteRow(). Por ejemplo. int sales = uprs.println("SQLException: " + ex. int id = uprs. La cuarta fila ha sido eliminada de uprs y de la base de datos. con. Si existe una fila en blanco en lugar de la fila borrada. Borrar una fila es la tercera forma de modificar un objeto ResultSet.insertRow().getMessage()). si queremos borrar la cuarta fila de la hoja de resultados uprs.updateFloat("PRICE". uprs. while (uprs. El único problema con las eliminaciones es lo que ResultSet realmente hace cuando se borra una fila.updateInt("TOTAL". stmt. uprs.close().absolute(4).err. si re-ejecutamos la misma petición.next()) { String name = uprs.print(name + " " + id + " " + price).updateInt("SALES". uprs. 0).insertRow().close().

(La urgencia de obtener los últimos datos es bastante improvable en la tabla COFFEES. generalmente no podremos ver los cambios hechos mientras esté abierta. Observa que la hoja se resultados debería ser sensible. En un objeto ResultSet que sea TYPE_SCROLL_INSENSITIVE. Algunos programadores utilizan sólo este tipo de objeto ResultSet porque quieren una vista consistente de los datos y no quieren ver los cambios hechos por otros. estaremos más interesados en los cambios hechos por otros). especialmente si el controlador de la base de datos devuelve múltiples filas cada vez que se llama a refreshRow. el rendimiento se empobrece. podríamos subir el nive de aislamiento a TRANSACTION_REPEATABLE_READ. puede utilizarse cuando es crítico tener los últimos datos. pero puede mostrar los cambios que podrían tener problemas de consistencia. Con este nivel de aislamiento. basada en los datos actuales de la tabla.producirá una nueva hoja de resultados. Para permitir menores niveles de inconsistencia. De todas formas. Y siempre estamos limitados por lo que proporcionan las bases de datos y los drivers. nuestro objeto ResultSet no mostrará ningún cambio antes de ser enviado. pero la única forma de estar seguros es utilizar los métodos DatabaseMetaData que devuelven esta información. la siguiente línea de código. selecciona el nivel de aislamiento de la conexión a TRANSACTION_READ_COMMITTED. O. Esta hoja de resultados reflejara naturalmente los cambios que hayamos hecho anteriormente. El siguiente código ilustra cómo una aplicación podría utilizar el método refreshRow cuando es absolutamente crítico ver los últimos valores. utilizar el método refreshRow es el único método para asegurarnos que estamos viendo los últimos datos. si queremos utilizar el método refreshRow con un objeto ResultSet que sea TYPE_SCROLL_INSENSITIVE. Se puede utilizar el método refreshRow para obtener los últimos valores de una fila en la base de datos. donde con es un objeto Connection activo. Incluso aunque una hoja de resultados sea sensible y los cambios sean visibles. pero la fortuna de un inversor. siempre podremos ver las actualizaciones que alguien haga en los valores de las columnas. 268 . no hará nada. depende de conocer los últimos precios en la amplia fluctuación del mercado del café. Por ejemplo. La respuesta depende del controlador de la base de datos.setTransactionIsolation(TRANSACTION_READ_COMMITTED). Este método puede utilizar muchos recursos. con. Con un objeto ResultSet que sea TYPE_SCROLL_SENSITIVE. Podemos regular la extensión de que los cambios sean visibles aumentando o bajando el nivel de aislamiento de la transación con la base de datos. Normalmente veremos inserciones y eliminaciones. Por eso. (Generalmente. del driver. una aplicación no podría ver siempre los últimos cambios si el driver recupera varias filas a la vez y las almacena. El problema es que a niveles más altos de aislamiento. y del tipo del objeto ResultSet utilizado. La cuestión es si podemos ver los cambios que hayamos realizado mientras el objeto ResultSet esté todavía abierto.

} 269 . uprs.absolute(4).getFloat("PRICE"). ResultSet. uprs. . . uprs. ResultSet uprs = stmt. Float price2 = uprs.por ejemplo.executeQuery(SELECT COF_NAME. .CONCUR_UPDATABLE). querriamos asegurarnos de que el nuestro asiento reservado en el avión de regreso todavía está disponible). PRICE FROM COFFEES). // do something.absolute(4). .refreshRow(). Float price1 = uprs.getFloat("PRICE"). Statement stmt = con.TYPE_SCROLL_SENSITIVE.createStatement( ResultSet. if (price2 > price1) { // do something.

Sign up to vote on this title
UsefulNot useful