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

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

8 .

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

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

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

por lo que es más rápido. como Netscape o Internet Explorer. puede ser aminorada por los compiladores Just-InTime (JIT). Además. principalmente porque la gestión de memoria y punteros es realizada por el propio lenguaje y no por el programador. Las aplicaciones creadas en este lenguaje son susceptibles de contener pocos errores. Esta deficiencia en cuanto a la velocidad. aunque es más lento que el mismo programa escrito en C++. El lenguaje Java es robusto.4 La Máquina Virtual Java (JVM). 1. La máquina virtual Java es la idea revolucionaria 4 del lenguaje. Suelen ser incorporados por los navegadores. 12 .mucho más rápido que cualquier otro programa interpretado como por ejemplo Visual Basic. 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. Es la entidad que proporciona la independencia de plataforma para los programas Java “compilados” en byte-code. Un compilador JIT transforma los bytecodes de un programa o un applet en código nativo de la plataforma donde se ejecuta. 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.

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

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

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

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

• La herencia impone una relación jerárquica entre clases en la cual una clase hija hereda de su clase padre. 17 . • Herencia simple: la clase solo puede recibir características de otra clase base. • 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. Cada objeto reacciona a este mensaje haciendo el cálculo correspondiente de la superficie. el cual difiere de una figura a otra.• 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.6 Polimorfismo • Polimorfismo: significa la cualidad de tener más de una forma. • Herencia múltiple: la clase recibe propiedades de mas de una clase base. se puede definir la operación de sumar dos cadenas: concatenación. O además. • Polimorfismo es la capacidad del código de un programa para ser utilizado con diferentes tipos de datos u objetos. • De modo similar: suponiendo un número de figuras geométricas que responden todas al mensaje Calcular _ superficie. 2. flotantes. • Ejemplo: Operación sumar.

La forma natural de construir una clase es la de definir una serie de atributos que. prácticamente todo son clases (objetos). la palabra reservada class y el nombre que recibe la clase. •Los tipos polimórficos. 3. 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. no son accesibles fuera del mismo objeto. Para que un programa se pueda ejecutar. e incluso los métodos. • Las funciones polimórficas son aquellas funciones que pueden evaluarse y/o ser aplicadas a diferentes tipos de datos de forma indistinta. Por esta razón. 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. por su parte. Así nacen los conceptos de funciones polimórficas y tipos polimórficos. pero sí que puede asegurarse que la misma contendrá. un programa estará formado por uno o varios ficheros fuente y en cada uno de ellos habrá definida una o varias clases. El cuerpo de las clases comienza con una llave abierta({) y termina con una llave cerrada (}).7 Encapsulacion El encapsulamiento consiste en la propiedad que tienen los objetos de ocultar sus atributos. 2. como mínimo. 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. sino que únicamente pueden modificarse a través de los métodos que son definidos como accesibles desde el exterior de esa 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 general. En Java.0 VISIÓN GENERAL Y ELEMENTOS BÁSICOS DEL LENGUAJE. Dentro del cuerpo de la clase se declaran los atributos y los métodos de la clase. debe contener una clase que tenga un método main con la siguiente declaración: public static void main( String args [] ) 18 . a otras partes del programa u otros objetos.

Este ejemplo habrá que crearlo mediante un editor cualquiera y guardar el fichero con el nombre Hola. mundo” y terminará. 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. Las llaves no sirven únicamente para marcar el inicio y el fin de una clase. Entre las llaves de la clase Hola. que es descendiente. contiene muchos de los conceptos de la programación orientada a objetos en Java. La primera línea del programa declara una clase llamada Hola. 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. } } El lenguaje Java. otras llaves abierta y cerrada dentro del método main(). class Hola { public static void main(String args[]) { System.java El resultado de la ejecución será la visualización en pantalla del mensaje: Hola.java El compilador creará un fichero que se llama Hola. al no indicar nosotros que herede de otra clase. 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. distinguiendo entre mayúsculas y minúsculas). se aprendan y comprendan la totalidad de los aspectos de la POO y la sintaxis del Java.class u Hola. se declaran los atributos y los métodos de la clase.3.out. al igual que C. 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. En el ejemplo existen. El programa simplemente mostrará en pantalla el mensaje “hola.java línea a línea: Este simple programa. Todo lo que se encuentre entre la llave abierta ( { ) y la llave cerrada ( } ) pertenece a la clase Hola.java (ATENCIÓN: Es importante que tenga el mismo nombre que la clase “Hola”. además de las llaves abierta y cerrada de la clase. este es mi primer programa"). se estará en un punto bastante cercano a los conocimientos básicos necesarios para entenderlos. pero sí que puede afirmarse que una vez comprendida y asimilada su filosofía. En nuestro ejemplo.println("Hola. La extensión del mismo debe ser .1 Mi primer programa. No se pretende que.java Para compilar el programa. 19 . hay que teclear: javac Hola. a partir del mismo. por lo que es importante transcribirlo literalmente. únicamente tiene un método: main. de la clase Object. este es mi primer programa Explicación del programa Hola. aunque el sistema operativo empleado no haga esta distinción. a pesar de no ser muy extenso.class que contiene el código bytecode (“pseudoejecutable”) Para ejecutarlo: java Hola Se escribe únicamente el nombre de la clase Hola y no Hola. distingue entre mayúsculas y minúsculas. En primer lugar.

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

basta con poner dos barras inclinadas: // Ejemplo: for (i=0. 21 . 3.3 Variables y Tipos de Datos Las variables son las partes importantes de un lenguaje de programación: ellas son las entidades (valores. datos) que actúan y sobre las que se actúa. Una declaración de variable siempre contiene dos componentes. } No puede ponerse código después de un comentario introducido por // en la misma línea. coma flotante. 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. La tabla siguiente muestra todos los tipos primitivos soportados por el lenguaje Java. las clases y los interfaces como tipos de datos referenciados. Los tipos primitivos contienen un sólo valor e incluyen los tipos como los enteros.out. En Java tenemos los arrays. los caracteres. 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.1 Tipos de Variables Todas las variables en el lenguaje Java deben tener un tipo de dato. Existe otro tipo de comentario que sirve para generar documentación automáticamente en formato HTML mediante la herramienta javadoc . i<20. 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. etc. su formato.i++) // comentario de bucle { System. el tipo de la variable y su nombre: tipoVariable nombre.3. 3.. Existen dos categorias de datos principales en el lenguaje Java: los tipos primitivos y los tipos referenciados.println(“Adiós”).

por lo que el resultado de dicha operación será un int siempre. no deben tener el mismo nombre que otras variables cuyas declaraciones aparezcan en el mismo ámbito. Del mismo modo estas normas se extenderán para int. 3. Si una variable está compuesta de más de una palabra. La regla número 3 implica que podría existir el mismo nombre en otra variable que aparezca en un ámbito diferente. un short con un short o un short con un byte Java empleará para dicha operación el operador de los datos tipo int. 22 . La “jerarquía” en las conversiones de mayor a menor es: double <. 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. Un nombre de variable Java: 1.168 caracteres. esta ha de ser. Por convención.float <.2 Nombres de Variables Un programa se refiere al valor de una variable por su nombre. Veamos una ejemplo para comprender su sintaxis: class Cast { public static void main(String[] args) { int i = 9. 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. Por convención. por ejemplo: -Si cualquier operando es double todos se convertirán en double. Unicode es un sistema de codificación que soporta texto escrito en distintos lenguajes humanos.k. de una jerarquía mayor o igual a la jerarquía de la máxima variable involucrada en la operación. short y byte. De este modo cuando operemos un byte con un byte. No puede ser el mismo que una palabra clave o el nombre de un valor booleano (true or false) 3. en Java. 2. al menos. el Griego. Esto le permite utilizar en sus programas Java varios alfabetos como el Japonés. Si es de rango superior no habrá problemas. -Si cualquier operando es long y no hay datos reales todos se convertirán en long. el Ruso o el Hebreo.short <byte.3. como 'nombreDato' las palabras se ponen juntas y cada palabra después de la primera empieza con una letra mayúscula. los nombres de variables empiezan por un letra minúscula. Es posible convertir un dato de jerarquía “superior” a uno con jerarquía “inferior”.int <. los nombres de las variables empiezan con una letra minúscula (los nombres de las clases empiezan con una letra mayúscula). -Si cualquier operando es float y no hay ningún double todos se convertirán a float. Esto es importante para que los programadores pueden escribir código en su lenguaje nativo.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.3.long <. Este tipo de operación (almacenar el contenido de una variable de jerarquía superior en una de jerarquía inferior) se denomina cast. así. Debe ser un identificador legal de Java comprendido en una serie de caracteres Unicode.Unicode perminte la codificación de 34. y otro que emplea para operar datos de tipo int.

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

prt("i : " + i).tienen versiones unarias que seleccionan el signo del operando: Además.println(s). Invocando a prt podremos //imprimir por consola la cadena de caracteres que le pasemos static void prt(String s) { System. // Post-incremento.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. ++ que incrementa en uno su operando.//Ahora i vale 1 } //esto nos ahorrara teclear. primero //incrementa y luego imprime por consola prt("i++ : " + i++). Los operadores + y . Ejemplo: class Incremento{ public static void main(String[] args) { int i = 1.que decrementa en uno el valor de su operando.: " + i--).Esta tabla sumariza todas las operaciones aritméticas binarias en Java: Operador Uso + op1 + op2 op1 . // Pre-incremento. prt("i : " + i).out. prt("i : " + i). primero imprime //“2” por consola y luego incrementa i. y -. existen dos operadores de atajos aritméticos. // Pre-decremento. } } 24 .//i por lo tanto vale 3 prt("--i : " + --i). primero //decrementa i y luego lo imprime por consola prt("i-. prt("++i : " + ++i). // Post-decremento. primero imprime //i por consola y luego de decrementa.

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

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

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

Lo operadores con la misma precedencia se evalúan de izquierda a derecha. el compilador evaluará primero y / 100. 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.in. El valor devuelto por != es true o false dependiendo de la salida de la comparación. Por ejemplo.read() se ha declarado como un entero.in. la expresión System. por lo tanto. 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. Una expresión de llamada a un método devuelve el valor del método.in. Sin embargo. Por ejemplo. La salida es siempre la misma sin importar el orden en que se apliquen las multiplicaciones. él decide basándose en la precedencia asignada a los operadores y otros elementos que se utilizan dentro de una expresión. Recuerda que este operador comprueba si los dos operandos son distintos. Como has podido ver. toma la siguiente expresión compuesta: x * y * z En este ejemplo particular. no importa el orden en que se evalúe la expresión porque el resultado de la multiplicación es independiente del orden. 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 ). El operador división tiene una precedencia mayor que el operador suma. La expresión count++ devuelve un entero porque ++ devuelve un valor del mismo tipo que su operando y count es un entero. Los operadores con mayor precedencia se evalúan antes que los operadores con un precedencia relativamente menor. esto no es cierto para todas las expresiones. 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. Por ejemplo. 28 .in..in. en la expresión anterior x + y / 100. para aclarar la sentencia anterior. el orden en que se evalúan los componentes de una expresión compuesta. etc. el valor devuelto por System. System.read() != -1 compara dos enteros. El método System. Los operadores se han listado por orden de precedencia de mayor a menor.in.in. cadenas. La tabla siguiente muestra la precedencia asignada a los operadores de Java. se podría escribir: (x + y)/ 100.read() y -1. Por ejemplo.read() devuelve un entero. Los operadores con una precedencia más alta se evalúan primero.read() != -1 utiliza el operador !=.read() es un operando válido para != porque devuelve un entero. por eso.read() y -1. En esta sentencia los operandos son System.. También habrás podido concluir del ejemplo anterior. Si no le dices explícitamente al compilador el orden en el que quieres que se realicen las operaciones. Otras expresiones devuelven valores booleanos. Así System.El tipo del dato devuelto por una expresión depende de los elementos utilizados en la expresión. La segunda expresión contenida en la sentencia System.

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

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

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

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

si se verifica se continua ejecutando el código del bucle hasta que esta deje de verificarse. que por la disposición de los caracteres Unicode //será un letra del abecedario. } } } } 4. „i‟. //Math. Al sumarle un carácter. 4. „o‟ o „u‟ imprimimos //vocal. for(int i = 0.random()*26 será un número real aleatorio entre 0 y //26. 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. Ejecutará 100 veces el código que tiene dentro.print(c + ": ").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. Será un carácter //aleatorio. Su sintaxis es: while(condición){ Grupo de sentencias} Ilustramos su funcionamiento con un ejemplo: 33 . i++) { //Math.random() * 26 + 'a').println("consonante"). i < 100. //Se transforma el número aleatorio entre 97y 97 + 26 en el //carácter correspodiente a su parte entera. default: //Si no era ninguna de las anteriores imprimimos consonante. System. System.out. „a‟ = 97. aunque también hay que reconocer que a veces se le puede sacar partido. Esto es en muchas ocasiones fuente de errores. char c = (char)(Math. switch(c) { case 'a': case 'e': case 'i': case 'o': case 'u': //Si el carácter es „a‟. System.out. break.random() es un métod estático que genera un número real //aleatorio entre 0 y 1.2 BUCLES Son instrucciones que nos permiten repetir un bloque de código mientras se cumpla una determinada condición.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.out.println("vocal").2. „a‟ el carácter se transforma a //un enteroy se le suma. „e‟. Pasemos a ver sus tipos.

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

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

la forma en que un programador implemente sus objetos no influye en absoluto en lo que los demás programadores hagan. En Java todo es un objeto. que dialogan entre ellos pasándose mensajes para llegar a resolver el problema en cuestión.5. 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). 5. 5. sólo le importa a que mensajes es capaz de responder. y al final hay que juntar todos estos con el programa central que los llama. Object Oriented Programing). C++. por ejemplo. Todos los objetos pertenecen a una determinada clase. y en lo único que tendrán que ponerse de acuerdo entre ellos es en los mensajes que se van a pasar. A un objeto no le importa en absoluto como está implementado otro objeto. 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. ¿qué es un objeto? y ¿qué es la programación orientada a objetos?. que variables usa.0 OBJETOS Y CLASES Como ya hemos comentado Java es un lenguaje totalmente orientado a objetos. independientes entre si. 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). reales y char. y esta era la única capacidad de reuso de código posible.. 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. en principio. 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. a excepción de los tipos básicos de variables enteras. La única posibilidad de repartir trozos de código relativamente independientes entre programadores son los procedimientos. Aquí un programa no es un código que llama a procedimientos. En los años 70 se empezó a imponer con fuerza otro estilo de programación: POO. mucho más que.. totalmente desconocida para los demás objetos (a veces no es así. Pero bien. que ha de ser conocida por los demás.. La OOP permite abordar con más posibilidades de éxito y con un menor coste temporal grandes proyectos de software. pero es lo ideal en un buena OOP). programación orientada o objetos (en la literatura suele aparecer como OOP. 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 . aquí un programa es un montón de objetos. 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. Un objeto que se crea a partir de una clase se dice que es una instancia de esa clase. Esta segunda parte es. y además cada programador tendrá total libertad para llevarla a cabo como él considere oportuno. Responder a estas preguntas no es en absoluto trivial. Un programa era un código que se ejecutaba. 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. siendo frecuente encontrar problemas al unir estos trozos de código. varios o ningún dato y nos devuelve un dato a cambio. Las distintas clases tienen distintas relaciones de herencia entre si: una clase puede 36 . que código tiene o deja de tener. Por ser desconocida para los demás objetos podemos en cualquier momento modificarla sin que a los demás les importe.1 INTRODUCCIÓN En los años 60 la programación se realizaba de un modo “clásico” (no orientado a objetos). simplificándole además la tarea al programador. Un método es muy semejante a un procedimiento de la programación clásica: a un método se le pasan uno. Si hay que repartir un programa de grandes dimensiones entre varios programadores a cada uno se le asignan unos cuantos objetos. Un mensaje es la invocación de un método de otro objeto.2 CLASES Y HERENCIA Una clase es la “plantilla” que usamos para crear los objetos.

nombre_clase_padre es el nombre de la clase padre.out. 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.println("Hola mundo"). no se puede derivar ninguna clase de ella. de la cual hereda los métodos y variables.2.2. final: Indicará que esta clase no puede “tener hijo”. Veamos que opciones tenemos: 5. 5. Ninguno: La clase es “amistosa”. 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.1 Modificadores de clases public: La clase es pública y por lo tanto accesible para todo el mundo.println(edad). al menos durante este curso. nombre_clase es el nombre que le queramos dar a nuestra clase.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.out. } } 5. String nombre.1. } Los campos que van entre corchetes son optativos.2. Vamos a continuación a profundizar en todos estos conceptos y a explicar su sintaxis en Java. 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. toda referencia al término “package”.println(nombre). Como nunca trabajaremos en varios directorios asumiremos que la ausencia de modificador es equivalente a que la clase sea pública.1. Será accesible para las demás clases del package. abstract: Se trata de una clase de la cual no se puede instanciar ningún objeto.out. 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. Sólo podemos tener una clase public por unidad de compilación. observar que tiene métodos con el mismo nombre: 37 . public void nace(){ System. } public void get_edad(){ System.derivarse de otra. Declaración de métodos. Por motivos de tiempo no abordaremos en este curso que es un package. o haremos breves referencias a este concepto sin dar demasiadas explicaciones. } public void get_nombre(){ System.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. En general en lo que al alumno respecta se recomienda ignorar. aunque es posible no tener ninguna. Los modificadores indican las posibles propiedades de la clase. Ejemplo: class Animal{ int edad. 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.

out.out. no siendo necesario indicar que el tipo de dato devuelto es void.class Animal{ int edad.1.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. 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(edad). } public void get_nombre(){ System.. abrir un archivo o una conexión de internet. } } 38 .println(edad). Como cualquier método. } public void get_edad(){ System.println(nombre).println("Hola mundo"). String nombre. Cuando creamos un objeto (ya se verá más adelante como se hace) podemos invocar al constructor que más nos convenga.)..println(nombre +" " +edad). } public void get_nombre(int i){ System.out.2. } public void get_edad(){ System. nombre = _nombre. String nombre.out. class Animal{ int edad.println("Hola mundo").println(nombre +" " +edad).println(nombre). Ejemplo: Veamos la clase Animal y sus constructores. public void nace(){ System. un constructor admite sobrecarga.out.. } public void nace(){ System. } } 5. String _nombre){ //constructor con 2 argumentos edad = _edad. public Animal(){ //constructor por defecto } public Animal(int _edad.out. } public void get_nombre(int i){ System.out..} public void get_nombre(){ System.

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

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

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

} Otro posible uso de this..println("Miau"). else System.hablar(). String nombre){ //this. Una interface es formalmente como una clase. Veámoslo con un ejemplo: interface Animal1{ public int edad = 10. public Animal(int edad. 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). this. como ya se empleó en un ejemplo. 5. En principio esto pudiera parecer una propiedad interesante que le daría una mayor potencia al lenguaje de programación.2.edad =edad.. } } class GatoMagico extends Gato { boolean gente_presente. 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.nombre=nombre.3 INTERFACES En Java no está soportada la herencia múltiple.out. llamar al constructor de la clase padre. public String nombre = "Bob".. con dos diferencias: sus métodos están vacíos.. que ya se ha visto en ejemplos anteriores es diferenciar entre variables locales de un método o constructor y variables del objeto. } 5.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. void hablar(){ if(gente_presente) //Invoca al método sobreescrito de la clase padre super.out. no hacen nada. y a la hora de definirla en vez de emplear la palabra clave “class” se emplea “inteface”. 42 .} . } } Uno de los principales usos de super es.println("Hola"). no está permitido que una misma clase pueda heredar las propiedades de varias clases padres.edad = variable del objeto perro //edad = variable definida sólo dentro del constructor this.

println(nombre ). } ***************************************************** public class Perro1 implements Animal1{ Perro3(){ get_nombre(). 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. public void get_nombre(). } //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. Para que un método sobrescriba a otro ha de tener el mismo nombre.out. se le han de pasar los mismos datos. } public void get_nombre(int i){ System. Su función es la de ser una especie de constantes para todos los objetos que implementen dicha interface. get_nombre(8). //Compruébese como esta línea da un error al compilar debido //a intentar asignar un valor a una variable final // dog. Además no pueden llevar modificadores private ni protected. 43 .println("hola mundo"). Veámoslo con un ejemplo de una clase que implementa la anterior interface: interface Animal1{ public int edad = 10.out. public void nace(){ System.public void nace(). } } Las variables que se definen en una interface llevan todas ellas el atributo final. y es obligatorio darles un valor dentro del cuerpo de la interface. Si no tuviera el mismo modificador el compilador nos daría un error y no nos dejaría seguir adelante.println(nombre +" " +i). 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 String nombre = "Bob". void get_nombre(int i). ha de devolver el mismo tipo de dato y ha de tener el mismo modificador que el método al que sobrescribe. } public void get_nombre(){ System. void get_nombre(int i). } public static void main (String[] args){ Perro1 dog = new Perro1().out. public void get_nombre(). } Cabe preguntarnos cual es el uso de una interface si sus métodos están vacíos. public void nace().edad = 8. Bien. sólo public.

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

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

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

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

desde = getParameter ("desde"). } public void paint (Graphics g) { g. if (desde == null) desde = "aqui". g. para = getParameter ("para").green).setColor (Color. g. if (para == null) para = "alla".drawString ("Desde " + desde + " para " + para. 40). 80).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 .setFont (f). 5. if (mssg == null) mssg = "no hay mensaje". g.red). g. } } Codigo html: <HTML> <HEAD> <TITLE>Ejemplo con Argumentos !!!</TITLE> </HEAD> <BODY> <P><H2>Bienvenido a Programacion III:</H2><P> <APPLET CODE="EjemploArgumento.setColor (Color. mssg = getParameter ("mensaje").drawString ("El mensaje es: " + mssg. 5.

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

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

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

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

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

Para definir un botón hay que crear un objeto de tipo Button indicando el texto que desplegará el botón: Constructores: Button().LEFT. se genera un evento de acción que se envía a cualquier 58 . 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. }} 7. Label lbl3 = new Label().CENTER).applet. Para obtener el alineamiento de la etiqueta se utiliza el método getAlignment() Ejemplo: import java.0 Abstract Window Toolkit y Eventos 7.7. Label.RIGHT). public void init () { lbl3. 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(). si queremos obtener el texto de una etiqueta se utiliza el metodo getText(). Label lbl2 = new Label ("Etiqueta dos".RIGHT.CENTER Se puede establecer o cambiar el texto de la etiqueta con el método setText(). Label.1 Etiquetas Una etiqueta es un texto no editable que despliega un letrero en la pantalla. int how) El valor de how debe ser cualquiera de estas constantes: Label. import java. Label(String str. Se puede establecer el alineamiento del string dentro de la etiqueta utilizando el método setAlignment(). add (lbl3). Label(String str).setAlignment(Label. add (lbl2). add (lbl).setText("Etiqueta tres").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. Button(String str) Una vez creado el boton se le puede asignar un Label llamando a setLabel().awt. lbl3.*.*. Label.

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

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

add (solaris).cbg. public class Checkbox2Applet extends Applet implements ItemListener{ String msg="". win98. Como argumento de este metodo se pasa un objeto ItemEvent. add (linux).cbg. solaris=new Checkbox("Solaris".true).applet.6. Cada auditor implementa la interfaz ItemListener. linux.addItemListener(this). linux.Gestión de Checkbox Cada vez que se selecciona o se deselecciona un checkbox.*. g.getSelectedCheckbox().awt. } public void paint(Graphics g){ msg="Seleccion Actual : ".drawString(msg. 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. Esta interfaz define el metodo itemStateChanged().50). import java. import java.awt.addItemListener(this). que encapsula la inforarmacion sobre el evento. solaris.addItemListener(this).*.false). win98=new Checkbox("Window98". } } 61 . Checkbox win98.false). } public void itemStateChanged(ItemEvent ie){ repaint().getLabel(). msg+=cbg. CheckboxGroup cbg.event.cbg. add (win98).*. solaris. Ejemplo: import java. linux=new Checkbox("Linux". public void init (){ cbg=new CheckboxGroup().

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

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

break. g. // dibuja la cubierta g. case 2 : g. break.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.black). 160).class miCanvas extends Canvas { int color_mesa = 0. 157. case 3 : g.drawLine (175. break.drawLine (215. 40. -65. 89). 175.drawArc (85. 312). case 1 : g. 110. 58).fillArc (78. break. } } 7. 50. -174). mientras el campo de texto puede leer solo una línea de texto. 40. case 3 : g.fillArc (173. 50. break. } g.red).setColor (Color.drawArc (85. case 2 : g. 290). break. La diferencia es que.green).blue). 62.fillOval (120. 177. 250. } g.setColor (Color.setColor (Color.green). el área de texto puede leer varias. g.setColor (Color.drawLine (125.black).drawLine (85. 87. 250. 177.8. 180). } public void cambiaColorMesa (int c) { color_mesa = c. int color_lampara = 0.red). 160).setColor (Color.blue). public void paint (Graphics g) { switch (color_mesa) { case 0 : g. repaint (). 63. repaint (). break. 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.setColor (Color.setColor (Color. 72 . // dibuja las motas g. g. 100. 125. // dibuja la base g. // dibuja la mesa switch (color_lampara) { case 0 : g. 96. 250. 40. 40. g. break. 40. 290.fillRect (0. 40). case 1 : g. 181. g. 119. } public void cambiaColorLampara (int c) { color_lampara = c. 89). 130. 130.setColor (Color. 120.

Después de escribir un texto cualquiera en la primera área de texto. El texto capturado se puede recuperar llamando al método getText.getText (). // texto inicial TextArea ta4 = new TextArea ("hola". TextArea ta1 = new TextArea (). ta2. A pesar de que el texto esté en varias líneas. // 10 renglones y 60 columnas TextArea ta3 = new TextArea ("hola mundo". String s = ta1. El siguiente ejemplo presenta un applet con dos áreas de texto. 10. 60. TextArea. al oprimir el botón de Cuenta. como si fuera una sola cadena de caracteres. el área de texto lo trata como un string.setText ("Esto es una línea\nEsto es otra línea"). // el tamaño se deja al diseño TextArea ta2 = new TextArea (10. 73 . La figura muestra la salida del programa. es decir. Se puede asignar texto desde el programa con el método setText. la segunda área de texto despliega el número de líneas y de caracteres que se escribieron. 60). 60).SCROLLBARS_NONE). 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. un tamaño preferido de desplegado en renglones y columnas y un indicador para que despliegue o no barras de scroll de inicio.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. 10.

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

La figura muestra la salida del programa. // cinco opciones visibles a la vez List lst3 = new List (5. Al oprimir el botón.add ("opción uno").8. // permite escoger una opción List lst2 = new List (5).getSelectedIndexes (). lst2. } } 7. lst2. // permite opciones múltiples Las opciones se agregan con el método add. En las listas que permiten la selección de únicamente un elemento el método getSelectedIndex devuelve la posición del elemento seleccionado.add ("opción dos"). 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. El listado ejemplo presenta un applet con un choice. int opción = lst1. una lista que permite seleccionar un solo elemento y una lista que permite selección múltiple. true). en la parte inferior se despliegan las opciones que fueron seleccionadas en el choice y en las listas. 75 .getSelectedIndex ().} }).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. int opciones[] = lst3. En las listas que permiten múltiples selecciones el método getSelectedIndexes devuelve un arreglo de enteros con las posiciones de los elementos seleccionados. List lst1 = new List ().

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

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

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

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

los diálogos se utilizan en forma modal y para avisar de errores en el programa o pedir datos al usuario. true). 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. setLocation. Un diálogo modal impide que sean accesadas otras ventanas hasta que el diálogo sea cerrado. // el diálogo es no modal por default Dialog dlg2 = new Dialog (frame. Por estos motivos y por lo general. no tienen indicadores de maximizar ni de minimizar y pueden operar en forma modal. dispose y addWindowListener 80 . } }).dispose (). Dialog dlg1 = new Dialog (frame). setVisible. Las diferencias son que los diálogos necesitan tener un frame ligado a ellos. } } 7. // el diálogo es modal Dialog dlg3 = new Dialog (frame. "titulo".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.8. // tiene título y es modal Los métodos setLayout. true).public void windowClosing (WindowEvent e) { frm_1. add. setSize.

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

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

AWT y del subpaquete java. éste objeto es recogido por el método setLayout() de la clase Container. viendo qué es un gestor de diseño desde tres puntos de vista diferentes:   Desde el punto de vista del lenguaje. 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. un gestor de diseño es un interfaz. para poder incorporar controles en una ventana (ya sea de una aplicación o de un applet). un objeto del tipo deseado de gestor de diseño con el que se desea trabajar. 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. un Gestor de diseño es una propiedad del contenedor. como ya hemos comentado. 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). que es la que se encuentra en la raíz de la jerarquía de clases. vamos a tratar dos características del interfaz de usuario en los programas Java. en éste veremos lo común a los dos tipos de componentes. siempre que se crea un Container. 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á. 8. es necesario que estos estén contenidos en un gestor de diseño.1 Gestores de diseño Los gestores de diseño (Layout Managers) tienen una gran importancia en el leguaje Java. qué gestor de diseño se asignará al contenedor. y deriva directamente de la clase Object. Veamos esto de una forma más detenida. por ejemplo. vamos a continuar con la creación de interfaces de usuario en Java. que puede almacenar cualquier tipo de objeto que derive de la clase Container (normalmente bien controles o bien otros gestores de diseño). Lo que se hace pasándole al método setLayout() de la clase Container.8. Comencemos por lo tanto. aunque muchas de las clases que implementan los gestores de diseño y el tratamiento de eventos se encuentran dentro del paquete JAVA. El gestor de diseño es parte del Container. se hace necesario indicar con cual de los disponibles deseamos trabajar. los gestores de diseño y los eventos. o dicho de otro modo. es decir.events.  Desde el punto de vista operativo. 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 operador new devuelve un gestor de diseño del tipo FlowLayout.0 Gestores de diseño Introducción A lo largo de este capítulo. Veamos. Sin embargo.awt. 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. quien a partir de ahora ya sabe con qué gestor deseamos trabajar.setLayout(new FlowLayout()). un gestor de diseño es un "estilo de visualización". de otro modo no funcionarán correctamente. 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. se puede especificar con cual o cuales de los gestores de diseño disponibles en Java se quiere trabajar. 83 . de hecho.  Desde el punto de vista de la jerarquía de clases de Java. la siguiente línea de código: this.

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

A continuación vamos a comentar los distintos gestores de diseño que podemos encontrar dentro del paquete JAVA. 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.Aunque no lo he dicho. 8. JButton b4 = new JButton ( "D" ) .1. Ejemplo: import java.*.AWT.add ( b2 ) . class EjemploFlowLayout extends JFrame{ public EjemploFlowLayout( ) { Container c = getContentPane ( ) . JButton b1 = new JButton ( "A" ) . } 85 . cuando acaba con una fila de controles. 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. es también el más simple de todos. Es decir. además de ser el gestor de diseño por defecto de los applets.*. import java.setLayout (new FlowLayout ( ) ) . JButton b2 = new JButton ( "B" ) . tras ejecutar el programa veremos como nuestro botón es considerablemente más grande. En el ejemplo anterior.1 FlowLayout El gestor de diseño FlowLayout. actuando con los controles como lo hace un editor de textos con las palabras.swing. distribuye los controles de izquierda a derecha llenando el ancho del contenedor de arriba a abajo. inicialmente podríamos pensar que se verá un botón de 80 puntos de largo por 25 de ancho.awt.add ( b5 ) .event. Los cinco gestores de diseño son los que se comentan a continuación. todos los layout managers implementan la interfaz LayoutManager directa o indirectamente (a través de LayoutManager). Sin embargo. 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. ¿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. c. por lo que nuestra llamada a setMaximumSize() no hace ningún efecto. import javax.add ( b4 ) . sigue con la siguiente. c. c. JButton b5 = new JButton ( "E" ) . Es decir. c.add ( b3 ) . Este atributo indica el tamaño que a un componente le gustaría tener.*. JButton b3 = new JButton ( "Botón largo " ) . si que se establece el tamaño máximo de 80x25 para el botón. los controles fluyen (Flow). c. Si creamos un pequeño programa que contenga las líneas de código anteriores y lo ejecutamos. c.awt. El último aspecto importante a tener en cuenta es el significado del atributo preferredSize. Este gestor.add ( b1 ) .

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

el que se encontraba en el contenedor desaparecerá y el nuevo ocupará su lugar.EAST BorderLayout. Con los componentes de las posiciones este y oeste pasa lo contrario. Cuando añadimos un componente en las posiciones norte o sur. 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. 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. al añadi r un elemento al BorderLayout tenemos que especificar la región en la cual lo queremos añadir.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.WEST BorderLayout. Aunque ya las hemos visto en el código las resumiremos de nuevo: BorderLayout. Si no especificamos ninguna región por defecto el componente se inserta en el centro del contenedor. Por ejemplo. Por lo tanto tenemos que tener cuidado con donde insertamos los componentes. una barra de estado en el panel sur y quizás un árbol de navegación en el panel izquierdo o derecho. BorderLayout. Para finalizar con este layout manager vamos a hablar de como trata el tamaño de los componentes. Si insertamos un componente en una región donde había otro componente previamente. es muy útil para muchas aplicaciones. por su estructura.Como podemos ver en el código f uente anterior.SOUTH BorderLayout. 87 . dejando el panel central para el resto del interfaz. BorderLayout respeta su alto mientras que la longitud del mismo se ajusta hasta ocupar todo el ancho del contenedor. Por último el objeto que se situe en la zona central ocupará el resto de espacio disponible. sería bastante normal colocar una barra de herramientas en el panel norte de nuestra ventana.NORTH BorderLayout.

Veamos un ejemplo simple: import javax.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.*. Por último. public class TestCardLayout extends JFrame { public static void main(String[] args) { TestCardLayout frame = new TestCardLayout().8.add(label4.CENTER). siguiente.EXIT_ON_CLOSE). panelComponentes.”2”).addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { layout. BorderLayout.setSize(400.add(siguiente. BorderLayout. import java. public void previous(Container contenedor). panelComponentes. panelComponentes.getContentPane().”1”). frame.add(label1. este nombre lo podremos utilizar con el método show para mostrar el componente directamente. JLabel label1 = new JLabel(“Componente 1”). container. String nombre).add(label2. 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.add(panelComponentes.”3”). container. Este método inserta un componente dentro de un contenedor y le asigna un nombre. panelComponentes. frame. public void next(Container contenedor). String nombre).swing.setLayout(layout).next(panelComponentes). public void last(Container contenedor). public void show(Container container. JLabel label2 = new JLabel(“Componente 2”). } }).event.”4”).add(label3.setDefaultCloseOperation(JFrame. El método más común para añadir un componente es: public void add(Component componente.*. JLabel label4 = new JLabel(“Componente 4”). Container container = frame.awt.NORTH). JButton siguiente = new JButton(“siguiente”).awt.setTitle("Prueba de BorderLayoutLayout"). Para seleccionar el componente que queremos mostrar en cada momento disponemos de varios métodos: public void first(Container contenedor). import java. 88 .300). frame. JLabel label3 = new JLabel(“Componente 3”). 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.1. Los componentes a medida que se insertan en el contenedor van formando una secuencia. En este layout manager los componentes ocuparán todo el tamaño disponible en el contenedor. JPanel panelComponentes = new JPanel(). panelComponentes. CardLayout layout = new CardLayout().*.

Cada fila y cada columna tiene el mismo tamaño y el área del contenedor se distribuye equitativamente entre todas las celdas. Es similar a los controles de pestaña o "tabs" de Windows. } } El ejemplo es muy sencillo y muestra un contenedor con varias etiquetas. Al pulsar el botón se muestra la etiqueta siguiente llamando al método next() de CardLayout. y las fichas (o tarjetas si se prefiere) no tienen la correspondiente pestaña asociada.awt. por lo que no existe una forma preestablecida de interactuar con los controles para cambiar de unas fichas a otras. en un conjunto de filas y columnas.4 GridLayout GridLayout divide el espacio de un contenedor en forma de tabla. El número de filas y columnas se especifica en el constructor. El problema que este gestor de diseño tiene es que la implementación que en Java se ha hecho de él. container.*.Y)).1. 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.frame. En lugar de eliminar el panel e insertar otro nuevo. es decir. Veamos un ejemplo simple de funcionamiento: import javax. 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. Con un botón podemos ir avanzando de etiqueta. siendo necesario crear este mecanismo programáticamente con los inconvenientes de pérdida de tiempo y esfuerzo que esto supone. for (int i = 0.setVisible(true). Container container = frame. 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).getContentPane(). int X = 3. i++) { 89 . Este tercer gestor permite manejar varias "fichas intercambiables". es decir. import java.setLayout(new GridLayout(X. o en lugar de eliminar los componentes e insertar otros nuevos. 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. int Y = 3. i < X.swing. 8. public class TestGridLayout extends JFrame { public static void main(String[] args) { TestGridLayout frame = new TestGridLayout(). podemos utilizar un CardLayout que nos ahorra gran cantidad de trabajo. 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.*. de forma tal que sólo una esté visible a la vez y ocupando todo el área del contenedor.

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

A continuación vamos a ver los atributos importantes. 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. Estas restricciones especifican exactamente como se mostrará cada elemento dentro del contenedor.• Las interfaces construidas son más ligeras. Comprendiendo a la perfección su significado no habrá ningún interfaz que se nos resista. • 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. No sólo es necesario comprender su funcionamiento sino que también es necesario haber hecho bastantes ejemplos para llegar a dominarlo. no voy a mostrar la totalidad de atributos para no complicar las cosas a los menos experimentados. Realmente no siempre es necesario establecer su valor ya que en los casos más simples nos llegaría con gridwidth y gridheight.Layout sea un juego de niños. 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. también tiene sus inconvenientes: • Requiere un tiempo de aprendizaje bastante grande. Básicamente lo que indican 91 . 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. GridBagConstraints. La clase GridBagConstraints posee bastantes atributos que nos permiten configurar el layout de un contenedor a nuestro gusto. GridBagLayout a fondo GridBagLayout basa su funcionamiento en una clase auxiliar que establece restricciones a los componentes. sin embargo la experiencia dice que poner este atributo es recomendable ya que permite saber en que elemento nos encontramos de una manera visual. Los paneles son objetos bastante pesados y tener una gran cantidad de los mismos puede influir perjudicialmente en el rendimiento de nuestro programa. Con GridBagLayout se pueden crear interfaces exactamente iguales pero con un único panel con lo que nuestra interfaz será mucho más ligera. 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.

indica que el componente ocupará el espacio disponible desde la fila o columna actual hasta la última fila o columna disponibles.RELATIVE. su valor puede ser: • Un número cardinal.gridheight=1 c. 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.RELATIVE 92 .gridwidth y gridheight es el número de celdas que ocupará un componente dentro del GridBagLayout. Analicemos la figura anterior para comprender el significado de estos dos atributos.Siempre y cuando no se use gridx y gridy. Ambos tienen como gridheight RELATIVE ya que se encuentran en la penúltima fila. El primer componente tiene de gridwidth REMAINDER. es decir. 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.REMAINDER c.RELATIVE c. • GridBagConstraints. Todos los componentes ocupan una celda en horizontal y en vertical luego su gridwidth y gridheight ha de ser igual a uno.REMAINDER.RELATIVE c.gridwidth=1 c. en este caso indica exactamente el número de filas o columnas que ocupará el componente.gridheight=1 c.gridwidth=GridBagConstraints. 1.1 En la segunda fila tenemos dos componentes. ocupará todo el espacio hasta el último componente.gridheight=1 c. • GridBagConstraints. indica que el componente es el último de la fila actual o columna actual.gridwidth=GridBagConstraints.gridheight=GridBagConstraints. En la primera fila tenemos tres componentes. En el segundo y tercer componente en lugar de ponerle uno como valor de gridwidth hemos de poner RELATIVE y REMAINDER. c.gridwidth=GridBagConstraints.

NORTHWEST. anchor especifica la posición que ocupará un componente dentro de una celda.REMAINDER c.gridwidth=GridBagConstraints. NORTHEAST.RELATIVE Por último en la tercera fila tan sólo tenemos un componente con gridwidth REMAINDER y gridheight REMAINDER. anchor Este atributo es mucho más sencillo. SOUTHWEST. • VERTICAL: El componente ocupará todo el espacio vertical de la celda mientras que su longitud será la que tenga como preferida. Como veis es bastante sencillo.REMAINDER c. Los valores que puede tomar este atributo están definidos como variables estáticas dentro de la clase GridBagConstraints y son: NORTH. WEAST. • BOTH: El componente ocupará la totalidad de la celda Veámoslo en una imágen: 93 . 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. 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. 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.c.gridheight=GridBagConstraints. Como intuiréis indican la orientación de los componentes dentro de la celda que ocupan.gridwidth=GridBagConstraints. fill El atributo fill especifica el espacio que ocupará el componente dentro de la celda.gridheight=GridBagConstraints. SOUTHEAST y CENTER. 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. SOUTH. gridwidth y gridheight especifican el número de celdas horizontal y vertical que abarcará un componente.

Sin embargo existe un pequeño problema que veremos a continuación. Fijaros en la figura anterior. ¿Cómo hacemos entonces para que las celdas ocupen la totalidad del contenedor?. las líneas marcan los bordes de las celdas. Como se puede apreciar en la figura según el valor del atributo anchor los componentes abarcarán más o menos espacio. en este caso las celdas si que ocupan todo el contenedor. pero eso es debido a que he utilizado los atributos weightx y weighty. 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. 94 .Como antes. Como veis las celdas tienen de largo la longitud máxima de los componentes y de alto la altura máxima de los componentes. 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. 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. Como habéis podido observar hasta ahora no ha habido nada complicado. 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. 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. la respuesta como cabía esperar son los atributos weightx y weighty. weightx y weighty Estos dos atributos son la clave de los dolores de cabeza que GridBagLayout le da a tanta gente.

0. Este número representa al porcentaje de espacio libre que ocupará cada celda. por lo tanto a cada uno le tocan 125 puntos.4. Veamos como queda el ejemplo anterior pero utilizando los atributos weightx y weighty: 95 .weightx=0.Los atributos weightx y weighty especifican el porcentaje de espacio libre que ocupará una celda eterminada. Obviamente cuando estemos diseñando el interfaz no estaremos pensando en si este componente va a tener unos puntos y otro otros.weightx=1.weighty=1. Veamoslo: Este espacio libre (flechas) se dividirá entre todas las celdas que especifiquen valores dentro de los atributos weightx y weighty. c. 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. 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. c. en total 200 puntos. En el ejemplo anterior una vez añadidos los componentes queda una determinada cantidad de espacio libre tanto horizontal como vertical.0 y 1. Como ambos componentes han pedido espacio libre. Como vimos antes se divide el espacio libre entre los componentes que lo han pedido. En este caso como los dos componentes han pedido la totalidad de su parte a ambos les corresponden 75 puntos.0 Veamos como se asigna el espacio horizontal.0 • Componente 2: c. éste se divide entre ambos.0. La forma de especificar el espacio que quiere ocupar cada componente es mediante un número entre 0.weighty=1. El espacio vertical es más sencillo. Un ejemplo: • Espacio libre 250 puntos en horizontal y 150 en vertical • Componente 1: c.

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

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

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. hacer clic con el ratón. El objeto que escucha los eventos es el que se encargará de responder a ellos adecuadamente. pulsar el ratón sobre un botón o menú (Java distingue entre simplemente pulsar el ratón en un sitio cualquiera o hacerlo. y ellas deciden si han de responder o no de algún modo a este evento.0 EVENTOS El sistema de gestión de eventos de Java de la AWT es similar al de SWING. estos atributos no son estrictamente necesarios al igual que tampoco lo son gridwidth o gridheight. 98 . Como ya os he comentado. por ejemplo. por ejemplo un scroll. consideraron que era lo suficientemente bueno. 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. A menudo con utilizar una de las dos alternativas será suficiente pero habrá ocasiones en las que tendremos que utilizar ambos atributos.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.0. en un botón). 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. mover el ratón. 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. ¿Qué es un evento? Todos los sistemas operativos están constantemente atendiendo a los eventos generados por los usuarios. Estos eventos pueden ser pulsar una tecla. El sistema operativo notifica a las aplicaciones que están ocurriendo estos eventos. 9. Dónde se produce el evento se denomina “fuente del evento”. sobre todo si se compara con el sistema de gestión de eventos de Java 1. mucho más engorroso de usar y menos elegante. Realmente este sistema de gestión de eventos es bastante elegante y sencillo.

El objeto que escucha los eventos ha de implementar para ello una interface. Cuando el usuario genere el evento deseado (en este caso pulse el botón). por ello se dice que la fuente delega la gestión del evento en el manejador. responder al evento.. Lo que la fuente de eventos le pasa al objeto encargado de escuchar los eventos es. 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. A la fuente del evento. manejador que ha de extender la clase Adapter correspondiente o implementar la interfaz Listener (interfaz ActionLitener en este caso). Es un objeto tipo Event. como no. 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.. 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. y no de la fuente. otro objeto. manejador ha de pertenecer a una clase que implemente la interface MouseListener. A continuación en la siguiente tabla mostramos los 99 ..Gestión de eventos en Java. en este caso un botón. le indicamos quién será su manejador de eventos. Es responsabilidad del manejador.addMouseListener(manejador). Para hacer que un objeto escuche los eventos de otro objeto se emplea el método add[nombre_evento]Listener. En este objeto va toda la información necesaria para la correcta gestión del evento por parte del objeto que escucha los eventos. para que escuche eventos de teclado KeyListener. que tiene un total de 7 métodos que ha de implementar..

eventos más comunes. 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. En la columna de la derecha se presentarán diversos componentes que pueden generar dichos eventos. 100 .

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

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. 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). 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. pero nosotros sólo estaremos interesados en un método de dicha interfase: mouseClicked.Así por ejemplo si estamos interesados en escuchar clics de ratón hemos de crear una clase que implemente MouseListener.

y la fuente será el botón que lanzará el evento correspondiente.awt. 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 . Así por ejemplo. se verá mucho más claro cuando se muestren algunos ejemplos más adelante. Las clases adaptadoras permiten sobrescribir solamente los métodos del interfaz en los que se esté interesado. De esta forma se consigue un código más claro y limpio. si queremos atrapar un click del ratón. 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.  simple y fácil de aprender. 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. lo que hemos llamado oyentes.  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(). y queremos que al pulsar el botón aparezca un mensaje en la caja de texto.Todos estos conceptos que estamos introduciendo acerca del tratamiento de eventos en Java. en lo que al tratamiento de eventos se refiere. 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. heredamos de la clase adaptadora de los eventos de ratón. Así por ejemplo. Este modelo de eventos ofrece las siguientes características:  Ofrece un estructura robusta para soportar programas Java complejos. Un oyente en lugar de implementar un interfaz. 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. el oyente será la ventana que contiene al botón y a la caja de texto. Las clases adaptadoras las utilizaremos para simplificar nuestro código. si tenemos el siguiente GUI: un botón y una caja de texto dentro de una ventana. Es  Ofrece una clara separación entre el código de la aplicación y del interfaz de usuario. ya que implementan de forma vacía todos los métodos de un interfaz de tratamiento de eventos determinado.event. Cada conjunto de eventos tiene asociado un interfaz. es decir. en lugar de implementar el interfaz MouseListener. puede utilizar una clase que herede de una clase adaptadora de eventos del paquete java. Otras clases que también hemos comentado y que se utilizan dentro del tratamiento de eventos en Java son las clases adaptadoras. es decir de la clase MouseAdapter.

event. se debería escribir lo que objetoBoton. Aunque los pasos son genéricos. 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. siempre que utilizamos un interfaz con un único método vamos a implementarlo. 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.*. Se registra cada uno de ellos con el tipo adecuado de oyente.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.awt.addActionListener(this). 104 . public class MiClase extends ClasePadre implements ActionListener{ Debemos determinar que componentes van a generar los eventos. si tenemos en cuenta el ejemplo anterior del botón. una pulsación de un botón) generado por un botón. Una vez hecho esto debemos crear las implementaciones de todos los métodos del interfaz que la clase debe implementar. Lo primero es importar el paquete java. ya que no tiene ningún sentido. A continuación escribiremos la declaración de la clase para que implemente el interfaz adecuado (listener interface). los interfaces que únicamente poseen un método no tienen clase adaptadora correspondiente.event: import java. 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. será necesario implementar el interfaz ActionListener.awt. Estos ejemplos además nos van a servir para repasar distintos puntos del lenguaje Java comentados hasta ahora. Por ejemplo si se está tratando de atrapar un evento ActionEvent (es decir.

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

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

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

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

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

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

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

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

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

catch( IOException ref ){ System. } System.println( “Error de apertura” ). Un bloque try puede tener varios catch asociados.out. a.println( “Finalización normal de f2” ). } ¿ 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 .actualizaDatos(). } catch( IOException ref ){ System. Si no se produce ninguna excepción el bloque catch se ignora.out. Al finalizar éste. Por ejemplo: void f1( int accion ) throws EOFException { try{ if( accion == 1 ) throw new FileNotFoundException(). uno para cada tipo de excepción que se pueda producir. } System.out. a.println( “Error de E/S” ).leeCabecera(). Por ejemplo. se interrumpe el bloque try y se ejecuta el catch. } Si se produce una excepción que no se corresponde con ningún catch indicado. try{ a.out. } void f2( int accion ) { try{ f1( accion ): } catch( EOFException e ){ System.println( “Error corregido” ). else if( accion == 2 ) throw new EOFException().out.println( “Error corregido” ). } Si alguna de las operaciones del bloque produce una excepción.println( “Finalización normal de f1” ). se continúa normalmente. la excepción se propaga hacia atrás en la secuencia de invocaciones hasta encontrar un catch adecuado.abreFichero(). } catch( FileNotFoundException ref ){ System.println( “Error de E/S” ). } catch( FileNotFoundException e ){ System.out.out.

a menudo hay que recurrir a la segunda alternativa. es obligatorio: · Que se maneje el error (en un catch)..Cuando se invoca a un método que lanza excepciones. 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(){ . · Que se indique mediante throws su propagación. } Es mejor intentar tratar los errores en cuanto sea posible (alternativa 1). } 115 .. en vez de dejarlos para que los gestione alguien por encima (alternativa 2).FINALLY Puede haber ocasiones en que se desea realizar alguna operación tanto si se producen excepciones como si no. } 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. no siempre es posible tratarlos en el mismo momento en que se producen y por tanto... Por ejemplo: void f1() throws IOException { . } void libera(){ . De todos modos. o se trata el error o se avisa que se va a continuar sin haberlo corregido para que otro método lo corrija. void f2() throws IOException { f1().4.. Dichas operaciones se pueden situar dentro de un bloque finally.. 10. Es decir..

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

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

DataFormatException. etc. EmptyStackException. IllegalArgumentException. NullPointerException. etc. Se utilizan las RunTimeException para indicar un error de programación. Esta clase. a su vez. LinkageError. CannotUndoException. 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. y cuando así sea. lo único que se puede hacer es intentar cerrar el programa sin perder datos. ClassCastException. Los programas en Java trabajarán con las excepciones de la rama Exception. NoSuchMethodException. IndexOutOfBoundsException. tiene otras clases derivadas. IOException. Estas excepciones se clasifican en: · Explícitas: las que derivan directamente de Exception. StackOverflowError. PrinterException. VirtualMachineError) · Exception (ClassNotFoundException. Estas excepciones rara vez ocurren. · Implícitas: las que derivan de RunTimeException.La jerarquía de excepciones en Java es la siguiente: · Throwable · Error (AWTError. Tampoco deberían ser lanzadas por las clases del usuario. CloneNotSupportedException. CannotRedoException. etc. Ejemplos de este tipo de excepciones son OutOfMemoryError. ArrayStoreException. ThreadDeath.) 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. GeneralSecurityException. Si se produce una 118 .) · RuntimeException (ArithmeticException. la cual se divide en dos subclases: Error y Exception. NoSuchFieldException. tiene una subclase llamada RuntimeException que. IllegalAccessException. a su vez.

Las implícitas no deben declararse (el compilador no lo exige. Por tanto. 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). ¿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. uso de un puntero null. En la práctica. Por ejemplo: un error de E/S. · de Exception en cualquier otro caso. etc. i++ ) { // Imprimir cliente[i] if( “error impresión” ) throw new PrinterException(). 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. 10. Los métodos deben declarar sólo las excepciones explícitas. i<clientes. aunque pueden producirse igualmente). Por ejemplo: un cast incorrecto. } } } Vemos ahora otro ejemplo en el que creamos y lanzamos una excepción de tipo RuntimeException: class MesInvalidoException extends RuntimeException {} class Ejemplo { 119 .7. 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.excepción de este tipo hay que arreglar el código. La única condición es que la clase derive de la clase Throwable o de alguna derivada..CREACIÓN DE EXCEPCIONES Si se necesita notificar algún error no contemplado en Java se puede crear una nueva clase de Excepción. etc. error de conexión. se lanzará. acceso a un array fuera de rango.length. normalmente derivará: · de RuntimeException si se desea notificar un error de programación. El resto de las Exception indican que ha ocurrido algún error debido a alguna causa ajena al programa (está correcto).

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

} } class Ejemplo { public static void main( String[] args ) { Fecha fecha = new Fecha(). } public String toString() // Método heredado de la clase Throwable. } getMesInvalido() { return mes. 121 . } } Java obliga a atrapar las excepciones explícitas. { return “Mes inválido: “ + mes. y que pueden ser implementados por las nuevas excepciones que se creen. 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 ). 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(). } } class Fecha { void setMes( int m ) { if( m < 1 || m > 12 ) throw new MesInvalidoException( m ). ¿qué pasa si no se atrapa una implícita.Otro ejemplo con una excepción descendiente de RuntimeException: class MesInvalidoException extends RuntimeException { private int mes. · Por defecto. que devuelve // la representación String del error. 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). · 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). La clase Throwable tiene una serie de métodos que tienen ya implementados todas las excepciones de Java (por herencia). fecha. MesInvalidoException( int m ) { mes = m.. el programa termina de manera anormal.

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

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

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

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

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

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

Tenemos dos threads ejecutándose. 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() ).print("NO ").start(). 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). i++) System. el tiempo de la CPU se reparte entre todos los procesos y threads del sistema. con lo cuál.2 Otro ejemplo  class DosThreads { public static void main(String args[] ) { NoThread n = new NoThread().Thread start() (t. s.out. 11. n. SiThread s = new SiThread().1.start(). } } 128 . Una vez se inicia la ejecución del thread.i<=20.start() ). } } class NoThread extends Thread { public void run() { int i. for (i=1.

3 Y otro ejemplo más. } public void run() { int i. i++) System. } } class SiNoThread extends Thread { private String SiNo. SiNo=s.6. i++) System. s.3. Una vez que finalizan su ejecución. class UnThreadDosInstancias { public static void main(String args[] ) { SiNoThread s = new SiNoThread("SI").print(++Contador+":"+SiNo+" ").4. } } 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. Cada una de ellas con sus propios atributos de objeto (String SiNo). el programa termina.out. SiNoThread n = new SiNoThread("NO"). … Esto es debido a que se ha accedido concurrentemente a una misma zona de memoria sin que se produzca exclusión mutua. Puede comprobarse que el contador no ha funcionado todo lo correctamente que pudiera esperarse: 1.print("SI ").out.i<=20. Estos dos threads se reparten el tiempo de la CPU y se ejecutan concurrentemente. for (i=1. for (i=1. pero comparten los atributos de clase40 (int Contador). 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().2. 129 . n. 11.i<=20.8.5.class SiThread extends Thread { public void run() { int i. public SiNoThread(String s) { super(). al igual que en el ejemplo anterior.start().1. static int Contador=0.start(). } } La salida del programa.

si se le asigna la CPU.11. 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. el thread pasará al estado ejecutable y. El ciclo de vida de un thread puede pasar por varios estados ilustrados en la siguiente figura: Cuando se instancia un thread. 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. 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. ejecutable o no ejecutable). se inicializa sin asignarle recursos. 130 .2 Estado de un thread. lo sitúa en el estado ejecutable y llama al método run() del objeto. 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(). 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(). La llamada al método start() asigna los recursos necesarios al objeto. proseguirá su ejecución. Está en el estado nuevo Thread. Un thread en este estado únicamente acepta las llamadas a los métodos start() o stop(). momento en el cual.

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

Una vez declarada la clase que implementa la interface Runnable. 4) Redefinir el método run() tal y como se hace en la otra alternativa de creación de threads (mediante subclases de Thread). 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. public static Thread currentThread(). 11. cualquier subclase descendiente de esta clase poseerá también las características propias de los threads. } } En este caso se utiliza el constructor de la clase Thread: public Thread(Runnable destino).2 isAlive().1 currentThread(). ya puede ser instanciada e iniciada como cualquier thread.start(). la clase Thread se los asigna por defecto como Thread-1. public final boolean isAlive().start(). Devuelve el thread que se está ejecutando acutalmente. s. 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). 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. Para poder después averiguarlo mediante el método: public final String getName(). Ambas formas de crear threads admiten un parámetro de tipo String que identifica al thread por su nombre: public Thread(String nombre). Si no se ha asignado nombre a los threads. SegundoThread ss = new SegundoThread(). Thread-2.4. … 11.start(). Es más.4. 11. ss.4 Operaciones sobre threads. Iniciar el thread: t. ambas son Thread. 132 . public Thread(Runnable destino. y por lo tanto.public static void main(String args[]) { SegundoThread s = new SegundoThread(). String nombre).

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

start(). Para cada salida por pantalla. 2) El thread estará “esperando” hasta que sea notificado o expire el timeout (milisegundos).6 yield(). (System.i<=20.print(++Contador+":"+SiNo+" ").println(++Contador+”:”SiNo+” “). Transfiere el control al siguiente Thread en el scheduler 41 (con la misma prioridad que el actual) que se encuentre en estado ejecutable. n.start(). i++) { System. s.out. for (i=1.4. 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 . class UnThreadDosInstanciasAmables { public static void main(String args[] ) { SiNoThreadAmable s = new SiNoThreadAmable("SI"). ya que puede perder la CPU antes y por consiguiente no tienen porqué salir los Síes y Noes alternativamente. } } } En este caso hay dos threads que se ejecutan concurrentemente. SiNoThreadAmable n = new SiNoThreadAmable("NO"). static int Contador=0. SiNo=s. public SiNoThreadAmable(String s) { super(). } public void run() { int i. de la cuál heredan todos sus métodos todas las clases creadas en Java.11. 11.out. ) el thread cede la CPU al otro thread mediante la llamada a yield(). El método wait() es heredado de la superclase Object. Esto no significa que el otro thread continúe su ejecución hasta llegar a su propio yield(). yield().4. 3) public final void wait(long milisegundos. int nanosegundos) throws InterruptedException 1) Causa el paso al estado “esperando” del thread indefinidamente hasta que el thread sea notificado mediante notify() o notifyAll().5 wait(). 2) public final void wait(long milisegundos) throws InterruptedException. 3) El thread estará “esperando” hasta que sea notificado o expire el timeout (milisegundos + nanosegundos). } } class SiNoThreadAmable extends Thread { private String SiNo. 1) public final void wait() throws InterruptedException. public static void yield().

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). t.start().  class MiThread extends Thread { public void run() { int i. System. for (i=1. public final void join() throws InterruptedException.11.join().join(). int nanoseg) throws InterruptedException. public final synchronized void join(long miliseg.println("El thread ha terminado"). 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. 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().i<=100. En estos dos casos. } } class Join1 { public static void main (String args[]) throws InterruptedException { MiThread t = new MiThread(). t.out. 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.print(i+" ").4.out.7 join(). } } El thread de la clase Join1 espera indefinidamente hasta que finalice el thread t. i++) System. 135 .

Este flujo de datos puede ser almacenado en una zona de memoria compartida por ambos threads. En este caso. sin embargo. ya que de lo contrario. Existen.11. 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.2 Sección crítica. puede encontrarse con que no hay datos que consumir o que se consuman más de una vez (si no elimina los datos consumidos. 11. situaciones en las que es imprescindible sincronizar en cierta forma la ejecución de distintos threads que buscan un objetivo común. si el consumidor es más rápido que el productor. si el productor genera los datos más deprisa de lo que el consumidor es capaz de tratarlos.5. cooperando entre ellos para su correcto funcionamiento. 11. 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. la sincronización es vital.1 El paradigma productor/consumidor.5 Threads y sincronismo. que se ejecutaban concurrentemente.5. por otra parte. En este caso. debe existir un mecanismo que “frene” al productor o al consumidor en los casos necesarios. sino que los elimina el productor). cada uno de ellos se ejecutaba independientemente de los demás. puede producirse un desbordamiento de la memoria asignada al efecto.

c2 = new Contable(c). Contador c = new Contador(). } System.getValor()). public Contable (Contador c) { contador=c. aux=valor. class Contador { private long valor=0. } } class Contable extends Thread { Contador contador. las secciones críticas se marcan con la palabra reservada synchronized. c1. es preferible hacerlo a nivel de método. } public void run () { int i. Aunque está permitido marcar bloques de código más pequeños que un método como synchronized. aux++. c2 . c1 = new Contable(c). para seguir una buena metodología de programación.En Java. } } class ThreadSinSync { public static void main(String arg[]) { Contable c1 . i++) { contador. long aux. } public long getValor() { return valor.start().out.i<=100000. for (i=1.incrementa().println("Contado hasta ahora: "+ contador.start(). c2. } } 137 . public void incrementa() { long aux. valor=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. la sección crítica es la línea: contador. esto mismo ha ocurrido un gran número de veces durante la ejecución de los threads. Lo que ha ocurrido en realidad para que se produzca este resultado equivocado es lo siguiente Evidentemente. de forma que no pudieran ejecutarlo simultáneamente dos threads sobre el mismo objeto (contador). ya que desde esta instrucción se accede a un objeto (contador) que es compartido por ambos threads (c1 y c2). En este caso. a efectos didácticos.incrementa(). 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. aunque el efecto de haber codificado valor++ habría sido similar. 138 .Para realizar el incremento en el método incrementa(). y en la segunda línea el valor 200000. se ha empleado una variable auxiliar intermedia (aux).

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

i++) c. p. Productor p = new Productor(cj).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().int i. 140 . sacar(): Muestra en pantalla el valor almacenado y pone ese valor a cero. se declaran los métodos meter y sacar como synchronized.sacar(). Tanto el thread productor como el consumidor comparten el mismo objeto de la clase Caja. 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.start(). que el consumidor intente sacar varios valores consecutivamente. Existe un objeto de la clase Caja que es capaz de almacenar un único número entero. ya que el productor puede almacenar varios valores antes de que el consumidor extraiga el valor o. } } En este ejemplo existen dos threads que se comportan siguiendo el paradigma productor/consumidor. Para asegurar la exclusión mutua en la zona crítica (la que accede a valor). c. Consumidor c = new Consumidor(cj). Pero esto no es suficiente para que el programa funcione correctamente. for (i=1. también. i<=10.

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

start(). i++) c.start(). } } class ProdCons3 { public static void main(String argum[]) { Caja cj = new Caja(). Productor p = new Productor(cj). System. disponible=false. for (i=1. private boolean disponible=false. } } class Consumidor extends Thread { Caja c.sacar(). p.out. public Productor(Caja nc) { c = nc. i<=10.out. public Consumidor(Caja nc) { c = nc. i<=10. valor=0. } catch (InterruptedException e) { } } valor = nv.meter(i). public synchronized void meter(int nv) { if (disponible) { try { wait(). for (i=1. } catch (InterruptedException e) { } } System. i++) c. Consumidor c = new Consumidor(cj). disponible=true. c. notify(). notify().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.println("sacado el valor: "+valor). } public void run() { int i. } } Produce el resultado deseado: metido el valor: 1 142 . } public synchronized void sacar() { if (!disponible) { try { wait(). } public void run() { int i.println("metido el valor: "+valor). } } class Productor extends Thread { Caja c.

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. 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. 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.

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

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

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

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). } } El método getName() devuelve un String que contiene el nombre del grupo.1.1.2 Operaciones sobre grupos.2 Operaciones sobre threads agrupados.println(tg.currentThread().8. “MiGrupo2”). 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. Ejemplo: ThreadGroup tg2 = new ThreadGroup( tg . Este grupo pertenecerá al grupo que se pasa como parámetro (padre). Convierte al grupo en daemon si el parámetro es true43. public final boolean isDaemon(). String nombreDelThread).1 Asignación de un thread a un grupo. public final void setMaxPriority(int pri). La salida por pantalla. 147 . Como se ha visto.2.Ejemplo: ThreadGroup tg = new ThreadGroup(“MiGrupo”). 11. Runnable destino. public final void setDaemon(boolean daemon).getThreadGroup().8. Devuelve true si el grupo es un daemon y false en caso contrario.8. public final void stop(). System. public final void resume(). Un grupo daemon es destruido automáticamente cuando no contiene ningún thread o grupo.2.8. Esto se realiza en la llamada al constructor del thread: public Thread(ThreadGroup grupo. Establece la máxima prioridad que puede tener un thread descendiente de este grupo.2. Pasan al estado “muerto” todos los threads descendientes de este grupo.2. evidentemente es: main 11.1 Operaciones sobre threads. Pasan al estado de “ejecutable” todos los threadsdescendientes de este grupo que estaban en estado “suspendido”. String nombreDelThread). 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. public Thread(ThreadGroup grupo. 11.2 Operaciones sobre un conjunto de threads. 11. 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). public final void suspend(). 2) Crea un grupo cuyo nombre se pasa como parámetro.8. 11.getName()).out.

MiThread t21 = new MiThread(tg2.public final void destroy() throws IllegalThreadStateException. 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."grupo dos"). Destruye el grupo (pero no los threads descendientes). tg.i<t. 3) public int enumerate(ThreadGroup lista[]). 1) public int enumerate(Thread lista[]). String nom) { super(tg. boolean recurr)."Thread 1. 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."Thread 2. } } class Grupo2 { public static void main(String args[]) throws InterruptedException { ThreadGroup tg = new ThreadGroup("grupo uno"). Thread t[] = new Thread[4].println("Ejecutado "+getName()).println(t[i]). int i. de lo contrario se genera una excepción de la clase IllegalThreadStateException.8.  class MiThread extends Thread { public MiThread(ThreadGroup tg. 2) public int enumerate(Thread lista[]."Thread 2.enumerate(t). 11. MiThread t22 = new MiThread(tg2. for (i=0.1"). hay que llamar antes al método stop() del grupo44 para que todos los threads descendientes pasen al estado “muerto”. 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.2.1").2"). añadiendo los threads o grupos del grupo sobre el que se realiza la llamada y de los grupos descendientes del mismo. public final boolean parentOf(ThreadGroup g). } public void run() { System.i++) System. 4) public int enumerate(ThreadGroup lista[].out.3 Obtención del contenido de un grupo. ThreadGroup tg2 = new ThreadGroup(tg.2").length."Thread 1. MiThread t12 = new MiThread(tg. } } 148 . se obtienen listas de threads (y grupos) recursivas. boolean recurr).nom).out. MiThread t1 = new MiThread(tg. Por defecto. Este grupo debe estar vacío: no debe contener threads activos.

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

es decir.event.event. 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. 150 . aspecto y comportamiento configurables. de hecho se debe importar el paquete JAVA. así por ejemplo. 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. y además añaden nuevos eventos que se pueden encontrar en el paquete javax. como pueden ser los eventos o los gestores de diseño siguen siendo válidos para los componentes Swing. los componentes Swin utilizan las clases de los eventos incluidas en el paquete java. pero Swing aporta un nuevo gestor de diseño (que veremos en el siguiente capítulo. A lo largo de este capítulo describiremos algunos de los componentes Swing. 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. paneles con pestañas y listas. sería necesario un curso de la misma extensión de éste (o más) para tratar Swing de forma completa.AWT para utilizarlos. los gestores de diseño que utilizan los componentes Swing son los mismos que los vistos en los componentes AWT. 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. también dedicado por completo al extenso mundo de los componentes Swing) que se encuentra en el paquete javax.swing.12. En el segundo capítulo trataremos el otro gran grupo de componentes Swing. los contenedores Swing. Lo mismo sucede con los eventos. Swing es bastante extenso y aun utilizando tres capítulos no lo vamos a ver completamente. no todos ya que Swing ofrece un gran número de clases agrupadas en 15 paquetes distintos. diálogos y ventanas hasta cajas de texto. barras de menú.0 Swing Interfaces de usuario en Java: componentes Swing / contenedores Introducción Muchos de los conceptos vistos en capítulos anteriores. los componentes atómicos.awt. Como hemos dicho vamos a tener tres capítulos dedicados a Swing.swing. barras de progreso.

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 del JDK y eran los únicos componentes que se encontraban disponibles para desarrollar interfaces de usuario.  API Java 2D: al igual que ocurría con la característica o funcionalidad anterior. En muchos casos se utilizan indistintamente los términos JFC y Swing sin hacer ningún tipo de distinción. aunque la plataforma Java 2 soporta perfectamente los componentes AWT como hemos podido comprobar en capítulos anteriores. Soporte para Pluggable Look and Feel: es decir. Los componentes AWT se utilizan principalmente en las versiones 1. en el tratamiento de gráficos en dos dimensiones.  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. Los componentes Swing se encuentran disponibles de dos formas distintas.1 del lenguaje (que coincidían con las versiones de la herramienta JDK). tanto en la herramienta JDK 1.1. El API Java 2D se escapa también del alcance y pretensiones de este curso.  Soporte para arrastrar y soltar (Drag and Drop): permite la posibilidad de arrastrar y soltar componentes entra aplicaciones Java y aplicaciones en otros lenguajes. 151 . Los componentes AWT aparecieron en la versión 1. soporte para una apariencia y comportamiento configurables. 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.1) denominada JFC 1. Así por ejemplo una misma aplicación puede presentar una apariencia y comportamiento al estilo de Java o bien tipo Windows.2 o como en el JDK 1. imágenes y texto. y el porqué de la existencia de dos grupos distintos de componentes. 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. se trata de un conjunto de clases especializadas. En nuestro caso vamos a utilizar la versión que se encuentran integrada con la plataforma Java 2.0 y 1. Permite a cualquier programa que utilice componentes Swing definir un tipo de apariencia y comportamiento (Look and Feel). La denominación swing aparece también en los paquetes correspondientes.1 (versión de Java 1. y como una extensión del JDK 1. En el apartado correspondiente volveremos a retomar esta característica y la trataremos en detalle. Desde Sun nos recomiendan que utilicemos si es posible los componentes Swing en lugar de los componentes AWT.3. como parte de la plataforma Java 2.

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

//se crea la barra de menú JMenuBar barraMenuCyan = new JMenuBar(). Veamos un sencillo ejemplo que muestra un contenedor de alto nivel.awt.  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. JDialog (diálogo) y JApplet.  Opcionalmente se puede añadir una barra de menú a un contenedor de alto nivel.setPreferredSize(new Dimension(200.*.setOpaque(true). 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. La barra de menú se sitúa en el contenedor de alto nivel. 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").setBackground(Color. barraMenuCyan. etiquetaAmarilla. es el equivalente a la clase Window de los componentes AWT.  Para aparecer en pantalla todo componente de interfaz de usuario debe formar parte de una jerarquía de contenedores. Cada jerarquía de contenedores posee un contenedor de alto nivel como raíz. //se crea la etiqueta JLabel etiquetaAmarilla = new JLabel("").setBackground(Color.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. etiquetaAmarilla. A lo largo de este capítulo iremos viendo como en los componentes Swing encontramos equivalentes de los componentes AWT. Los componentes de alto nivel se basan en los siguientes principios:  Swing ofrece tres clases que representan a componentes de alto nivel: JFrame (ventana).swing. Y el código fuente completo de este ejemplo es : import java. 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. En la Figura se puede ver el aspecto del contenedor.cyan).*. etiquetaAmarilla. 180)). barraMenuCyan.setOpaque(true). pero fuera del panel de contenido. 153 .yellow). import javax.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 addTab(String texto. mediante una constante que recibe como parámetro. 173 . pero existe otro constructor que permite.Si se prueba el ejemplo anterior se puede comprobar que no se ha escrito ningún código para realizar el tratamiento de eventos. Component componente): en este caso además se indica el icono que se va a mostrar en la pestaña. Component componente. este método presenta las siguientes versiones:  addTab(String texto. 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. BOTTOM. Icon icono. Icon icono. la clase JTabbedPane realiza este tratamiento (mostrar los componentes de la pestaña seleccionada) de forma automática. Obtenemos el resultado siguiente: Para añadir una nueva pestaña ya sabemos que debemos utilizar el método addTab(). 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. 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.  addTab(String texto.BOTTOM). LEFT y RIGHT.

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

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

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

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

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.getIconHeight()).icono. panelCapas. El valor de esta posición va desde -1 hasta n-1. nuevaEtiqueta. es decir. Al contrario que las capas. Si al ejemplo anterior le añadimos las líneas que muestra el Código siguiente. El nuevo aspecto del panel de capas es el que aparece en la Figura. 178 . a una profundidad determinada. ImageIcon icono = new ImageIcon("imagen.getIconWidth().new Integer(2). se puede especificar la posición de un componente. Utilizar -1 es equivalente a utilizar n-1. Dentro de una capa. cuanto menor es el número mayor es la profundidad del componente dentro de la capa.icono. 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"). Como se puede ver el método y los atributos utilizado son estáticos. 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.setBounds(180. indica la posición más en el fondo. Es posible por lo tanto definir la posición de un componente respecto al resto de componentes dentro de la misma capa. una vez creadas las etiquetas en las distintas capas. Se ha utilizado un bucle for para ir recorriendo estos arrays y crear las etiquetas mediante el método crearEtiqueta(). Si utilizamos 0 el componente se encontrará por encima del resto. JLabel nuevaEtiqueta=new JLabel(icono).75. ya que los utilizamos directamente en el método main() si lanzarlos sobre una instancia de una clase.0).add(nuevaEtiqueta.

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

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

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

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

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

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

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

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

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

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

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

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

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ú. 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. ventana. 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.creaMenu(). 191 . El área de texto (JTextArea) encargada de ir mostrando los eventos que se producen se añade a un panel de scroll (ScrollPane). menuPopup. ventana.creaTexto(). } } Los elementos de menú lanzan eventos ActionEvent.setVisible(true).texto. El oyente que se ocupa de mostrar el menú contextual lanza el método show() sobre la instancia correspondiente de la clase JPopupMenu. elementoMenu=new JMenuItem("Segundo del popup".addActionListener(this). el oyente debe detectar que el usuario a pulsado el botón derecho del ratón para mostrar el menú contextual correspondiente. llamado menuPopup que pertenece a la clase JPopupMenu. ventana. Se va añadir un nuevo atributo a nuestra clase.KeyEvent.gif")). //se crean y añadden los distinos elementos de menú de la misma manera elementoMenu=new JMenuItem("Primer elemento del popup". public void creaPopup(){ menuPopup=new JPopupMenu().pack(). Como se puede ver se han añadido dos teclas rápidas mediante el método setAccelerator().append(mensaje). También se va a añadir un nuevo método llamado creaPopup().VK_P).add(elementoMenu). ventana. y los elementos de menú del tipo JCheckBoxMenuItem lanzan eventos de la clase ItemEvent. } public static void main(String args[]) { Menus ventana = new Menus().new ImageIcon("icono2. 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

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

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

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

ventana. 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 este componente permite mostrar de forma sencilla un diálogo que permite seleccionar también un color. Para obtener el tanto por ciento de la tarea realizada (completada) representada por la barra de progreso disponemos del método getPercentComplete(). pero bastante complejo y completo que permite seleccionar colores de distintas formas.creaBoton().BarraProgreso ventana = new BarraProgreso(). además en algunos casos permiten editar esta información. } } Como se puede comprobar en el ejemplo. La clase JColorChooser representa un componente Swing atómico. respectivamente. la barra de progreso muestra el tanto por ciento (%) de la operación realizada. 200 .setVisible(true). ventana.creaBarra(). JColorChooser Este componente Swing además de ofrecer una información estructurada. este tanto por ciento lo calcula teniendo en cuenta el valor actual y sus valores máximo y mínimo. nos permite seleccionar un elemento determinado de esa información. ventana. 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. 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. 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. 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. como pueden ser los distintos colores.200). Este es el último de los componentes Swing pertenecientes al grupo de componentes encargados de mostrar información.setSize(200.

awt.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.event. public SelectorColor() { super("Selector de color"). 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.swing. import java.colorchooser. etiqueta. etiqueta.setFont(new Font("SansSerif".white). } public void creaEtiqueta(){ //Configuramos la etiqueta sobre la que se aplica la selección de color etiqueta= new JLabel("La Plataforma Java 2".colorchooser. Para obtener la instancia de la clase ColorSelectionModel correspondiente a un objeto de la clase JColorChooser.exit(0). import javax. sino sobre su ColorSelectionModel. pero no se debe hacer directamente sobre el componente JColorChooser.setForeground(Color.swing.*. 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.*. Font. 201 . public class SelectorColor extends JFrame implements ChangeListener{ private JLabel etiqueta. etiqueta.setBackground(Color. El modelo de selección de color (instancia de la clase ColorSelectionModel). 24)).CENTER). debemos lanzar sobre el objeto JColorChooser el método getSelectionModel(). this. Si queremos detectar los cambios de selección de color del componente JColorChooser debemos registrar el oyente correspondiente al evento ChageEvent.*.*.*.JLabel. } }).green).setOpaque(true). import javax.swing. private JColorChooser selectColor.swing. un panel con pestañas (JTabbedPane) y un panel con la muestra de la selección (preview). 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). etiqueta. El panel de selección con pestañas encuentra en la parte superior y presenta tres pestañas.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. El panel de muestra se encuentra en la parte inferior y va mostrando el color seleccionado en cada momento del panel de selección.BOLD. import java. import javax. cada una de ellas permite una forma distinta de seleccionar los colores.event.awt.

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

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

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

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

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

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

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

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

add(Box.*.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.BorderLayout.30)). se suele utilizar la clase Box.setLayout(new BoxLayout(panelSuperior.5))). panelInferior. JPanel panelSuperior=new JPanel(). public class DosBoxLayout{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout").CENTER).green)).add(new JTextArea(5.Y_AXIS)). ventana.pack(). } } 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. import java.setVisible(true).createRigidArea(new Dimension(0.getContentPane().add(Box.*.BoxLayout. panelInferior.getContentPane().setBorder(BorderFactory. panelSuperior. panelSuperior.swing. panelSuperior.add(new JLabel("Esto es una etiqueta")).add(panelInferior.add(new JButton("Botón 2")).X_AXIS)). ventana.add(Box. 210 . 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.exit(0).setBorder(BorderFactory.*. panelInferior.awt. uno de arriba a abajo y otro de izquierda a derecha. } }). JPanel panelInferior=new JPanel().createRigidArea(new Dimension(10. ventana. panelInferior.BoxLayout.createLineBorder(Color.NORTH).0))). panelSuperior.event.add(new JButton("Botón 1")). panelSuperior. ventana. panelInferior. import java.createLineBorder(Color.Conjuntamente con la clase BoxLayout.awt.red)). panelInferior.setLayout(new BoxLayout(panelInferior.BorderLayout. ventana.createHorizontalGlue()).add(panelSuperior. import javax.

JPanel panelContenido=new JPanel().event. enviando al segundo botón a la derecha del todo. La clase Box ofrece también el método createVerticalGlue(). 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.setAlignmentX(Component. import java.*. En el segundo panel se utiliza otro método de la clase Box. JButton boton3=new JButton("Otro botón"). este método rellena el espacio sobrante y desplaza a los componentes hacia la derecha.CENTER_ALIGNMENT). En este caso se ha indicado una separación vertical de cinco pixels. JButton boton2=new JButton("Soy un botón más").addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System. en este caso el área invisible se extiende de forma vertical enviando los componentes dentro del panel hacia la zona inferior. } }). En este panel inferior también se utiliza el método createRigidArea() para separar los dos botones diez pixels. public class BoxLayoutSencillo{ public static void main(String args[]) { JFrame ventana = new JFrame("Ventana con BoxLayout").setAlignmentX(Component.Se ha aplicado un borde a cada uno de estos dos paneles para distinguirlos más claramente. 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.RIGHT_ALIGNMENT). este método provoca que los dos botones que se añadan a continuación se desplacen hacia la derecha. JButton boton4=new JButton("Soy el último").awt. boton3. es decir.*. JButton boton1=new JButton("Soy un botón"). 211 . 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. ventana. aunque para que no existan problemas de alineación todos los componentes deben tener la misma. boton1. 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(). en este caso se ha utilizado un área sólo con componente horizontal. Si modificamos el primer ejemplo visto en este apartado tenemos: import java.exit(0). el método createHorizontalGlue(). El método createHorizontalGlue() crea un área invisible que crece horizontalmente para rellenar todo el espacio libre disponible dentro del contenedor.

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

 Mac: este último Look & Feel es el correspondiente a los sistemas Macintosh.MacLookAndFeel.  Motif: representa el aspecto CDE/Motif. Este Look & Feel es implementado por la clase com. es decir.motif. lo que se denomina Pluggable Look & Feel. Se corresponde con la implementación de la clase javax. también denominado Metal (fue el código que se le dio al proyecto que lo desarrolló). Se encuentra en al clase javax. Cuando no se indica ningún Look & Feel determinado Swing utiliza el Look & Feel por defecto. 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.MotifLookAndFeel.plaf. A diferencia del anterior Look & Feel. tienen la característica común que todas ellas heredan de la clase abstracta javax. Todas estas clases que implementan un Look & Feel determinado. ya que en nuestros ejemplos no hemos especificado ningún Look & Feel.swing. 213 . La clase UIManager ofrece un método estático llamado setLookAndFeel().java.LookAndFeel.MetalLookAndFeel.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. que es el Look & Feel de Java.java.swing. 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. Este Look & Feel lo podemos utilizar en cualquier plataforma.windows. como veremos un poco más adelante. 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.swing. Al igual que ocurría con el Look & Feel de Windows.swing.sun.plaf.  Windows: es aspecto que presentan los sistemas Windows y lo encontramos implementado en la clase com. y al igual que el Look & Feel de Java puede ser utilizado en cualquier plataforma.metal. esta plataforma es la plataforma Mac OS.mac.plaf. a nuestra aplicación Java le podemos asignar un aspecto específico.WindowsLookAndFeel. este Look & Feel está restringido a una plataforma específica.swing. podemos establecer y cambiar en tiempo de ejecución de nuestra aplicación su Look & Feel. éste únicamente puede ser utilizado en plataformas Windows. Incluso.sun.swing.plaf. que es el aspecto que tienen las plataformas de Sun.

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

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

cada una con otro nuevo Look & Feel. en los que se ha ofrecido el código completo del ejemplo.Y_AXIS). ya que he utilizado una plataforma Windows para ejecutar la aplicación de ejemplo. La primera corresponde al Look & Feel de Windows y la segunda al Look & Feel de Motif. 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.utiliza es BoxLayout. No vamos hacer como en otros ejemplos de este curso. En mi caso no he podido utilizar el Look & Feel de Mac. 216 . 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. descrito en el apartado anterior. A continuación se muestran otras dos figuras. Podemos ir asignando a la aplicación los distintos Look & Feel seleccionando la opción correspondiente. por lo tanto éste Look & Feel no estará disponible. 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. 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).

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

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

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

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

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

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

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

boton. g.getSize()).getSize()).swing. JPanel p =new JPanel(). 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.getWidth(). 224 . g.*.*. Container contentpane = this.drawLine(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. g.red).setColor(Color.addActionListener(this). JButton boton = new JButton("Dibujar"). 200).add(p. g.setColor(Color. } JPanel panel = new JPanel(). BorderLayout. } Graphics g = panel. g. g.awt.} public void actionPerformed(ActionEvent e){ String comando = e.awt.(int) (this. import java.drawRect(100.(int)(this.drawLine(150.exit(0).getGraphics(). 150).SOUTH).fillRect(110. Veamos como haríamos esto sobre el ejemplo Dibujar1: Ejemplo 2.getHeight()). contentpane. } } 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. todo lo demás es “borrado”.equals("Salir")){ System. Cuando este método es invocado lo único que aparecerá en el componente es lo que se dibuje desde el. import java.blue). En este método se halla toda la información que se necesita para dibujar el componente en pantalla. 90.event. 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.0. 100).400). setTitle("Dibujo"). 150. p. public class Dibujar2 extends JFrame implements ActionListener{ public Dibujar2(){ setSize(400.add(boton). Además el componente se dibujará cuando se crea y cuando se invoque el método repaint(). 200. 100. 80. contentpane. if(comando.setLayout (new BorderLayout()).getContentPane().getActionCommand(). JButton boton2 = new JButton("Salir"). boton. 150. import javax.*.setActionCommand("Dibujar"). public static void main(String[] args){ new Dibujar1().

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

226 .

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

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

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

que ofrecen un rendimiento más rápido. o puede ser Internet. este nivel intermedio ha sido escrito en lenguajes como C ó C++. que envía las sentencias SQL a la base de datos. con la introducción de compiladores optimizadores que traducen el bytecode en código máquina eficiente. Finalmente en muchos casos la arquitectura de tres niveles puede proporcionar ventajas de rendimiento. se está convirtiendo en práctico desarrollar este nivel intermedio en Java. Las sentencias SQL de usuario se envían a la base de datos.4 Modelos en dos y tres pisos. Aplicacion Java Máquina cliente JDBC Protocolo propietario DBMS DBMS Servidor de BD. La red puede ser una intranet. que conecta a los empleados dentro de la corporación. y el resultado de estas sentencias se envían al usuario. 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. un applet Java o una aplicación habla directamente con la base de datos. que a su vez lo envía al usuario. 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. 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. En el modelo de dos-pisos.1. Hasta ahora. 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. El API JDBC soporta los modelos en dos y tres pisos de acceso a base de datos. De cualquier modo. En el modelo de tres-pisos. por ejemplo. La base de datos puede estar localizada en otra máquina a la que el usuario se conecta mediante la red. 230 . La base de datos procesa las sentencias SQL y devuelve los resultados a el „piso intermedio‟.

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.1. estos no conforman la sintaxis más recientemente definidas o semánticas para funcionalidades más avanzadas. De hecho una consulta de una aplicación incluso no tiene por que ser SQL. 1. el API de JDBC debe soportar SQL tal como es. pero se corre el riesgo de recibir un error en el DBMS. Aplicacion Java Máquina cliente llamadas HTTP. Es de esperar que la porción de SQL que es verdaderamente estándar se expandirá para incluir más y más funcionalidad. de cualquier modo.Esta es una gran ventaja al hacer posible aprovechar las características de robustez. multiproceso y seguridad de Java. Entretanto. no todas las bases de datos soportan procedimientos almacenados o joins de salida. o puede ser una derivación especializada de SQL 231 . Por ejemplo. 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. Esto quiere decir que una aplicación es libre de usar la sentencia SQL tal como quiera. RML ó CORBA Aplicacion Servidora (Java) JDBC Servidor (Lógica de negocio) Protocolo propietario del DBMS DBMS Servidor de BD. y aquellas que lo hacen no son consistentes con otras.5 SQL Conforme SQL es el lenguaje estándar para el acceso a las bases de datos relacionales.

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

233 .2. 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.1. El puente JDBC-ODBC permite a los drivers ODBC usarse como drivers JDBC. Solo los drivers que pasan el test pueden ser designados JDBC COMPLIANT. 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.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.

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

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.1. referida como la capa de gestión JDBC. Este método toma una cadena que contiene una URL. Puede pensarse en ella como una dirección.getConnection.1.1 Vista Preliminar Un objeto Connection representa una conexión con una base de datos. de cualquier modo. Normalmente. 235 .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. La clase DriverManager mantiene una lista de clases Driver registradas y cuando se llama al método getConnection. o puede tener varias conexiones con varias bases de datos diferentes. CONEXIÓN 2. String url = "jdbc:odbc:wombat". se chequea con cada driver de la lista hasta que encuentra uno que pueda conectar con la base de datos especificada en la URL. "12Java"). 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. La clase DriverManager. "oboy". Connection con = DriverManager. Un usuario puede evitar la capa de gestión de JDBC y llamar a los métodos de Driver directamente.2 Uso general de URL’s Dado que URL‟s causan a menudo cierta confusión.getConnection(url. 2.2. daremos primero una breve explicación de URL en general y luego entraremos en una discusión sobre URL‟s de JDBC. 2. 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. Una URL (Uniform Resource Locator) da información para localizar un recurso en Internet. intenta localizar un driver que pueda conectar con la base de datos representada por la URL. 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”. Una única aplicación puede tener una o más conexiones con una única base de datos.

236 . las URL‟s JDBC permiten a los desarrolladores de drivers codificar toda la información de la conexión dentro de ella.com 2.sun. 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.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. Dado que los JDBC URL se usan con varios tipos de drivers. por ejemplo.1. El rol de JDBC es recomendar algunas convenciones a los fabricantes de drivers para su uso. el resto de la URL identifica el host y puede opcionalmente dar un path más específico al sitio. Tercero. Para los protocolos ftp y http. da información sobre donde se encuentra la fuente de los datos. el siguiente es la URL para la home page de JavaSoft. Por ejemplo.com/products/jdk/CurrentRelease file:/home/haroldw/docs/books/tutorial/summary. Primero. Esta URL identifica solo al host: http://java.sun. 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.com/docs/JDK-1_apidocs. Segundo. todo después de los dos puntos. por ejemplo.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. permite que las URL contengan valores de atributos (pero no los requieren). Si el protocolo es file. que especifica “file transfer protocol” y http que especifica “hypertext transfer protocol”. 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. Los desarrolladores de drivers son los que determinan actualmente que JDBC URL identifica su driver particular.html El resto de la URL. las convenciones son necesariamente muy flexibles. Esto hace posible. el resto de la URL es el path al fichero. Algunos protocolos comunes son ftp. EL subprotocolo odbc. Los usuarios no tienen por que preocuparse sobre como se forma una URL JDBC. permiten a diferentes drivers usar diferentes esquemas para nombrar las bases de datos. ellos simplemente usan la URL suministrada con el driver que usan. las URL‟s JDBC permiten un nivel de indirección.

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

Cuando la clase DriverManager presenta este nombre a su lista de drivers registrados. JDBC no pone ninguna restricción sobre los tipos de sentencias que pueden enviarse: esto da un alto grado de flexibilidad.1. y quisiera registrar “miracle” como el subprotocolo para el driver JDBC que conecte a su DBMS Miracle no tiene que usar sino ese nombre. 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í. se usa para pasar sentencias SQL a la base de datos subyacente.CacheSize=20. JDBC requiere que un driver cumpla al menos ANSI SQL-2 Entry 238 .4 El subprotocolo “odbc” El subprotocolo “odbc” es un caso especial. //hostname:port/subsubname Suponiendo que “dbnet” es un protocolo para conectar a un host.UID=kgh. 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. Por ejemplo.<attribute-name>=<attribute-value>]* Todos los siguientes son nombres válidos jdbc:odbc jdbc:odbc:qeor7 jdbc:odbc:wombat jdbc:odbc:wombat.5 Registro de subprotocolos Un desarrollador de drivers puede reservar un nombre para usar como el subprotocolo en una URL JDBC. Si fuera. Por ejemplo odbc está reservado para el puente JDBC-ODBC.6 Envío de Sentencias SQL Una vez que la conexión se haya establecido. 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>[. 2.PWD=fooey 2.subnombre y debería seguir a la convención estándar de nomenclatura de URL. por poner otro ejemplo. permitiendo el uso de sentencias específicas de la base de datos o incluso sentencias no SQL.1. la URL JDBC debería parecerse a algo como: jdbc:dbnet://wombat:356/fred 2. Se requiere de cualquier modo. 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.1. Miracle Corporation.ExtensionCase=LOWER jdbc:odbc:qeora.

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

Normalmente. la transacción no terminará hasta que se llame al método commit o al método rollback explícitamente. El método commit hace permanente cualquier cambio que una sentencia SQL realiza en la base de datos.(debido a que 240 . se llama al método rollback. En este caso. restaurando los valores existentes l inicio de la transacción. y libera cualquier bloqueo mantenido por la transacción. un driver JDBC-compliant debe soportar transacciones. DatabaseMetaData suministra información que describe el nivel de transacción soportado por el DBMS. Esto puede hacerse desactivando el modo auto-commit y agrupando ambas actualizaciones en una transacción. el nivel de transacción más alto es el más lento en la ejecución de la aplicación. cada sentencia es „commitada‟ individualmente. 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. 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. Muchos drivers JDBC soportan transacciones. por tanto una transacción se compone de una única sentencia. y esto significa que cuando se completa se llama automáticamente al método commit. De hecho.Una conexión nueva se abre por defecto en modo auto-commit. ¿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?. todas las sentencias de la transacción son “commitadas‟ o deshechas en grupo. El nivel de aislamiento más alto. tendrá que manejar de alguna forma los potenciales conflictos que puedan surgir cuando dos transacciones están operando sobre una base de datos concurrentemente.1. El método rollback descarta estos cambios. En este segundo caso. el que más cuidado toma para evitar conflictos. si uno o los dos fallan. Si el modo auto-commit es desactivado. 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. Si ambas actualizaciones tienen éxito se llama al método commit haciendo estos cambios permanentes. dado que el valor cambiado leído por la segunda transacción será invalido si la primera transacción ha hecho rollback?. ¿Debería permitirse. A veces un usuario no quiere que tenga efecto un determinado cambio a menos que se efectué otro.8 Niveles de aislamiento de transacciones Si un DBMS soporta el proceso de transacciones. 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. Por ejemplo.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED). 2.

1. 3. Como su nombre indica. Para aplicaciones simples. pero normalmente por defecto es el de la DBMS subyacente. 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. 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.1 Vista preliminar La clase DriverManager implementa la capa de gestión de JDBC.registerDriver directamente. 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.1 Mantenimiento de la lista de drivers disponibles. pero en la mayoría de los casos es preferible dejar que la clase DriverManager gestione los detalles al establecer la conexión. Por supuesto. el único método en esta clase que necesita un programador general para su uso directamente es DriverManager. 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. debería llamarse 241 . su nivel de aislamiento depende del driver. Guarda la lista de los drivers que están disponibles y establece la conexión entre la base de datos y el driver apropiado.getConnection. Un usuario puede llamar al método setIsolationLevel para cambiar el nivel de aislamiento de la transacció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. Para cambiar el nivel de aislamiento solo para una transacción. este método establece una conexión con la base de datos. provocando que los cambios hasta ese punto se hagan permanentes en la base de datos. Cuando se crea un nuevo objeto Connection.registerDriver. 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. JDBC permite al usuario llamar a los métodos de DriverManager getDriver. LA CLASE DriverManager 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. y trabaja como intermediaria entre el usuario y los drivers. el nivel de aislamiento que pueda soportarse depende de las posibilidades de la base de datos subyacente.se incrementan los bloqueos y se disminuye la concurrencia de los usuarios). 3.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful