0% encontró este documento útil (0 votos)
10 vistas644 páginas

Programaçao - Java Tutorial 2

El documento es un tutorial sobre Java que abarca desde la instalación del JDK hasta conceptos avanzados como multithreading y manejo de excepciones. Incluye secciones sobre clases, gráficos, y comunicación en Java, además de ofrecer descargas del tutorial en diferentes formatos. Se menciona que el tutorial está en desarrollo y se recomienda no enlazar directamente a él.

Cargado por

headworxjeff
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
10 vistas644 páginas

Programaçao - Java Tutorial 2

El documento es un tutorial sobre Java que abarca desde la instalación del JDK hasta conceptos avanzados como multithreading y manejo de excepciones. Incluye secciones sobre clases, gráficos, y comunicación en Java, además de ofrecer descargas del tutorial en diferentes formatos. Se menciona que el tutorial está en desarrollo y se recomienda no enlazar directamente a él.

Cargado por

headworxjeff
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

accesos ha tenido este sitio Web, desde el 8 de Octubre de 1996 fecha

El Tutorial se ve
mejor con

AVISOS
Ya está en proceso de Publicación la versión actualizada de este Tutorial. El sitio no es definitivo, por lo que nadie debería
hacer enlaces directamente a él, sino a través de esta página. Cubre la versión del JDK 1.2 beta 2 y posteriores y todavía
está en desarrollo. Siguiendo este ENLACE A LA NUEVA VERSION o picando en el parche de la imagen superior se
llega a él.

Si alguien hace alguna referencia al Tutorial, o desea incluirlo en algún medio de transmisión (CD, BBS, etc.), le ruego me
lo comunique.

© Agustín Froufe Ultima Actualización: 1 de Enero de 1997 Introducción | Indice | ftp


DOWNLOAD DEL TUTORIAL
Aquí tienes la posibilidad de tener en tu casa todo el Tutorial.

Antes de bajarte el Tutorial, procura darte un paseo desde la primera página para ver si realmente cumple
con las expectativas que esperas, para que no gastes tiempo en descargar algo que a lo peor no satisface en
nada lo que andas buscando.

Si no te causa demasiado trastorno, te rogaría que completaras el formulario para así acceder directamente a
la página que te permitirá bajar el fichero que selecciones.

Puedes bajarte el fichero utilizando http o ftp; en la página de download generada con el fichero que desees
llevarte, podrás seleccionar el protocolo que se usará para que el Tutorial llegue a ti.

Cuando lo rellenes te aparecerá otra página de confirmación y listo.

Los formatos y tamaños de los ficheros disponibles son:

● [Link] - 2172474 bytes

Formato HTML para Windows (PC) comprimido con WinZip 6.2 (El
descompresor debe soportar nombres largos de ficheros)

● [Link] - 1966448 bytes

Formato HTML, comprimido con GNUzip

Nombre:

Empresa/Organización:

Provincia/País:

e-mail:
Fichero que deseas descargar: [Link]

Texto a tu disposición para decir lo que quieras:


Borrar Aceptar

Tutorial de Java [Home] [Indice]


Agustín Froufe (froufe@[Link])
1. Introducción a Java
2. Instalación del JDK
3. Conceptos Básicos de Java
4. Programas Básicos en Java
5. El Depurador de Java - jdb
6. Clases Java
7. AWT
8. Gráficos
9. Excepciones en Java
10. Threads y Multithreading
11. Código Nativo
12. Entrada/Salida por fichero en Java
13. Comunicaciones en Java
14. Arquitectura MVC en Java
15. Aplicaciones Java
16. Final y Agradecimientos

Navegación por el Tutorial


Download del Tutorial

1. Introducción a Java
1. Origen de Java
2. Características de Java
■ Simple

■ Orientado a Objetos

■ Distribuido

■ Robusto

■ De Arquitectura Neutral

■ Seguro

■ Portable

■ Interpretado

■ Multithreaded
■ Dinámico
3. HotJava
4. Java para aplicaciones corporativas
■ Desarrollo rápido de aplicaciones

■ Aplicaciones efectivas y eficientes

■ Portabilidad para programador y programa

■ Costes de desarrollo

■ Mantenimiento y soporte

■ Aprendizaje

■ Resumen

2. Instalación del JDK


1. Windows 95
2. Solaris
3. Linux
4. Compilación sin JDK
3. Conceptos Básicos de Java
1. Programación en Java
■ Comentarios

■ Identificadores

1. Palabras clave
2. Palabras reservadas
■ Literales

■ Arrays

■ Operadores

■ Separadores

2. Control del Flujo


■ Sentencias de Salto

■ Sentencias de Bucles

■ Excepciones

■ Control General del Flujo

3. Clases
■ Tipos de Clases

4. Variables y Métodos de Instancia


■ Ambito de una variable

■ Métodos y Constructores

■ Finalizadores

5. Alcance de Objetos y Reciclado de Memoria


6. Herencia
7. Control de Acceso
8. Variables y Métodos Estáticos
9. this y super
10. Clases Abstractas
11. Interfaces
12. Métodos Nativos
13. Paquetes
■ Import

■ Paquetes de Java

14. Referencias
■ Punteros

■ Referencias en C++

■ Referencias en Java

■ Referencias y Arrays

■ Referencias y Listas

■ Punteros C/C++ y Referencias Java

4. Programas Básicos en Java


1. Una mínima aplicación en Java
■ HolaMundo

■ Compilación y Ejecución de HolaMundo

1. Ficheros fuente java


2. Compilación
3. Ejecución
■ Problemas de compilación

2. El visor de Applets de Sun (appletviewer)


■ Applet

■ Llamadas a Applets con appletviewer

■ Arquitectura de appletviewer

■ Ciclo de vida de un Applet

■ Métodos de appletviewer

1. Sinopsis
2. Ejemplo de uso
■ Funciones de menú de appletviewer

3. Un Applet básico en Java


■ HolaMundo

■ Componentes básicos de un Applet

1. Clases incluidas
2. La clase Applet
3. Métodos de Applet
■ Compilación de un Applet

■ Llamada a Applets

■ Prueba de un Applet

■ La marca APPLET de html

1. Atributos de APPLET
2. Paso de parámetros a Applets
3. Tokens en parámetros de llamada
4. El parámetro ARCHIVE
■ Depuración general
■ Ciclo de vida de un Applet
■ Protección de Applets

4. Escribir Applets Java


■ init

■ destroy

■ start

■ stop

■ resize

■ width

■ height

■ paint

■ update

■ repaint

■ getParameter

■ getDocumentBase

■ getCodeBase

■ print

5. La aplicación Fecha (Aproximación a OOP)


5. El Depurador de Java - jdb
1. Depurar HolaMundo
2. Comando help
3. Comando threadgroups
4. Comando threads
5. Comando run
6. Comando where
7. Comando use
8. Comando list
9. Comando dump
10. Comando step
6. Clases Java
1. La clase Math
■ Funciones matemáticas

2. La clase Character
■ Declaraciones

■ Comprobaciones booleanas

■ Traslaciones de caracteres

■ Traslaciones de carácter/dígito

■ Métodos de la clase Character

3. La clase Float
■ Declaraciones

■ Valores de Float

■ Conversiones de Clase/Cadena

■ Comprobaciones
■ Conversiones de Objetos
■ Otros Métodos

4. La clase Double
■ Declaraciones

■ Valores de Double

■ Métodos de Double

5. La clase Integer
■ Declaraciones

■ Valores de Integer

■ Métodos de Integer

6. La clase Long
■ Declaraciones

■ Valores de Long

■ Métodos de Long

7. La clase Boolean
■ Declaraciones

■ Valores de Boolean

■ Métodos de Boolean

8. La clase String
■ Funciones Básicas

1. Funciones de Comparación de Strings


2. Funciones de Comparación de Subcadenas
■ Funciones ValueOf

1. Funciones de Conversión
9. La clase StringBuffer
■ Cambio de Tamaño

■ Modificación del Contenido

■ Operadores de Concatenación

10. Uso de Conversiones


7. AWT
1. Introducción al AWT
2. Interface de Usuario
3. Estructura del AWT
4. Componentes y Contenedores
■ Tipos de Componentes

5. Componentes
■ Botones

1. Eventos Button
2. De pulsación (Push)
3. De lista (Choice)
4. De marcación (CheckBox)
5. De selección (Radio)
6. Autocontenidos
■ Etiquetas
■ Listas

■ Campos de Texto

■ Areas de Texto

■ Canvas

■ Barras de Desplazamiento

■ Diseño de Componentes propios

6. Contenedores
■ Window

■ Frame

■ Dialog

■ Panel

■ Crear un Contenedor

■ Añadir Componentes a un Contendor

7. Creación de Aplicaciones con AWT


■ Crear el Marco de la Aplicación

■ Inicializar Fuentes, Colores y Recursos

■ Crear Menús y Barras de Menús

■ Diálogos y Ventanas

8. Paneles
9. Layouts
■ FlowLayout

■ BorderLayout

■ GridLayout

■ GridBagLayout

■ CardLayout

■ Crear un Layout propio

10. Control de Eventos


■ La clase Event

■ Tipos de Eventos

1. Eventos de Ventana
2. Eventos de Teclado
3. Eventos de Ratón
4. Eventos de Barras
5. Eventos de Lista
6. Eventos Varios
■ Generación y Propagación de Eventos

■ Métodos de Control de Eventos

■ ACTION_EVENT

11. Mejorar el Diseño de Interfaces


■ Cambio de Font de Caracteres

■ Colores de Fondo y Texto

■ Fijar el Tamaño Preferido


■ Uso de Insets
■ Habilitar y Deshabilitar Componentes
■ Botón Gráfico
8. Gráficos
1. Objetos Gráficos
2. Métodos para Dibujos
■ Líneas

■ Rectángulos

■ Círculos, Elipses

■ Polígonos

■ Funciones Gráficas

■ Fractales

■ Líneas Flotantes

3. Métodos para Imágenes


4. Doble Buffering de Gráficos
■ Contextos Gráficos

■ Creación de Contextos Gráficos

■ Utilización de Contextos Gráficos

5. Nuevas Clases para Dibujo


6. La Clase MediaTracker
■ Manejo de Imágenes para Animación

■ Creación de un Objeto MediaTracker

■ Ejemplo de Animación

7. Sonido en Java
■ Reproducción de Sonido

■ Reproducción Repetitiva

8. Entrada por Ratón


9. Excepciones en Java
1. Manejo de Excepciones
2. Generar Excepciones en Java
3. Excepciones Predefinidas
4. Crear Excepciones Propias
5. Capturar Excepciones
■ try

■ catch

■ finally

6. Propagación de Excepciones
10. Threads y Multithreading
1. Flujo en Programas
■ Programas de Flujo Unico

■ Programas de Flujo Múltiple

2. Creación y Control de Threads


■ Creación de un Thread
■ Arranque de un Thread
■ Manipulación de un Thread

■ Suspensión de un Thread

■ Parada de un Thread

3. Arrancar y Parar Threads


4. Suspender y Reanudar Threads
5. Estados de un Thread
■ Nuevo Thread

■ Ejecutable

■ Parado

■ Muerto

■ El método isAlive()

6. Scheduling
7. Prioridades, demonios...
■ Prioridades

■ Threads Demonio

■ Diferencia de Threads con fork()

8. Ejemplo de Animación
9. Comunicación entre Threads
■ Productor

■ Consumidor

■ Monitor

■ Monitorización del Productor

11. Métodos Nativos


1. Escribir Código Java
2. Compilar el Código Java
3. Crear el fichero de Cabecera
4. Crear el fichero de Stubs
5. Escribir la función C
6. Crear la Librería Dinámica
■ Unix

■ Windows '95

7. Ejecutar el Programa
12. Entrada/Salida Estándar
1. La clase System
■ Stdin

■ Stdout

■ Stderr

2. Clases comunes de Entrada/Salida


13. Ficheros en Java
1. Ficheros
■ Creación de un objeto File

■ Comprobaciones y Utilidades
2. Streams de Entrada
■ Objetos FileInputStream

1. Apertura de un FileInputStream
2. Lectura de un FileInputStream
3. Cierre de FileInputStream
4. Ejemplo: Visualización de un fichero
■ Objetos DataInputStream

1. Apertura y cierre de DataInputStream


2. Lectura de un DataInputStream
■ Streams de entrada de URLs

1. Apertura de un Stream de entrada


3. Streams de Salida
■ Objetos FileOutputStream

1. Apertura de un FileOutputStream
2. Escritura en un FileOutputStream
3. Cierre de FileOutputStream
4. Ejemplo: Almacenamiento de Información
■ Streams de salida con buffer

1. Creación de Streams de salida con buffer


2. Volcado y Cierre de Streams de salida con buffer
■ Streams DataOutput

1. Apertura y cierre de objetos DataOutputStream


2. Escritura en un objeto DataOutputStream
3. Contabilidad de la salida
4. Ficheros de Acceso Aleatorio
■ Creación de un Fichero de Acceso Aleatorio

■ Acceso a la Información

■ Actualización de Información

14. Comunicaciones en Java


1. Comunicaciones en Unix
2. Sockets
■ Sockets Stream

■ Sockets Datagrama

■ Sockets Raw

3. Diferencias entre Sockets Stream y Datagrama


4. Uso de Sockets
■ Puertos y Servicios

■ La clase URL

5. Dominios de Comunicaciones
■ Dominio Unix

■ Dominio Internet

6. Modelo de Comunicaciones con Java


■ Apertura de Sockets
Creación de Streams de Entrada

■ Creación de Streams de Salida

■ Cierre de Sockets

■ Mínimo Cliente SMTP

■ Servidor de Eco

■ Mínimo Servidor TCP/IP

■ Mínimo Cliente TCP/IP

■ Servidor Simple de HTTP

■ Red en Windows '95 (sin conexión)

1. Configuración del TCP/IP de Windows '95


2. Crear una entrada en la Red
3. Comprobación de la Red
4. Problemas más frecuentes
7. Clases Utiles en Comunicaciones
15. Arquitectura MVC en Java
1. La Arquitectura MVC
■ Definición de las partes

2. Observador y Observable
■ Funciones de Observer y Observable

1. Observer
2. Observable
■ Cómo utilizar Observer y Observable

1. Extender un Observable
2. Implementar un Observador
3. Usando Observador y Observable
3. Ejemplo de aplicación MVC
16. Aplicaciones en Java
1. Etiqueta
2. Reloj Digital
3. Persiana
4. Solapas
5. Transparencia
6. Calculadora
7. Cuenta-Kilómetros
8. Potenciómetro
9. Cartel (de Luis Angel Ortega)

Seguro que quedan cosas pendientes que podríamos acometer, pero esto tiene que tener un fin y como
creemos que hemos desarrollado todo lo importante, e incluso algunas que no lo son tanto, de Java, pues
aquí lo dejamos.

No obstante, este Tutorial está totalmente abierto, y si alguien cree que falta algún aspecto importante de
Java todavía por desarrollar, agradeceríamos que nos enviase su comentario. Dentro de nuestras
posibilidades, veríamos la forma de incluir más capítulos en este Tutorial.
Tutorial de Java [Presentación] [Home] [Siguiente]
1. Origen de Java
2. Características de Java
❍ Simple

❍ Orientado a Objetos

❍ Distribuido

❍ Robusto

❍ De Arquitectura Neutral

❍ Seguro

❍ Portable

❍ Interpretado

❍ Multithreaded

❍ Dinámico

3. HotJava
4. Java para aplicaciones corporativas
❍ Desarrollo rápido de aplicaciones

❍ Aplicaciones efectivas y eficientes

❍ Portabilidad para programador y programa

❍ Costes de desarrollo

❍ Mantenimiento y soporte

❍ Aprendizaje

❍ Resumen

El uso principal que se hace de Internet e incluso de las redes internas (corporativas) es correo electrónico
(e-mail), aunque actualmente hay un auge sorprendente de la navegación web. Los documentos web
pueden contener variedad de texto, gráficos de todas clases y proporcionar enlaces hipertexto hacia
cualquier lugar de la red. Los navegadores utilizan documentos escritos en lenguaje HTML. La
combinación actual de navegadores HTML/WWW están limitados pues, a texto y gráficos. Si se quiere
reproducir un sonido o ejecutar un programa de demostración, primero hemos de bajarnos (download) el
fichero en cuestión y luego utilizar un programa en nuestro ordenador capaz de entender el formato de ese
fichero, o bien cargar un módulo (plug-in) en nuestro navegador para que pueda interpretar el fichero que
hemos bajado.

Hasta ahora, la única forma de realizar una página web con contenido interactivo, era mediante la interfaz
CGI (Common Gateway Interface), que permite pasar parámetros entre formularios definidos en lenguaje
HTML y programas escritos en Perl o en C. Esta interfaz resulta muy incómoda de programar y es pobre
en sus posibilidades.

El lenguaje Java y los navegadores con soporte Java, proporcionan una forma diferente de hacer que ese
navegador sea capaz de ejecutar programas. Con Java se puede reproducir sonido directamente desde el
navegador, se pueden visitar home pages con animaciones, se puede enseñar al navegador a manejar
nuevos formatos de ficheros, e incluso, cuando se pueda transmitir video por las líneas telefónicas, nuestro
navegador estará preparado para mostrar esas imágenes.

Utilizando Java, se pueden eliminar los inconvenientes de la interfaz CGI y también se pueden añadir
aplicaciones que vayan desde experimentos científicos interactivos de propósito educativo a juegos o
aplicaciones especializadas para la televenta. Es posible implementar publicidad interactiva y periódicos
personalizados. Por ejemplo, alguien podría escribir un programa Java que implementara una simulación
química interactiva (una cadena de adn). Utilizando un navegador con soporte Java, un usuario podría
recibir fácilmente esa simulación e interaccionar con ella, en lugar de conseguir simplemente un dibujo
estático y algo de texto. Lo recibido cobra vida. Además, con Java podemos estar seguros de que el código
que hace funcionar el experimento químico no contiene ningún trozo de código malicioso que dañe al
sistema. El código que intente actuar destructivamente o que contenga errores, no podrá traspasar los
muros defensivos colocados por las características de seguridad y robustez de Java.

Además, Java proporciona una nueva forma de acceder a las aplicaciones. El software viaja
transparentemente a través de la red. No hay necesidad de instalar las aplicaciones, ellas mismas vienen
cuando se necesitan. Por ejemplo, la mayoría de los navegadores del Web pueden procesar un reducido
número de formatos gráficos (típicamente GIF y JPEG). Si se encuentran con otro tipo de formato, el
navegador estándar no tiene capacidad para procesarlo, tendría que ser actualizado para poder aprovechar
las ventajas del nuevo formato. Sin embargo, un navegador con soporte Java puede enlazar con el servidor
que contiene el algoritmo que procesa ese nuevo formato y mostrar la imagen. Por lo tanto, si alguien
inventa un nuevo algoritmo de compresión para imágenes, el inventor sólo necesita estar seguro de que
hay una copia en código Java de ese algoritmo instalada en el servidor que contiene las imágenes que
quiere publicar. Es decir, los navegadores con soporte Java se actualizan a sí mismos sobre la marcha,
cuando encuentran un nuevo tipo de fichero o algoritmo.

Tutorial de Java [Navegación] [Indice] [Siguiente]


1. Windows 95
2. Solaris
3. Linux
4. Compilación sin JDK

En el instante en que estoy escribiendo esto, Java todavía no es un producto comercial. No todas las
máquinas disponen de la versión del Java Development Kit para ejecutarse en ellas. Por ello, solamente
comentaré la instalación de JDK en Solaris, Windows 95 y Linux.

Actualmente ya hay entornos de desarrollo integrados completos para Java, diferentes del JDK de Sun.
Symantec dispone de un compilador de Java para Windows 95 y Windows NT, con las ventajas del
aumento de velocidad de proceso y capacidades multimedia que esto proporciona, Symantec Café.
Borland también está trabajando en ello y la nueva versión de su entorno de desarrollo soporta Java. Sun
ha lanzado la versión comercial de su propio entorno de desarrollo para Java, el Java Workshop,
enteramente escrito en Java. Y Microsoft ha puesto en el mercado Visual J++, que sigue el estilo de todas
sus herramientas de desarrollo.

No obstante, trataremos solamente el JDK, que hasta el momento es lo más conocido. El entorno básico
del JDK de Java que proporciona Sun está formado por herramientas en modo texto, que son: java,
intérprete que ejecuta programas en byte-code. javac, compilador de Java que convierte el código fuente
en byte-code. javah, crea ficheros de cabecera para implementar métodos para cualquier clase. javap, es un
descompilador de byte-code a código fuente Java. javadoc, es un generador automático de documentos
HTML a partir del código fuente Java. javaprof, es un profiler para aplicaciones de un solo thread.
HotJava, es un navegador Web escrito completamente en Java.

El entorno habitual pues, consiste en un navegador que pueda ejecutar applets, un compilador que
convierta el código fuente Java a byte-code y el intérprete Java para ejecutar los programas. Estos son los
componenetes básicos para desarrollar algo en Java. No obstante se necesita un editor para escribir el
código fuente, y no son estrictamente necesarias otras herramientas como el debugger, un entorno visual,
la documentación o un visualizador de jerarquía de clases. Tan es así, que disponiendo del navegador
Netscape 2.0 no se necesita ni tan siquiera el JDK (a petición de varios amigos que disfrutan del uso de
Linux pero no disponen de soporte ELF para poder utilizar el JDK portado por Randy Chapman, les
indicaré como conseguir utilizar el compilador embebido en Netscape).

Windows
La versión del JDK para Windows es un archivo autoextraible. Se necesitan alrededor de 6 Mb de espacio
libre en disco. Ejecutar el fichero, que desempaquetará el contenido del archivo. El directorio donde se
instale no es importante, pero supondremos que se instala en el raiz del disco C:, en cuyo caso los
archivos colgarán de c:\java. Es necesario añadir c:\java\bin a la variable de entorno PATH.

Además de los ficheros java, el JDK incluye dos librerías dinámicas, [Link] y [Link],
que se instalarán en el directorio de Java. Si tienes ninguna copia de estos ficheros en tu ordenador
(probablemente en el directorio system de Windows) copia estos ficheros en el directorio
c:\java\bin. Si estos ficheros ya están en tu ordenador, elimina las copias extra que instala el JDK.

Solaris

La versión del JDK para Solaris es un fichero tar comprimido. Se necesitan alrededor de 9 Mb de disco
para descomprimir el JDK, aunque el doble de espacio sería una cifra más cómoda. Ejecutar los siguientes
comandos:

% uncompress [Link].Z
% tar xvf JDK-beta-solaris2-sparc-tar

Puedes descomprimir el archivo en tu directorio home, o, si tienes privilegios de supervisor, en algún sitio
más conveniente de /usr/local para que todos los usuarios tengan acceso a los ficheros. Sin embargo,
los privilegios del supervisor no son necesarios para instalar y ejecutar Java. Por simplicidad, supondré
que has descomprimido el JDK en /usr/local, aunque el path completo donde se haga no tiene
relevancia (también es posible colocarlo en /opt que es donde residen todas las aplicaciones de Solaris).
Si lo has colocado en un sitio diferente, simplemente sustituye /usr/local por ese directorio (si lo has
descomprimido en tu home, puedes utilizar ~/java y ~/hotjava, en vez del path completo).

Es necesario añadir /usr/local/java/bin a la variable de entorno PATH. Utiliza el siguiente


comando (suponiendo que tengas el shell csh o tcsh):

set path=($PATH /usr/local/java/bin)

También puedes añadir esta línea al final del fichero .profile y .cshrc, y ya tienes el sistema listo para
ejecutar applets. Si quieres desembarazarte de la ventana que aparece cada vez que lances el appletviewer
con la licencia de Sun, crea un directorio que se llame .hotjava en el directorio java/bin y ya no volverás a
verla.

Linux

Necesitas un kernel que soporte binarios ELF, por lo tanto tu Linux debe ser la versión 1.2.13 o superior,
las anteriores tienen un bug que hacen que javac no funcione. Necesitas también Netscape, versión 2.0b4 o
posterior. Sobre la versión 1.2.13 del kernel de Linux, hay que seguir los pasos que indico para conseguir
que JDK funcione:

● Bajarse el JDK, [Link] y [Link] a


/usr/local, descomprimirlo y hacer 'tar xvf'
● En el fichero .java_wrapper (si no existe, crearlo) cambiar las variable J_HOME y PRG, para que
queden como:

J_HOME=/usr/local/java
PRG=/usr/local/java/bin

● Bajarse la librería [Link] a /, descomprimirla, hacer 'tar xvf'. Asegurarse de que


/lib/[Link].5 es un link simbólico a este nuevo fichero. Si no lo es, hacer el /lib 'ln -s
[Link].5.2.18 [Link].5'
● Bajarse [Link] a un directorio temporal, descomprimirlo y hacer 'tar xvf'. Ejecutar
'[Link]' y eliminar el directorio temporal.
● Añadir /usr/local/java a la variable de entorno PATH. Si se desea que esté fijada para todos los
usuarios, incorporar el directorio a la varible PATH que se fija en el fichero /etc/profile.
● Bajarse [Link].z a /usr/local/netscape, descomprimirlo y
hacer 'tar xvf'
● Crear un link en /usr/local/bin a /usr/local/netscape/netscape

Esto debería ser suficiente para compilar cualquier cosa en Java/Linux. En caso de tener problemas, es el
momento de recurrir a las FAQ.

Siguiendo los pasos indicados ya se puede ejecutar el ejemplo del Tic-Tac-Toe que propone la hoja de
instalación que Sun ha incluido en todas sus versiones y que en Linux consistiría en cambiarse al
directorio de la demo:

% cd /usr/local/java/demo/TicTacToe

ejecutar el visualizador de applets sobre la página html:

% appletviewer [Link]

y a jugar a las tres en raya. Por cierto, que el algoritmo que usa el ordenador está falseado por lo que es
posible ganarle.

Compilación sin JDK

Parece raro, pero se puede conseguir. Lo único necesario es el navegador Netscape 2.0. Este navegador,
junto con la máquina virtual Java (JVM) y el sistema run-time, tiene un compilador Java. Si no se dispone
del Java Development Kit (JDK), que no está disponible para todas las plataformas, pero sí de la versión
de Netscape para nuestra plataforma, aquí van los pasos a seguir para utilizar el compilador de Java
embebido en Netscape.

Como necesito partir de algún punto para tomarlo como referencia, voy a suponer que estamos sobre
Linux y que vamos a prescindir del JDK de Randy Chapman. Lo que habría que hacer sería lo siguiente.

Primero. Instalar Netscape en el ordenador. Asegurarse de entender perfectamente y leerse hasta el final
el fichero README, para seguir las instrucciones específicas de la instalación de Netscape en la
plataforma y que Netscape funcione perfectamente. En nuestro caso, en que vamos a intentar compilar
código Java con Netscape sobre Linux, la pieza clave es la situación del fichero moz2_0.zip, que en mi
máquina está en /usr/local/netscape/java/classes.

Segundo. Extraer de una copia cualquiera del JDK (aunque sea de otra plataforma), el fichero
java/lib/[Link] y guardarlo en el mismo sitio que el fichero moz2_0.zip; esta localización no es
necesaria, pero simplifica la estructura.

Tercero. Fijar la variable de entorno CLASSPATH para que Netscape pueda encontrar sus propias clases
además de las clases del Java de Sun. Asegurarse de incluir el "directorio actual", para poder compilar a la
vez que se usan los ficheros .zip de Netscape y Sun. Por ejemplo:

setenv CLASSPATH
.:/usr/local/netscape/java/classes/moz2_0.zip :
/usr/local/netscape/java/classes/[Link]

Cuarto. Compilar el código Java (applet o aplicación) con el comando:

netscape -java [Link] [fichero].java

(sustituir el nombre del fichero con el código Java en vez de [fichero]). Esto convertirá el código fuente
Java en byte-code, generándose el archivo [fichero].class.

Quinto. Comprobar si se puede ejecutar la aplicación con el comando:

netscape -java [clase]

(sustituir el nombre de la clase de la aplicación -la que contiene la rutina main- en vez de [clase]).

Sexto. Si se ha compilado un applet Java, construir una página html que lo utilice para visualizarlo con el
navegador en su forma normal. O también se puede visualizar utilizando el appletviewer, ejecutando:

netscape -java [Link] [clase]

Desgraciadamente, la sentencia anterior no parece funcionar en todos los sistemas. Hay amigos míos que
no han sido capaces de visualizar applets con este método.

Para aprovechar el tiempo, se puede crear un script que recoja los pasos 3, 4 y 6. Si estamos utilizando el
csh, el contenido del script sería:

#/bin/csh -f setenv CLASSPATH


.:/usr/local/netscape/java/classes/moz2_0.zip:
/usr/local/netscape/java/classes/[Link]
netscape -java [Link] $1

y lo almacenaríamos como javac. Se ha de hacer el script ejecutable y cambiar /bin/csh por el path
completo donde esté situado el csh. De forma semejante podemos definir el intérprete java y el
appletviewer, sustituyendo la línea adecuada de llamada a Netscape.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Programación en Java
❍ Comentarios

❍ Identificadores

1. Palabras clave
2. Palabras reservadas
❍ Literales

❍ Arrays

❍ Operadores

❍ Separadores

2. Control del Flujo


❍ Sentencias de Salto

❍ Sentencias de Bucle

❍ Excepciones

❍ Control General del Flujo

3. Clases
❍ Tipos de Clases

4. Variables y Métodos de Instancia


❍ Ambito de una Variable

❍ Métodos y Constructores

❍ Finalizadores

5. Alcance de Objetos y Reciclado de Memoria


6. Herencia
7. Control de Acceso
8. Variables y Métodos Estáticos
9. this y super
10. Clases Abstractas
11. Interfaces
12. Métodos Nativos
13. Paquetes
❍ Import

❍ Paquetes de Java

14. Referencias
❍ Punteros

❍ Referencias en C++
❍ Referencias en Java
❍ Referencias y Arrays
❍ Referencias y Listas
❍ Punteros C/C++ y Referencias Java

Ahora que ya hemos visto a grandes rasgos lo que Java puede ofrecernos, y antes de entrar a saco en la
generación de nuestro primer código Java, vamos a echar un vistazo al lenguaje Java en sí. Lo básico
resultará muy familiar a los que tengan conocimientos de C/C++. Los programadores con experiencia en
otros lenguajes procedurales reconocerán la mayor parte de las construcciones. Esperemos que este
capítulo no resulte demasiado intenso, no obstante, sí debe estar presente, porque más de una vez
recurriremos a él como referencia. En posteriores capítulos profundizaremos sobre aspectos de la
programación en Java por los que aquí pasaremos de puntillas e iremos presentando ejemplos de código de
cada uno de esos aspectos de la programación en Java.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Una mínima aplicación en Java
❍ HolaMundo

❍ Compilación y Ejecución de HolaMundo

1. Ficheros fuente java


2. Compilación
3. Ejecución
❍ Problemas de compilación

2. El visor de Applets de Sun (appletviewer)


❍ Applet

❍ Llamadas a Applets con appletviewer

❍ Arquitectura de appletviewer

❍ Ciclo de vida de un Applet

❍ Métodos de appletviewer

1. Sinopsis
2. Ejemplo de uso
❍ Funciones de menú de appletviewer

3. Un Applet básico en Java


❍ HolaMundo

❍ Componentes básicos de un Applet

1. Clases incluidas
2. La clase Applet
3. Métodos de Applet
❍ Compilación de un Applet

❍ Llamada a Applets

❍ Prueba de un Applet

❍ La marca APPLET de html

1. Atributos de APPLET
2. Paso de parámetros a Applets
3. Tokens en parámetros de llamada
4. El parámetro ARCHIVE
❍ Depuración general

❍ Ciclo de vida de un Applet

❍ Protección de Applets

4. Escribir Applets Java


❍ init
❍ destroy

❍ start

❍ stop

❍ resize

❍ width

❍ height

❍ paint

❍ update

❍ repaint

❍ getParameter

❍ getDocumentBase

❍ getCodeBase

❍ print

5. La aplicación Fecha (Aproximación a OOP)

Como cualquier otro lenguaje, Java se usa para crear aplicaciones. Pero, también Java tiene la
particularidad especial de poder crear aplicaciones muy especiales, son los applets, que es una mini (let)
aplicación (app) diseñada para ejecutarse en un navegador. Vamos a ver en detalle lo mínimo que
podemos hacer en ambos casos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Depurar HolaMundo
2. Comando help
3. Comando threadgroups
4. Comando threads
5. Comando run
6. Comando where
7. Comando use
8. Comando list
9. Comando dump
10. Comando step

El depurador de Java, jdb es un depurador de línea de comandos, similar al que Sun proporciona en sus
Sistemas, dbx. Es complicado de utilizar y un tanto críptico, por lo que, en principio, tiene escasa practicidad
y es necesaria una verdadera emergencia para tener que recurrir a él.

Trataremos por encima los comandos que proporciona el jdb, pero sin entrar en detalles de su
funcionamiento, porque no merece la pena. Casi es mejor esperar a disponer de herramientas visuales para
poder depurar con cierta comodidad nuestro código Java.

Para poder utilizar el depurador, las aplicaciones Java deben estar compiladas con la opción de depuración
activada, -g. Posteriormente se puede lanzar appletviewer con la opción de depuración, debug, y habremos
puesto en marcha jdb.

Depurar HolaMundo

Hemos modificado nuestro applet de ejemplo para utilizarlo en nuestra sesión de ejemplo con el depurador.
Se compilaría con el comando:

%javac -g [Link]

y el contenido de nuestro applet HolaMundo modificado y guardado en el fichero [Link] sería el siguiente:

//
// Applet HolaMundo de ejemplo, para depurar
//
import [Link];
import [Link];

public class hm extends Applet {


int i;

public void paint( Graphics g ) {


i = 10;
[Link]( "Hola Mundo!",25,25 );
}
}

Una vez compilado, iniciamos la sesión lanzando el visor de applets de Sun con la opción de depuración,
utilizando el comando:

%appletviewer -debug [Link]

El fichero [Link] contiene las líneas mínimas para poder activar el applet, estas líneas son las que
reproducimos:

<html>
<applet code=[Link] width=100 height=100>
</applet>
</html>

Se inicia pues la sesión con el depurador y vamos a ir reproduciendo lo que aparece en la pantalla a medida
que vamos introduciendo comandos:

%appletviewer -debug [Link]


Loading jdb...
0xee301bf0:class([Link])
>

Comando help

El comando help proporciona una lista de los comandos que están disponibles en la sesión de jdb. Esta lista
es la que sigue, en donde hemos aprovechado la presencia de todos los comandos para comentar la acción
que cada uno de ellos lleva a cabo.

>help
** command list **
threads [threadgroup] -- lista threads
thread <thread id> -- establece el thread por defecto
suspend [thread id(s)] -- suspende threads (por defecto, todos)
resume [thread id(s)] -- continúa threads (por defecto, todos)
where [thread id]|all -- muestra la pila de un thread
threadgroups -- lista los grupos de threads
threadgroup <name> -- establece el grupo de thread actual

print <id> [id(s)] -- imprime un objeto o campo


dump <id> [id(s)] -- imprime toda la información del objeto

locals -- imprime las variables locales de la pila actual

classes -- lista las clases conocidas


methods <class id> -- lista los métodos de una clase

stop in <class id>.<method> -- fija un punto de ruptura en un método


stop at <class id>:<line> -- establece un punto de ruptura en una línea
up [n frames] -- ascender en la pila de threads
down [n frames] -- descender en la pila de threads
clear <class id>:<line> -- eliminar un punto de ruptura
step -- ejecutar la línea actual
cont -- continuar la ejecución desde el punto de ruptura

catch <class id> -- parar por la excepción especificada


ignore <class id> -- ignorar la excepción especificada

list [line number] -- imprimir código fuente


use [source file path] -- ver o cambiar la ruta del fichero fuente
memory -- informe del uso de la memoria
load <classname> - carga la clase Java a ser depurada
run <args> - comienza la ejecución de la clase cargada
!! - repite el último comando
help (or ?) - lista los comandos
exit (or quit) - salir del depurador
>

Comando threadgroups

El comando threadgroups permite ver la lista de threads que se están ejecutando. Los grupos system y main
deberían estar siempre corriendo.

>threadgroups
1.([Link])0xee300068 system
2.([Link])0xee300a98 main
>

Comando threads

El comando threads se utiliza para ver la lista completa de los threads que se están ejecutando actualmente.

>threads
Group system:
1.([Link])0xee300098 clock handler cond
2.([Link])0xee300558 Idle thread run
3.([Link])0xee3005d0 sync Garbage Collector cond
4.([Link])0xee300620 Finalizer thread cond
5.([Link])0xee300a20 Debugger agent run
6.([Link])0xee300b58) Breakpoint handler cond
Group main:
7.([Link])0xee300048 main suspended
>

Comando run

El comando run es el que se utiliza para arrancar el appletviewer en la sesión de depuración. Lo teclearemos
y luego volveremos a listar los threads que hay en ejecución.

>run
run [Link] [Link]
running...
main[1]threads
threads
Group [Link]:
1.([Link])0xee3000c0 AWT-Motif running
2.([Link])0xee302ed0 ScreenUpdater cond. Waiting
Group [Link]:
3.([Link])0xee302f38 Thread-6 cond. Waiting
main[1]

El visor de applets de Sun aparecerá en la pantalla y mostrará el conocido mensaje de saludo al Mundo.
Ahora vamos a rearrancar el appletviewer con un punto de ruptura, para detener la ejecución del applet, y
podamos seguir mostrando los comandos disponibles en el jdb.

main[1]exit
%appletviewer -debug [Link]
Loading jdb...
0xee3009c8:class([Link])
>stop in [Link]
Breakpoint set in [Link]
>run
run [Link] [Link]
running...
Breakpoint hit: [Link]([Link])
AWT-Motif[1]

Comando where
El comando where mostrará la pila de ejecución del applet.

AWT-Motif[1]where
[1][Link]([Link])
[2][Link]([Link])
[3][Link]([Link])
AWT-Motif[1]

Comando use

El comando use nos informa del camino donde jdb va a buscar los ficheros fuentes que contienen el código
Java de las clases que se están depurando. Por defecto, utilizará el camino que se especifique en la variable
de entorno CLASSPATH.

AWT-Motif[1]use
/usr/local/java/classes:
AWT-Motif[1]

Comando list

El comando list mostrará el código fuente actual al comienzo del punto de ruptura que hayamos fijado.

AWT-Motif[1]list
9 public void paint( Graphics g ) {
10 => i = 10;
11 [Link]( "Hola Mundo!",25,25 ) ;
12 }
13 }
AWT-Motif[1]

Comando dump

El comando dump nos permitirá ahora ver el valor del objeto g pasado desde el appletviewer.

AWT-Motif[1]dump g
g = ([Link].X11Graphics)0xee303df8 {
int pData = 1342480
Color foreground = ([Link])0xee302378
Font font = ([Link])0xee302138
int originX = 0
int originY = 0
float scaleX = 1
float scaleY = 1
Image image = null
}
AWT-Motif[1]

Comando step

El comando step nos porporciona el método para ejecutar la línea actual,


que estará siendo apuntada por el indicador si hemos utilizado el comando
list.

AWT-Motif[1]step
Breakpoint hit: [Link]([Link])
AWT-Motif[1]list
9 public void paint( Graphics g ) {
10 i = 10;
11 => [Link]( "Hola Mundo!",25,25 );
12 }
13 }
AWT-Motif[1]

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. La clase Math
❍ Funciones matemáticas

2. La clase Character
❍ Declaraciones

❍ Comprobaciones booleanas

❍ Traslaciones de caracteres

❍ Traslaciones de carácter/dígito

❍ Métodos de la clase Character

3. La clase Float
❍ Declaraciones

❍ Valores de Float

❍ Conversiones de Clase/Cadena

❍ Comprobaciones

❍ Conversiones de Objetos

❍ Otros Métodos

4. La clase Double
❍ Declaraciones

❍ Valores de Double

❍ Métodos de Double

5. La clase Integer
❍ Declaraciones

❍ Valores de Integer

❍ Métodos de Integer

6. La clase Long
❍ Declaraciones

❍ Valores de Long

❍ Métodos de Long

7. La clase Boolean
❍ Declaraciones

❍ Valores de Boolean

❍ Métodos de Boolean

8. La clase String
❍ Funciones Básicas

1. Funciones de Comparación de Strings


2. Funciones de Comparación de Subcadenas
❍ Funciones ValueOf

1. Funciones de Conversión
9. La clase StringBuffer
❍ Cambio de Tamaño

❍ Modificación del Contenido

❍ Operadores de Concatenación

10. Uso de Conversiones

En cualquier lenguaje orientado a objetos, las clases definen cualquier objeto que se pueda manipular. Java
tiene muchas clases útiles, no solamente aquellas que se utilizan para gráficos y sonido, usadas en la
construcción de applets mucho más complejos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Introducción al AWT
2. Interface de Usuario
3. Estructura del AWT
4. Componentes y Contenedores
❍ Tipos de Componentes

5. Componentes
❍ Botones

1. Eventos Button
2. De pulsación (Push)
3. De lista (Choice)
4. De marcación (CheckBox)
5. De selección (Radio)
6. Autocontenidos
❍ Etiquetas

❍ Listas

❍ Campos de Texto

❍ Areas de Texto

❍ Canvas

❍ Barras de Desplazamiento

❍ Diseño de Componentes propios

6. Creación de Aplicaciones con AWT


❍ Crear el Marco de la Aplicación

❍ Inicializar Fuentes, Colores y Recursos

❍ Crear Menús y Barras de Menús

❍ Diálogos y Ventanas

7. Paneles
8. Layouts
❍ FlowLayout

❍ BorderLayout

❍ GridLayout

❍ GridBagLayout

❍ CardLayout

❍ Crear un Layout propio

9. Control de Eventos
❍La clase Event
❍ Tipos de Eventos

1. Eventos de Ventana
2. Eventos de Teclado
3. Eventos de Ratón
4. Eventos de Barras
5. Eventos de Lista
6. Eventos Varios
❍ Generación y Propagación de Eventos

❍ Métodos de Control de Eventos

❍ ACTION_EVENT

10. Mejorar el Diseño de Interfaces


❍ Cambio de Font de Caracteres

❍ Colores de Fondo y Texto

❍ Fijar el Tamaño Preferido

❍ Uso de Insets

❍ Habilitar y Deshabilitar Componentes

❍ Botón Gráfico

Introducción al AWT
AWT es el acrónimo del X Window Toolkit para Java, donde X puede ser cualquier cosa: Abstract,
Alternative, Awkward, Another o Asqueroso; aunque parece que Sun se decanta por Abstracto, seriedad
por encima de todo. Se trata de una biblioteca de clases Java para el desarrollo de Interfaces de Usuario
Gráficas. La versión del AWT que Sun proporciona con el JDK se desarrolló en sólo dos meses y es la
parte más débil de todo lo que representa Java como lenguaje. El entorno que ofrece es demasiado simple,
no se han tenido en cuenta las ideas de entornos gráficos novedosos, sino que se ha ahondado en
estructuras orientadas a eventos, llenas de callbacks y sin soporte alguno del entorno para la construcción
gráfica; veremos que la simple acción de colocar un dibujo sobre un botón se vuelve una tarea harto
complicada. Quizá la presión de tener que lanzar algo al mercado haya tenido mucho que ver en la pobreza
de AWT.

JavaSoft, asegura que esto sólo era el principio y que AWT será multi-idioma, tendrá herramientas
visuales, etc. En fin, al igual que dicen los astrólogos, el futuro nos deparará muchas sorpresas.

La estructura básica del AWT se basa en Componentes y Contenedores. Estos últimos contienen
Componentes posicionados a su respecto y son Componentes a su vez, de forma que los eventos pueden
tratarse tanto en Contenedores como en Componentes, corriendo por cuenta del programador (todavía no
hay herramientas de composición visual) el encaje de todas las piezas, así como la seguridad de
tratamiento de los eventos adecuados. Nada trivial.

No obstante y pese a ello, vamos a abordar en este momento la programación con el AWT para tener la
base suficiente y poder seguir profundizando en las demás características del lenguaje Java, porque como
vamos a ir presentando ejemplos gráficos es imprescindible el conocimiento del AWT. Mientras tanto,
esperemos que JavaSoft sea fiel a sus predicciones y lo que ahora veamos nos sirva de base para migrar a
un nuevo y maravilloso AWT.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Objetos Gráficos
2. Métodos para Dibujos
❍ Líneas

❍ Rectángulos

❍ Círculos, Elipses

❍ Funciones Gráficas

❍ Fractales

❍ Líneas Flotantes

3. Métodos para Imágenes


4. Doble Buffering de Gráficos
❍ Contextos Gráficos

❍ Creación de Contextos Gráficos

❍ Utilización de Contextos Gráficos

5. Nuevas Clases para Dibujo


6. La Clase MediaTracker
❍ Manejo de Imágenes para Animación

❍ Creación de un Objeto MediaTracker

❍ Ejemplo de Animación

7. Sonido en Java
❍ Reproducción de Sonido

❍ Reproducción Repetitiva

8. Entrada por Ratón

Objetos Gráficos

En páginas anteriores ya se ha mostrado cómo escribir applets, cómo lanzarlos y los fundamentos básicos
de la presentación de información sobre ellos. Ahora, pues, querremos hacer cosas más interesantes que
mostrar texto; ya que cualquier página HTML puede mostrar texto. Para ello, Java proporciona la clase
Graphics, que permite mostrar texto a través del método drawString(), pero también tiene muchos otros
métodos de dibujo. Para cualquier programador, es esencial el entendimiento de la clase Graphics, antes
de adentrarse en el dibujo de cualquier cosa en Java. Esta clase proporciona el entorno de trabajo para
cualquier operación gráfica que se realice dentro del AWT. Juega dos importantes papeles: por un lado, es
el contexto gráfico, es decir, contiene la información que va a afectar a todas las operaciones gráficas,
incluyendo los colores de fondo y texto, la fuente de caracteres, la localización y dimensiones del
rectángulo en que se va a pintar, e incluso dispone de información sobre el eventual destino de las
operaciones gráficas (pantalla o imagen). Por otro lado, la clase Graphics proporciona métodos que
permiten el dibujo de primitivas, figuras y la manipulación de fonts de caracteres y colores. También hay
clases para la manipulación de imágenes, doble-buffering, etc.

Para poder pintar, un programa necesita un contexto gráfico válido, representado por una instancia de la
clase Graphics. Pero, como esta clase es abstracta, no se puede instanciar directamente; así que debemos
crear un componente y pasarlo al programa como un argumento a los métodos paint() o update().

Los dos métodos anteriores, paint() y update(), junto con el método repaint() son los que están
involucrados en la presentación de gráficos en pantalla. El AWT, para reducir el tiempo que necesitan
estos métodos para realizar el repintado en pantalla de gráficos, tiene dos axiomas:

● Primero, el AWT repinta solamente aquellos Componentes que necesitan ser repintados, bien
porque estuviesen cubiertos por otra ventana o porque se pida su repintado directamente
● Segundo, si un Componente estaba tapado y se destapa, el AWT repinta solamente la porción del
Componente que estaba oculta

En la ejecución del applet que aparece a continuación, [Link], podemos observar como se
realiza este proceso. Ignorar la zona de texto de la parte superior del applet de momento, y centrar la
mirada en la parte coloreada. Utilizando otra ventana, tapar y destapar parte de la zona que ocupa el applet.
Se observará que solamente el trozo de applet que estaba cubierto es el que se repinta. Yendo un poco más
allá, solamente aquellos componentes que estén ocultos y se vuelvan a ver serán los que se repinten, sin
tener en cuenta su posición dentro de la jerarquía de componentes.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de


la apariencia del applet en pantalla:

La pantalla en Java se incrementa de izquierda a derecha y de arriba hacia abajo, tal como muestra la
figura:
Los pixels de la pantalla son pues: posición 0 + ancho de la pantalla - 1.

En los textos, el punto de inserción se encuentra en la línea base de la primera letra.

Métodos para Dibujos

Vamos a presentar métodos para dibujar varias figuras geométricas. Como estos métodos funcionan
solamente cuando son invocados por una instancia válida de la clase Graphics, su ámbito de aplicación se
restringe a los componentes que se utilicen en los métodos paint() y update(). Normalmente los métodos
de dibujo de primitivas gráficas funcionan por pares: un método pinta la figura normal y el otro pinta la
figura rellena.

drawLine( x1,y1,x2,y2 )
drawRect( x,y,ancho,alto )
fillRect( x,y,ancho,alto )
clearRect( x,y,[Link] )
drawRoundRect( x,y,ancho,alto,anchoArco,altoArco )
fillRoundRect( x,y,ancho,alto,anchoArco,altoArco )
draw3DRect( x,y,ancho,alto,boolean elevado )
fill3DRect( x,y,ancho,alto,boolean elevado )
drawOval( x,y,ancho,alto )
fillOval( x,y,ancho,alto )
drawArc( x,y,ancho,alto,anguloInicio,anguloArco )
fillArc( x,y,ancho,alto,anguloInicio,anguloArco )
drawPolygon( int[] puntosX,int[] puntosY[],numPuntos )
fillPolygon( int[] puntosX,int[] puntosY[],numPuntos )
drawString( string s,x,y )
drawChars( char data[],offset,longitud,x,y )
drawBytes( byte data[],offset,longitud,x,y )
copyArea( xSrc,ySrc,ancho,alto,xDest,yDest )

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Manejo de Excepciones
2. Generar Excepciones en Java
3. Excepciones Predefinidas
4. Crear Excepciones Propias
5. Capturar Excepciones
❍ try

❍ catch

❍ finally

6. Propagación de Excepciones

Las excepciones en Java están destinadas, al igual que en el resto de los lenguajes que las soportan, para la
detección y corrección de errores. Si hay un error, la aplicación no debería morirse y generar un core (o un
crash en caso del DOS). Se debería lanzar (throw) una excepción que nosotros deberíamos capturar
(catch) y resolver la situación de error. Java sigue el mismo modelo de excepciones que se utiliza en C++.
Utilizadas en forma adecuada, las excepciones aumentan en gran medida la robustez de las aplicaciones.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Flujo en Programas
❍ Programas de Flujo Unico

❍ Programas de Flujo Múltiple

2. Creación y Control de Threads


❍ Creación de un Thread

❍ Arranque de un Thread

❍ Manipulación de un Thread

❍ Suspensión de un Thread

❍ Parada de un Thread

3. Arrancar y Parar Threads


4. Suspender y Reanudar Threads
5. Estados de un Thread
❍ Nuevo Thread

❍ Ejecutable

❍ Parado

❍ Muerto

❍ El método isAlive()

6. Scheduling
7. Prioridades, demonios...
❍ Prioridades

❍ Threads Demonio

❍ Diferencia de Threads con fork()

8. Ejemplo de Animación
9. Comunicación entre Threads
❍ Productor

❍ Consumidor

❍ Monitor

❍ Monitorización del Productor

Considerando el entorno multithread, cada thread (hilo, flujo de control del programa) representa un
proceso individual ejecutándose en un sistema. A veces se les llama procesos ligeros o contextos de
ejecución. Típicamente, cada thread controla un único aspecto dentro de un programa, como puede ser
supervisar la entrada en un determinado periférico o controlar toda la entrada/salida del disco. Todos los
threads comparten los mismos recursos, al contrario que los procesos en donde cada uno tiene su propia
copia de código y datos (separados unos de otros). Gráficamente, los threads se parecen en su
funcionamiento a lo que muestra la figura siguiente:

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Escribir Código Java
2. Compilar el Código Java
3. Crear el fichero de Cabecera
4. Crear el fichero de Stubs
5. Escribir la función C
6. Crear la Librería Dinámica
❍ Unix

❍ Windows '95

7. Ejecutar el Programa

Un método nativo es un método Java (una instancia de un objeto o una clase) cuya implementación se ha
realizado en otro lenguaje de programación, por ejemplo, C. Vamos a ver cómo se integran métodos
nativos en clases Java. Actualmente, el lenguaje Java solamente proporciona mecanismos para integrar
código C en programas Java.

Veamos pues los pasos necesarios para mezclar código nativo C y programas Java. Recurriremos (¡Cómo
no!) a nuestro saludo; en este caso, el programa HolaMundo tiene dos clases Java: la primera implementa
el método main() y la segunda, HolaMundo, tiene un método nativo que presenta el mensaje de saludo.
La implementación de este segundo método la realizaremos en C.

Las acciones que debemos realizar, para conseguir que nuestra nueva versión del saludo funcione, serán
las que desarrollaremos en las páginas siguientes del Tutorial.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. La clase System
❍ Stdin

❍ Stdout

❍ Stderr

2. Clases comunes de Entrada/Salida

Los usuarios de Unix, y aquellos familiarizados con las líneas de comandos de otros sistemas como DOS, han
utilizado un tipo de entrada/salida conocida comúnmente por entrada/salida estándar. El fichero de entrada
estándar (stdin) es simplemente el teclado. El fichero de salida estándar (stdout) es típicamente la pantalla (o la
ventana del terminal). El fichero de salida de error estándar (stderr) también se dirige normalmente a la
pantalla, pero se implementa como otro fichero de forma que se pueda distinguir entre la salida normal y (si es
necesario) los mensajes de error.

La clase System

Java tiene acceso a la entrada/salida estándar a través de la clase System. En concreto, los tres ficheros que se
implementan son:

Stdin

[Link] implementa stdin como una instancia de la clase InputStream. Con [Link], se accede a los métodos
read() y skip(). El método read() permite leer un byte de la entrada. skip( long n ), salta n bytes de la
entrada.

Stdout

[Link] implementa stdout como una instancia de la clase PrintStream. Se pueden utilizar los métodos print()
y println() con cualquier tipo básico Java como argumento.

Stderr

[Link] implementa stderr de la misma forma que stdout. Como con [Link], se tiene acceso a los métodos
de PrintStream.

Vamos a ver un pequeño ejemplo de entrada/salida en Java. El código siguiente, [Link], reproduce, o
funciona como la utilidad cat de Unix o type de DOS:

import [Link].*;
class miType {
public static void main( String args[] ) throws IOException {
int c;
int contador = 0;

while( (c = [Link]() ) != '\n' )


{
contador++;
[Link]( (char)c );
}
[Link](); // Línea en blanco
[Link]( "Contados "+ contador +" bytes en total." );
}
}

Clases comunes de Entrada/Salida

Además de la entrada por teclado y salida por pantalla, se necesita entrada/salida por fichero, como son:

FileInputStream
DataInputStream
FileOutputStream
DataOutputStream

También existen otras clases para aplicaciones más específicas, que no vamos a tratar, por ser de un uso muy
concreto:

PipedInputStream
BufferedInputStream
PushBackInputStream
StreamTokenizer
PipedOutputStream
BufferedOutputStream

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Ficheros
❍ Creación de un objeto File

❍ Comprobaciones y Utilidades

2. Streams de Entrada
❍ Objetos FileInputStream

1. Apertura de un FileInputStream
2. Lectura de un FileInputStream
3. Cierre de FileInputStream
4. Ejemplo: Visualización de un fichero
❍ Objetos DataInputStream

1. Apertura y cierre de DataInputStream


2. Lectura de un DataInputStream
❍ Streams de entrada de URLs

1. Apertura de un Stream de entrada


3. Streams de Salida
❍ Objetos FileOutputStream

1. Apertura de un FileOutputStream
2. Escritura en un FileOutputStream
3. Cierre de FileOutputStream
4. Ejemplo: Almacenamiento de Información
❍ Streams de salida con buffer

1. Creación de Streams de salida con buffer


2. Volcado y Cierre de Streams de salida con buffer
❍ Streams DataOutput

1. Apertura y cierre de objetos DataOutputStream


2. Escritura en un objeto DataOutputStream
3. Contabilidad de la salida
4. Ficheros de Acceso Aleatorio
❍ Creación de un Fichero de Acceso Aleatorio

❍ Acceso a la Información

❍ Actualización de Información

Todos los lenguajes de programación tienen alguna forma de interactuar con los sistemas de ficheros
locales; Java no es una excepción.
Cuando se desarrollan applets para utilizar en red, hay que tener en cuenta que la entrada/salida directa a
fichero es una violación de seguridad de acceso. Muchos usuarios configurarán sus navegadores para
permitir el acceso al sistema de ficheros, pero otros no.

Por otro lado, si se está desarrollando una aplicación Java para uso interno, probablemente será necesario
el acceso directo a ficheros.

Ficheros

Antes de realizar acciones sobre un fichero, necesitamos un poco de información sobre ese fichero. La
clase File proporciona muchas utilidades relacionadas con ficheros y con la obtención de información
básica sobre esos ficheros.

Creación de un objeto File

Para crear un objeto File nuevo, se puede utilizar cualquiera de los tres constructores siguientes:

File miFichero;
miFichero = new File( "/etc/kk" );

miFichero = new File( "/etc","kk" );

File miDirectorio = new File( "/etc" );


miFichero = new File( miDirectorio,"kk" );

El constructor utilizado depende a menudo de otros objetos File necesarios para el acceso. Por ejemplo, si
sólo se utiliza un fichero en la aplicación, el primer constructor es el mejor. Si en cambio, se utilizan
muchos ficheros desde un mismo directorio, el segundo o tercer constructor serán más cómodos. Y si el
directorio o el fichero es una variable, el segundo constructor será el más útil.

Comprobaciones y Utilidades

Una vez creado un objeto File, se puede utilizar uno de los siguientes métodos para reunir información
sobre el fichero:

● Nombres de fichero

String getName()
String getPath()
String getAbsolutePath()
String getParent()
boolean renameTo( File nuevoNombre )
● Comprobaciones

boolean exists()
boolean canWrite()
boolean canRead()
boolean isFile()
boolean isDirectory()
boolean isAbsolute()

● Información general del fichero

long lastModified()
long length()

● Utilidades de directorio

boolean mkdir()
String[] list()

Vamos a desarrollar una pequeña aplicación que muestra información sobre los ficheros pasados como
argumentos en la línea de comandos, [Link]:

import [Link].*;

class InfoFichero {

public static void main( String args[] ) throws IOException {


if( [Link] > 0 )
{
for( int i=0; i < [Link]; i++ )
{
File f = new File( args[i] );
[Link]( "Nombre: "+[Link]() );
[Link]( "Camino: "+[Link]() );
if( [Link]() )
{
[Link]( "Fichero existente " );
[Link]( ([Link]() ?
" y se puede Leer" : "" ) );
[Link]( ([Link]() ?
" y se puese Escribir" : "" ) );
[Link]( "." );
[Link]( "La longitud del fichero son "+
[Link]()+" bytes" );
}
else
[Link]( "El fichero no existe." );
}
}
else
[Link]( "Debe indicar un fichero." );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Comunicaciones en Unix
2. Sockets
❍ Sockets Stream

❍ Sockets Datagrama

❍ Sockets Raw

3. Diferencias entre Sockets Stream y Datagrama


4. Uso de Sockets
❍ Puertos y Servicios

❍ La clase URL

5. Dominios de Comunicaciones
❍ Dominio Unix

❍ Dominio Internet

6. Modelo de Comunicaciones con Java


❍ Apertura de Sockets

❍ Creación de Streams de Entrada

❍ Creación de Streams de Salida

❍ Cierre de Sockets

❍ Mínimo Cliente SMTP

❍ Servidor de Eco

❍ Mínimo Servidor TCP/IP

❍ Mínimo Cliente TCP/IP

❍ Servidor Simple de HTTP

❍ Red en Windows '95 (sin conexión)

1. Configuración del TCP/IP de Windows '95


2. Crear una entrada en la Red
3. Comprobación de la Red
4. Problemas más frecuentes
7. Clases Utiles en Comunicaciones

En este capítulo no nos vamos a extender demasiado en profundidades sobre la comunicación y


funcionamiento de redes, aunque sí proporcionaremos un breve baño inicial para sentar, o recordar, los
fundamentos de la comunicación en red, tomando como base Unix. Presentaremos un ejemplo básico de
cliente/servidor sobre sockets TCP/IP, proporcionando un punto de partida para el desarrollo de otras
aplicaciones cliente/servidor basadas en sockets, que posteriormente implementaremos.
Tutorial de Java [Anterior] [Indice] [Siguiente]
1. La Arquitectura MVC
❍ Definición de las partes

2. Observador y Observable
❍ Funciones de Observer y Observable

1. Observer
2. Observable
❍ Cómo utilizar Observer y Observable

1. Extender un Observable
2. Implementar un Observador
3. Usando Observador y Observable
3. Ejemplo de aplicación MVC

Vamos a presentar, por curiosidad más que por otra cosa, una introducción a la interface Observer y a la
clase Observable que proporciona Java. Vamos a implementar programas basados en la arquitectura
Modelo/Vista/Controlador, popularizada por el lenguaje Smalltalk.

Presentamos el problema: queremos diseñar un programa que visualice los datos de una escena en tres
dimensiones y lo pase a dos dimensiones. El programa debe ser modular y permitir vistas múltiples y
simultáneas de la misma escena. Cada vista debe ser capaz de presentar la escena desde diferentes puntos
de vista y distintas condiciones de iluminación. Y, más importante todavía, si alguna porción de una
escena cambia, las vistas deben actualizarse automáticamente. Otra versión del problema sería el de una
hoja de cálculo, en donde tenemos una serie de datos que queremos ver representados gráficamente, para
ello dispondremos de varias vistas con gráficos de línea, de barra o de tarta, y deben actualizarse
automáticamente según vayan cambiando los datos que figuran en la hoja de cálculo.

Ninguno de los requerimientos anteriores presenta una carga de programación imposible. Si el código que
controla cada uno de los requerimientos ha de ser escrito de nuevo, sin embargo, si que supondría un
esfuerzo significativo. Afortunadamente, el soporte para estas tareas ya esta proporcionado por la librería
de Java, a través del interface Observer y la clase Observable. Las funcionalidades de las dos se han
inspirado, en parte, en la arquitectura Modelo/Vista/Controlador.

Tutorial de Java [Anterior] [Indice] [Siguiente]


1. Etiqueta
2. Reloj Digital
3. Persiana
4. Solapas
5. Transparencia
6. Calculadora
7. Cuenta-Kilómetros
8. Potenciómetro
9. Cartel (de Luis Angel Ortega)

Los applets anteriores son simplemente ejemplos de lo que se puede conseguir con Java. Son un poco más
complicados que los desarrollados en el Tutorial, pero tampoco tan complicados como para que no se
pueda seguir adecuandamente el código fuente.

Se han desarrollado sobre Windows'95, por lo que no estoy seguro de que en otros sistemas se visualice
todo correctamente, sobre todo teniendo en cuenta que no todas las fuentes de caracteres están disponibles
siempre. Si se desea hacer un uso comercial de estos applets, habría que añdirles más detalles de
configuración y, sobre todo, capturar todas las excepciones posibles, porque lo que en un sitio va bien, en
otro puede generar una excepción.

Tutorial de Java [Anterior] [Indice] [Siguiente]


...Y esto ha sido todo, amigos!

Espero que todo el esfuerzo que hemos realizado para que este Tutorial de Java pudiese ver la luz haya
servido para que, al menos, alguien de los que se hayan atrevido a seguirlo dominen un poco más el
lenguaje que representa Java.

Nosotros (yo) sí que he aprendido mucho durante estos meses que me he pasado escribiendo y
desarrollando ejemplos. Me he encontrado con problemas, que quizás en un uso normal de Java no se
hubiesen presentado, sobre todo porque he utilizado tres plataformas diferentes para probar lo que hacía:
Solaris 2.5, Linux 1.3.20 y Windows '95. El escoger los volcados de Windows '95 para los ejemplos ha
sido porque todo el Tutorial se ha escrito en Word para Windows '95.

Agradecimientos

Mi agradecimiento a Juan Antonio Ruíz y Ramón M. Gómez ( bético hasta la médula), webmaster de este
site y para la Facultad de Informática de Sevilla, por haberme permitido utilizar su servidor para que todo
el mundo pueda conocer mi trabajo. Y por supuesto a mi familia, sin cuya comprensión no hubiese podido
llevar este proyecto a buen trérmino, porque les he robado gran cantidad del tiempo que debería estar con
ellos.

Copyrights

Este documento no tiene, en principio, copyright; aunque si se utiliza alguna información en él contenida,
agradecría que se citase la procedencia. Por supuesto, cualquier tipo de distribución del Tutorial está
absolutamente permitida, aunque también me gustaría conocerla. Las fuentes principales de las que he
recogido información para poder desarrollar este Tutorial de Java corresponden a documentación de Sun,
aunque también a otras:

● The Java Tutorial de Sun Microsystems


● Brewing Java: A Tutorial de Elliot Rusty Harold
● Revista Electrónica JavaWorld
● Gamelan, gran fuente de applets
● Revista Electrónica SunWorld Online
● Faq's de Java en DigitalFocus
● WWWiz, lista impresionante de libros sobre Java, Internet, etc.
● Java Programming Resources, de Marty Hall, infinidad de recursos sobre Java
El dibujo del grano de café con sombrero andaluz es una variación del logo de Cafés Catunambú, de
Sevilla (España)
HotJava(tm), Java(tm) y Duke son Marcas Registradas de Sun Microsystems
Microsoft es una marca registrada y el logo del Microsoft Internet Explorer es una marca registrada de
Microsoft

Tutorial de Java [Home] [Indice]


Agustín Froufe (froufe@[Link])
cap5

UN APPLET BASICO EN JAVA


Vamos a comenzar la creación del código fuente del un applet que satisfaga nuestras necesidades. Recordamos que
Java utiliza la extensión .java para designar los ficheros fuente.

HolaMundo

A continuación está el código fuente del applet HolaMundo, que es la versión applet de la mínima aplicación Java
que antes habíamos escrito. Guardar este código en un fichero fuente Java como [Link].

//
// Applet HolaMundo de ejemplo
//
import [Link];
import [Link];

public class HolaMundo extends Applet {


public void paint( Graphics g ) {
[Link]( "Hola Mundo!",25,25 ) ;
}
}

Componentes básicos de un Applet

El lenguaje Java implementa un modelo de Programación Orientada a Objetos. Los objetos sirven de bloques
centrales de construcción de los programas Java. De la misma forma que otros lenguajes de programación, Java tiene
variables de estado y métodos.

Veamos como se descompone un applet en sus piezas/objetos:

/*
Sección de importaciones
*/

public class NombreDelNuevoApplet extends Applet {


/*
Aquí se declaran las variables de estado (public y private)
*/

/*
Los métodos para la interacción con los objetos se
declaran y definen aquí
*/
public void MetodoUno( parámetros ) {
/*
Aquí viene para cada método, el código Java que
desempeña la tarea.
Qué código se use depende del applet
*/
}
}

Para HolaMundo, se importan las dos clases que necesita. No hay variables de estado, y sólo se tiene que definir un
método para que el applet tenga el comportamiento esperado.

Clases incluidas

El comando import carga otras clases dentro de nuestro código fuente. El importar una clase desde un paquete de
Java hace que esa clase importada esté disponible para todo el código incluido en el fichero fuente Java que la
importa. Por ejemplo, en el applet HolaMundo se importa la clase [Link], y podremos llamar a los
métodos de esta clase desde cualquier método de nuestro programa que se encuentre en el fichero [Link].
Esta clase define una área gráfica y métodos para poder dibujar dentro de ella. La función paint() declara a g como
un objeto de tipo Graphics; luego, paint() usa el método drawString() de la clase Graphics para generar su salida.

La clase Applet

Se puede crear una nueva clase, en este caso HolaMundo, extendiendo la clase básica de Java: Applet. De esta
forma, se hereda todo lo necesario para crear un applet. Modificando determinados métodos del applet, podemos
lograr que lleve a cabo las funciones que deseamos.

import [Link];
. . .
public class HolaMundo extends Applet {

Métodos de Applet

La parte del applet a modificar es el método paint(). En la clase Applet, se llama al método paint() cada vez que el
método arranca o necesita ser refrescado, pero no hace nada. En nuestro caso, lo que hacemos es:

public void paint( Graphics g ) {


[Link]( "Hola Mundo!",25,25 );
}

De acuerdo a las normas de sobrecarga, se ejecutará este último paint() y no el paint() vacío de la clase Applet.
Luego, aquí se ejecuta el método drawString(), que le dice al applet cómo debe aparecer un texto en el área de
dibujo.

Otros métodos básicos para dibujar son:

drawLine( int x1,int y1,int x2,int y2 )


drawRect( int x,int y,int ancho,int alto )
drawOval( int x,int y,int ancho,int alto )
Tanto para drawRect() como para drawOval(), las coordenadas (x,y) son la esquina superior izquierda del
rectángulo (para drawOval, el óvalo es encajado en el rectángulo que lo circunscribe).

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

COMPILACION DE UN APPLET
Ahora que tenemos el código de nuestro applet básico y el fichero fuente Java que lo contiene, necesitamos
compilarlo y obtener un fichero .class ejecutable. Se utiliza el compilador Java, javac, para realizar la tarea. El
comando de compilación será:

%javac [Link]

Eso es todo. El compilador javac generará un fichero [Link] que podrá ser llamado desde cualquier
navegador con soporte Java y, por tanto, capaz de ejecutar applets Java.

Llamada a Applets

¿Qué tienen de especial HotJava, Microsoft Explorer o Netscape con respecto a otros navegadores? Con ellos se
puede ver html básico y acceder a todo el texto, gráfico, sonido e hipertexto que se pueda ver con cualquier otro
navegador. Pero además, pueden ejecutar applets, que no es html estándar. Ambos navegadores entienden código
html que lleve la marca <APPLET>:

<APPLET CODE="[Link]" WIDTH=100 HEIGHT=50>


</APPLET>

Esta marca html llama al applet [Link] y establece su ancho y alto inicial. Cuando se acceda a la página
Web donde se encuentre incluida la marca, se ejecutará el byte-code contenido en [Link], obteniéndose el
resultado de la ejecución del applet en la ventana del navegador, con soporte Java, que estemos utilizando.

Prueba de un Applet

El JDK, Kit de Desarrollo de Java, incluye el visor de applets básico, appletviewer, que puede utilizarse para la
visualización rápida y prueba de nuestros applets, tal como se ha visto ya. La ejecución de un applet sobre
appletviewer se realiza a través de la llamada:

%appletviewer [Link]

En nuestro caso el fichero con el código html que ejecutará nuestro applet HolaMundo es [Link] que
generará la salida que se mostraba en la sección sobre el Ejemplo de uso de appletviewer.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

LA MARCA APPLET DE HTML


Dado que los applets están mayormente destinados a ejecutarse en navegadores Web, había que preparar el lenguaje
HTML para soportar Java, o mejor, los applets. El esquema de marcas de HTML, y la evolución del estándar
marcado por Netscape hicieron fácil la adición de una nueva marca que permitiera, una vez añadido el
correspondiente código gestor en los navegadores, la ejecución de programas Java en ellos.

La sintaxis de las etiquetas <APPLET> y <PARAM> es la que se muestra a continuación y que iremos explicando en
párrafos posteriores:

<APPLET CODE= WIDTH= HEIGTH= [CODEBASE=] [ALT=]


[NAME=] [ALIGN=] [VSPACE=] [HSPACE=]>
<PARAM NAME= VALUE= >
</APPLET>

Atributos obligatorios:

CODE : Nombre de la clase principal

WIDTH : Anchura inicial

HEIGHT : Altura inicial

Atributos opcionales:

CODEBASE : URL base del applet

ALT : Texto alternativo

NAME : Nombre de la instancia

ALIGN : Justificación del applet

VSPACE : Espaciado vertical

HSPACE : Espaciado horizontal

Los applets se incluyen en las páginas Web a través de la marca <APPLET>, que para quien conozca html resultará
muy similar a la marca <IMG>. Ambas necesitan la referencia a un fichero fuente que no forma parte de la página en
que se encuentran embebidos. IMG hace esto a través de SRC=parámetro y APPLET lo hace a través
CODE=parámetro. El parámetro de CODE indica al navegador dónde se encuentra el fichero con el código Java
compilado .class. Es una localización relativa al documento fuente.

Por razones que no entiendo muy bien, pero posiblemente relacionadas con los packages y classpaths, si un applet
reside en un directorio diferente del que contiene a la página en que se encuentra embebido, entonces no se indica un
URL a esta localización, sino que se apunta al directorio del fichero .class utilizando el parámetro CODEBASE,
aunque todavía se puede usar CODE para proporcionar el nombre del fichero .class.

Al igual que IMG, APPLET tiene una serie de parámetros que lo posicionan en la página. WIDTH y HEIGHT
especifican el tamaño del rectángulo que contendrá al applet, se indican en pixels. ALIGN funciona igual que con
IMG (en los navegadores que lo soportan), definiendo cómo se posiciona el rectángulo del applet con respecto a los
otros elementos de la página. Los valores posibles a especificar son: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE,
ABSMIDDLE, BASELINE, BOTTOM y ABSBOTTOM. Y, finalmente, lo mismo que con IMG, se puede
especificar un HSPACE y un VSPACE en pixels para indicar la cantidad de espacio vacío que habrá de separación
entre el applet y el texto que le rodea.

APPLET tiene una marca ALT. La utilizaría un navegador que entendiese la marca APPLET, pero que por alguna
razón, no pudiese ejecutarlo. Por ejemplo, si un applet necesita escribir en el disco duro de nuestro ordenador, pero
en las características de seguridad tenemos bloqueada esa posibilidad, entonces el navegador presentaría el texto
asociado a ALT.

ALT no es utilizado por los navegadores que no entienden la marca APPLET, por ello se ha definido la marca
</APPLET>, que finaliza la descripción del applet. Un navegador con soporte Java ignorará todo el texto que haya
entre las dos marcas <APPLET> y </APPLET>, sin embargo, un navegador que no soporte Java ignorará las marcas
y presentará el texto que se encuentre entre ellas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

ATRIBUTOS DE APPLET
Los atributos que acompañan a la etiqueta <APPLET>, algunos son obligatorios y otros son opcionales. Todos los
atributos, siguiendo la sintaxis de html, se especifican de la forma: atributo=valor. Los atributos obligatorios son:

CODE

Indica el fichero de clase ejecutable, que tiene la extensión .class. No se permite un URL absoluto,
como ya se ha dicho, aunque sí puede ser relativo al atributo opcional CODEBASE.

WIDTH

Indica la anchura inicial que el navegador debe reservar para el applet en pixels.

HEIGHT

Indica la altura inicial en pixels. Un applet que disponga de una geometría fija no se verá
redimensionado por estos atributos. Por ello, si los atributos definen una zona menor que la que el
applet utiliza, únicamente se verá parte del mismo, como si se visualiza a través de una ventana, eso sí,
sin ningún tipo de desplazamiento.

Los atributos opcionales que pueden acompañar a la marca APPLET comprenden los que se indican a continuación:

CODEBASE

Se emplea para utilizar el URL base del applet. En caso de no especificarse, se utilizará el mismo que
tiene el documento.

ALT

Como ya se ha dicho, funciona exactamente igual que el ALT de la marca <IMG>, es decir, muestra un
texto alternativo, en este caso al applet, en navegadores en modo texto o que entiendan la etiqueta
APPLET pero no implementen una máquina virtual Java.

NAME

Otorga un nombre simbólico a esta instancia del applet en la página que puede ser empleado por otros
applets de la misma página para localizarlo. Así, un applet puede ser cargado varias veces en la misma
página tomando un nombre simbólico distinto en cada momento.

ALIGN
Se emplea para alinear el applet permitiendo al texto fluir a su alrededor. Puede tomas los siguientes
valores: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM y
ABSBOTTOM.

VSPACE

Indica el espaciado vertical entre el applet y el texto, en pixels. Sólo funciona cuando se ha indicado
ALIGN = LEFT o RIGHT.

HSPACE

Funciona igual que el anterior pero indicando espaciamiento horizontal, en pixels. Sólo funciona
cuando se ha indicado ALIGN = LEFT o RIGHT.

Es probable encontrar en algunas distribuciones otras etiquetas para la inclusión de applets, como <APP>. Esto se
debe a que estamos ante la tercera revisión de la extensión de HTML para la incrustación de applets y ha sido
adoptada como la definitiva. Por ello, cualquier otro medio corresponde a implementaciones obsoletas que han
quedado descartadas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

PASO DE PARAMETROS A APPLETS


El espacio que queda entre las marcas de apertura y cierre de la definición de un applet, se utiliza para el paso de
parámetros al applet. Para ello se utiliza la marca PARAM en la página HTML para indicar los parámetros y el
método getParameter() de la clase [Link] para leerlos en el código interno del applet. La construcción
puede repetirse cuantas veces se quiera, una tras otra.

Los atributos que acompañan a la marca PARAM son los siguientes:

NAME

Nombre del parámetro que se desea pasar al applet.

VALUE

Valor que se desea transmitir en el parámetro que se ha indicado antes.

Texto HTML

Texto HTML que será interpretado por los navegadores que no entienden la marca APPLET en
sustitución del applet mismo.

Para mostar esta posibilidad vamos a modificar nuestro applet básico HolaMundo para que pueda saludar a
cualquiera. Lo que haremos será pasarle al applet el nombre de la persona a quien queremos saludar. Generamos el
código para ello y lo guardamos en el fichero [Link]

import [Link];
import [Link];

public class HolaTal extends Applet {


String nombre;

public void init() {


nombre = getParameter( "Nombre" );
}

public void paint( Graphics g ) {


[Link]( "Hola "+nombre+"!",25,25 );
}
}

Si compilamos el ejemplo obtendremos el fichero [Link] que incluiremos en nuestra página Web. Vamos a
generar el fichero [Link], en el que incluiremos nuestro applet, y que debería tener el siguiente contenido:
<HTML>
<APPLET CODE=[Link] WIDTH=300 HEIGHT=100>
<PARAM NAME="Nombre" VALUE="Agustin">
</APPLET>
</HTML>

Por supuesto, que puedes sustituir mi nombre por el tuyo. Este cambio no afectará al código Java, no será necesario
recompilarlo para que te salude a ti el applet.

Los parámetros no se limitan a uno solo. Se puede pasar al applet cualquier número de parámetros y siempre hay que
indicar un nombre y un valor para cada uno de ellos.

El método getParameter() es fácil de entender. El único argumento que necesita es el nombre del parámetro cuyo
valor queremos recuperar. Todos los parámetros se pasan como Strings, en caso de necesitar pasarle al applet un
valor entero, se ha de pasar como String, recuperarlo como tal y luego convertirlo al tipo que deseemos. Tanto el
argumento de NAME como el de VALUE deben ir colocados entre dobles comillas (") ya que son String.

El hecho de que las marcas <APPLET> y <PARAM> sean ignoradas por los navegadores que no entienden Java, es
inteligentemente aprovechado a la hora de definir un contenido alternativo a ser mostrado en este último caso. Así la
etiqueta es doble:

<APPLET atributos>
parámetros
contenido alternativo
</APPLET>

Nuestro fichero para mostrar el applet de ejemplo lo modificaremos para que pueda ser visualizado en cualquier
navegador y en unos casos presente la información alternativa y en otros, ejcute nuestro applet:

<HTML>
<APPLET CODE=[Link] WIDTH=300 HEIGHT=100>
<PARAM NAME="Nombre" VALUE="Agustin">
No verás lo bueno hasta que consigas un navegador
<I>Java Compatible</I>
</APPLET>
</HTML>

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

TOKENS EN PARAMETROS DE LLAMADA


Ya de forma un poco más avanzada vamos a ver como también se pueden pasar varios parámetros en la llamada
utilizando separadores, o lo que es lo mismo, separando mediante delimitadores los parámetros, es decir, tokenizando
la cadena que contiene el valor del parámetro, por ejemplo:

<PARAM NAME=Nombre VALUE="Agustin|Antonio">

En este caso el separador es la barra vertical "|", que delimita los dos tokens, pero también podemos redefinirlo y
utilizar cualquier otro símbolo como separador:

<PARAM NAME=Separador VALUE="#">


<PARAM NAME=Nombre VALUE="Agustin#Antonio">

Si ahora intentamos cambiar de color de fondo en que aparecen los textos en el applet, utilizando el mismo método,
podríamos tener:

<PARAM NAME=Nombre VALUE="Agustin|Antonio">


<PARAM NAME=Color VALUE="green|red">

Es más, podríamos hacer que parpadeasen los mensajes en diferentes colores, cambiando el color de fondo y el del
texto:

<PARAM NAME=Nombre1 VALUE="Agustin|green|yellow">


<PARAM NAME=Nombre2 VALUE="Antonio|red|white">

Para recoger los parámetros pasados en este último caso, bastaría con hacer un pequeño bucle de lectura de los
parámetros que deseamos:

for( int i=1; ; i++ )


p = getParameter( "Nombre"+i );
if( p == null )
break;
. . .
}

incluso podríamos utilizar un fichero para pasar parámetros al applet. La llamada sería del mismo tipo:

<PARAM NAME=Fichero VALUE="FicheroDatos">

y el FicheroDatos debería tener un contenido, en este caso, que sería el siguiente:


Agustin
fondoColor=green
textoColor=yellow
fuente=Courier
fuenteTam=14
Antonio
fondoColor=red
textocolor=white

E incluso ese FicheroDatos, podríamos hacer que se encontrase en cualquier URL, de forma que utilizando el
método getContent() podríamos recuperar el contenido del fichero que contiene los parámetros de funcionamiento
del applet:

String getContent( String url ) {


URL url = new URL( null,url );

return( (String).[Link]() );
}

Para recuperar los parámetros que están incluidos en la cadena que contiene el valor podemos utilizar dos métodos:

StringTokenizer( string,delimitadores )
treamTokenizer( streamentrada )

Así en la cadena Agustin|Antonio si utilizamos el método:

StringTokenizer( cadena,"|" );

obtenemos el token Agustin, el delimitador "|" y el token Antonio. El código del método sería el que se muestra a
continuación:

// Capturamos el parámetro
p = getParameter( "p" );

// Creamos el objeto StringTokenizer


st = new StringTokenizer( p,"|" );

// Creamos el almacenamiento
cads = new String[ [Link]() ];

// Separamos los tokens de la cadena del parámetro


for( i=0; i < [Link]; i++ )
cadenas[i] = [Link]();

En el caso de que utilicemos un fichero como verdadera entrada de parámetros al applet y el fichero se encuentre en
una dirección URL, utilizamos el método StreamTokenizer() para obtener los tokens que contiene ese fichero:

// Creamos el objeto URL para acceder a él


url = new URL( "[Link] );

// Creamos el canal de entrada


ce = [Link]();
// Creamos el objeto StreamTokenizer
st = new StreamTokenizer( ce );

// Capturamos los tokens


[Link]();

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

EL PARAMETRO ARCHIVE
Una de las cosas que se achacan a Java es la rapidez. El factor principal en la percepción que tiene el usuario de la
velocidad y valor de los applets es el tiempo que tardan en cargarse todas las clases que componen el applet. Algunas
veces tenemos que estar esperando más de un minuto para ver una triste animación, ni siquiera buena. Y,
desafortunadamente, esta percepción de utilidad negativa puede recaer también sobre applets que realmente sí son
útiles.

Para entender el porqué de la necesidad de un nuevo método de carga para acelerarla, necesitamos comprender
porqué el método actual es lento. Normalmente un applet se compone de varias clases, es decir, varios ficheros .class.
Por cada uno de estos ficheros .class, el cargador de clases debe abrir una conexión individual entre el navegador y el
servidor donde reside el applet. Así, si un applet se compone de 20 ficheros .class, el navegador necesitará abrir 20
sockets para transmitir cada uno de los ficheros. La sobrecarga que representa cada una de estas conexiones es
relativamente significante. Por ejemplo, cada conexión necesita un número de paquetes adicionales que incrementan
el tráfico en la Red.

Me imagino que ya el lector habrá pensado la solución al problema: poner todos los ficheros en uno solo, con lo cual
solamente sería necesaria una conexión para descargar todo el código del applet. Bien pensado. Esto es lo mismo que
han pensado los dos grandes competidores en el terreno de los navegadores, Netscape y Microsoft.

Desafortunadamente, las soluciones que han implementado ambas compañías no son directamente compatibles.
Microsoft, en su afán de marcar diferencia, crea su propio formato de ficheros CAB. La solución de Netscape es
utilizar el archiconocido formato ZIP. Por suerte, nosotros podemos escribir nuestro código HTML de forma que
maneje ambos formatos, en caso necesario. Esto es así porque podemos especificar cada uno de estos formatos de
ficheros especiales en extensiones separadas de la marca <APPLET>.

No vamos a contar la creación de ficheros CAB; quien esté interesado puede consultar la documentación de Java que
proporciona Microsoft con su SDK para Java. Una vez que disponemos de este fichero, podemos añadir un parámetro
CABBASE a la marca <APPLET>:

<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50 >


<PARAM NAME=CODEBASE VALUE="[Link]
<PARAM NAME=CABBASE VALUE="[Link]">
</APPLET>

El VALUE del parámetro CABBASE es el nombre del fichero CAB que contiene los ficheros .class que componen el
conjunto de applet.

Crear un archivo ZIP para utilizarlo con Netscape es muy fácil. Se deben agrupar todos los ficheros .class necesarios
en un solo fichero .zip. Lo único a tener en cuenta es que solamente hay que almacenar los ficheros .class en el
archivo; es decir, no hay que comprimir.

Si se está utilizando pkzip, se haría:


Pkzip -e0 [Link] listaFicherosClass

El parámetro de la línea de comandos es el número cero, no la "O" mayúscula.

Para utilizar un fichero .zip hay que indicarlo en la marca ARCHIVE de la sección <APPLET>:

<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50


CODEBASE VALUE="[Link]
ARCHIVE="[Link]">
</APPLET>

Pero hay más. Podemos crear ambos tipos de ficheros y hacer que tanto los usuarios de Netscape Navigator como los
de Microsoft Internet Explorer puedan realizar descargas rápidas del código del applet. No hay que tener en cuenta
los usuarios de otros navegadores, o de versiones antiguas de estos dos navegadores, porque ellos todavía podrán
seguir cargando los ficheros a través del método lento habitual. Para compatibilizarlo todo, ponemos las piezas
anteriores juntas:

<APPLET NAME="Hola" CODE="HolaMundo" WIDTH=50 HEIGHT=50


CODEBASE VALUE="[Link]
ARCHIVE="[Link]">
<PARAM NAME=CABBASE VALUE="[Link]">
<PARAM NAME=CODEBASE VALUE="[Link]
<PARAM NAME=CABBASE VALUE="[Link]">
</APPLET>

Ahora que se puede hacer esto con ficheros .cab y .zip, JavaSoft ha definido un nuevo formato de ficheros, que
incorporará en del JDK 1.1, para incluir juntos todos los ficheros de imágenes, sonido y class. JavaSoft llama a esto
formato JAR (Java Archive). La marca <APPLET> de HTML se modificará para manejar este nuevo formato JAR a
través del parámetro ARCHIVES. Y dejamos al lector el trabajo de poner los tres formatos juntos bajo el mismo
paraguas de la marca <APPLET>.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

DEPURACION GENERAL
Compilar y ejecutar el programa [Link] a través del fichero [Link] no debería suponer ningún
problema, pero alguna vez nos encontraremos frente a programas más difíciles y se necesitará el truco de depuración
al que se recurre en el desarrollo de programas en cualquier lenguaje.

[Link]

Una de las herramientas de depuración más efectivas en cualquier lenguaje de programación es simplemente la salida
de información por pantalla. El comando [Link] imprime la cadena que se le especifique en la ventana de
texto en la que se invocó al navegador. La forma de usarlo se muestra a continuación:

public void paint( Graphics g ) {


[Link]( "Hola Mundo!",25,25 );
[Link]( "Estamos en paint()" );
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

CICLO DE VIDA DE UN APPLET


Para seguir el ciclo de vida de un applet, supondremos que estamos ejecutando en nuestro navegador el applet básico
HolaMundo, a través de la página HTML que lo carga y corre.

Lo primero que aparece son los mensajes "initializing... starting...", como resultado de la carga del applet en el
navegador. Una vez cargado, lo que sucede es:

Se crea una instancia de la clase que controla al applet


El applet se inicializa a si mismo
Comienza la ejecución del applet

Cuando se abandona la página, por ejemplo, para ir a la siguiente, el applet detiene la ejecución. Cuando se regresa a
la página que contiene el applet, se reanuda la ejecución.

Si se utiliza la opción del navegador de Reload, es decir, volver a cargar la página, el applet es descargado y vuelto a
cargar. El applet libera todos los recursos que hubiese acaparado, detiene su ejecución y ejecuta su finalizador para
realizar un proceso de limpieza final de sus trazas. Después de esto, el applet se descarga de la memoria y vuelve a
cargarse volviendo a comenzar su inicialización.

Finalmente, cuando se concluye la ejecución del navegador, o de la aplicación que está visualizando el applet, se
detiene la ejecución del applet y se libera toda la memoria y recursos ocupados por el applet antes de salir del
navegador.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

PROTECCION DE APPLETS
Como curiosidad, más que como algo verdaderamente útil, podemos proteger nuestros applets de forma muy sencilla,
o por lo menos evitar que nadie pueda ocultar en sus páginas HTML que nosotros somos los legales autores de un
applet.

El método es muy sencillo y se basa en la utilización de un parámetro del cual comprobamos su existencia, por
ejemplo:

<PARAM NAME=copyright
VALUE="Applet de Prueba, [Link] (C)1996,
Todos los derechos reservados">

y en el código Java de nuestro applet, comprobaríamos que efectivamente el parámetro copyright existe y ese es su
contenido:

if( !getParameter( "copyright").equals( "..." )


throw( new Exception( "Violacion del Copyright" ) );

donde "..." es el texto completo del valor del parámetro. Pero también podemos hacerlo de forma más elegante:

copyright = getParameter( "copyright" );


// [Link]( [Link]() );

if( copyright != -913936799 )


throw( new Exception( "Violacion del Copyright" ) );

en donde la sentencia comentada nos proporciona el valor del copyright para poder introducirlo en la comparación de
la presencia o no del parámetro en la llamada al applet. Habría que declarar y definir correctamente tipos y variables,
pero la idea básica es la que expuesta.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

ESCRIBIR APPLETS JAVA


Para escribir applets Java, hay que utilizar una serie de métodos, algunos de los cuales ya se hay sumariado al hablar
de los métodos del appletviewer, que es el visualizador de applets de Sun. Incluso para el applet más sencillo
necesitaremos varios métodos. Son los que se usan para arrancar (start) y detener (stop) la ejecución del applet, para
pintar (paint) y actualizar (update) la pantalla y para capturar la información que se pasa al applet desde el fichero
HTML a través de la marca APPLET.

init()

Esta función miembro es llamada al crearse el applet. Es llamada sólo una vez. La clase Applet no hace nada en
init(). Las clases derivadas deben sobrecargar este método para cambiar el tamaño durante su inicialización, y
cualquier otra inicialización de los datos que solamente deba realizarse una vez. Deberían realizarse al menos las
siguientes acciones:

● Carga de imágenes y sonido


● El resize del applet para que tenga su tamaño correcto
● Asignación de valores a las variables globales

Por ejemplo:

public void init() {


if( width < 200 || height < 200 )
resize( 200,200 );
valor_global1 = 0;
valor_global2 = 100;

// cargaremos imágenes en memoria sin mostrarlas


// cargaremos música de fondo en memoria sin reproducirla
}

destroy()

Esta función miembro es llamada cuando el applet no se va a usar más. La clase Applet no hace nada en este método.
Las clases derivadas deberían sobrecargarlo para hacer una limpieza final. Los applet multithread deberán usar
destroy() para "matar" cuanquier thread del applet que quedase activo.

start()

Llamada para activar el applet. Esta función miembro es llamada cuando se visita el applet. La clase Applet no hace
nada en este método. Las clases derivadas deberían sobrecargarlo para comenzar una animación, sonido, etc.
public void start() {
estaDetenido = false;

// comenzar la reproducción de la música


[Link]();
}

También se puede utilizar start() para eliminar cualquier thread que se necesite.

stop()

Llamada para detener el applet. Se llama cuando el applet desaparece de la pantalla. La clase Applet no hace nada en
este método. Las clases derivadas deberían sobrecargarlo para detener la animación, el sonido, etc.

public void stop() {


estaDetenido = true;

if( /* ¿se está reproduciendo música? */ )


[Link]();
}

resize( int width,int height )

El método init() debería llamar a esta función miembro para establecer el tamaño del applet. Puede utilizar las
variables ancho y alto, pero no es necesario. Cambiar el tamaño en otro sitio que no sea init() produce un reformateo
de todo el documento y no se recomienda.

En el navegador Netscape, el tamaño del applet es el que se indica en la marca APPLET del HTML, no hace caso a
lo que se indique desde el código Java del applet.

width

Variable entera, su valor es el ancho definido en el parámetro WIDTH de la marca HTML del APPLET. Por defecto
es el ancho del icono.

height

Variable entera, su valor es la altura definida en el parámetro HEIGHT de la marca HTML del APPLET. Por defecto
es la altura del icono. Tanto width como height están siempre disponibles para que se puede chequear el tamaño
del applet.

Podemos retomar el ejemplo de init():

public void init() {


if( width < 200 || height < 200 )
resize( 200,200 );
...

paint( Graphics g )
Se llama cada vez que se necesita refrescar el área de dibujo del applet. La clase Applet simplemente dibuja una caja
con sombreado de tres dimensiones en el área. Obviamente, la clase derivada debería sobrecargar este método para
representar algo inteligente en la pantalla.

Para repintar toda la pantalla cuando llega un evento Paint, se pide el rectángulo sobre el que se va a aplicar paint() y
si es más pequeño que el tamaño real del applet se invoca a repaint(), que como va a hacer un update(), se actualizará
toda la pantalla.

Podemos utilizar paint() para imprimir nuestro mensaje de bienvenida:

void public paint( Graphics g ) {


[Link]( "Hola Java!",25,25 );
// Dibujaremos la imágenes que necesitemos
}

update( Graphics g )

Esta es la función que se llama realmente cuando se necesita actualizar la pantalla. La clase Applet simplemente
limpia el área y llama al método paint(). Esta funcionalidad es suficiente en la mayoría de los casos. De cualquier
forma, las clases derivadas pueden sustituir esta funcionalidad para sus propósitos.

Podemos, por ejemplo, utilizar update() para modificar selectivamente partes del área gráfica sin tener que pintar el
área completa:

public void update( Graphics g ) {


if( estaActualizado )
{
[Link](); // garantiza la pantalla limpia
repaint(); // podemos usar el método padre: [Link]()
}
else
// Información adicional
[Link]( "Otra información",25,50 );
}

repaint()

A esta función se la debería llamar cuando el applet necesite ser repintado. No debería sobrecargarse, sino dejar que
Java repinte completamente el contenido del applet.

Al llamar a repaint(), sin parámetros, internamente se llama a update() que borrará el rectángulo sobre el que se
redibujará y luego se llama a paint(). Como a repaint() se le pueden pasar parámetros, se puede modificar el
rectángulo a repintar.

getParameter( String attr )

Este método carga los valores parados al applet vía la marca APPLET de HTML. El argumento String es el nombre
del parámetro que se quiere obtener. Devuelve el valor que se le haya asignado al parámetro; en caso de que no se le
haya asignado ninguno, devolverá null.

Para usar getParameter(), se define una cadena genérica. Una vez que se ha capturado el parámetro, se utilizan
métodos de cadena o de números para convertir el valor obtenido al tipo adecuado.

public void init() {


String pv;

pv = getParameter( "velocidad" );
if( pv == null )
velocidad = 10;
else
velocidad = [Link]( pv );
}

getDocumentBase()

Indica la ruta http, o el directorio del disco, de donde se ha recogido la página HTML que contiene el applet, es decir,
el lugar donde está la hoja en todo Internet o en el disco.

getCodeBase()

Indica la ruta http, o el directorio del disco, de donde se ha cargado el código bytecode que forma el applet, es decir,
el lugar donde está el fichero .class en todo Internet o en el disco.

print( Graphics g )

Para imprimir en impresora, al igual que paint() se puede utilizar print(), que pintará en la impresora el mapa de bits
del dibujo.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

LA APLICACION FECHA (Aproximación a OOP)


Veamos ahora una aplicación un poco más útil que HolaMundo, presentaremos en pantalla la fecha y hora del
sistema. Aprovecharemos también para realizar un introducción muy sencilla a los conceptos fundamentales de la
programación orientada a objetos, clases y objetos, a través de esta simple aplicación.

import [Link];

class FechaApp {
public static void main( String args[] ) {
Date hoy = new Date();
[Link]( hoy );
}
}

Esta aplicación es una versión modificada de HolaMundoApp de la que difiere porque se importa la clase Date, la
aplicación se llama ahora FechaApp en vez de HolaMundoApp, se crea un objeto Date y el mensaje de salida a
pantalla es diferente. Almacenaremos esta nueva aplicación en el fichero [Link].

La línea de código:

class FechaApp {

es el inicio del bloque de la declaración de nuestra clase. Ya hemos dicho que todas las funciones y variables en Java,
existen dentro de una clase o un objeto, Java no soporta funciones o variables globales. Por tanto, la declaración de la
clase se convierte en el esqueleto de cualquier aplicación Java. La clase, el bloque básico de un lenguaje orientado a
objetos como Java, es la plantilla que usamos para describir los datos y el entorno asociado a las instancias de esa
clase. Cuando se instancia una clase, se crea un objeto del tipo definido por la clase y exactamente igual que
cualquier otra instancia realizada de la misma clase. Los datos asociados a la clase u objeto son las variables y el
entorno asociado con la clase u objeto son los métodos.

Un ejemplo de clase es la clase que representa un rectángulo. Esta clase contiene las variables que indican las
coordenadas del origen del rectángulo y su ancho y alto. La clase puede contener un método para calcular el área de
ese rectángulo. Ahora podemos instanciarlo para muy diferentes propósitos, es decir, podemos tener objetos
rectángulo específicos, así podremos obtener información de las dimensiones de nuestro dormitorio o de las
dimensiones de la ventana en donde se está visualizando esta página.

class NombreDeLaClase {
. . .
}

Esta es la forma general de definición de una clase en Java, donde la palabra clave class inicia la definición de la
clase NombreDeLaClase. Las variables y métodos de la clase han de ir colocados entre las llaves que delimitan el
bloque de definición de la clase. FechaApp no tiene variables y solamente tiene un método llamado main().

Este método, main(), es el cerebro de cualquier aplicación Java. Cuando se ejecuta una aplicación Java utilizando el
intérprete Java, se debe especificar el nombre de la clase que se desea ejecutar. El intérprete entonces, invoca al
método main() definido dentro de esa clase, que debe controlar el flujo del programa, pedir al sistema los recursos
que necesite y ejecutar cualquier otro método necesario para completar la funcionalidad de la aplicación.

La definición del método main() debe estar precedida por tres modificadores:

● public indica que el método main() puede ser llamado por cualquier objeto
● static indica que el método main() es un método estático, es decir, un método propio de la clase
● void indica que el método main() no devolverá ningún valor

El método main() en Java es similar a la función main() de C y C++. Cuando se ejecuta un programa escrito en C o
C++, arranca llamando en primer lugar a la función main(), que llamará a las demás funciones necesarias en la
ejecución del programa. De forma similar, en el lenguaje Java, cuando se ejecuta una clase con el intérprete Java, el
sistema comienza llamando al método main() de la clase, que llamará a los demás métodos necesarios para completar
la ejecución de la aplicación. Si se intenta ejecutar una clase con el intérprete Java que no contenga el método main(),
el intérprete generará un mensaje de error.

El método main() acepta como argumento un array de Strings:

public static void main( Strings args[] ) {

Este array de Strings es el mecanismo a través del cual el sistema puede pasar información a la aplicación. Cada una
de las cadenas String es un argumento de línea de comandos. Permiten pasar información a la aplicación, para variar
su ejecución, sin necesidad de recompilarla. Por ejemplo, si desarrollamos una aplicación de ordenación, podríamos
permitir al usuario seleccionar el método, ascendente o descendente, en la línea de comandos de ejecución de la
aplicación.

-descendente

Nuestra aplicación FechaApp ignora los argumentos de la línea de comandos, así que no nos extendemos más, pero
volveremos sobre ello más adelante. No obstante, los programadores de C y C++ deben tener en cuenta que en Java
el número y tipo de argumentos de la línea de comandos es diferente a los que se pasan a la función main() en C y
C++.

La aplicación FechaApp es el programa más simple que podemos hacer que realice algo interesante, pero por su
misma sencillez no necesita ninguna clase adicional. Sin embargo, la mayoría de los programas que escribamos serán
más complejos y necesitarán que escribamos otras clases y utilizar las que nos proporciona Java como soporte.

Nuestra aplicación FechaApp utiliza dos clases, la clase System y la clase Date, que nos proporciona el entorno de
desarrollo de Java. La clase System proporciona un acceso al sistema independiente del hardware sobre el que
estemos ejecutando la aplicación y la clase Date proporciona un acceso a las funciones de Fecha independientemente
del sistema en que estemos ejecutando la aplicación.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

LA APLICACION FECHA (continuación)


Date hoy = new Date();

Esta primera línea del método main() declara, instancia e inicializa un objeto de tipo Date, hoy. Date hoy indica
al compilador que la palabra hoy será utilizada en adelante para referirse a un objeto cuyo tipo es Date, el operador
new instancia un nuevo objeto Date y Date() inicializa el objeto. El constructor utilizado para inicializar al objeto
hoy es el constructor por defecto que inicializa a los objetos de tipo Date, que los carga con la fecha y hora actual del
sistema.

Las declaraciones pueden aparecer como parte de la creación del objeto como en este caso, o pueden también
aparecer solas:

Date hoy;

De cualquier modo, la declaración de un objeto siempre será de la forma:

tipo nombre

Donde tipo puede ser un tipo de dato simple como int, float o boolean, o un tipo de datos más complejo como en este
caso la clase Date. nombre es la palabra que se utilizará para reconocer la variable. Las declaraciones simplemente
informan al compilador de que se usará la palabra nombre para referirse a una variable del tipo tipo. Las
declaraciones no realizan la instanciación del objeto, para instanciar un objeto de tipo Date, o cualquier otro objeto,
es necesario utilizar el operador new.

El operador new instancia un nuevo objeto reservando memoria para él. Requiere un solo argumento: el método
constructor para el objeto que se creará. Es este método constructor el responsable de la inicialización del nuevo
objeto.

Las clases deben proporcionar métodos para inicializar nuevos objetos de ese tipo. En una declaración de clase, los
constructores se pueden distinguir del resto de métodos porque tienen el mismo nombre de la clase y no devuelven
ningún valor. Por ejemplo, el método constructor de objetos Date que usamos en FechaApp es:

Date()

que no tiene ningún argumento, por lo cual recibe el nombre de contructor por defecto. Al igual que Date, la mayoría
de las clases tienen al menos un constructor, el constructor por defecto; sin embargo, las clases pueden tener
múltiples constructores, todos ellos con el mismo nombre de la clase y distinto número y tipo de argumentos. Por
ejemplo, la clase Date soporta un constructor que necesita tres parámetros de entrada:

Date( int año,int mes,int dia )


que inicializa el nuevo objeto Date con el año, mes y día que se especifican en esos tres parámetros.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

FUNCIONES DE MENU DE APPLETVIEWER


El appletviewer tiene un único menú mostrado en la imagen siguiente y que vamos a explicar en cada una de sus
opciones, ya que lo usaremos a menudo cuando vayamos avanzando en nuestros conocimientos de Java.

● Restart

La función Restart llama al método stop() y seguidamente llama de nuevo a start(), que es el método
que ha lanzado inicialmente la ejecución del applet. Se puede utilizar Restart para simular el
movimiento entre páginas en un documento html.

● Reload

La función Reload llama al método stop() y luego al método destroy() en el applet actual. A
continuación carga una nueva copia del applet y la arranca llamando al método start().

● Clone

La función Clone crea una copia del applet actual en una ventana de appletviewer nueva. En realidad
es un appletviewer idéntico con el mismo URL.

● Tag

La función Tag muestra en una ventana hija del appletviewer el código html cargado para su ejecución.
Es similar a la función View Source que figura en la mayoría de los navegadores, Netscape, Internet
Explorer y HotJava incluidos.

● Info
La función Info lee los comentarios de documentación contenidos en el fichero html y muestra la
información de los parámetros (si la hay).

● Properties

El appletviewer tiene las funciones básicas de presentación de un navegador y la función Properties


(propiedades de la red) permite cambiar o establecer el modo de seguridad o fijar los servidores de
proxy o firewall.

● Close

La función Close llama al método destroy() de la ventana actual del appletviewer, teminando su
ejecución.

● Quit

La función Quit llama al método destroy() de cada una de las copias del appletviewer que se
encuentren lanzadas, concluyendo la ejecución de todas ellas y terminando entonces el appletviewer.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

METODOS DE APPLETVIEWER
Vamos a utilizar como excusa la función asociada al appletviewer de los siguientes métodos para adentrarnos en su
presentación, aunque a lo largo de secciones posteriores, volveremos a referirnos a ellos, porque también son los
métodos propios de la clase Applet.

init()

El método init() se llama cada vez que el appletviewer carga por primera vez la clase. Si el applet
llamado no lo sobrecarga, init() no hace nada. Fundamentalmente en este método se debe fijar el
tamaño del applet, aunque en el caso de Netscape el tamaño que vale es el que se indique en la línea
del fichero html que cargue el applet. También se deben realizar en este método las cargas de imágenes
y sonidos necesarios para la ejecución del applet. Y, por supuesto, la asignación de valores a las
variables globales a la clase que se utilicen. En el caso de los applet, este método únicamente es
llamado por el sistema al cargar el applet.

start()

start() es la llamada para arrancar el applet cada vez que es visitado. La clase Applet no hace nada en
este método. Las clases derivadas deben sobrecargarlo para comenzar la animación, el sonido, etc. Esta
función es llamada automáticamente cada vez que la zona de visualización en que está ubicado el
applet se expone a la visión, a fin de optimizar en uso de los recursos del sistema y no ejecutar algo
que no puede ser apreciado (aunque el programador puede variar este comportamiento y hacer que un
applet siga activo aun cuando esté fuera del área de visión). Esto es, imaginemos que cargamos un
applet en un navegador minimizado; el sistema llamará al método init(), pero no a start(), que sí será
llamado cuando restauremos el navegador a un tamaño que permita ver el applet. Naturalmente, start()
se puede ejecutar varias veces: la primera tras init() y las siguientes (porque init() se ejecuta solamente
una vez) tras haber aplicado el método stop().

stop()

stop() es la llamada para detener la ejecución del applet. Se llama cuando el applet desaparece de la
pantalla. La clase Applet tampoco hace nada en este método, que debería ser sobrecargado por las
clases derivadas para detener la animación, el sonido, etc. Esta función es llamada cuando el navegador
no incluye en su campo de visión al applet; por ejemplo, cuando abandona la página en que está
insertado, de forma que el programador puede paralizar los threads que no resulten necesarios respecto
de un applet no visible, y luego recuperar su actividad mediante el método start().

destroy()

El método destroy() se llama cuando ya no se va a utilizar más el applet, cuando se necesita que sean
liberados todos los recursos dispuestos por el applet, por ejemplo, cuando se cierra el navegador. La
clase Applet no hace nada en este método. Las clases derivadas deberían sobrecargarlo para hacer una
limpieza final. Los applet multithread deberían utilizar destroy() para detener los threads que quedasen
activos.

El appletviewer también contiene la clase Component (componente), que usa dos métodos para
ayudas al applet a escribir en el espacio gráfico que el appletviewer le proporciona para su ejecución.

paint( Graphics g )

Es la función llamada cada vez que el área de dibujo del applet necesita ser refrescada. La clase Applet
simplemente dibuja un rectángulo gris en el área, es la clase derivada, obviamente, la que debería
sobrecargar este método para representar algo inteligente en la pantalla. Cada vez que la zona del
applet es cubierta por otra ventana, se desplaza el applet fuera de la visión o el applet cambia de
posición debido a un redimensionamiento del navegador, el sistema llama automáticamente a este
método, pasando como argumento un objeto de tipo Graphics que delimita la zona a ser pintada; en
realidad se pasa una referencia al contexto gráfico en uso, y que representa la ventana del applet en la
página web.

update( Graphics g )

Esta es la función que realmente se llama cuando se necesita una actualización de la pantalla. La clase
Applet simplemente limpia el área y llama al método paint(). Esta funcionalidad es suficiente para la
mayoría de los casos; aunque, de cualquier forma, las clases derivadas pueden sustituir esta
funcionalidad para sus propósitos especiales. Es decir, en las situaciones detalladas anteriormente que
dañan la zona de exposición del applet, el sistema llama al método paint(), pero en realidad la llamada
se realiza al método update(), cuyo comportamiento establecido en la clase Component es llamar al
método paint(), tras haber rellenado la zona del applet con su color de fondo por defecto. Pudiera
parecer así que se trata de un método de efecto neutro, pero si la función paint() cambiara el color del
fondo, podríamos percibir un flick de cambio de colores nada agradable. Por tanto, habrá que cuidarse
por lo común, de eliminar este efecto de limpia primero, sobrecargando el método update(), para que
llame únicamente a paint(). Otra solución sería insertar el código de pintado en una sobrecarga del
método update() y escribir un método paint() que sólo llame a update(). La última solución pasaría por
usar el mismo método setBackground( Color ), en el método init() para así evitar el efecto
visual sin tener que sobrecargar el método update(). Estas son las mismas razones que aconsejan usar
el método resize() inserto en init(), para evitar el mismo desagradable efecto.

repaint

Llamando a este método se podrá forzar la actualización de un applet, la llamada a update(). Pero hay
que tener cierto cuidado, porque AWT posee cierta inteligencia (combinación casi siempre nefasta), de
forma que si se llama a update() mediante repaint() con una frecuencia muy corta, AWT ignorará las
llamadas a update() que estime oportuno, pues considera a esta función como un bien escaso.

Sinopsis

La llamada a appletviewer es de la forma:

appletviewer [-debug] urls...

El appletviewer toma como parámetro de ejecución, o bien el nombre del un fichero html conteniendo el tag (marca)
<APPLET>, o bien un URL hacia un fichero HTML que contenga esa marca.
Si el fichero html no contiene un tag <APPLET> válido, el appletviewer no hará nada. El appletviewer no muestra
otras marcas html.

La única opción válida que admite la llamada a appletviewer es -debug, que arranca el applet en el depurador de
Java, jdb. Para poder ver el código fuente en el depurador, se tiene que compilar el fichero .java con la opción -g.

Ejemplo de uso

En el ejemplo de llamada al appletviewer siguiente, hacemos que se ejecute el applet básico que crearemos en la
sección siguiente y que lanzaremos desde un fichero html del mismo nombre que nuestro fichero de código fuente
Java.

%appletviewer [Link]

Esta llamada lanzaría la ejecución de [Link] en el appletviewer, abriéndose en pantalla la ventana


siguiente:

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

ARQUITECTURA DE APPLETVIEWER
El appletviewer representa el mínimo interfaz de navegación. En la figura se muestran los pasos que seguiría
appletviewer para presentarnos el resultado de la ejecución del código de nuestra clase.

Esta es una visión simplificada del appletviewer. La función principal de esta aplicación es proporcionar al usuario
un objeto de tipo Graphics sobre el que dibujar, y varias funciones para facilitar el uso del objeto Graphics.

Ciclo de vida de un Applet

Cuando un applet se carga en el appletviewer, comienza su ciclo de vida, que pasaría por las siguientes fases:

● Se crea una instancia de la clase que controla el applet. En el ejemplo de la figura anterior, sería la clase
HolaMundo.

● El applet se incializa.

● El applet comienza a ejecutarse.

● El applet empieza a recibir llamadas. Primero recibe una llamada init (inicializar), seguida de un mensaje start
(empezar) y paint (pintar). Estas llamadas pueden ser recibidas asíncronamente.
Tutorial de Java [Anterior] [Indice] [Siguiente]
cap5

EL VISOR DE APPLETS DE SUN (appletviewer)


El visualizador de applets (appletviewer) es una aplicación que permite ver en funcionamiento applets, sin necesidad
de la utilización de un navegador World-Wide-Web como HotJava, Microsoft Explorer o Nescape. En adelante,
recurriremos muchas veces a él, ya que el objetivo del tutorial es el lenguaje Java.

Applet

La definición más extendida de applet, muy bien resumida por Patrick Naughton, indica que un applet es "una
pequeña aplicación accesible en un servidor Internet, que se transporta por la red, se instala automáticamente y se
ejecuta in situ como parte de un documento web". Claro que así la definición establece el entorno (Internet, Web,
etc.). En realidad, un applet es una aplicación pretendidamente corta (nada impide que ocupe más de un gigabyte, a
no ser el pensamiento de que se va a transportar por la red y una mente sensata) basada en un formato gráfico sin
representación independiente: es decir, se trata de un elemento a embeber en otras aplicaciones; es un componente en
su sentido estricto.

Un ejemplo en otro ámbito de cosas podría ser el siguiente: Imaginemos una empresa, que cansada de empezar
siempre a codificar desde cero, diseña un formulario con los datos básicos de una persona (nombre, dirección, etc.).
Tal formulario no es un diálogo por sí mismo, pero se podría integrar en diálogos de clientes, proveedores,
empleados, etc. El hecho de que se integre estática (embebido en un ejecutable) o dinámicamente (intérpretes, DLLs,
etc.) no afecta en absoluto a la esencia de su comportamiento como componente con que construir diálogos con
sentido autónomo.

Pues bien, así es un applet. Lo que ocurre es que, dado que no existe una base adecuada para soportar aplicaciones
industriales Java en las que insertar nuestras miniaplicaciones (aunque todo se andará), los applets se han construido
mayoritariamente, y con gran acierto comercial (parece), como pequeñas aplicaciones interactivas, con movimiento,
luces y sonido... en Internet.

Llamadas a Applets con appletviewer

Un applet es una mínima aplicación Java diseñada para ejecutarse en un navegador Web. Por tanto, no necesita
preocuparse por un método main() ni en dónde se realizan las llamadas. El applet asume que el código se está
ejecutando desde dentro de un navegador. El appletviewer se asemeja al mínimo navegador. Espera como argumento
el nombre del fichero html que debe cargar, no se le puede pasar directamente un programa Java. Este fichero html
debe contener una marca que especifica el código que cargará el appletviewer:

<HTML>
<APPLET CODE=[Link] WIDTH=300 HEIGHT=100>
</APPLET>
</HTML>

El appletviewer crear un espacio de navegación, incluyendo un área gráfica, donde se ejecutará el applet, entonces
llamará a la clase applet apropiada. En el ejemplo anterior, el appletviewer cargará una clase de nombre HolaMundo
y le permitirá trabajar en su espacio gráfico.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

COMPILACION Y EJECUCION DE HolaMundo


Vamos a ver a continuación como podemos ver el resultado de nuestra primera aplicación Java en pantalla.
Generaremos un fichero con el código fuente de la aplicación, lo compilaremos y utilizaremos el intérprete java para
ejecutarlo.

Ficheros Fuente Java

Los ficheros fuente en Java terminan con la extensión ".java". Crear un fichero utilizando cualquier editor de texto
ascii que tenga como contenido el código de las ocho líneas de nuestra mínima aplicación, y salvarlo en un fichero
con el nombre de [Link]. Para crear los ficheros con código fuente Java no es necesario un procesador
de textos, aunque puede utilizarse siempre que tenga salida a fichero de texto plano o ascii, sino que es suficiente con
cualquier otro editor.

Compilación

El compilador javac se encuentra en el directorio bin por debajo del directorio java, donde se haya instalado el JDK.
Este directorio bin, si se han seguido las instrucciones de instalación, debería formar parte de la variable de entorno
PATH del sistema. Si no es así, tendría que revisar la Instalación del JDK. El compilador de Java traslada el código
fuente Java a byte-codes, que son los componentes que entiende la Máquina Virtual Java que está incluida en los
navegadores con soporte Java y en appletviewer.

Una vez creado el fichero fuente [Link], se puede compilar con la línea siguiente:

%javac [Link]

Si no se han cometido errores al teclear ni se han tenido problemas con el path al fichero fuente ni al compilador, no
debería aparecer mensaje alguno en la pantalla, y cuando vuelva a aparecer el prompt del sistema, se debería ver un
fichero [Link] nuevo en el directorio donde se encuentra el fichero fuente.

Si ha habido algún problema, en Problemas de compilación al final de esta sección, hemos intentado reproducir los
que más frecuentemente se suelen dar, se pueden consultar por si pueden aportar un poco de luz al error que haya
aparecido.

Ejecución

Para ejecutar la aplicación HolaMundoApp, hemos de recurrir al intérprete java, que también se encuentra en el
directorio bin, bajo el directorio java. Se ejecutará la aplicación con la línea:

%java HolaMundoApp
y debería aparecer en pantalla la respuesta de Java:

%Hola Mundo!

El símbolo % representa al prompt del sistema, y lo utilizaremos para presentar las respuestas que nos ofrezca el
sistema como resultado de la ejecución de los comandos que se indiquen en pantalla o para indicar las líneas de
comandos a introducir.

Problemas de compilación

A continuación presentamos una lista de los errores más frecuentes que se presentan a la hora de compilar un fichero
con código fuente Java, nos basaremos en errores provocados sobre nuestra mínima aplicación Java de la sección
anterior, pero podría generalizarse sin demasiados problemas.

%javac: Command not found

No se ha establecido correctamente la variable PATH del sistema para el compilador javac. El


compilador javac se encuentra en el directorio bin, que cuelga del directorio java, que cuelga del
directorio donde se haya instalado el JDK (Java Development Kit).

%[Link]: Method printl([Link]) not found in class


[Link].
[Link]( "HolaMundo!);
^

Error tipográfico, el método es println no printl.

%In class HolaMundoApp: main must be public and static

Error de ejecución, se olvidó colocar la palabra static en la declaración del método main de la
aplicación.

%Can´t find class HolaMundoApp

Este es un error muy sutil. Generalmente significa que el nombre de la clase es distinto al del fichero
que contiene el código fuente, con lo cual el fichero nombre_fichero.class que se genera es diferente
del que cabría esperar. Por ejemplo, si en nuestro fichero de código fuente de nuestra aplicación
[Link] colocamos en vez de la declaración actual de la clase HolaMundoApp, la línea:

class HolaMundoapp {

se creará un fichero [Link], que es diferente del [Link], que es el nombre


esperado de la clase; la diferencia se encuentra en la a minúscula y mayúscula.

Tutorial de Java [Anterior] [Indice] [Siguiente]


cap5

UNA MINIMA APLICACION EN JAVA


La aplicación más pequeña posible es la que simplemente imprimir un mensaje en la pantalla. Tradicionalmente, el
mensaje suele ser "Hola Mundo!". Esto es justamente lo que hace el siguiente fragmento de código:

//
// Aplicación HolaMundo de ejemplo
//
class HolaMundoApp {
public static void main( String args[] ) {
[Link]( "Hola Mundo!" ) ;
}
}

HolaMundo

Vamos ver en detalle la aplicación anterior, línea a línea. Esas líneas de código contienen los componenetes mínimos
para imprimir Hola Mundo! en la pantalla.

//
// Aplicación HolaMundo de ejemplo
//

Estas tres primera líneas son comentarios. Hay tres tipos de comentarios en Java, // es un comentario orientado a
línea.

class HolaMundoApp {

Esta línea declara la clase HolaMundoApp. El nombre de la clase especificado en el fichero fuente se utiliza para
crear un fichero [Link] en el directorio en el que se compila la aplicación. En nuestro caso, el
compilador creará un fichero llamado [Link].

public static void main( String args[] ) {

Esta línea especifica un método que el intérprete Java busca para ejecutar en primer lugar. Igual que en otros
lenguajes, Java utiliza una palabra clave main para especificar la primera función a ejecutar. En este ejemplo tan
simple no se pasan argumentos.

public significa que el método main puede ser llamado por cualquiera, incluyendo el intérprete Java.

static es una palabra clave que le dice al compilador que main se refiere a la propia clase HolaMundoApp y no a
ninguna instancia de la clase. De esta forma, si alguien intenta hacer otra instancia de la clase, el método main no se
instanciaría.

void indica que main no devuelve nada. Esto es importante ya que Java realiza una estricta comprobación de tipos,
incluyendo los tipos que se ha declarado que devuelven los métodos.

args[] es la declaración de un array de Strings. Estos son los argumentos escritos tras el nombre de la clase en la línea
de comandos:

%java HolaMundoApp arg1 arg2 ...

[Link]( "Hola Mundo!" );

Esta es la funcionalidad de la aplicación. Esta línea muestra el uso de un nombre de clase y método. Se usa el método
println() de la clase out que está en el paquete System.

El método println() toma una cadena como argumento y la escribe en el stream de salida estándar; en este caso, la
ventana donde se lanza la aplicación.

}
}

Finalmente, se cierran las llaves que limitan el método main() y la clase HolaMundoApp.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

//
// Aplicación HolaMundo de ejemplo
//
class HolaMundoApp {

// Para generar una aplicación independiente es imprescindible la


// presencia del método main() en la clase
public static void main( String args[] ) {

// Pinta el mensaje en la posición indicada


[Link]( "Hola Mundo!" ) ;
}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 04-Jun-1996 06:26:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

//
// Applet HolaMundo de ejemplo
//
import [Link];
import [Link];

public class HolaMundo extends Applet {

public void paint( Graphics g ) {


// Pinta el mensaje en la posición indicada
[Link]( "Hola Mundo!",25,25 ) ;
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 6-Jun-1996 08:13:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link];
import [Link];

public class HolaTal extends Applet {


String nombre;

public void init() {


// Obtiene la cadena del parámetro "nombre" que se fija en la
// llamada al applet desde la página html
nombre = getParameter( "Nombre" );
}

public void paint( Graphics g ) {


// Pinta el saludo en la posición indicada
[Link]( "Hola "+nombre+"!",25,25 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 07-Jun-1996 02:35:08
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link];

class FechaApp {

public static void main( String args[] ) {


// Obtiene la fecha del sistema
Date hoy = new Date();

// La imprime en la consola
[Link]( hoy );
}
}

//------------------------------------------ Final del fichero [Link]


PROGRAMACION EN JAVA
Cuando se programa en Java, se coloca todo el código en métodos, de la misma forma que se escriben funciones en
lenguajes como C.

Comentarios

En Java hay tres tipos de comentarios:

// comentarios para una sola línea

/* comentarios de una o
más líneas
*/

/** comentario de documentación, de una o más líneas


*/

Los dos primeros tipos de comentarios son los que todo programador conoce y se utilizan del mismo modo. Los
comentarios de documentación, colocados inmediatamente antes de una declaración (de variable o función), indican
que ese comentario ha de ser colocado en la documentación que se genera automáticamente cuando se utiliza la
herramienta de Java, javadoc. Dichos comentarios sirven como descripción del elemento declarado permitiendo
generar una documentación de nuestras clases escrita al mismo tiempo que se genera el código.

En este tipo de comentario para documentación, se permite la introducción de algunos tokens o palabras clave, que
harán que la información que les sigue aparezca de forma diferente al resto en la documentación.

Identificadores

Los identificadores nombran variables, funciones, clases y objetos; cualquier cosa que el programador necesite
identificar o usar.

En Java, un identificador comienza con una letra, un subrayado (_) o un símbolo de dólar ($). Los siguientes
caracteres pueden ser letras o dígitos. Se distinguen las mayúsculas de las minúsculas y no hay longitud máxima.

Serían identificadores válidos:

identificador
nombre_usuario
Nombre_Usuario
_variable_del_sistema
$transaccion
y su uso sería, por ejemplo:

int contador_principal;
char _lista_de_ficheros;
float $cantidad_en_Ptas;

Palabras clave
Las siguientes son las palabras clave que están definidas en Java y que no se pueden utilizar como indentificadores:

abstract continue for new switch


boolean default goto null synchronized
break do if package this
byte double implements private threadsafe
byvalue else import protected throw
case extends instanceof public transient
catch false int return true
char final interface short try
class finally long static void
const float native super while

Palabras Reservadas
Además, el lenguaje se reserva unas cuantas palabras más, pero que hasta ahora no tienen un cometido específico.
Son:

cast future generic inner


operator outer rest var

Literales

Un valor constante en Java se crea utilizando una representación literal de él. Java utiliza cinco tipos de elementos:
enteros, reales en coma flotante, booleanos, caracteres y cadenas, que se pueden poner en cualquier lugar del código
fuente de Java. Cada uno de estos literales tiene un tipo correspondiente asociado con él.

Enteros:

byte 8 bits complemento a dos


short 16 bits complemento a dos
int 32 bits complemento a dos
long 64 bits complemento a dos
Por ejemplo: 21 077 0xDC00

Reales en coma flotante:

float 32 bits IEEE 754


double 64 bits IEEE 754
Por ejemplo: 3.14 2e12 3.1E12

Booleanos:

true
false

Caracteres:

Por ejemplo: a \t \u???? [????] es un número unicode

Cadenas:

Por ejemplo: "Esto es una cadena literal"

Arrays

Se pueden declarar en Java arrays de cualquier tipo:

char s[];
int iArray[];

Incluso se pueden construir arrays de arrays:

int tabla[][] = new int[4][5];

Los límites de los arrays se comprueban en tiempo de ejecución para evitar desbordamientos y la corrupción de
memoria.

En Java un array es realmente un objeto, porque tiene redefinido el operador []. Tiene una función miembro: length.
Se puede utilizar este método para conocer la longitud de cualquier array.

int a[][] = new int[10][3];


[Link]; /* 10 */
a[0].length; /* 3 */

Para crear un array en Java hay dos métodos básicos. Crear un array vacío:

int lista[] = new int[50];

o se puede crear ya el array con sus valores iniciales:

String nombres[] = {
"Juan","Pepe","Pedro","Maria"
};

Esto que es equivalente a:

String nombres[];
nombres = new String[4];
nombres[0] = new String( "Juan" );
nombres[1] = new String( "Pepe" );
nombres[2] = new String( "Pedro" );
nombres[3] = new String( "Maria" );
No se pueden crear arrays estáticos en tiempo de compilación:

int lista[50]; // generará un error en tiempo de compilación

Tampoco se puede rellenar un array sin declarar el tamaño con el operador new:

int lista[];
for( int i=0; i < 9; i++ )
lista[i] = i;

Es decir, todos los arrays en Java son estáticos. Para convertir un array en el equivalente a un array dinámico en
C/C++, se usa la clase vector, que permite operaciones de inserción, borrado, etc. en el array.

Operadores

Los operadores de Java son muy parecidos en estilo y funcionamiento a los de C. En la siguiente tabla aparecen los
operadores que se utilizan en Java, por orden de precedencia:

. [] ()
++ --
! ~ instanceof
* / %
+ -
<< >> >>>
< > <= >= == !=
& ^ |
&& ||
? :
= op= (*= /= %= += -= etc.) ,

Los operadores numéricos se comportan como esperamos:

int + int = int

Los operadores relacionales devuelven un valor booleano.

Para las cadenas, se pueden utilizar los operadores relacionales para comparaciones además de + y += para la
concatenación:

String nombre = "nombre" + "Apellido";

El operador = siempre hace copias de objetos, marcando los antiguos para borrarlos, y ya se encargará el garbage
collector de devolver al sistema la memoria ocupada por el objeto eliminado.

Separadores

Sólo hay un par de secuencias con otros caracteres que pueden aparecer en el código Java; son los separadores
simples, que van a definir la forma y función del código. Los separadores admitidos en Java son:

() - paréntesis. Para contener listas de parámetros en la definición y llamada a métodos. También se


utiliza para definir precedencia en expresiones, contener expresiones para control de flujo y rodear las
conversiones de tipo.

{} - llaves. Para contener los valores de matrices inicializadas automáticamente. También se utiliza para
definir un bloque de código, para clases, métodos y ámbitos locales.

[] - corchetes. Para declarar tipos matriz. También se utiliza cuando se referencian valores de matriz.

; - punto y coma. Separa sentencias.

, - coma. Separa identificadores consecutivos en una declaración de variables. También se utiliza para
encadenar sentencias dentro de una sentencia for.

. - punto. Para separar nombres de paquete de subpaquetes y clases. También se utiliza para separar
una variable o método de una variable de referencia.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CONTROL DE FLUJO
Muchas de las sentencias de control del flujo del programa se han tomado del C:

Sentencias de Salto

if/else

if( Boolean ) {
sentencias;
}
else {
sentencias;
}

switch

switch( expr1 ) {
case expr2:
sentencias;
break;
case expr3:
sentencias;
break;
default:
sentencias;
break;
}

Sentencias de Bucle

Bucles for

for( expr1 inicio; expr2 test; expr3 incremento ) {


sentencias;
}

El siguiente trocito de código Java que dibuja varias líneas en pantalla alternando sus colores entre rojo, azul y verde.
Este fragmento sería parte de una función Java (método):

int contador;
for( contador=1; contador <= 12; contador++ ) {
switch( contador % 3 ) {
case 0:
setColor( [Link] );
break;
case 1:
setColor( [Link] );
break;
case 2:
setColor( [Link] );
break;
}
[Link]( 10,contador*10,80,contador*10 );
}

También se soporta el operador coma (,) en los bucles for

for( a=0,b=0; a < 7; a++,b+=2 )

Bucles while

while( Boolean ) {
sentencias;
}

Bucles do/while

do {
sentencias;
}while( Boolean );

Excepciones

try-catch-throw

try {
sentencias;
} catch( Exception ) {
sentencias;
}

Java implementa excepciones para facilitar la construcción de código robusto. Cuando ocurre un error en un
programa, el código que encuentra el error lanza una excepción, que se puede capturar y recuperarse de ella. Java
proporciona muchas excepciones predefinidas.

Control General del Flujo

break [etiqueta]
continue [etiqueta]
return expr;
etiqueta: sentencia;

En caso de que nos encontremos con bucles anidados, se permite el uso de etiquetas para poder salirse de ellos, por
ejemplo:

uno: for( )
{
dos: for( )
{
continue; // seguiría en el bucle interno
continue uno; // seguiría en el bucle principal
break uno; // se saldría del bucle principal
}
}

En el código de una función siempre hay que ser consecuentes con la declaración que se haya hecho de ella. Por
ejemplo, si se declara una función para que devuelva un entero, es imprescindible que se coloque un return final para
salir de esa función, independientemente de que haya otros en medio del código que también provoquen la salida de
la función. En caso de no hacerlo se generará un Warning, y el código Java no se puede compilar con Warnings.

int func()
{
if( a == 0 )
return 1;
return 0; // es imprescindible porque se retorna un entero
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


CLASES
Las clases son lo más simple de Java. Todo en Java forma parte de una clase, es una clase o describe como funciona
una clase. El conocimiento de las clases es fundamental para poder entender los programas Java.

Todas las acciones de los programas Java se colocan dentro del bloque de una clase o un objeto. Todos los métodos
se definen dentro del bloque de la clase, Java no soporta funciones o variables globales. Esto puede despistar a los
programadores de C++, que pueden definir métodos fuera del bloque de la clase, pero esta posibilidad es más un
intento de no separarse mucho y ser compatible con C, que un buen diseño orientado a objetos. Así pues, el esqueleto
de cualquier aplicación Java se basa en la definición de una clase.

Todos los datos básicos, como los enteros, se deben declarar en las clases antes de hacer uso de ellos. En C la unidad
fundamental son los ficheros con código fuente, en Java son las clases. De hecho son pocas las sentencias que se
pueden colocar fuera del bloque de una clase. La palabra clave import (equivalente al #include) puede colocarse
al principio de un fichero, fuera del bloque de la clase. Sin embargo, el compilador reemplazará esa sentencia con el
contenido del fichero que se indique, que consistirá, como es de suponer, en más clases.

Tipos de Clases

Hasta ahora sólo se ha utilizado la palabra clave public para calificar el nombre de las clases que hemos visto, pero
hay tres modificadores más. Los tipos de clases que podemos definir son:

abstract

Una clase abstract tiene al menos un método abstracto. Una clase abstracta no se instancia, sino que se
utiliza como clase base para la herencia.

final

Una clase final se declara como la clase que termina una cadena de herencia. No se puede heredar de
una clase final. Por ejemplo, la clase Math es una clase final.

public

Las clases public son accesibles desde otras clases, bien sea directamente o por herencia. Son
accesibles dentro del mismo paquete en el que se han declarado. Para acceder desde otros paquetes,
primero tienen que ser importadas.

synchronizable

Este modificador especifica que todos los métodos definidos en la clase son sincronizados, es decir,
que no se puede acceder al mismo tiempo a ellos desde distintos threads; el sistema se encarga de
colocar los flags necesarios para evitarlo. Este mecanismo hace que desde threads diferentes se puedan
modificar las mismas variables sin que haya problemas de que se sobreescriban.

Tutorial de Java [Anterior] [Indice] [Siguiente]


VARIABLES Y METODOS DE INSTANCIA
Una clase en Java puede contener variables y métodos. Las variables pueden ser tipos primitivos como int, char, etc.
Los métodos son funciones.

Por ejemplo, en el siguiente trozo de código podemos observarlo:

public MiClase {
int i;
public MiClase() {
i = 10;
}
public void Suma_a_i( int j ) {
i = i + j;
}
}

La clase MiClase contiene una variable (i) y dos métodos, MiClase que es el constructor de la clase y Suma_a_i( int
j ).

Ambito de una variable

Los bloques de sentencias compuestas en Java se delimitan con dos llaves. Las variables de Java sólo son válidas
desde el punto donde están declaradas hasta el final de la sentencia compuesta que la engloba. Se pueden anidar estas
sentencias compuestas, y cada una puede contener su propio conjunto de declaraciones de variables locales. Sin
embargo, no se puede declarar una variable con el mismo nombre que una de ámbito exterior.

El siguiente ejemplo intenta declarar dos variables separadas con el mismo nombre. En C y C++ son distintas, porque
están declaradas dentro de ámbitos diferentes. En Java, esto es ilegal.

Class Ambito {
int i = 1; // ámbito exterior
{ // crea un nuevo ámbito
int i = 2; // error de compilación
}
}

Métodos y Constructores

Los métodos son funciones que pueden ser llamadas dentro de la clase o por otras clases. El constructor es un tipo
específico de método que siempre tiene el mismo nombre que la clase.
Cuando se declara una clase en Java, se pueden declarar uno o más constructores opcionales que realizan la
inicialización cuando se instancia (se crea una ocurrencia) un objeto de dicha clase.

Utilizando el código de ejemplo anterior, cuando se crea una nueva instancia de MiClase, se crean (instancian) todos
los métodos y variables, y se llama al constructor de la clase:

MiClase mc;
mc = new MiClase();

La palabra clave new se usa para crear una instancia de la clase. Antes de ser instanciada con new no consume
memoria, simplemente es una declaración de tipo. Después de ser instanciado un nuevo objeto mc, el valor de i en el
objeto mc será igual a 10. Se puede referenciar la variable (de instancia) i con el nombre del objeto:

mc.i++; // incrementa la instancia de i de mc

Al tener mc todas las variables y métodos de MiClase, se puede usar la primera sintaxis para llamar al método
Suma_a_i() utilizando el nuevo nombre de clase mc:

mc.Suma_a_i( 10 );

y ahora la variable mc.i vale 21.

Finalizadores

Java no utiliza destructores (al contrario que C++) ya que tiene una forma de recoger automáticamente todos los
objetos que se salen del alcance. No obstante proporciona un método que, cuando se especifique en el código de la
clase, el reciclador de memoria (garbage collector) llamará:

// Cierra el canal cuando este objeto es reciclado


protected void finalize() {
close();
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


ALCANCE DE OBJETOS Y RECICLADO DE MEMORIA
Los objetos tienen un tiempo de vida y consumen recursos durante el mismo. Cuando un objeto no se va a utilizar
más, debería liberar el espacio que ocupaba en la memoria de forma que las aplicaciones no la agoten (especialmente
las grandes).

En Java, la recolección y liberación de memoria es responsabilidad de un thread llamado automatic garbage


collector (recolector automático de basura). Este thread monitoriza el alcance de los objetos y marca los objetos que
se han salido de alcance. Veamos un ejemplo:

String s; // no se ha asignado todavia


s = new String( "abc" ); // memoria asignada
s = "def"; // se ha asignado nueva memoria
// (nuevo objeto)

Más adelante veremos en detalle la clase String, pero una breve descripción de lo que hace esto es; crear un objeto
String y rellenarlo con los caracteres "abc" y crear otro (nuevo) String y colocarle los caracteres "def".

En esencia se crean dos objetos:

Objeto String "abc"


Objeto String "def"

Al final de la tercera sentencia, el primer objeto creado de nombre s que contiene "abc" se ha salido de alcance. No
hay forma de acceder a él. Ahora se tiene un nuevo objeto llamado s y contiene "def". Es marcado y eliminado en la
siguiente iteración del thread reciclador de memoria.

Tutorial de Java [Anterior] [Indice] [Siguiente]


HERENCIA
La Herencia es el mecanismo por el que se crean nuevos objetos definidos en términos de objetos ya existentes. Por
ejemplo, si se tiene la clase Ave, se puede crear la subclase Pato, que es una especialización de Ave.

class Pato extends Ave {


int numero_de_patas;
}

La palabra clave extends se usa para generar una subclase (especialización) de un objeto. Una Pato es una subclase de
Ave. Cualquier cosa que contenga la definición de Ave será copiada a la clase Pato, además, en Pato se pueden
definir sus propios métodos y variables de instancia. Se dice que Pato deriva o hereda de Ave.

Además, se pueden sustituir los métodos proporcionados por la clase base. Utilizando nuestro anterior ejemplo de
MiClase, aquí hay un ejemplo de una clase derivada sustituyendo a la función Suma_a_i():

import MiClase;
public class MiNuevaClase extends MiClase {
public void Suma_a_i( int j ) {
i = i + ( j/2 );
}
}

Ahora cuando se crea una instancia de MiNuevaClase, el valor de i también se inicializa a 10, pero la llamada al
método Suma_a_i() produce un resultado diferente:

MiNuevaClase mnc;
mnc = new MiNuevaClase();
mnc.Suma_a_i( 10 );

En Java no se puede hacer herencia múltiple. Por ejemplo, de la clase aparato con motor y de la clase animal no se
puede derivar nada, sería como obtener el objeto toro mecánico a partir de una máquina motorizada (aparato con
motor) y un toro (aminal). En realidad, lo que se pretende es copiar los métodos, es decir, pasar la funcionalidad del
toro de verdad al toro mecánico, con lo cual no sería necesaria la herencia múltiple sino simplemente la compartición
de funcionalidad que se encuentra implementada en Java a través de interfaces.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CONTROL DE ACCESO
Cuando se crea una nueva clase en Java, se puede especificar el nivel de acceso que se quiere para las variables de
instancia y los métodos definidos en la clase:

public

public void CualquieraPuedeAcceder(){}

Cualquier clase desde cualquier lugar puede acceder a las variables y métodos de instacia públicos.

protected

protected void SoloSubClases(){}

Sólo las subclases de la clase y nadie más puede acceder a las variables y métodos de instancia
protegidos.

private

private String NumeroDelCarnetDeIdentidad;

Las variables y métodos de instancia privados sólo pueden ser accedidos desde dentro de la clase. No
son accesibles desde las subclases.

friendly (sin declaración específica)

void MetodoDeMiPaquete(){}

Por defecto, si no se especifica el control de acceso, las variables y métodos de instancia se declaran
friendly (amigas), lo que significa que son accesibles por todos los objetos dentro del mismo paquete,
pero no por los externos al paquete. Es lo mismo que protected.

Los métodos protegidos (protected) pueden ser vistos por las clases derivadas, como en C++, y también, en Java, por
los paquetes (packages). Todas las clases de un paquete pueden ver los métodos protegidos de ese paquete. Para
evitarlo, se deben declarar como private protected, lo que hace que ya funcione como en C++ en donde sólo se puede
acceder a las variables y métodos protegidos de las clases derivadas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


VARIABLES Y METODOS ESTATICOS
En un momento determinado se puede querer crear una clase en la que el valor de una variable de instancia sea el
mismo (y de hecho sea la misma variable) para todos los objetos instanciados a partir de esa clase. Es decir, que
exista una única copia de la variable de instancia. Se usará para ello la palabra clave static.

class Documento extends Pagina {


static int version = 10;
}

El valor de la variable version será el mismo para cualquier objeto instanciado de la clase Documento. Siempre
que un objeto instanciado de Documento cambie la variable version, ésta cambiará para todos los objetos.

De la misma forma se puede declarar un método como estático, lo que evita que el método pueda acceder a las
variables de instancia no estáticas:

class Documento extends Pagina {


static int version = 10;
int numero_de_capitulos;
static void annade_un_capitulo() {
numero_de_capitulos++; // esto no funciona
}
static void modifica_version( int i ) {
version++; // esto si funciona
}
}

La modificación de la variable numero_de_capitulos no funciona porque se está violando una de las reglas de
acceso al intentar acceder desde un método estático a una variable no estática.

Todas las clases que se derivan, cuando se declaran estáticas, comparten la misma página de variables; es decir, todos
los objetos que se generen comparten la misma zona de memoria. Las funciones estáticas se usan para acceder
solamente a variables estáticas.

class UnaClase {
int var;
UnaClase()
{
var = 5;
}
UnaFuncion()
{
var += 5;
}
}

En el código anterior, si se llama a la función UnaFuncion a través de un puntero a función, no se podría acceder a
var, porque al utilizar un puntero a función no se pasa implícitamente el puntero al propio objeto (this). Sin
embargo, sí se podría acceder a var si fuese estática, porque siempre estaría en la misma posición de memoria para
todos los objetos que se creasen de UnaClase.

Tutorial de Java [Anterior] [Indice] [Siguiente]


this Y super
Al acceder a variables de instancia de una clase, la palabra clave this hace referencia a los miembros de la propia
clase. Volviendo al ejemplo de MiClase, se puede añadir otro constructor de la forma siguiente:

public class MiClase {


int i;
public MiClase() {
i = 10;
}
// Este constructor establece el valor de i
public MiClase( int valor ) {
this.i = valor; // i = valor
}
public void Suma_a_i( int j ) {
i = i + j;
}
}

Aquí this.i se refiere al entero i en la clase MiClase.

Si se necesita llamar al método padre dentro de una clase que ha reemplazado ese método, se puede hacer referencia
al método padre con la palabra clave super:

import MiClase;
public class MiNuevaClase extends MiClase {
public void Suma_a_i( int j ) {
i = i + ( j/2 );
super.Suma_a_i( j );
}
}

En el siguiente código, el constructor establecerá el valor de i a 10, después lo cambiará a 15 y finalmente el método
Suma_a_i() de la clase padre (MiClase) lo dejará en 25:

MiNuevaClase mnc;
mnc = new MiNuevaClase();
mnc.Suma_a_i( 10 );

Tutorial de Java [Anterior] [Indice] [Siguiente]


CLASES ABSTRACTAS
Una de las características más útiles de cualquier lenguaje orientado a objetos es la posibilidad de declarar clases que
definen como se utiliza solamente, sin tener que implementar métodos. Esto es muy útil cuando la implementación es
específica para cada usuario, pero todos los usuarios tienen que utilizar los mismos métodos. Un ejemplo de clase
abstracta en Java es la clase Graphics:

public abstract class Graphics {


public abstract void drawLine( int x1,int y1,int x2,
int y2 );
public abstract void drawOval( int x,int y,int width,
int height );
public abstract void drawArc( int x,int y,int width,
int height,int startAngle,int arcAngle );
. . .
}

Los métodos se declaran en la clase Graphics, pero el código que ejecutará el método está en algún otro sitio:

public class MiClase extends Graphics {


public void drawLine( int x1,int y1,int x2,int y2 ) {
<código para pintar líneas -específico de
la arquitectura->
}
}

Cuando una clase contiene un método abstracto tiene que declararse abstracta. No obstante, no todos los métodos de
una clase abstracta tienen que ser abstractos. Las clases abstractas no pueden tener métodos privados (no se podrían
implementar) ni tampoco estáticos. Una clase abstracta tiene que derivarse obligatoriamente, no se puede hacer un
new de una clase abstracta.

Una clase abstracta en Java es lo mismo que en C++ virtual func() = 0; lo que obliga a que al derivar de la clase haya
que implementar forzosamente los métodos de esa clase abstracta.

Tutorial de Java [Anterior] [Indice] [Siguiente]


INTERFACES
Los métodos abstractos son útiles cuando se quiere que cada implementación de la clase parezca y funcione igual,
pero necesita que se cree una nueva clase para utilizar los métodos abstractos.

Los interfaces proporcionan un mecanismo para abstraer los métodos a un nivel superior.

Un interface contiene una colección de métodos que se implementan en otro lugar. Los métodos de una clase son
public, static y final.

La principal diferencia entre interface y abstract es que un interface proporciona un mecanismo de encapsulación de
los protocolos de los métodos sin forzar al usuario a utilizar la herencia.

Por ejemplo:

public interface VideoClip {


// comienza la reproduccion del video
void play();
// reproduce el clip en un bucle
void bucle();
// detiene la reproduccion
void stop();
}

Las clases que quieran utilizar el interface VideoClip utilizarán la palabra implements y proporcionarán el código
necesario para implementar los métodos que se han definido para el interface:

class MiClase implements VideoClip {


void play() {
<código>
}
void bucle() {
<código>
}
void stop() {
<código>
}

Al utilizar implements para el interface es como si se hiciese una acción de copiar-y-pegar del código del
interface, con lo cual no se hereda nada, solamente se pueden usar los métodos.

La ventaja principal del uso de interfaces es que una clase interface puede ser implementada por cualquier número
de clases, permitiendo a cada clase compartir el interfaz de programación sin tener que ser consciente de la
implementación que hagan las otras clases que implementen el interface.

class MiOtraClase implements VideoClip {


void play() {
<código nuevo>
}
void bucle() {
<código nuevo>
}
void stop() {
<código nuevo>
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


METODOS NATIVOS
Java proporciona un mecanismo para la llamada a funciones C y C++ desde nuestro código fuente Java. Para definir
métodos como funciones C o C++ se utiliza la palabra clave native.

public class Fecha {


int ahora;
public Fecha() {
ahora = time();
}
private native int time();
static {
[Link]( "time" );
}
}

Una vez escrito el código Java, se necesitan ejecutar los pasos siguientes para poder integrar el código C o C++:

● Utilizar javah para crear un fichero de cabecera (.h)


● Utilizar javah para crear un fichero de stubs, es decir, que contiene la declaración de las funciones
● Escribir el código del método nativo en C o C++, es decir, rellenar el código de la función, completando el
trabajo de javah al crear el fichero de stubs
● Compilar el fichero de stubs y el fichero .c en una librería de carga dinámica (DLL en Windows '95 o [Link]
en Unix)
● Ejecutar la aplicación con el appletviewer

Más adelante trataremos en profundidad los métodos nativos, porque añaden una gran potencia a Java, al permitirle
integrar a través de librería dinámica cualquier algoritmo desarrollado en C o C++, lo cual, entre otras cosas, se
utiliza como método de protección contra la descompilación completa del código Java.

Tutorial de Java [Anterior] [Indice] [Siguiente]


PAQUETES
La palabra clave package permite agrupar clases e interfaces. Los nombres de los paquetes son palabras separadas
por puntos y se almacenan en directorios que coinciden con esos nombres.

Por ejemplo, los ficheros siguientes, que contienen código fuente Java:

[Link], [Link], [Link], [Link]

contienen en su código la línea:

package [Link];

Y las clases que se obtienen de la compilación de los ficheros anteriores, se encuentran con el nombre
nombre_de_clase.class, en el directorio:

java/applet

Import

Los paquetes de clases se cargan con la palabra clave import, especificando el nombre del paquete como ruta y
nombre de clase (es lo mismo que #include de C/C++). Se pueden cargar varias clases utilizando un asterisco.

import [Link];
import [Link].*;

Si un fichero fuente Java no contiene ningún package, se coloca en el paquete por defecto sin nombre. Es decir, en el
mismo directorio que el fichero fuente, y la clase puede ser cargada con la sentencia import:

import MiClase;

Paquetes de Java

El lenguaje Java proporciona una serie de paquetes que incluyen ventanas, utilidades, un sistema de entrada/salida
general, herramientas y comunicaciones. En la versión actual del JDK, los paquetes Java que se incluyen son:

[Link]

Este paquete contiene clases diseñadas para usar con applets. Hay una clase Applet y tres interfaces:
AppletContext, AppletStub y AudioClip.
[Link]

El paquete Abstract Windowing Toolkit (awt) contiene clases para generar widgets y componentes
GUI (Interfaz Gráfico de Usuario). Incluye las clases Button, Checkbox, Choice, Component,
Graphics, Menu, Panel, TextArea y TextField.

[Link]

El paquete de entrada/salida contiene las clases de acceso a ficheros: FileInputStream y


FileOutputStream.

[Link]

Este paquete incluye las clases del lenguaje Java propiamente dicho: Object, Thread, Exception,
System, Integer, Float, Math, String, etc.

[Link]

Este paquete da soporte a las conexiones del protocolo TCP/IP y, además, incluye las clases Socket,
URL y URLConnection.

[Link]

Este paquete es una miscelánea de clases útiles para muchas cosas en programación. Se incluyen, entre
otras, Date (fecha), Dictionary (diccionario), Random (números aleatorios) y Stack (pila FIFO).

Tutorial de Java [Anterior] [Indice] [Siguiente]


REFERENCIAS
Java se asemeja mucho a C y C++. Esta similitud, evidentemente intencionada, es la mejor herramienta para los
programadores, ya que facilita en gran manera su transición a Java. Desafortunadamente, tantas similitudes hacen
que no nos paremos en algunas diferencias que son vitales. La terminología utilizada en estos lenguajes, a veces es la
misma, pero hay grandes diferencias subyacentes en su significado.

C tiene tipos de datos básicos y punteros. C++ modifica un poco este panorama y le añade los tipos referencia. Java
también especifica sus tipos primitivos, elimina cualquier tipo de punteros y tiene tipos referencia mucho más claros.

Todo este maremágnum de terminología provoca cierta consternación, así que vamos a intentar aclarar lo que
realmente significa.

Conocemos ya ampliamente todos los tipos básicos de datos: datos base, integrados, primitivos e internos; que son
muy semejantes en C, C++ y Java; aunque Java simplifica un poco su uso a los desarrolladores haciendo que el
chequeo de tipos sea bastante más rígido. Además, Java añade los tipos boolean y hace imprescindible el uso de este
tipo booleano en sentencias condicionales.

Tutorial de Java [Anterior] [Indice] [Siguiente]


PUNTEROS Y REFERENCIAS C++
Punteros

C y C++ permiten la declaración y uso de punteros, que pueden ser utilizados en cualquier lugar. Esta tremenda
flexibilidad resulta muy útil, pero también es la causa de que podamos colgar todo el sistema.

La intención principal en el uso de los punteros es comunicarnos más directamente con el hardware, haciendo que el
código se acelere. Desafortunadamente, este modelo de tan bajo nivel hace que perdamos robustez y seguridad en la
programación y hace muy difíciles tareas como la liberación automática de memoria, la defragmentación de
memoria, o realizar programación distribuida de forma clara y eficiente.

Referencias en C++

Las referencias se incorporaron a C++ en un intento de manejar punteros de C de forma más limpia y segura. Sin
embargo, como no elimina los punteros, la verdad es que su propósito lo consigue a medias. Es más, podríamos decir
que con las referencias C++, el lenguaje se vuelve más complicado y no es más poderoso que antes.

Las referencias deben ser inicializadas cuando se declaran y no se pueden alterar posteriormente. Esto permite
incrementar la eficiencia en tiempo de ejecución sobre la solución basada en punteros, pero es más por las
deficiencias de los punteros que por las ventajas de las referencias.

Tutorial de Java [Anterior] [Indice] [Siguiente]


REFERENCIAS EN JAVA
Las referencias en Java no son punteros ni referencias como en C++. Este hecho crea un poco de confusión entre los
programadores que llegan por primera vez a Java. Las referencias en Java son identificadores de instancias de las
clases Java. Una referencia dirige la atención a un objeto de un tipo específico. No tenemos por qué saber cómo lo
hace ni necesitamos saber qué hace ni, por supuesto, su implementación.

Pensemos en una referencia como si se tratase de la llave electrónica de la habitación de un hotel. Vamos a utilizar
precisamente este ejemplo del Hotel para demostrar el uso y la utilización que podemos hacer de las referencias en
Java. Primero crearemos la clase Habitacion, implementada en el fichero [Link], mediante instancias de la
cual construiremos nuestro Hotel:

public class Habitacion {


private int numHabitacion;
private int numCamas;

public Habitacion() {
habitacion( 0 );
}

public Habitacion( int numeroHab ) {


habitacion( numeroHab );
}

public Habitacion( int numeroHab,int camas ) {


habitacion( numeroHab );
camas( camas );
}

public synchornized int habitacion() {


return( numHabitacion );
}

public synchronized void habitacion( int numeroHab ) {


numHabitacion = numeroHab;
}

public synchronized int camas() {


return( camas );
}

public syncronized void camas( int camas ) {


numCamas = camas;
}
}
El código anterior sería el corazón de la aplicación. Vamos pues a construir nuestro Hotel creando Habitaciones y
asignándole a cada una de ellas su llave electrónica; tal como muestra el código siguiente, [Link]:

public class Hotel1 {


public static void main( String args[] ) {
Habitacion llaveHab1; // paso 1
Habitacion llaveHab2;

llaveHab1 = new Habitacion( 222 ); // pasos 2, 3, 4 y 5


llaveHab2 = new Habitacion( 1144,3 );
// ^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^
// A B y D C
}
}

Para explicar el proceso, dividimos las acciones en los cinco pasos necesarios para poder entrar en nuestra habitación.
Aunque no se incluye, podemos también considerar el caso de que necesitemos un cerrajero, para que cuando
perdamos la llave, nos abra la puerta; y que en nuestro caso sería el garbage collector, que recicla la habitación una
vez que se hayan perdido todas las llaves.

El primer paso es la creación de la llave, es decir, definir la variable referencia, por defecto nula.

El resto de los pasos se agrupan en una sola sentencia Java. La parte B en el código anterior indica al gerente del
Hotel que ya dispone de una nueva habitación. La parte C llama al decorador de interiores para que "vista" la
habitación según un patrón determinado, para que no desentonen unas habitaciones con otras y no se pierdan las
señas de identidad del hotel. El código electrónico que nos permitirá acceder a la habitación se genera en la parte D,
una vez conocido el interior de la habitación y se programa en la llave en la parte A.

Si dejamos el ejemplo real a un lado y nos vamos a lo que ocurre en la ejecución del código, vemos que el operador
new busca espacio para una instancia de un objeto de una clase determinada e inicializa la memoria a los valores
adecuados. Luego invoca al método constructor de la clase, proporcionándole los argumentos adecuados. El operador
new devuelve una referencia a sí mismo, que es inmediatamente asignada a la variable referencia.

Podemos tener múltiples llaves para una misma habitación:

. . .
Habitacion llaveHab3,llaveHab4;
llaveHab3 = llaveHab1;
llaveHab4 = llavehab2;

De este modo conseguimos copias de las llaves. Las habitaciones en sí mismas no se han tocado en este proceso. Así
que, ya tenemos dos llaves para la habitación 222 y otras dos para la habitación 1144.

Una llave puede ser programada para que funcione solamente con una habitación en cualquier momento, pero
podemos cambiar su código electrónico para que funcione con alguna otra habitación; por ejemplo, para cambiar una
habitación anteriormente utilizada por un empedernido fumador por otra limpia de olores y con vistas al mar.
Cambiemos pues la llave duplicada de la habitación del fumador (la 222) por la habitación con olor a sal marina,
1144:

. . .
llaveHab3 = llaveHab2;
Ahora tenemos una llave para la habitación 222 y tres para la habitación 1144. Mantendremos una llave para cada
habitación en la conserjería, para poder utilizarla como llave maestra, en el caso de que alguien pierda su llave
propia.

Alguien con la llave de una habitación puede hacer cambios en ella, y los compañeros que tengan llave de esa misma
habitación, no tendrán conocimiento de esos cambios hasta que vuelvan a entrar en la habitación. Por ejemplo, vamos
a quitar una de las camas de la habitación, entrando en ella con la llave maestra:

. . .
[Link]( 2 );

Ahora cuando los inquilinos entren en la habitación podrán comprobar el cambio realizado:

. . .
[Link]();

Tutorial de Java [Anterior] [Indice] [Siguiente]


REFERENCIAS Y ARRAYS
Como en C y C++, Java dispone de arrays de tipos primitivos o de clases. Los arrays en C y C++ son básicamente un
acompañante para los punteros. En Java, sin embargo, son ciudadanos de primera clase.

Vamos a expandir nuestro hotel creando todo un ala de habitaciones, [Link]. Crearemos un juego de llaves
maestras y luego construiremos las habitaciones:

public class Hotel2 {


// Número de habitaciones por ala
public static final int habPorAla = 12;

public static void main( String args[] ) {


Habitacion llavesMaestras[]; // paso 1
llavesMaestras = new Habitacion[ habPorAla ]; // pasos 2-5
// ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// A B, C, D y E
int numPiso = 1;
for( int i=0; i < habPorAla; i++ ) // pasos 6-9
llavesMaestras[ i ] = new Habitacion( numPiso * 100 + i,
( 0 == (i%2)) ? 2 : 1 );
for( int i=0; i < habPorAla; i++ ) // pasos 10-11
llavesMaestras[i].printData();
}
}

Cada paso en el ejemplo es semejante al que ya vimos antes. El paso 1 especifica que el juego de llaves maestras es
un grupo de llaves de habitaciones.

Los pasos 2 a 5 son, en este caso, la parte principal. En lugar de crear una habitación, el gerente ordena construir un
grupo contiguo de habitaciones. El número de llaves se especifica entre corchetes y todas se crean en blanco.

Los pasos 6 a 9 son idénticos a los pasos 2 a 5 del ejemplo anterior, excepto en que en este caso todas las llaves pasan
a formar parte del juego maestro. Los números de piso se dan en miles para que cuando se creen las habitaciones,
todas tengan el mismo formato. También todas las habitaciones de número par tienen una sola cama, mientras que las
habitaciones impares tendrán dos camas.

Los pasos 10 y 11 nos permiten obtener información de cada una de las habitaciones.

Tutorial de Java [Anterior] [Indice] [Siguiente]


REFERENCIAS Y LISTAS
Hay gente que piensa que como Java no dispone de punteros, resulta demasiado complejo construir listas enlazadas,
árboles binarios y grafos. Vamos a demostrar que quien así piense está bastante equivocado.

Retomemos el ejemplo de los arrays, y en vez de éstos vamos a usar una lista doblemente enlazada. El paquete de la
lista simple se compone de dos clases. Cada elemento de la lista es un NodoListaEnlazada,
[Link]:

public class NodoListaEnlazada {


private NodoListaEnlazada siguiente;
private NodoListaEnlazada anterior;
private Object datos;
// . . .
}

Cada NodoListaEnlazada contiene una referencia a su nodo precedente en la lista y una referencia al nodo que
le sigue. También contiene una referencia genérica a cualquier clase que se use para proporcionar acceso a los datos
que el usuario proporcione.

La lista enlazada, [Link], contiene un nodo principio-fin y un contador para el número de nodos en la
lista:

public class ListaEnlazada {


public NodoListaEnlazada PrincipioFin;
private int numNodos;
// . . .
}

El nodo especial PrincipioFin es sencillo, para simplificar el código. El contador se usa para optimizar los casos
más habituales.

Revisemos pues el código de nuestro Hotel, ahora [Link], que será prácticamente el mismo que en el caso de los
arrays:

public class Hotel3 {


// Número de habitaciones por ala
public static final int habPorAla = 12;

public static void main( String args[] ) {


ListaEnlazada llaveMaestra; // paso 1
llaveMaestra = new ListaEnlazada(); // pasos 2-5
int numPiso = 1;
for( int i=0; i < habPorAla; i++ ) // pasos 6-9
[Link]( i,
new Habitacion( numPiso * 100 + i,
( 0 == (i%2)) ? 2 : 1 );
for( int i=0; i < habPorAla; i++ ) // pasos 10-12
( (Habitacion)[Link](i) ).printData();
}
}

El paso 1 es la llave maestra de la lista. Está representada por una lista genérica; es decir, una lista de llaves que
cumple la convención que nosotros hemos establecido. Podríamos acelerar el tiempo de compilación metiendo la
lista genérica ListaEnlazada dentro de una ListaEnlazadaHabitacion.

Los pasos 2 a 5 son equivalentes a los del primer ejemplo. Construimos e inicializamos una nueva
ListaEnlazada, que usaremos como juego de llaves maestras.

Los pasos 6 a 9 son funcionalmente idénticos a los del ejemplo anterior con arrays, pero con diferente sintaxis. En
Java, los arrays y el operador [] son internos del lenguaje. Como Java no soporta la sobrecarga de operadores por
parte del usuario, tenemos que usarlo siempre en su forma normal.

La ListaEnlazada proporciona el método insertAt() que coge el índice en la lista, donde el nuevo nodo ha de ser
insertado, como primer argumento. El segundo argumento es el objeto que será almacenado en la lista. Obsérvese
que no es necesario colocar moldeo alguno para hacer algo a una clase descendiente que depende de uno de sus
padres.

Los pasos 10 a 12 provocan la misma salida que los pasos 10 y 11 del ejemplo con arrays. El paso 10 coge la llave
del juego que se indica en el método getAt(). En este momento, el sistema no sabe qué datos contiene la llave, porque
el contenido de la habitación es genérico. Pero nosotros sí sabemos lo que hay en la lista, así que informamos al
sistema haciendo un moldeado a la llave de la habitación (este casting generará un chequeo en tiempo de ejecución
por el compilador, para asegurarse de que se trata de una Habitacion). El paso 12 usa la llave para imprimir la
información.

Tutorial de Java [Anterior] [Indice] [Siguiente]


PUNTEROS C/C++ Y REFERENCIAS JAVA
Ahora que ya sabemos un poco más sobre las referencias en Java, vamos a compararlas con los punteros de C y C++.

Los punteros en C y C++ están orientados hacia un modelo físico de funcionamiento. Es decir, que el modelo de
punteros se mapea directamente sobre el modelo hardware. Este modelo asume cosas como el no movimiento, lo que
hace que mecanismos como la liberación automática resulten mucho menos eficientes o simplemente imposibles.
Cosas como la distribución en redes y la persistencia de objetos son muy difíciles de conseguir en C y C++. Aunque
no hay implementaciones en Java, por ahora, para la persistencia y la distribución, la característica opaca de las
referencias en Java hace que el soporte para estas prestaciones sea mucho más simple.

C y C++ permiten el uso de punteros de tal forma que podemos corromper el sistema, cosa que no puede suceder con
las referencias en Java. Cualquier intento de hacer esto sería abortado por el compilador o por el sistema en ejecución
(lanzando una excepción). C y C++ dejan la protección de memoria al sistema operativo, que solamente tiene el
recurso de generar un error del sistema cuando un puntero accede a una posición no válida. Por el contrario, con el
uso de las referencias, Java nos protege contra nuestras propias tendencias autodestructivas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Oct-1996 11:37:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

// Esta clase es realmente un objeto muy simple que usaremos para


// poder levantar nuestro Hotel
public class Habitacion {
private int numHabitacion;
private int numCamas;

// Constructor basico, inicializa todos los datos miembros


public Habitacion() {
habitacion( 0 );
camas( 2 );
}

// Constructor de conveniencia, inicializa la habitacion con


// un numero determinado
public Habitacion( int numeroHab ) {
habitacion( numeroHab );
camas( 2 );
}

// Constructor de conveniencia, inicializa la habitacion con


// un numero determinado y con una cantidad de camas dada
public Habitacion( int numeroHab,int camas ) {
habitacion( numeroHab );
camas( camas );
}

// Este metodo devuelve el numero de la habitacion


public synchronized int habitacion() {
return( numHabitacion );
}

// Este metodo le asigna a la habitacion un numero


public synchronized void habitacion( int numeroHab ) {
numHabitacion = numeroHab;
}

// Este metodo devuelve el numero de camas de una habitacion


public synchronized int camas() {
return( numCamas );
}

// Este metodo asigna un numero de camas determinado a una habitacion


public synchronized void camas( int camas ) {
numCamas = camas;
}
// Este metodo imprime los datos de una habitacion, numero y camas
public synchronized void printData() {
[Link]( "Habitacion #"+numHabitacion+": "+
numCamas+" camas" );
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Oct-1996 11:47:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import Habitacion;

// Implementacion basica del Hotel


public class Hotel1 {
public static void main( String args[] ) {
// Primero creamos dos variables Referencia, que necesitaremos
// para que contengan las Referencia en si mismas
// Que quede claro que aqui todavia NO se crean los objetos
// Referencia
Habitacion llaveHab1;
Habitacion llaveHab2;

// Ahora, creamos los objetos Habitacion y los asignamos


// directamente con su llave
llaveHab1 = new Habitacion( 222 );
llaveHab2 = new Habitacion( 1144,3 );
// Imprimimos el estado actual de la situacion
[Link]();
[Link]();

// Hagamos un duplicaco de la llave de las habitaciones


Habitacion llaveHab3; // Creamos las variables referencia
Habitacion llaveHab4;
llaveHab3 = llaveHab1; // Copiamos la llave, no la Habitacion
llaveHab4 = llaveHab2;
// Imprimimos ahora como tenemos la situacion
[Link]( "\n" );
[Link]();
[Link]();
[Link]();
[Link]();

// Cambiamos el codigo electronico de la llave a otra Habitacion


llaveHab3 = llaveHab2;
// Imprimimos ahora el contenido de las llaves
[Link]( "\n" );
[Link]();
[Link]();
[Link]();
[Link]();

// Ahora cogemos una llave y le quitamos una cama a la Habitacion


[Link]( 2 );
// El primero que entre se encontrara con una cama menos...
[Link]( "\n" );
[Link]();
[Link]();
[Link]();
[Link]();
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Oct-1996 12:50:34
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import Habitacion;

// Este es un ejemplo con Referencias y Arrays


// Se construye un Hotel de Habitaciones
public class Hotel2 {
// Numero de habitaciones en cada ala del Hotel
public static final int habPorAla = 12;

public static void main( String args[] ) {


// Creamos el llavero para guardar todas las llaves
// de las habitaciones
// Comenzamos con un ala simple sobre un solo piso que
// contiene 12 habitaciones
Habitacion llavesMaestras[];
llavesMaestras = new Habitacion[habPorAla];

// Ahora, creamos cada una de las habitaciones y guardamos


// su llave en el llavero maestro
int numPiso = 1;
for( int i=0; i < habPorAla; i++ )
{
// Los numeros de las habitaciones se dan en miles para que
// al imprimir quede mas bonito. Las habitaciones pares las
// ponemos con 1 cama y las impares con 2 camas
llavesMaestras[i] = new Habitacion( numPiso * 1000 + i,
( 0 == (i % 2) ) ? 2 : 1 );
}

// Imprimimos los datos, para ver lo que hemos hecho


for( int i=0; i < habPorAla; i++ )
llavesMaestras[i].printData();
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

// Aqui implementamos una Lista Enlazada muy simple.


// Para usarla en serio habria que implementar un control
// de los errores que se pudiesen producir y la posibilidad
// de borrar nodos, que no se ha hecho porque, en principio,
// no lo necesitamos
public class NodoListaEnlazada {
// Referencias al nodo anterior y posterior en la lista
private NodoListaEnlazada nodoSiguiente;
private NodoListaEnlazada nodoAnterior;

// Referencia a los datos actuales del objeto


// Esto no funcionaria con tipos basicos, porque no
// se pueden pasar como objetos
private Object nodoDatos;

// Constructor Basico
public NodoListaEnlazada() {
// Reseteamos los apuntadores
siguiente( null );
anterior( null );

// En principio, no hay datos


datos( null );
}

// Construimos un nuevo nodo y lo insertamos en medio


// de los dos que nos indiquen
public NodoListaEnlazada( NodoListaEnlazada antes,
NodoListaEnlazada despues,Object datos ) {
insertEntre( antes,despues,datos );
}

// Inserta un nodo entre dos determinados


public void insertEntre( NodoListaEnlazada antes,
NodoListaEnlazada despues,Object datos ) {
// Fijamos nuestros apuntadores
anterior( antes );
siguiente( despues );

// Fijamos los apuntadores de los otros nodos a nosotros


[Link]( this );
[Link]( this );

// Fijamos los datos del nodo


datos( datos );
}

// Inserta un nodo antes del que nos indiquen


public void insertAntes( NodoListaEnlazada despues,Object datos ) {
// Fijamos nuestros apuntadores
anterior( [Link]() );
siguiente( despues );

// Fijamos los apuntadores de los otros nodos a nosotros


anterior().siguiente( this );
[Link]( this );

// Fijamos los datos del nodo


datos( datos );
}

// Inserta un nodo despues del que nos indiquen


public void insertDespues( NodoListaEnlazada antes,Object datos ) {
// Fijamos nuestros apuntadores
anterior( antes );
siguiente( [Link]() );

// Fijamos los apuntadores de los otros nodos a nosotros


[Link]( this );
siguiente().anterior( this );

// Fijamos los datos del nodo


datos( datos );
}

// Acceso a los elementos de un nodo


public NodoListaEnlazada anterior() {
return( nodoAnterior );
}

public NodoListaEnlazada siguiente() {


return( nodoSiguiente );
}

public Object datos() {


return( nodoDatos );
}

// Modificacion de los elementos de un nodo


public void anterior( NodoListaEnlazada nodo ) {
nodoAnterior = nodo;
}

public void siguiente( NodoListaEnlazada nodo ) {


nodoSiguiente = nodo;
}

public void datos( Object datos ) {


nodoDatos = datos;
}
}

//--------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import NodoListaEnlazada;

// Aqui tenemos la implementacion de una lista enlazada desordenada


// Al igual que con el nodo, si se quiere utilizar en proyectos de
// mas envergadura, habria que dotarla de comprobacion y manejo de
// errores, borrato, iteracion... Es decir, que eso solo sirve como
// ejemplo y para nuestra pequena y simple aplicacion; no debe
// usarse, tal como esta, para nada mas
public class ListaEnlazada {
// Usaremos un nodo 'dummy' para controlar el principio y final
// de la lista doblemente enlazada que estamos implementando,
// lo que nos simplifica bastante las cosas
public NodoListaEnlazada PrincipioFin;

// Mantenemos un contador del numero de nodos en la lista


private int numNodos;

// Constructor basico
public ListaEnlazada() {
// Inicialmente, no hay ningun nodo
numNodos = 0;

// Creamos nuestro nodo dummy


PrincipioFin = new NodoListaEnlazada();

// Hacemos que los apuntadores del nodo dummy lo hagan a


// si mismo, incluso que sus datos se refieran a los suyos
[Link]( PrincipioFin,PrincipioFin,PrincipioFin );
}

// Acceso al numero de nodos


public int longitud() {
return( numNodos );
}

// Modificacion del numero de nodos


private protected void incLongitud() {
numNodos++;
}

private protected void decLongitud() {


numNodos--;
}
// Insertamos los datos que nos indiquen como nueva cabecera
// de la lista
public void insertAtHead( Object datos ) {
NodoListaEnlazada nuevoNodo;

nuevoNodo = new NodoListaEnlazada();


[Link]( PrincipioFin,datos );
incLongitud();
}

// Insertamos los datos que nos indiquen al final de la lista


public void insertAlFinal( Object datos ) {
NodoListaEnlazada nuevoNodo;

nuevoNodo = new NodoListaEnlazada();


[Link]( PrincipioFin,datos );
incLongitud();
}

// Insertamos los datos en la posicion que nos digan, o al


// final de la lista en caso de que no sea tan larga como
// indique el indice
public void insertAt( int indice,Object datos ) {
// Comprobamos que la lista tenga suficientes nodos
if( longitud() < indice )
{
// Si no los tiene, insertamos al final
insertAlFinal( datos );
}
else
{
NodoListaEnlazada tempNodo;
NodoListaEnlazada nuevoNodo;

// Vamos saltando de nodo en nodo hasta llegar al indicado


tempNodo = PrincipioFin;
for( int i=0; i < indice; i++ )
tempNodo = [Link]();

// Creamos un nuevo nodo en esa posicion y lo incorporamos a


// la lista
nuevoNodo = new NodoListaEnlazada( tempNodo,
[Link](),datos );
incLongitud();
}
}

// Recupera los datos de un determinado nodo (o del ultimo elemento


// si la lista no tiene tantos nodos), o devuelve null si la
// lista esta vacia
public Object getAt( int indice ) {
// Comprobamos si la lista tiene tantos nodos como indica el indice
if( longitud() < indice )
{
// Comprobamos que la lista no este vacia
if( longitud() == 0 )
// La lista esta todavia vacia
return( null );
else
return( [Link]() );
}
else
{
// Estamos dentro del rango de la lista
NodoListaEnlazada tempNodo;

// Vamos saltando por los nodos hasta alcanzar el pedido


tempNodo = [Link]();
for( int i=0; i < indice; i++ )
tempNodo = [Link]();
// Devolvemos los datos de ese nodo
return( [Link]() );
}
}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Oct-1996 15:01:15
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import Habitacion;
import ListaEnlazada;

// Aqui tenemos otra demostracion, en este caso utilizamos para


// levantar nuestro Hotel las referencias Java y estructuras
// de datos complejas, como la Lista Doblemente Enlazada
public class Hotel3 {
// Numero de habitaciones en cada ala del Hotel
public static final int habPorAla = 12;

public static void main( String args[] ) {


// Creamos el llavero para guardar todas las llaves
// de las habitaciones
// Comenzamos con un ala simple sobre un solo piso que
// contiene 12 habitaciones
ListaEnlazada llaveMaestra;
llaveMaestra = new ListaEnlazada();

// Ahora, creamos cada una de las habitaciones y guardamos


// su llave en el llavero maestro
int pisoNum = 1;
for( int i=0; i < habPorAla; i++ )
{
// Los numeros de las habitaciones se dan en miles para que
// al imprimir quede mas bonito. Las habitaciones pares las
// ponemos con 1 cama y las impares con 2 camas
[Link]( i,new Habitacion( pisoNum * 1000 + i,
( 0 == (i % 2)) ? 2 : 1 ) );
}

// Imprimimos los datos, para ver lo que hemos hecho


for( int i=0; i < habPorAla; i++ )
( (Habitacion)[Link](i) ).printData();
}
}

//-------------------------------------------- Final del fichero [Link]


DECLARACION DE INTENCIONES
Antes de nada, vamos con una Declaración de Intenciones y un poco de explicación del porqué este
Tutorial de Java está aquí.

Este tutorial va dirigido a todos aquellos que intentan entrar en el mundo Java, que han oído o leído cosas,
pero no saben a ciencia cierta que es eso de Java. Procuraremos ser lo más claros posible, aunque no
podremos evitar la influencia de los gustos personales, pero intentaremos que el contenido se adapte lo
mejor posible a la mayor parte de la audiencia.

Java es una palabra que actualmente está en boca de todos y ha creado una auténtica revolución. Nosotros
nos enfocaremos al lenguaje Java, y la verdad es que no es para tanto el armar ese revuelo. Cierto es que
Java es una gran idea, pero, no escandalosamente genial. Quizá todo se haya visto magnificado por
Internet, pero Java se anuncia como un lenguaje completo de propósito general y, bueno, hay ciertas
porciones del mismo que no están definidas o son discutibles, y algunas características son ciertamente
oscuras. A lo largo del Tutorial iremos presentando todas esas cosas.

La creación de este tutorial ha partido de la necesidad de aprendizaje del lenguaje Java para implantarlo en
aplicaciones críticas. Se necesitaba una evaluación del lenguaje para comprobar si podría emplearse en el
desarrollo de pequeñas aplicaciones (no necesariamente con Internet por medio, aunque también). Esto ha
hecho que hayamos investigado en muchas fuentes, principalmente de Sun Microsystems, y obtenido las
conclusiones a que queríamos llegar. Que resumiendo vienen a indicarnos que, tal como se encuentra
definido Java actualmente y con las herramientas que hay, si no hay inter‰s en Internet, lo mejor es
olvidarse de Java.

En toda esta historia nos hemos dado cuenta de que falta literatura en castellano; como siempre, vamos a
remolque. Por ello, vamos a desarrollar este Tutorial de Java, que esperamos (espero) humildemente, sea
de provecho para alguien. Eso sería ya una gran satisfacción para mi. Quizá yo no sea la persona más
indicada para estar escribiendo esto, porque todavía soy un principiante en Java, pero sí que puedo
transmitir los pocos conocimientos que he adquirido, y eso es lo que haré.

Todas las sugerencias que alguien pueda ofrecer, será bienvenida. Prometemos (prometo) contestar a todo
el mundo, si no me sobrepasa el correo. Y nos gustaría que pudiésemos ir haciendo crecer este Tutorial de
Java entre mucha más gente. No obstante, la experiencia de muchos años de BBS me dice que hay mucho
escuchador y poco participador, por lo que el tutorial esta casi planteado en un noventa por ciento.
Aunque, repito, todas las colaboraciones serán bienvenidas y si van con el estilo, incluidas en el Tutorial
de Java que arranca aquí.

Y una recomendación final, antes de que alguien se decida a publicar un applet nada más terminar de
leerse este u otro Tutorial sobre Java. Hay que ser críticos con nuestro trabajo. Debemos valorar mucho
nuestra estima y, por ende, el código que escribimos bajo nuestro nombre. Actualmente hay muchos
applets que se pueden visualizar y, desgraciadamente, bastantes de ellos son de muy baja calidad, escritos
por programadores que están dando sus primeros balbuceos en Java. Más que applets son crapplets ( crap
es una forma coloquial de mierda); algunos de ellos incluso se quedan colgados o no tienen un
rendimiento mínimo aceptable. Debemos renunciar a una excesiva rapidez de desarrollo en beneficio de un
código fiable y bien diseñado. Y parafraseando palabras de Alex Newman, director ejecutivo de Sun User
Group/Java: "Hay un montón de buenos programadores que no se dedican a ir por ahí vendiendo código.
Lo que hacen es buscar trabajo. Saber programar en Java será algo positivo para incluir en el
currículum".

Aclaraciones

No tenemos nada que ver con Sun Microsystems, por lo que todas las cosas que aquí leas son de entera
responsabilidad nuestra (mía) y ni Sun ni nadie relacionado con Sun tiene algo que ver en ellas.

La libre distribución de este documento está totalmente permitida, siempre que no se modifique su
contenido, o si se publican partes de él, éstas sean transcripciones literales. Y en cualquier caso, citar el
origen.

Hay partes del documento que son traducción libre del Java Tutorial de Sun Microsystems, por lo que el
copyright les pertenece a ellos. Además, HotJava(tm), Java(tm), Duke y Java Workshop(tm) son marcas
registradas de Sun.

Tutorial de Java [Home] [Indice] [Presentación]


PRESENTACION
En este tutorial presentaremos una visión general del lenguaje de programación Java, incluyendo la
programación de applets y aplicaciones. También trataremos algunas características avanzadas y el API
del lenguaje Java.

No obstante, y para que todos tengamos una idea general de lo que es Java, haremos una serie de
aclaraciones o indicaciones, para que alguien que no esté muy decidido a aprender Java, pueda tener
elementos de juicio y de comparación para tomar esa decisión. Por ello, haremos una introducción más
extensa de lo que sería habitual en un tutorial, lo que también me permitirá verter ciertas opiniones que en
otro sitio no tendrían cabida.

Conocimientos previos...

En el planteamiento inicial se supone que tú, que estás leyendo esto, tienes experiencia en algún lenguaje
de programación, como puede ser C o un lenguaje similar , también sabes utilizar un navegador de WWW
como Netscape o Internet Explorer, también eres capaz de desarrollar páginas WWW con HTML y
comprendes la programación orientada a objetos. Intentaremos que estos conocimientos sean suficientes
para poder seguir el tutorial.

El entorno de desarrollo habitual entre la gente que trabajamos con el JDK (los pobres sin poder para
comprarse herramientas comerciales) consiste en tener abiertas sobre el escritorio de la pantalla, ya sea en
Solaris, Windows '95/NT o Linux, varias ventanas, que usamos para lo siguiente:

● En una de ellas tenemos abierto HotJava, apuntando al fichero [Link] de la documentación


del API de Java, para poder tener al momento la información sobre los parámetros de llamada,
valores de retorno y la información de cada una de las funciones que estemos utilizando.
● Los que estén desarrollando sobre Windows '95 o NT, podrán disponer de la documentación del
API tambi‰n desde el sistema de ayuda de Windows si han descargado esta documentación en
formato Winhelp desde Dippy.
● En otra tendremos abierto un navegador con soporte Java, normalmente será Netscape, en una
versión superior a la 2.0b4, para que tenga soporte audio en los applets que desarrollemos, o
Microsoft Explorer, en versión 3.0 o superior.
● Tendremos abierta otra ventana con un editor, donde iremos escribiendo el código de nuestro applet
o aplicación Java. En Windows '95 son muy utilizados el editor Jpad y Diva. Aunque en estos
momentos, quien tiene potencia suficiente en su ordenador, está programando Java desde el Java
Workshop de Sun.
● Y una ventana más donde tendremos acceso al prompt del sistema para poder invocar al
compilador y a las demás herramientas del JDK.
● Los que tengan algo de dinero podrán estar utilizando alguno de los entornos shareware que ya hay
disponibles como RadJa, Kawa o JavaMaker.
● Los que sí disponen de poder adquisitivo suficiente habrán empezado con el Symantec Café de
Symantec, porque ahora estarán trabajando con Borland C++ 5.0, que soporta Java o estarán
entusiasmados con el Visual J++ de Microsoft o estarán deseando ver ya en sus pantallas el
Borland Latte.
● Y los enamorados de OS2, que en su versión 4.0 ya incluye una Máquina Virtual Java (JVM) en su
kernel, se lo pasarán en grande con el IBM VisualAge for Java.

Objetivos

Los objetivos que nos hemos marcado, para que tú, navegante lector, cuando llegues al final del tutorial,
seas capaz de:

● Crear páginas HTML que llamen a applets Java


● Crear contextos gráficos en Java
● Utilizar los componentes del interfaz gráfico que proporciona Java
● Crear aplicaciones autónomas en Java
● Crear aplicaciones multi-threaded
● Utilizar las librerías de E/S para manipular ficheros de texto y datos
● Crear servidores y clientes TCP/IP que se comuniquen vía socket

Intentaremos cumplir lo que acabamos de prometer, aunque también pedimos paciencia, ya que Java, en
este momento, es un lenguaje con una notable vitalidad, que todavía estamos aprendiendo nosotros. Por
otro lado, no es nada sencillo el hacerse entender, por lo que tenemos que dar varias vueltas a cada uno de
los conceptos que escribimos para cerciorarnos de que tú que lo lees comprendes exactamente lo que
nosotros te queremos transmitir.

Además, tampoco esperes que te proporcionemos ungüentos milagrosos, que por arte de magia traspasen
el conocimiento. El estudio de Java, y sus applets, no será sino el examen de una particular forma de ver
las cosas, con un poco de estructuración en la presentación y un cierto trasfondo de Internet; el resto es,
como siempre, tarea del programador. Es decir, uno puede aprender a construir un applet, o dejar que
alguna de las herramientas lo construyan automáticamente, igual que puede enseñarse a codificar un
diálogo en un entorno gráfico, pero... la inteligencia de esa pieza siempre dependerá de la habilidad y
experiencia del programador respecto del lenguaje usado y de sus recursos. En fin, un buen applet será
únicamente resultado del trabajo de un buen programador Java.

A empezar...

Te recomendamos que, si vas a seguir el Tutorial a la vez que nosotros vayamos publicando capítulos,
utilices las opciones Hotlist o Bookmark de tu navegador para marcar la página por la que vas y poder
pasar fácilmente de unos capítulos a otros.
Hemos escrito el Tutorial de Java, enfocado a Netscape, en cualquier otro navegador se verá
decentemente, pero bien, bien... con Netscape, porque nos será imprescindible, al ser el más extendido de
los navegadores con soporte Java.

Y ya puedes pasar a ver lo que hemos preparado, para ello puedes empezar viendo como Navegar a través
del Tutorial o pasar directamente a la Tabla de Contenido, donde encontrarás enlaces con cada uno de los
capítulos y apartados.

Buena Suerte.

Tutorial de Java [Intenciones] [Indice] [Siguiente]


En la parte inferior de cada una de las páginas que componen el Tutorial de Java, podrás encontrar una
barra con tres iconos que permiten el desplazamiento a través del Tutorial. Esos tres iconos son:

Presenta la página anterior a la que estamos visualizando en la pantalla del navegador

Presenta la página siguiente a la que estamos visualizando en la pantalla del navegador

Nos desplaza directamente a la página de la Tabla de Contenido

Icono inactivo, es decir, que aunque se pulse sobre él, no pasará nada

Este es un menú con los iconos con igual significado, es decir, que sus acciones
con como las de sus semejantes anteriores, pero se encuentra situado
inmediatamente debajo del título de la página, para evitar tener que desplazarse al
final de la misma para pasar a la siguiente en secuencia

En la Tabla de Contenido es donde está el índice del documento totalmente desplegado, con enlaces a cada
uno de los capítulos y apartados de éstos.

La navegación se realiza a dos niveles: a nivel de capítulos y a nivel de apartados. Por ejemplo, si estamos
en una página que corresponde con el encabezado de un capítulo, la opción de ir a la Siguiente página nos
llevará al siguiente capítulo. Sin embargo, si seleccionamos uno de los apartados del capítulo en la tabla
de cotenido que corresponde al capítulo, que se presenta en cada una de las páginas principales de los
capítulos; se nos presentará la página que desarrolla el tema seleccionado en el apartado. Ahora, las
opciones de ir al Siguiente o al Anterior, nos harán desplazarnos por los distintos apartados de este
capítulo.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ETIQUETA
Vamos a desarrolllar un nuevo Componente para el AWT, para mejorar el Label que se proporciona con el AWT,
añadiéndole al original cosas como bordes, efectos de sombreado, etc., o posibilidad de fijarle características como el
color o el font de caracteres con que se presentará en pantalla.

En el código fuente de la clase, [Link], hemos introducido gran cantidad de comentarios, por lo que
explicaciones aquí serían redundantes, en la mayoría de las sentencias para que se vaya siguiendo paso a paso la
construcción y entendiendo qué hace cada uno de los métodos y, para que resulte sencillo al lector el añadir nuevos
tipos de efectos sobre el texto de la Etiqueta.

El applet [Link] presenta las tres posibilidades de presentar texto en pantalla que hemos implementado:
Texto normal, resaltado y hundido. A continuación se muestra el resultado de la ejecución del applet.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


RELOJ DIGITAL
Seguramente, siempre que hagamos una aplicación con una envergadura mínima, necesitaremos un temporizador.
Así que vamos a implementar uno que llegue a resolución de segundos; porque, también es casi seguro, que en una
aplicación normal, no necesitaremos más precisión.

Vamos a implementar nuestro temporizador, [Link], de la forma más general, haciendo que tenga un time-out,
que se pueda resetear automática o manualmente y lo vamos a construir como un thread individual, con lo cual,
podremos tener tantos timers como queramos.

La interface Temporizador, [Link], nos proporciona los métodos que necesitamos para implementar el
funcionamiento del Timer, es decir, que consideraremos al Timer como un elemento observable, de forma que
notifique a los observadores cuando algún evento ocurra, como puede ser el arranque del timer, la pérdida o su
muerte. Así, si una clase determinada quiere ser avisada cuando le ocurra algo al timer, debe implementar la interface
Temporizador, dejando vacíos los métodos que corresponden a los eventos que no le interese recoger.

La interface Temporizador consiste en cuatro métodos, de los cuales los más interesante son timerMuerto(), que se
llama cuando la duración del timer se ha cumplido y, timerIntervalo(), que ocurre a intervalos regulares, según el
tiempo que hayamos fijado.

Si una clase necesita más de un timer, puede implementar esta interface, pero entonces necesitaríamos incorporar a la
clase que la use métodos para que fije e indique su nombre; de este modo, los timers estarán identificados dentro de
la interface Temporizador y no habrá problemas al estar varios timers corriendo a la vez.

El applet que presentamos, [Link], simplemente recoge la hora del sistema y la va actualizando cada
segundo utilizando un timer. Hacemos uso también del componente Etiqueta que hemos desarrollado en otro
ejemplo, para presentar el texto con la hora en la pantalla.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


PERSIANA
Este applet presenta información desplazándose a través de la zona de pantalla que constituye el applet. Podemos
incorporar cualquier tipo de información para que sea presentada en pantalla, tal como se muestra en el ejemplo de
esta misma página. Se pueden conseguir múltiples efectos, a través de la selección de fuentes y utilización de colores.

El texto que se presenta en la pantalla va incluido en el fichero de código fuente, [Link], y no en la llamada al
applet. Además, se puede incorporar un dibujo de fondo, que será presentado a la vez que se ejecute el applet. El
código de este applet es muy sencillo y fácil de comprender, a pesar de que el efecto que se visualiza en pantalla
sugiera una programación complicada.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


SOLAPAS
Este applet nos muestra cómo se pueden incorporar nuevos Componentes al AWT. Hemos diseñado un sistema de
solapas o Tabs, como se suelen reconocer, para incorporar a nuestras aplicaciones. En el fichero [Link], se
encuentra el código que muestra cómo se usa y que corresponde a la ejecución del applet que aparece en esta misma
página.

Los ficheros de código fuente que se emplean para la implementación del sistema de solapas propuesto son:

[Link]

Se encarga de presentar el cuerpo de la ficha que corresponde a una solapa. Nos permite incorporar
cualquier otro elemento que deseemos a esa ficha, tal como muestra el ejemplo, en el cual hemos
añadido diferentes componentes a cada una de las fichas que se abren al seleccionar las solapas.

[Link]

Se encarga de gestionar cada una de las solapas. Nos indica cuando se ha pulsado en una solapa y tiene
implementados los métodos necesarios para indicarnos cuando una solapa está selecciona o no, cuando
se pica con el ratón dentro de una solapa, o para resaltar la solapa cuando se selecciona, entre otros.

[Link]

Este fichero contiene una clase compuesta de dos Objetos, uno de clase Solapa y otro de clase
CuerpoFicha. Se encarga de gestionar la presentación de la Ficha al completo, de forma que cuando se
selecciona una solapa, se presenta el contenido del objeto CuerpoFicha que tiene asociado ese objeto
Solapa que se ha elegido.

[Link]

Contiene un objeto Vector con todas las fichas que hayamos incorporado al applet. Aquí es donde
podemos indicar que el applet contendrá más o menos Fichas, que estarán representadas por las
Solapas que el usuario podrá elegir con el ratón.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:
Tutorial de Java [Anterior] [Indice] [Siguiente]
TRANSPARENCIA
Vamos a mostrar en esta aplicación un ejemplo de las nuevas técnicas que se están desarrollando actualmente.
Utilizaremos para demostrar este método de Transparencia el dibujo de presentación de la Home Page del Workshop
de Sun.

No sé si el applet está hecho tal como yo lo voy a reproducir, pero el resultado que obtendremos será exactamente el
mismo.

La técnica es muy sencilla, consiste en tener un dibujo grande con varias imágenes de la zona que queremos
reproducir en pantalla, y utilizando los eventos del ratón, presentamos una imagen u otra. Primero desarrollamos una
clase para que controle el repintado de las distintas imágenes, [Link], que se van a ir presentando y que no
se repinte la zona total del applet, lo que produciría un desagradable efecto de parpadeo. Luego extenderemos esta
clase para la imagen completa, creando instancias de objetos BotonImg ([Link]), que son los que van a
controlar cada una de las opciones. Funcionan como botones normales, sólo que cotnrolan de forma exhaustiva los
eventos que llegan del ratón, [Link]. Finalmente, en la clase MenuDeBotones ([Link]) es
donde creamos la clase principal, cargando la imagen de fondo y recuperando todos los parámetros que se pasen en la
llamada al applet.

Como podrá observarse, el código es muy sencillo y fácil de entender, y el resultado es altamente profesional (tanto,
que hasta Sun lo utiliza). Espero no haber violado ningún secreto comercial al reproducir el funcionamiento del
applet, aunque seguramente el método que he utilizado yo no es ni por asomo el que utiliza Sun. Yo no dejo de ser un
mero aficionado.

Esta técnica se puede utilizar con otras imágenes, otras opciones, y otros lanzamientos a direcciones. Espero que a
alguien pueda serle útil.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:
Applet Transparencia

Tutorial de Java [Anterior] [Indice] [Siguiente]


CALCULADORA
El applet [Link] presenta una calculadora básica, tomando como herramienta de construcción el AWT. Es
una calculadora que realiza las operaciones más habituales, tipo calculadora solar, pero que ilustra perfectamente los
mecanismos de presentación en pantalla de Componentes del AWT sobre un layout propio, ya que todos los botones
se colocan en posiciones determinadas.

Las operaciones matemáticas no son motivo de estudio, pero sí se podr•a completar la calculadora con más funciones
y hacerla semejante a las que se proporcionan con casi todos los entornos gráficos. La clase BotonCalculadora es la
fundamental en este ejemplo, ya que nos permite colocar botones en cualquier sitio y con cualquier tamaño.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


CUENTA-KILOMETROS
El applet [Link] presenta una imagen conocida de cuenta-kilómetros de coche, pero cuyo código nos sirve
para demostrar varias cosas. Podemos comprobar cómo se manipula el offset de un dibujo porque la imagen de los
números es un fichero gráfico que contiene los 10 dígitos posibles, y el contador va seleccionando cada uno de ellos
en función de la cifra que tiene que representar el cuanta-kilómetros. También podemos comprobar la utilización de
threads para la implementación del intervalo de tiempo que tarda el cuenta-kilómetros en pasar de una cifra a la
siguiente.

En la llamada al applet, podemos indicar el número de dígitos que va a contener el cuenta-kilómetros, el intervalo de
tiempo que transcurrirá entre los cambios de cifras y el valor incial en que arranca el contador. Además, como es un
applet muy sencillo, lo hemos adornado con algunas opciones, por ejemplo:

● Con la tecla "+" aceleramos el contador


● Con la tecla "-" disminuímos la velocidad con que cambian los números en el cuenta-kilómetros
● Con la tecla "0" ponemos a cero el contador
● Utilizando el ratón, si picamos una vez sobre el cuenta-kilómetros, se detiene la cuenta, y si picamos una
segunda vez, vuelve a seguir contando

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


POTENCIOMETRO
El applet [Link] presenta un ejemplo de uso de un Componente nuevo que hemos implementado para
incorporar a las posibilidades que ofrece el AWT. Se trata de una Barra de Desplazamiento, pero semejando el
potenciómetro deslizante de un equipo electrónico.

Incorpora una serie de posibilidades nuestro Componente [Link], que el ejemplo permite utilizar y
comporbar, como es el posicionamiento de la escala indicadora. En el applet ejemplo, hemos utilizado el
Componente Grupo, que ya habíamos implementado el capítulos anteriores.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


CARTEL
de Luis Angel Ortega
Este applet, [Link], resenta un texto en una sola línea que se desplaza a derecha o izquierda y es una contribución
de un lector del Tutorial. Lo siguiente es suyo.

-------------------------------sic
Applet de libre distribución, puedes enviar tus sugerencias a Luis Angel Ortega para compartir información y
conocimientos sobre el lenguaje Java y Internet.

Datos del autor:

Nombre: Luis Angel Ortega ¨LAO 1996


Dirección: lao@[Link]
Puedes visitar su Página Personal

-------------------------------sic

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Applet Cartel (Luis Angel Ortega)


Tutorial de Java [Anterior] [Indice] [Siguiente]
//*************************************************************************
// [Link]: Applet //
// //
// Propiedad LAO ® 1996 Luis Angel Ortega Todos los derechos reservados //
// //
// Permiso para usar copiar, modificar, y distribuir este software //
// y su documentacion, sin propositos comerciales. //
// //
// Para cualquier duda o comentario con el autor lao@[Link] //
// //
// Pagina WEB [Link] //
// //
// El autor no se resposabiliza de posibles daños que el software //
// pueda efectuar en cualquier equipo informatico. //
// //
// //
// Autor: Luis Angel Ortega LAO 25/11/1996 //
// Creado con Microsoft Visual J++ Version 1.0 //
// //
// El Applet es de libre distribucion, presenta un texto que se //
// desplaza a derecha o izquierda. //
// //
// Los parámetros son los siguientes: //
// //
// ==================================================================== //
// PARAMETROS | VALORES DE LOS PARAMETROS //
// ===================================================================== //
// TEXTO = Cadena de texto a desplazar. | "Texto a desplazar" //
// ===================================================================== //
// DESPLAZAMIENTO = Desplazar el texto | "IZQUIERDA" //
// a izquierda o derecha. | "DERECHA" //
// =================================================================== //
// COLORFONDO = Color para el fondo | "ROJO" //
// del texto. | "AZUL" //
// | "NEGRO" //
// | "BLANCO" //
// =================================================================== //
// COLORTEXTO = Color para el texto | "ROJO" //
// | "AZUL" //
// | "NEGRO" //
// | "BLANCO" //
// =================================================================== //
// WIDTH = Ancho del Applet | Un numero mayor que 12. //
// =================================================================== //
// HEIGHT = Ancho del Applet | Un numero mayor que 12. //
// =================================================================== //
// VELOCIDAD =Velocidad en milisegundos | Un numero mayor que 1 //
// de la actualización en pantalla del | //
// applet, depende de la velocidad del | //
// ordenador donde se visualiza el | //
// applet | //
// =================================================================== //
// //
// Notas: //
// El parámetro de la VELOCIDAD es opcional, por defecto es 10. //
// El texto se ajusta automáticamente al alto del Applet. //
// La velocidad de desplazamiento depende de la velocidad del //
// procesador. //
// Los valores de los parámetros pueden ser en minúsculas o mayúsculas. //
// //
// Ejemplo: //
// //
// <applet code="[Link]" //
// width="200" height="50" id="Cartel"> //
// <param name="COLORFONDO" value="negro"> //
// <param name="COLORTEXTO" value="rojo"> //
// <param name="TEXTO" value="Ejemplo de Applet"> //
// <param name="DESPLAZAMIENTO" value="izquierda"> //
// <param name="VELOCIDAD" value="5"> //
// Tu Visualizador WEB no puede ejecutar código JAVA</applet> //
// //
//*************************************************************************

import [Link].*;
import [Link].*;

public class Cartel extends Applet implements Runnable


{

Thread m_Cartel = null;

// Todas las constantes y Variables excepto Texto, son declaradas


// privadas para no poder ser usadas desde otra clase
// constantes
private final int RESTAFONT = 14;

// Variables
private int Velocidad; // Velocidad del thread en milisegundos
private int CordY; // Cordenada y donde situar el texto
private int CordX; // Cordenada x donde situar el texto
private int StringAncho; // Ancho de la cadena a desplazar
private int SizeDescent;
private Font font; // Tipo de letra del texto
private Dimension d; // Dimensiones del applet
// La misión de estas tres variables es almacenar un objeto gráfico
// en memoria, que es una copia del objeto que se crea al pintar el applet.
private Dimension offDimension;
private Image offImage;
private Graphics offGraphics;

private Color ColorTexto; // Color del texto


private Color ColorFondo; // Color del fondo
public String Texto; // Texto a desplazar
private boolean Scroll; // TRUE=Izquierda FALSE=Derecha

//**********************************************************************//
// Metodo Actualizar() //
// Utilizado para poder cambiar los parametros del applet, mediante //
// codigo en JavaScript o VBscript. //
// Nota: //
// Es posible cambiar el texto sin llamar al metodo Actualizar //
// //
// Entrada: //
// String Text = Texto a desplazar. //
// String Desplaza = Desplaza el texto a "IZQUIERDA O "DERECHA" //
// String ColFondo = Cambia el color del fondo //
// "ROJO","AZUL","NEGRO","BLANCO" //
// String ColTexto = Cambia el color del texto //
// "ROJO","AZUL","NEGRO","BLANCO" //
// String Veloc = Velocidad del Thread en milisegundos. //
// //
// Salida: void //
//**********************************************************************//

public void Actualizar (String Text,String Desplaza,String ColFondo,


String ColTexto, String Veloc)
{

try {

// Comprueba si los datos pasados al metodo son los correctos


ColFondo = [Link](); // Lo convierte a Mayusculas

ColorFondo = ([Link]("ROJO")==0) ? [Link] : ColorFondo;


ColorFondo = ([Link]("AZUL")==0) ? [Link] : ColorFondo;
ColorFondo = ([Link]("NEGRO")==0) ? [Link] : ColorFondo;
ColorFondo = ([Link]("BLANCO")==0) ? [Link] : ColorFondo;

ColTexto = [Link](); // Lo convierte a Mayusculas


ColorTexto = ([Link]("ROJO")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("AZUL")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("NEGRO")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("BLANCO")==0) ? [Link] : ColorTexto;

Desplaza = [Link](); // Lo convierte a Mayusculas


Scroll = ([Link]("DERECHA")==0) ? false : true;

Texto=Text;
offGraphics = null; // La proxima vez que pinte crea un nuevo Graphics
} catch (NullPointerException e) { // Ejecuta este codigo en el caso que
ColorTexto = [Link]; // algunas de las cadenas que preceden
ColorFondo = [Link]; // al catch sean un nulo
Scroll = true;
Texto= "Parametro del applet incorrecto";
Velocidad=10;
}
}

//**********************************************************************//
// Metodo CogerParametros() //
// Recoge los valores pasados como parametros dentro del codigo HTML //
// //
// Entrada: Ninguna //
// //
// Salida: void //
//**********************************************************************//

void CogerParametros ()
{

try {
String Parametro=getParameter("VELOCIDAD");// Obtiene el parametro velocidad

Integer Veloc=[Link](Parametro); // Convierte el String en un


// objeto tipo Integer

Velocidad=[Link](); // Convierte el valor del objeto Integer


// en un entero (int)

} catch (NumberFormatException e) { // La cadena introducida como parametro


// no es un numero entero
Velocidad=10; // Establece la velocidad del Thread
// en 10 milisegundos

} catch (NullPointerException e ) { // Cadena introducida es un nulo


Velocidad=10;
}

try {

// Coge los parametros del applet, los compara y almacena en variables


// el valor adecuado
String Parametro=getParameter ("COLORFONDO");
Parametro=[Link](); // Lo convierte a Mayusculas
ColorFondo = ([Link]("ROJO")==0) ? [Link] : ColorFondo;
ColorFondo = ([Link]("AZUL")==0) ? [Link] : ColorFondo;
ColorFondo = ([Link]("NEGRO")==0) ? [Link] : ColorFondo;
ColorFondo = ([Link]("BLANCO")==0) ? [Link] : ColorFondo;
Parametro=getParameter ("COLORTEXTO");
Parametro=[Link](); // Lo convierte a Mayusculas
ColorTexto = ([Link]("ROJO")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("AZUL")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("NEGRO")==0) ? [Link] : ColorTexto;
ColorTexto = ([Link]("BLANCO")==0) ? [Link] : ColorTexto;

Parametro=getParameter ("DESPLAZAMIENTO");
Parametro=[Link](); // Lo convierte a Mayusculas
Scroll = ([Link]("DERECHA")==0) ? false : true;

Texto=getParameter ("TEXTO"); // Coge el texto

}
catch (NullPointerException e) { // Excepcion producida por alguna
// cadena vacia o nula
ColorTexto = [Link];
ColorFondo = [Link];
Scroll = true;
Texto = "Parametro del applet incorrecto";
}
}

//**********************************************************************//
// Metodo update() //
// Es llamado por el metodo repaint(), cada vez que se dispara el thread//
// //
// La primera vez que es llamado crea una copia en memoria //
// (doble buffer) del objeto Graphics g. //
// Una vez creado, todos los elementos graficos, son dibujados //
// sobre el buffer offGraphics, una vez dibujados son mostrados en la //
// pantalla del sistema. //
// //
// Entrada: Graphics g //
// //
// Salida: void //
//**********************************************************************//

public void update (Graphics g)


{
// Si offGraphics no existe o cambia de tamaño lo crea
if ( (offGraphics == null) ||
([Link] != [Link]) ||
([Link] != [Link]) ) {
offDimension = d;
offImage = createImage ([Link], [Link]); // Crea la imagen en
// memoria
offGraphics = [Link](); // Almacena el objeto
// grafico en memoria

// Establece el font
[Link] (font);

// Establece la medida descent del Font


FontMetrics fontmetrics = [Link]();
SizeDescent = [Link]();
// Almacena el ancho del la cadena
StringAncho = [Link](Texto);

// Establece las cordenadas de comienzo dependiendo de la variable


// Scroll (desplazamiento a derecha o izquierda)
CordX = Scroll ? [Link] : -StringAncho;
CordY=([Link]-SizeDescent)-7;
}
// Borra la imagen previa que tenemos en el buffer
[Link](getBackground());
[Link](0,0, [Link] , [Link]);
[Link] ([Link]);

[Link] (ColorFondo); // Establece el color de fondo


[Link] (0,0,[Link],[Link]); // Rellena el fondo

[Link](ColorTexto); // Establece el color de texto


[Link] (Texto,CordX,CordY); // Pinta el texto

CordX= Scroll ? --CordX : ++CordX; //Suma o resta la cordenada X,


// dependiendo del valor de la
// variable Scroll

// Comprueba si el texto que se desplaza llega al final del margen


// izquierdo o derecho del applet
if (CordX == [Link] ) CordX=-StringAncho; //Derecha
else if (CordX == -StringAncho) CordX=[Link]; // Izquierda

// Dibuja el marco del applet


[Link] ([Link]);
offGraphics.fill3DRect (0,0,[Link],5,true);
offGraphics.fill3DRect (0,([Link]-5),[Link],5,true);
offGraphics.fill3DRect (0,0,5,[Link],true);
offGraphics.fill3DRect (([Link]-5),0,5,[Link],true);

[Link] (offImage, 0 ,0 ,this); // Muestra la imagen almacenada


// en el buffer
}

//**********************************************************************//
// Metodo Cartel() //
// Constructor de la clase //
// //
// Entrada: Ninguna //
// //
// Salida: void //
//**********************************************************************//

public Cartel()
{
// Sin codigo
}

//**********************************************************************//
// Metodo getAppletInfo() //
// //
// Retorna los datos del applet, autor y sistema de desarrollo //
// //
// Entrada: Ninguna //
// //
// Salida: String //
//**********************************************************************//

public String getAppletInfo()


{
return "Name: Cartel\r\n" +
"Author: Luis Angel Ortega LAO 25/11/1996\r\n" +
"Created with Microsoft Visual J++ Version 1.0";
}

//**********************************************************************//
// Metodo init //
// //
// Este metodo es llamado por el AWT cuando el applet es cargado por //
// primera vez, o necesita ser recargado. //
// //
// Entrada: Ninguna //
// //
// Salida: Void //
//**********************************************************************//

public void init()


{
d = size(); // Almacena las dimensiones del applet
resize([Link],[Link]); // Redimensiona el applet de nuevo
// Es nesario en el caso de que se vuelva a
// cargar el applet

Toolkit toolkit = [Link]();


String h[] = [Link](); // Almacena en h todos los
// tipos de letra

// Crea un nuevo font con con el atributo de normal


// y el tamaño del ancho del applet menos RESTAFONT (14)
font = new Font (h[1],[Link],([Link]-RESTAFONT));

CogerParametros(); // Llama al metodo para coger los


// parametros del applet
}

//**********************************************************************//
// Metodo destroy() //
// //
// Este metodo es llamado cuando el applet es destruido de memoria //
// //
// Entrada: Ninguna //
// //
// Salida: Void //
//**********************************************************************//

public void destroy()


{
// Sin codigo
}

//**********************************************************************//
// Metodo paint() //
// //
// Este metodo es llamado cuando el applet necesita ser pintado. //
// Si colocamos una ventana que oculte el applet, o parte del mismo, //
// desplazamos o quitamos la ventana, se produce el evento paint. //
// //
// Nota: //
// La llamada de repaint no produce necesariamente la llamada al paint//
// //
// Entrada: Graphics g //
// //
// Salida: Void //
//**********************************************************************//

public void paint(Graphics g)


{
if (offImage != null ) { // Si offImage existe visuliza la imagen

[Link](offImage, 0 ,0 ,this);
}
}

//**********************************************************************//
// Metodo start //
// //
// Entrada: Ninguna //
// //
// Salida: Void //
//**********************************************************************//
public void start()
{
if (m_Cartel == null) // Si no existe el Thread lo crea
{
m_Cartel = new Thread(this);
m_Cartel.start(); // Produce la llamada al metodo run()
}
}

//**********************************************************************//
// Metodo stop //
// //
// Este metodo se produce cuando cambiamos de pagina o cerramos //
// el visualizador //
// La llamada al metodo provoca la parada del Thread //
// //
// Entrada: Ninguna //
// //
// Salida: Void //
//**********************************************************************//

public void stop()


{
if (m_Cartel != null) // Provoca la parada del Thread
{
m_Cartel.stop();
m_Cartel = null;
}
}

//**********************************************************************//
// Metodo run() //
// //
// Este metodo es llamado cuando el applet del Thread es llamado //
// //
// Entrada:Ninguna //
// //
// Salida: Void //
//**********************************************************************//

public void run()


{
while (true) // Produce un bucle infinito
{
try
{
repaint(); // Llama al metodo update()
[Link](Velocidad); // Establece la velocidad del Thread
}
catch (InterruptedException e) // Excepcion
{
stop(); // Llama al metodo stop() para el Thread
}
}
}

} //Final del la clase


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class Etiqueta extends Panel {


private String texto = "";
private Font font = null;
private FontMetrics metrica = null;
private Color color = [Link];
private int ancho = 0;
private int alto = 0;
private int sombra = 0;
private boolean borde = false;

// Declaramos las variables que indican como aparecera el texto en


// pantalla, para ello las hacemos "public" para que sean visibles
// a otras clases, "static" para que la compartan todos los objetos
// de la clase y "final" porque son valores constantes, que no van
// a variar de ninguna de las maneras
public static final int TextoNormal = 0;
public static final int TextoResaltado = 1;
public static final int TextoHundido = 2;

// Constructor basico, con una cadena vacia


public Etiqueta() {
this( "" );
}

// Constructor de conveniencia al que le pasamos una cadena de texto


// que se presentara con los valores de defecto
public Etiqueta( String Texto ) {
setText( Texto );
}

// Constructor de conveniencia al que le pasamos todos los datos


// para que pinte el texto como nostros queremos
// Tiene la particularidad de que lo podemos utilizar como plantilla
// para crear otros objetos que sean iguales a uno que ya tengamos,
// porque le pasamos este nuestro objeto y nos devuelve otro con
// las mismas caracteristicas
// Solo fijamos las caracteristicas, no indicamos el texto a
// presentar
public Etiqueta( Etiqueta plantilla ) {
copiaPlantilla( plantilla );
}
// Constructor de conveniencia completo, en el que le decimos
// el texto que debe aparecer y las caracteristicas con que
// debe presentarlo en pantalla
public Etiqueta( String Texto,Etiqueta plantilla ) {
copiaPlantilla( plantilla );
setText( Texto );
}

// Metodo que pasa los valores de las caracteristicas con que


// queremos pintar, a los atributos del objeto Texto que
// vamos a hacer aparecer en pantalla, crea un objeto a partir
// de otro
public void copiaPlantilla( Etiqueta plantilla ) {
texto = [Link];
font = [Link];
metrica = [Link];
color = [Link];
ancho = [Link];
sombra = [Link];
borde = [Link];
}

// Nos aseguramos de que se seleccione una fuente para pintar los


// caracteres. Si no se indica una, la creamos nosotros de la
// forma mas sencilla posible
public void checkFont() {
if( font == null )
font = new Font( "Helvetica",[Link],12 );
}

// Fija la cadena de texto que se va a presentar, asegurandose


// de que se indica con que font de caracteres queremos hacerlo,
// luego copia el texto en un miembro local y hace que el panel
// se repinte
public void setText( String Texto ) {
checkFont();
texto = Texto;
repaint();
}

// Fijamos una nueva fuente de caracteres para pintar el texto


public void setFont( String nombre,int estilo,int tam ) {
font = new Font( nombre,estilo,tam );
}

// Fijamos el ancho del rectangulo en donde vamos a inscribir el


// texto
public void setAncho( int Ancho ) {
ancho = Ancho;
}

// Fijamos la altura del rectangulo en donde vamos a inscribir el


// texto
public void setAlto( int Alto ) {
alto = Alto;
}

// Fijamos el color con que queremos presentar el texto en pantalla


public void setColor( Color cColor ) {
color = cColor;
}

// Fijamos los pixels de desplazamiento que habra respecto de los


// dos texto que se escriben para dar el efecto de sombra.
// Para conseguir este efecto, simplemente pintamos el texto con el
// color seleccionado para la sombra y luego lo volvemos a pintar
// con el color del texto y desplazado tantos pixels como indique
// este paramentro
public void setSombra( int Sombra ) {
sombra = Sombra;
}

// Fija el tamano del borde del rectangulo que circunscribe al


// texto que estamos presentando en pantalla
public void setBorde( boolean Borde ) {
borde = Borde;
}

// Funciones de recuperacion, equivalentes a las del grupo 'set',


// utilizadas para recuperar los atributos actueles fijados para
// el texto que actualmente se presenta en pantalla
public String getText() {
return( texto );
}

public Font getFont() {


return( font );
}

public int getAncho() {


return( ancho );
}

public Color getColor() {


return( color );
}

public int getSombra() {


return( sombra );
}

public boolean getBorde() {


return( borde );
}

// Este metodo se llama automaticamente cuando el objeto aparece


// en pantalla por primera vez o cuando se ve expuesto de nuevo,
// tras haber estado tapado por otra ventana
public void paint( Graphics g ) {
update( g );
}

// Este metodo es llamado por el propio objeto para mostrar


// en pantalla algo que haya cambiado o porque alguien lo llame
// directamente, como en el caso de update
public void update( Graphics g ) {
// Borramos todo el area que va a ocupar el texto
Color color = [Link]();
[Link]( 0,0,bounds().width,bounds().height );
// Si va a llevar borde el rectangulo que delimita el espacio en
// donde se va a pintar el texto, se lo ponemos
if( borde )
{
[Link]( [Link] );
g.draw3DRect( 0,0,bounds().width-1,bounds().height-1,false );
}
drawText( g );
[Link]( color );
}

// Este es el metodo encargado de pintar realmente el texto en la


// pantalla
private void drawText( Graphics g ) {
// Si no hay texto que pintar, nos vamos
if( texto == null )
return;

// Convertimos el texto en un array de caracteres


char caracteres[] = [Link]();
int Longitud = [Link]();
Color colorant = [Link]();

// Fijamos la fuente con que queremos que aparezca el texto y


// recogemos la informacion de esa fuente, porque necesitamos
// conocer el ancho de cada uno de los caracteres
[Link]( font );
FontMetrics metrica = getFontMetrics( font );
int stringWidth = [Link]( caracteres,0,Longitud );

// Controlamos el efecto que queremos darle al texto, si


// resaltado o hundido (hacia abajo), para conseguirlo
// pintamos dos cadenas en diferente color
if( sombra == TextoResaltado )
{
[Link]( [Link] );
[Link]( caracteres,0,Longitud,1,[Link]()-3 );
}
else if( sombra == TextoHundido )
{
[Link]( [Link] );
[Link]( caracteres,0,Longitud,3,[Link]()-1 );
}
// Aplicamos el color mas oscuro con un ligero desplazamiento
// y recuperamos el color antiguo con que estabamos trabajando
[Link]( color );
[Link]( caracteres,0,Longitud,2,[Link]()-2 );
[Link]( colorant );
}

// Este metodo devuelve el tamno minimo deseable para el rectangulo


// donde vamos a pintar el texto. Es importante porque nuestro
// objeto no deja de ser mas que un Componente en el Layout, y el
// gestor del layout a la hora de reconstruirlo, lo llama para
// saber cual es el minimo tamano posible
public Dimension minimumSize() {
if( alto == 0 )
{
if( font != null )
alto = [Link]();
else
alto = 12;
}
if( ancho == 0 )
ancho = 100;
return( new Dimension( ancho+3,alto+3 ) );
}

// Con este metodo pasa lo mismo, el manejador del Layout lo llama


// para saber cual es el tamano que ha fijado el creador del
// componente e intentar respetarlo (siempre que pueda)
public Dimension preferredSize() {
return( minimumSize() );
}

// Creamos un bordecito entre el texto y el borde del rectangulo


// que lo circunscribe
public Insets insets() {
return( new Insets( 3,3,3,3 ) );
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

public class EjEtiqueta extends Applet {

public static void main( String args[] ) {


EjEtiqueta texto = new EjEtiqueta();

// Creamos las etiquetas y montamos el layout


[Link]();

Frame fr = new Frame( "Etiquetas" );


[Link]( "Center",texto );
[Link]( 200,100 );
// lo hacemos todo visible
[Link]();
}

public void init() {


Etiqueta texto1 = new Etiqueta();

// Nos creamos un objeto etiqueta para presentar el texto


[Link]( "Helvetica",[Link],18 );
[Link]( new Color( 128,0,0 ) );
[Link]( 20 );
[Link]( 140 );
[Link]( [Link] );
[Link]( true );
[Link]( "Tutorial de Java" );

// Usamos la etiqueta anterior como plantilla y solamente le


// cambiamos la forma de presentar el texto
Etiqueta texto2 = new Etiqueta( texto1 );
[Link]( [Link] );
Etiqueta texto3 = new Etiqueta( texto1 );
[Link]( [Link] );

// Incorporamos los tres rotulos a la ventana


add( texto1 );
add( texto2 );
add( texto3 );
}

// Ponemos el fondo del applet en negro para que resalten mas los
// rectangulos con el texto
public void paint( Graphics g ) {
[Link]( [Link] );
[Link]( 0,0,size().width,size().height );
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 23-Oct-1996 014:53:09
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

public class Timer implements Runnable {


private Date inicio,parada;
private Thread thread = null;
private int duracion = 0;
private int duracionAnt = 0;
private int intervalo = 1000;
private boolean repeticion = false;
private boolean enEjecucion = false;
private Temporizador handler = null;

// Contructor basico, usado por defecto


Timer() { }

// Los siguientes constructores son de conveniencia, porque todas


// las caracteristicas del timer se pueden ver y modificar a
// traves de los metodos get y set
// Constructor de conveniencia que acepta un tiempo de duracion
Timer( int tiempo ) {
setDuracion( tiempo );
}

// Constructor de conveniencia que acepta un Temporizador


Timer( Temporizador Handler ) {
setHandler( Handler );
}

// Constructor de conveniencia que acepta un temporizador y una


// duracion
Timer( int tiempo,Temporizador Handler ) {
setDuracion( tiempo );
setHandler( Handler );
}

// Fija el numero se segundos que correra el timer


public void setDuracion( int tiempo ) {
duracion = tiempo;
}

// Fija el objeto que ha de ser notificado de los eventos que


// sucedan al timer
public void setHandler( Temporizador Handler ) {
handler = Handler;
}

// Fija el numero de milisegundos entre pulsos del timer


public void setIntervalo( int Intervalo ) {
intervalo = Intervalo;
}

// Funciones "get" para recoger los datos de las caracteristicas


// que se han fijado antes
public int getDuration() {
return( duracion );
}

public Temporizador getHandler() {


return( handler );
}

public int getIntervalo() {


return( intervalo );
}

// Devuelve el numero de segundos que han transcurrido desde que


// se arranco el timer
public int getElapsed() {
return( calculaLapso( new Date() ) );
}

// Este metodo permite resetear el timer antes de relanzarlo. Se


// podria usar el metodo setDuracion, pero este es mas corto
// y elegante
public void resetDuracion() {
duracion = duracionAnt;
}

// Aqui creamos un nuevo thread para correr el Timer. Lo incializamos


// con "this" de forma que el metodo run() se llame inmediatamente
// como comience la ejecucion del thread
public void start() {
thread = new Thread( this );
[Link]();
}

// Aqui almacenamos el momento en que se llama a este metodo.


// Tambien comprobamos si hay algun Temporizador asociado al Timer
// que estamos parando, en cuyo caso, notificamos a los observadores
// de este Timer que lo hemos detenido (para eso esta la interface
// Temporizador, que debera estar implementada en las clases que
// miren a este Timer)
public void stop() {
enEjecucion = false;
parada = new Date();
if ( handler != null )
[Link]( this );
}

public void run() {


enEjecucion = true;
duracionAnt = duracion;

// Arrancamos el Timer y lo notificamos a las clases que esten


// poendientes
inicio = new Date();
if( handler != null )
[Link]( this );

while( enEjecucion )
{
// Esperamos el tiempo que nos hayan dicho en la configuracion
// del intervalo
try {
esperar( intervalo );
} catch( InterruptedException e ) {
return;
}

// Cuando se cumple el intervalo, avisamos a las clases que


// esten pendientes. Si esas clases no quieren hacer nada
// con este evento periodico, es suficiente con que no lo
// sobrecarguen, que se quede vacio
if( handler != null )
[Link]( this );

// Si no indicamos una duracion para el Timer, estara


// corriendo indefinidamente
if( duracion > 0 )
{
// Comprobamos si el Timer esta muerto ya, para no
// tener que matarlo
if( estaMuerto() )
{
// Si esta muerto, lo propagamos
if( handler != null )
[Link]( this );

// Aqui comprobamos si se quiere una repeticion


// automatica, en cuyo caso, volvemos a arrancar
// el Timer
if( repeticion )
{
enEjecucion = true;
inicio = new Date();
if( handler != null )
[Link]( this );
}
else
{
enEjecucion = false;
}
}
}
}
}

// Metodos que nos informan del estado del Timer


public boolean estaCorriendo() {
return( enEjecucion );
}

public boolean estaParado() {


return( !enEjecucion );
}
public boolean estaMuerto() {
int segundos = 0;

// Calculamos el intervalo de tiempo que ha transcurrido desde


// que se ha arrancado el Timer
segundos = calculaLapso( new Date() );

if( segundos >= duracion )


return( true );
else
return( false );
}

private int calculaLapso( Date actual ) {


Date dfinal;
int segundos = 0;

if( enEjecucion )
dfinal = actual;
else
dfinal = parada;

// Si se quiere mas precision, en vez de Date(), se puede


// utilizar [Link](), que proporciona
// muchisima mas resolucion
segundos += ( [Link]() - [Link]() ) * 3600;
segundos += ( [Link]() - [Link]() ) * 60;
segundos += ( [Link]() - [Link]() );
return( segundos );
}

// Aqui implementamos la espera. El lapso en milisegundos se lo


// pasamos al metodo wait() del thread
// Este metodo es sincronizado porque sino salta una excepcion
// interna en el interprete de Java. No esta muy bien documentado
// el porque, pero parece ser que no se puede llamar al metodo
// wait() de un thread desde otro que no sea sincronizado
private synchronized void esperar( int lapso )
throws InterruptedException {
[Link]( lapso );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 23-Oct-1996 13:56:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

//
// Interface que vamos a utilizar en la implementacion del timer, con el
// que luego generaremos el reloj digital de demostracion
// Esta interface debe ser implementada por cualquier clase que desee
// ser informada de los eventos que genere el Timer, en nuetro caso el
// reloj
//
public interface Temporizador {
public void timerArrancado( Timer timer );
public void timerParado( Timer timer );
public void timerMuerto( Timer timer );
public void timerIntervalo( Timer timer );
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;

public class RelojDigital extends Applet implements Temporizador {


private Timer timer;
private Etiqueta horaActual;
private Color fondo;

// Este es el metodo main() para que podamos ejecutar la aplicacion


// desde la linea de comandos
public static void main( String args[] ) {
RelojDigital reloj = new RelojDigital();

[Link]();
[Link]();

// Craemos un frame para que se pueda visualizar el reloj


Frame frame = new Frame( "Reloj Digital" );
[Link]( "Center",reloj );
[Link]( 50,20 );
[Link]();
}

public void init() {


// Cargamos el parametro que nos indica el color de fondo que
// queremos para el reloj, si no se especifica o no se indica
// correctamente, fijamos uno por defecto
// Lo adecuado, en caso de presentar el applet sobre una pagina
// de un navegador es que este parametro coincida con el que
// se especifique para el color de Background de esa pagina
String Fondo = getParameter( "Fondo" );
if( Fondo == null )
fondo = [Link];
else
{
try {
fondo = new Color( [Link]( Fondo,16 ) );
} catch( NumberFormatException e ) {
fondo = [Link];
}
}
setBackground( fondo );
// Nos creamos un timer, para actualizar el reloj cada segundo
Timer timer = new Timer( this );

// Creamos un objeto Etiqueta, para que nuestro reloj aparezca


// con un texto decente y bonito
horaActual = new Etiqueta();
[Link]( "Helvetica",[Link],18 );
[Link]( new Color( 128,0,0 ) );
[Link]( 25 );
[Link]( 100 );
[Link]( [Link] );
[Link]( true );
add( horaActual );

// Arrancamos el timer para que el reloj empiece a marchar


[Link]();
}

// En cada aviso de que nuestro Timer ha llegado al intervalo de


// tiempo que nosotros hemos fijado, cogemos la hora del sistema
// y la presentamos
public void timerIntervalo( Timer t ) {
Date actual = new Date();
int horas = [Link]();
int minutos = [Link]();
int segundos = [Link]();
int hora;
String tiempo = "";

// Los "ifs" que siguen son para formatear la hora


// correctamente y que siempre ocupe lo mismo en la
// Etiqueta, para que no salten las horas de posicion al
// presentarse en pantalla
if( horas > 12 )
hora = horas - 12;
else
hora = horas;
if( hora < 10 )
tiempo += "0";
tiempo += hora;
tiempo += ":";

if( minutos < 10 )


tiempo += "0";
tiempo += minutos + ":";

if( segundos < 10 )


tiempo += "0";
tiempo += segundos;

if( horas > 12 )


tiempo += " pm";
else
tiempo += " am";

[Link]( tiempo );
}

// Sobrecargamos los metodos que no nos interesan de la interface


// Temporizador, porque solamente vamos a utilizar la que genera
// un evento cada cierto intervalo de tiempo, las demas no tienen
// interes en este ejemplo
public void timerArrancado( Timer t ) { }

public void timerParado( Timer t ) { }


public void timerMuerto( Timer t ) { }

public void paint( Graphics g ) {


[Link]( fondo );
[Link]( 0,0,size().width,size().height );
}
}

//-------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Oct-1996 06:22:56
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Persiana extends Applet implements Runnable {


Image imagenFondo;
Image offI;
Graphics offG;
int posicion;
String texto[];
Font font;
Font font1;
Font font2;
Font font3;
boolean puedePintar;
Thread thrd;
MediaTracker mdt;

public void init() {


mdt = new MediaTracker( this );

// Instanciación de los objetos fuente que vamos a utilizar durante


// la presentación del texto en su desplazamiento por la persiana
font = new Font( "Dialog",0,15 );
font1 = new Font( "Helvetica",1,23 );
font2 = new Font( "TimesRoman",1,30 );
font3 = new Font( "Dialog",1,16 );

// Cadenas de texto correspondientes al primer grupo de información


// que se va a presentar en la ventana
texto[0] = "Este Tutorial de Java proporciona suficientes conocimientos";
texto[1] = "para que, tanto los programadores noveles como aquellos que";
texto[2] = "conocen las bondades del lenguaje Java, puedan acercarse en un";
texto[3] = "caso y profundizar en el otro, en los más diversos aspectos del";
texto[4] = "lenguaje. Se recorren casi todas las características de Java,";
texto[5] = "desde las más sencillas como puede ser la descripción de los";
texto[6] = "tipos soportados por el lenguaje, hasta las más complicadas";
texto[7] = "como la implementación de un entorno cliente-servidor o el";
texto[8] = "desarrollo del modelo de arquitectura Modelo-Vista completo.";

// Información que se presentará a continuación del título


// del segundo bloque de información de la persiana
texto[9] = "Se hace un profundo recorrido por el Abstract Window Toolkit,";
texto[10] = "presentado todos los elementos que lo componen en su actual";
texto[11] = "versión, con múltiples líneas de código fuente para que el";
texto[12] = "navegante pueda ir comprobando cómo se usan y cómo Java";
texto[13] = "utiliza los recursos que pone en manos del programador.";
texto[14] = "También hay múltiples applets Java en funcionamiento a lo";
texto[15] = "largo del Tutorial, de forma que se puede ir comprobando";
texto[16] = "la apariencia que presentan los applets sobre el browser que";
texto[17] = "estemos utilizando.";

// Bloque final de información


texto[18] = "Como compendio a todo lo desarrollado en este Tutorial de";
texto[19] = "Java, se presentan varias aplicaciones autónomas y algunos";
texto[20] = "applets listos para utilizar, con toda la información";
texto[21] = "necesaria para su implementación y uso.";

// Recuperamos la imagen que se va a utilizar como fondo de la


// cadena que represente el título principal de la persiana
imagenFondo = getImage( getCodeBase(),"[Link]" );
try {
offI = createImage( 700,55 );
offG = [Link]();
} catch( Exception e ) {
offG = null;
}
return;
}

public void update( Graphics g ) {


if( puedePintar )
paint( g );
}

public void paint( Graphics g ) {


if( offG != null )
{
paintApplet( offG );
[Link]( offI,0,0,this );
return;
}
paintApplet( g );
}

public void paintApplet( Graphics g ) {


// Presentamos la imagen de fondo y el título principal que
// queremos asignar a la infromación que va a ir presentando
// la persiana.
// Para hacer un poco más atractiva la visualización del título
// hacemos que aparezca una especie de sombra de la cadena de
// texto. Para ello, simplemente la volvemos a escribir pero
// desplazada
[Link]( [Link] );
[Link]( 0,0,600,700 );
[Link]( font2 );
[Link]( imagenFondo,0,-posicion,this );
[Link]( [Link] );
[Link]( "Tutorial de Java",200,50-posicion );
[Link]( [Link] );
[Link]( "Turorial de Java",198,48-posicion );
[Link]( [Link] );
[Link]( font1 );
[Link]( 130,60-posicion,190,24 );
[Link]( [Link] );
[Link]( "Presentación",150,80-posicion );
[Link]( [Link] );
[Link]( font );
for( int i=0; i < 9; i++ )
[Link]( texto[i],5,105+i*19-posicion );

// Creamos otro rectángulo de color para colocar el título que


// encabeza al grupo de cadenas que van a seguir desplazándose
// por la persiana
[Link]( [Link] );
[Link]( 120,265-posicion,180,26 );
[Link]( [Link] );
[Link]( font1 );
[Link]( "AWT",180,287-posicion );
[Link]( [Link] );
[Link]( font );
for( int j=9; j < 18; j++ )
[Link]( texto[j],5,140+j*19-posicion );

// Presentamos el siguiente grupo de información, creando una


// cabecera para indicar de qué se trata la información que va a
// aparecer en la persiana
[Link]( [Link] );
[Link]( 120,471-posicion,200,30 );
[Link]( [Link] );
[Link]( font1 );
[Link]( "Ejemplos",165,493-posicion );
[Link]( [Link] );
[Link]( font );
for( int j=18; j < 22; j++ )
[Link]( texto[j],5,177+j*19-posicion );

// Esta es la misma información que la del principio


[Link]( font2 );
[Link]( imagenFondo,0,600-posicion,this );
[Link]( [Link] );
[Link]( "Tutorial de Java",200,650-posicion );
[Link]( [Link] );
[Link]( "Tutorial de Java",198,648-posicion );
}

public void start() {


// Creamos un nuevo thread y lo arrancamos
thrd = new Thread( this );
[Link]();
}

public void stop() {


[Link]();
}

public void run() {


for( puedePintar=false; true; puedePintar=false )
{
try {
puedePintar = true;
repaint();
// Si estamos al principio, alargamos un poco la espera
if( posicion == 0 )
{
[Link]();
[Link]( 5000 );
}
posicion++;
// Cuando lleguemos al final del texto, volvemos al
// principio, para repetir todos los mensajes
if( posicion == 600 )
posicion = 0;
[Link]();
// Aqui podemos hacer más rápido o más lento el
// desplazamiento del texto por la persiana
[Link]( 100 );
} catch( InterruptedException e ) {
;
}
}
}

// El constructor del applet se limita a crear el array de texto que


// contendrá todas las cadenas o líneas de texto que se irán pasando
// por la ventana
public Persiana() {
texto = new String[22];
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 11:35:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Presenta el cuerpo de la ficha en blanco, para que se puedan insertar los


// componentes que correspondan
// Es el contenedor del control tabular que estamos implementando
public class CuerpoFicha extends Panel {

// Lo unico que se pasa al constructor de esta clase es el color de


// fondo con que queremos que aparezca
public CuerpoFicha( Color colorCuerpo ) {
setBackground( colorCuerpo );
}

public void paint( Graphics g ) {


Rectangle area;

area = bounds();

// Pintamos el fondo del cuerpo de la ficha con el color


// que se haya indicado en el constructor de la clase
[Link]( getBackground() );
[Link]( area.x,area.y + 1,[Link],[Link]-1 );

// Pintamos una linea brillante el los lados superior e


// izquierdo
[Link]( [Link] );
[Link]( area.x,area.y,area.x+[Link],area.y );
[Link]( area.x,area.y,area.x,area.y+[Link] );

// Pintamos una linea gris en los lados inferior y derecho


// para dar sensacion de sombra
[Link]( [Link] );
[Link]( area.x,area.y+[Link]-1,
area.x+[Link]-1,area.y+[Link]-1 );
[Link]( area.x+[Link]-1,area.y+[Link]-1,
area.x+[Link]-1,area.y+1 );

// Pintamos la sombra de la sobra de los lados inferior y


// derecho, para aumentar la sensacion de tres dimensiones y
// profundidad
[Link]( [Link] );
[Link]( area.x,area.y+[Link],
area.x+[Link],area.y+[Link] );
[Link]( area.x+[Link],area.y+[Link],
area.x+[Link],area.y+1 );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 12-Sep-1996 11:57:07
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Este objeto se utiliza para seleccionar cada una de las fichas


// Pulsando con el raton sobre una de ellas, se visualizara el
// contenido de la ficha que tiene adosada
public class Solapa extends Canvas {
protected String rotulo; // Rotulo indicador de la solapa
protected Font seleFont; // Font cuando la solapa esta seleccionada
protected Font normFont; // Font del estado normal de la solapa
protected boolean seleccionada; // Indicador de seleccion de la solapa

public Solapa( String rotulo,Font normFont,


Font seleFont,Color captionColor,Color bgColor ) {
super();
[Link] = rotulo;
[Link] = normFont;
[Link] = seleFont;
setForeground( captionColor );
setBackground( bgColor );
seleccionada = false;
}

public void pintaRotulo( Graphics g ) {


int rotuloX;
int rotuloY;
FontMetrics fm;

// Comprobamos la fuente de caracteres que vamos a utilizar en la


// presentacion del rotulo, en funcion del estado de la ficha
if( seleccionada )
{
[Link]( seleFont );
fm = [Link]( seleFont );
}
else
{
[Link]( normFont );
fm = [Link]( normFont );
}

// Calculamos las coordenadas en que vamos a presentar el rotulo


// Teniendo en cuenta la longitud del texto del rotulo y
// la fuente de caracteres
rotuloX =
bounds().x +( (bounds().width - [Link](rotulo) ) / 2);
rotuloY = bounds().y + ( bounds().height / 2 ) -
[Link]() + ( [Link]() / 2 );

// Fijamos el color y pintamos el rotulo


[Link]( getForeground() );
[Link]( rotulo,rotuloX,rotuloY );
}

// Pinta la solapa en base a pares de lineas para proporcionar


// sensacion de tres dimensiones, en caso de que este seleccionada
// se pintara dos pixels mas grande para que de la sensacion
// de que esta delante del resto de fichas
public void pintaSolapa( Graphics g ) {
int delante;
Rectangle area;

delante = ( seleccionada ) ? 2 : 0;
area = bounds();
[Link]( getBackground() );

// Pintamos el rectangulo que va a ocupar la solapa


if ( !seleccionada )
{
[Link]( area.x,area.y+2, [Link],[Link]-2 );
[Link]( area.x+1,area.y+1,[Link]+area.x-2,area.y+1 );
}
else
{
[Link]( area.x-1,area.y,[Link]+2,[Link] );
[Link]( area.x,area.y-1,area.x+[Link],area.y-1 );
}

// left side, rounded corner and top side lit


[Link]( [Link] );
[Link]( area.x-delante,area.y+[Link]-2,
area.x-delante,area.y+2-delante );
[Link]( area.x-delante,area.y+2-delante,
area.x+2-delante,area.y-delante );
[Link]( area.x+2-delante,area.y-delante,
area.x+[Link]-2+delante,area.y-delante );

if( !seleccionada )
{
// Pintamos la sombra del lado derecho
[Link]( [Link] );
[Link]( area.x+[Link]-1,area.y,
area.x+[Link]-1,area.y+[Link]-2 );

// Pintamos la sombra de la sombra del lado derecho


// para dar mas sensacion de profundidad
[Link]( [Link] );
[Link]( area.x+[Link],area.y+2,
area.x+[Link],area.y+[Link]-2 );
}
else
{
// Pintamos la sombra del lado derecho
[Link]( [Link] );
[Link]( area.x+[Link]-1+delante,area.y-delante,
area.x+[Link]-1+delante,area.y+[Link]-2 );

// Pintamos la sombra de la sombra del lado derecho


[Link]( [Link] );
[Link]( area.x+[Link]+delante,area.y+2-delante,
area.x + [Link]+delante,area.y + [Link]-2 );
// Como la solapa esta seleccionada, pintamos en color del
// fondo la linea que une la solapa anterior con la
// siguiente, dando sensacion de que la solapa esta
// efectivamente pegada a la ficha
[Link]( getBackground() );
[Link]( area.x-delante+1,area.y+[Link],
area.x+[Link],area.y+[Link] );
}
}

// Devuelve el texto del rotulo de la solapa


public String getRotulo() {
return( rotulo );
}

// Devuelve el punto correspondiente a la posicion final de la


// solapa
public Point getFinal() {
return( new Point(bounds().x+bounds().width+2,bounds().y ) );
}

// Devuelve la altura de la solapa


public int getAlto() {
return( size().height );
}

// Devuelve la fuente de caracteres con que se pinta el rotulo de


// la solapa cuando esta seleccionada
public Font getFuenteSel() {
return( seleFont );
}

// Indica si la posicion que se pasa como parametro esta dentro


// de los limites de la solapa o no
public boolean estaDentro( int x,int y ) {
return( bounds().inside( x,y ) );
}

// Indica si la solapa esta seleccionada o no


public boolean estaSeleccionada() {
return( seleccionada );
}

// Cuando pulsamos el raton, nos devuelve true si lo hemos hecho


// sobre la solapa o false si lo hemos hecho fuera del rectangulo
// que ocupa la solapa
public boolean mouseDown( Event evt,int x,int y ) {
if( ( estaDentro( x,y ) ) && ( !estaSeleccionada() ) )
return( true );
else
return( false );
}

public void paint( Graphics g ) {


pintaSolapa( g );
pintaRotulo( g );
}
// Indica que la solapa esta seleccionada
public void seleccionar() {
seleccionada = true;
}

// Indica que la solapa deja de estar seleccionada


public void deSeleccionar() {
seleccionada = false;
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 12-Sep-1996 11:43:24
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import CuerpoFicha;
import Solapa;

// Crea un objeto que sera seleccionado cuando se pulse con el raton


// en su solapa. Contiene a dos objetos, uno de tipo Solapa y otro de
// tipo cuerpoFicha, de forma que al seleccionar en el primero
// aparecera la solapa marcada y el contenido del objeto cuerpoFichero
// asociado a esa solapa
public class Ficha extends Panel {
public static final int SOLAPA_SELECCIONADA = 2000;
protected Solapa solapa;
protected CuerpoFicha cuerpoFicha;

public Ficha( String rotulo,Font normFont,Font seleFont,


Color colorRotulo,Color colorFicha ) {
super();
solapa = new Solapa( rotulo,normFont,seleFont,
colorRotulo,colorFicha );
cuerpoFicha = new CuerpoFicha( colorFicha );
}

// Devuelve el rotulo identificador de la solapa


public String getRotulo() {
return( [Link]() );
}

// Devuelve los limites del cuerpo de la Ficha


public Rectangle getBordesFicha() {
return( [Link]() );
}

// Devuelve los limites que ocupa la solapa


public Rectangle getBordesSolapa() {
return( [Link]() );
}

// Devuelve el punto final, ams alejado de la solapa


public Point getFinalSolapa() {
return( [Link]() );
}
public boolean handleEvent( Event evt ) {
// La solapa devolvera true solamente si ha sido seleccionada
// en ese momento por el evento, aunque lo que siempre haremos
// sera notificarlo a ListaFichas, por lo que devolvemos false
// y el evento SOLAPA_SELECCIONADA se propagara hacia arriba
if( [Link]( evt ) )
{
[Link] = SOLAPA_SELECCIONADA;
[Link] = this;
}
return( false );
}

// Indica si la ficha esta seleccionada o no


public boolean estaSeleccionada() {
return( [Link]() );
}

public void medidas( Point solapaXY,Graphics g,


Dimension appTam,Point appPos ) {
FontMetrics fm;
int anchoRotulo;
int altoRotulo;

fm = [Link]( [Link]() );
anchoRotulo = [Link]( [Link]() );
altoRotulo = [Link]();
[Link]( solapaXY.x,solapaXY.y,anchoRotulo+altoRotulo,
altoRotulo+(altoRotulo / 3) );
[Link]( appPos.x,appPos.y+[Link](),
[Link]-1,[Link]()-1 );
}

public void paint( Graphics g ) {


if( estaSeleccionada() )
[Link]( g );
[Link]( g );
}

public void seleccionar() {


[Link]();
}

public void deSeleccionar() {


[Link]();
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 12-Sep-1996 12:46:13
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import Ficha;

public class ListaFichas extends Panel {


protected Vector fichas;
protected Point posicion;
protected Dimension tama;
protected Font normFont;
protected Font seleFont;
protected Color fgColor;
protected Color bgColor;
protected Panel contenido;

public ListaFichas( Point posicion,Dimension tama,Font normFont,


Font seleFont,Color fgColor,Color bgColor,
String primerRotulo,Panel primerPanel ) {

super();

// Aqui fijamos el layout a null, porque el metodo medidas()


// sera el que controle ese layout
setLayout( null );

// Nos creamos un objeto Vector, que nos va a permitir la


// manipulacion de la lista de las fichas
fichas = new Vector();
[Link] = posicion;
[Link] = tama;
[Link] = normFont;
[Link] = seleFont;
[Link] = fgColor;
[Link] = bgColor;
contenido = new Panel();
add( contenido );
[Link]( new CardLayout() );

// Incorporamos la primera ficha y la dejamos seleccionada


addFicha( primerRotulo,primerPanel );
primeraFicha().seleccionar();
}

// En este metodo incorporamos una ficha a la lista, con todos


// los valores por defecto
public synchronized void addFicha( String rotulo,Panel panel ) {
[Link]( new Ficha( rotulo,normFont,seleFont,
fgColor,bgColor) );
[Link]( rotulo,panel );
}

// En este metodo, nos permitimos especificar los colores de


// primer plano y de fondo con que se va a presentar la ficha
// en pantalla, a demas de incorporarla a la lista de fichas
public synchronized void addFicha( Color fgColor,Color bgColor,
String rotulo,Panel panel ) {
[Link]( new Ficha( rotulo,normFont,seleFont,
fgColor,bgColor ) );
[Link]( rotulo,panel );
}

// Presenta el contenido de la ficha que se ha seleccionado


public void presentaFichaSeleccionada() {
( (CardLayout)[Link]() ).show( contenido,
( getSeleccionada().getRotulo() ) );
}

// Devuelve la primera ficha de la lista


public synchronized Ficha primeraFicha() {
return( (Ficha)[Link]() );
}

// Devuelve el contenido del control Tabular completo


public Panel getContenido() {
return contenido;
}

// Devuelve la siguiente ficha a la que se le pasa como parametro


public synchronized Ficha getSigFicha( Ficha f ) {
Ficha nextF;

// La numeracion de los elementos empieza en 0


if( [Link]( f ) < ([Link]() - 1) )
nextF = fichaAt( [Link](f)+1 );
else
nextF = null;

return( nextF );
}

// Devuelve la ficha que actualmente esta seleccionada


public synchronized Ficha getSeleccionada() {
Ficha f;

// Nos colocamos en la primera y vamos comprobando


// ficha por ficha cual es la que esta seleccionada
f = primeraFicha();
while( (![Link]()) && (f != null) )
f = getSigFicha( f );

return( f );
}

// Devuelve informacisn de si el evento se ha controlado o no


// en este manejador
public boolean handleEvent( Event evt ) {
boolean manejado;
Ficha f;

// Localizamos la ficha que ha generado el evento


f = primeraFicha();
manejado = [Link]( evt );
if( !manejado )
f = getSigFicha( f );
while( (f != null) && (!manejado) )
{
manejado = [Link]( evt );
f = getSigFicha( f );
}

// Si han seleccionado otra ficha, liberamos la actualmente


// seleccionada y seleccionamos la que nos llega en el
// evento, que correponde a la solapa que se ha pulsado
if( [Link] == Ficha.SOLAPA_SELECCIONADA )
{
getSeleccionada().deSeleccionar();
( (Ficha)[Link] ).seleccionar();
presentaFichaSeleccionada();
repaint();
manejado = true;
}

// Si aqui no se ha controlado el evento, se intenta que lo


// controle directamente alguno de los componentes que se
// hayan colocado en la ficha
if( !manejado )
manejado = [Link]( evt );

return( manejado );
}

// Devuelve la ultima ficha del control Tabular


public synchronized Ficha ultimaFicha() {
return( (Ficha)[Link]() );
}

// Calcula el area que ocupa todo el Control Tabular


public void medidas( Graphics g ) {
Ficha f;
Point solapaXY;

// Calcula el area ocupada por las solapas


tama = size();
f = primeraFicha();
solapaXY = new Point( posicion.x+2,posicion.y+2 );
[Link]( solapaXY,g,tama,posicion );
if( f != ultimaFicha() )
{
do {
solapaXY = [Link]();
f = getSigFicha( f );
[Link]( solapaXY,g,tama,posicion );
} while( f != ultimaFicha() );
}

// Calcula el area ocupada por los paneles que forman el


// cuerpo de las fichas
Rectangle r = primeraFicha().getBordesSolapa();
[Link]( r.x+3,r.y+[Link]+3 );
r = primeraFicha().getBordesFicha();
[Link]( [Link]-10,[Link]-10 );
}

public void paint( Graphics g ) {


Ficha f;

medidas( g );
f = primeraFicha();
while( f != null )
{
if( ![Link]() )
[Link]( g );
f = getSigFicha( f );
}
getSeleccionada().paint( g );
[Link]( g );
}

// Devuelve la ficha que se encuentre en la posicion que se indique


// en el indice que se pasa como paramentro
public synchronized Ficha fichaAt( int indice ) {
Ficha f;

// Capturamos la excepcion de que se nos vaya fuera de


// limites el indice que nos pasan
try {
f = (Ficha)[Link]( indice );
} catch( ArrayIndexOutOfBoundsException e ) {
[Link]("Error : No hay ficha #" + indice );
return( null );
}
return( f );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 29-Oct-1996 11:04:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// En este applet lo que intentamos es que cuando llegue el mensaje de que


// actualicemos la pantalla, el método update() se encargue solamente de la
// zona que nosotros le indiquemos, y que no fluctúe todo el dibujo
public class AppletFijo extends Applet {
private Image imagen;
private Graphics imgGr;
private Dimension imgTam;

public final synchronized void update( Graphics g ) {


Dimension dim = size();

if( imagen == null || [Link] != [Link] ||


[Link] != [Link] )
{
imagen = createImage( [Link],[Link] );
imgTam = dim;
imgGr = [Link]();
[Link]( getFont() );
}
[Link]( 0,0,[Link],[Link] );
paint( imgGr );
[Link]( imagen,0,0,null );
}

public AppletFijo() {}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 11:35:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;
import [Link].*;

public class BotonImg {


private Applet appSuperior;
public Image imagen;
public Image imagenUp;
public Image imagenDown;
public Image imagenMove;
public ImageFilter filtro;
public String mensaje;
public int estado;
public int offX;
public int offY;
public int tamX;
public int tamY;
public URL url;
public String href;

// En este método vamos fijando las imágenes que se presentarán en función


// del estado en que se encuentre el ratón
// Utilizamos un método que Java proporciona en la clase [Link]
// que nos permite extraer una zona de una imagen y guardarla como imagen
// completa. De este modo extraemos del dibujo que contiene las tres imágenes
// posibles, cada imagen correspondiente a los eventos que le llegan al
// objeto enviados por el ratón
public void init() {
filtro = new CropImageFilter( 0,0,tamX,tamY );
imagenUp = [Link](
new FilteredImageSource( [Link](),filtro ) );
filtro = new CropImageFilter( 0, tamY,tamX,tamY );
imagenMove = [Link](
new FilteredImageSource( [Link](),filtro ) );
filtro = new CropImageFilter( 0,tamY*2,tamX,tamY );
imagenDown = [Link](
new FilteredImageSource( [Link](),filtro ) );
// Aquí componemos la dirección a la que saltar cuando se pique con el
// ratón la zona que corresponda al botón
try {
url = new URL( [Link](),href );
} catch( MalformedURLException e ) {
url = null;
}
return;
}

// Constructor, al que le pasamos el applet que correponde al dibujo completo


public BotonImg( Applet applet ) {
appSuperior = applet;
}

// Sobrecargamos el método showDocument, para que no se abra con las


// características del applet del botón, sino con las del padre, que sí
// tendrá las características de la página
public void showDocument( URL uRL ) {
[Link]().showDocument( uRL );
}

// En este método, pintamos un dibujo u otro sobre el botón, en función del


// estado que nos devuelva el sistema para el cursor y los botones del
// ratón
public void paint( Graphics g ) {
if( estado == 0 )
[Link]( imagenUp,offX,offY,appSuperior );
else if(estado == 1)
[Link]( imagenDown,offX,offY,appSuperior );
else if( estado == 2 )
[Link]( imagenMove,offX,offY,appSuperior );
}

// En los tres métodos que siguen, controlamos los eventos que nos llegan del
// ratón. La técnica a seguir es la misma en cada uno de ellos, mirar si
// el cursor se encuentra dentro del campo de acción del botón que estamos
// trantando, si no está dentro del campo del botón, pero sí dentro del
// dibujo general del applet, devolvemos el control al applet general para
// que siga comprobando si está el cursor sobre otro botón. Si el cursor se
// encuentra en nuestro campo de acción, actuamos en consecuencia
public boolean mouseDown( Event evt,int i,int j ) {
if( i >= offX && i < offX + tamX &&
j >= offY && j < offY + tamY )
{
// Fijamos el estado a 1, para que cuando se suelte el botón
// podamos saltar a la dirección que se haya especificado en la
// lista de parámetros del applet
estado = 1;
[Link]();
}
else if( estado != 0 )
{
[Link]( "" );
estado = 0;
[Link]();
}
return( false );
}

public boolean mouseUp( Event evt,int i,int j ) {


if( i >= offX && i < offX + tamX &&
j >= offY && j < offY + tamY )
{
// Si previamente habíamos pulsado el ratón sobre este botón, hacemos
// que se muestre la página correcpondiente a la dirección URL que se
// había cargado
if( estado == 1 )
showDocument( url );
estado = 2;
[Link]();
}
else if( estado != 0 )
{
[Link]( "" );
estado = 0;
[Link]();
}
return( false );
}

public boolean mouseMove( Event evt,int i,int j ) {


if( i >= offX && i < offX + tamX &&
j >= offY && j < offY + tamY )
{
// Si sólo movemos el cursor sobre el botón, nos limitamos a presentar
// el mensaje que se ha definido en los parámetros de llamada al
// applet
estado = 2;
[Link]( mensaje );
[Link]();
}
else if( estado != 0 )
{
[Link]( "" );
estado = 0;
[Link]();
}
return( false );
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 29-Oct-1996 11:44:46
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class MenuDeBotones extends AppletFijo {


private int colFondo;
BotonImg tit;
BotonImg dem;
BotonImg ovw;
BotonImg faq;
BotonImg res;
Image fondo;

// En este método leemos todos los datos que se pasan desde la llamada
// al applet en la página HTML. Por cada una de las opciones que se
// encuentren en la página, crearemos un objeto BotonImg que sera el
// que controle los movimientos del ratón sobre ese Boton
public void init() {
colFondo = [Link]( getParameter( "Color" ),16 );
// Carga la imagen de fondo
fondo = getImage( getCodeBase(),getParameter( "Fondo" ) );

// Obtenemos los datos del botón que corresponderá a la opción de


// "Java WorkShop - Home Page"
tit = new BotonImg( this );
// Esta es la posición X,Y en la que se coloca la imagen del botón
// sobre la imagen principal
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
// Este es el tamaño de la imagen que corresponde al botón en ancho y
// alto. En la imagen asociada que contiene las distintas imágenes de
// estados en que se puede encotnrar el botón, nos encontraremos con
// tres imágenes diferentes que estarán despalazadas en Y justamente
// el tamaño en altura que ocupa cada botón
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
// Esta es el dibujo que contiene las tres imágenes en que va a poder
// presentarse este botón
[Link] = getImage( getCodeBase(),getParameter( "[Link]" ) );
// Este es el mensaje que aparecerá en la zona de estado del Navegador
// cuando el cursor del ratón pase por la zona ocupada por el botón
[Link] = getParameter( "[Link]" );
// Esta es la dirección URL a la que se saltará cuando se actúe sobre
// el botón
[Link] = getParameter( "[Link]" );
[Link]();

// Obtenemos los datos del botón que corresponderá a la opción de


// "Demo Download Area & Product Pricing"
// Los parámetros son los mismos que en el caso anterior
dem = new BotonImg( this );
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = getImage( getCodeBase(),getParameter( "[Link]" ) );
[Link] = getParameter( "[Link]" );
[Link] = getParameter( "[Link]" );
[Link]();

// Obtenemos los datos del botón que corresponderá a la opción de


// "Development Tools Overview & Tutorials"
// Los parámetros son los mismos que en el caso anterior
ovw = new BotonImg( this );
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = getImage( getCodeBase(),getParameter( "[Link]" ) );
[Link] = getParameter( "[Link]" );
[Link] = getParameter( "[Link]" );
[Link]();

// Obtenemos los datos del botón que corresponderá a la opción de


// "Java WorkShop FAQ"
faq = new BotonImg(this);
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = [Link]( getParameter( "[Link]" ) ).intValue();
[Link] = getImage( getCodeBase(),getParameter("[Link]" ) );
[Link] = getParameter( "[Link]" );
[Link] = getParameter( "[Link]" );
[Link]();

// Obtenemos los datos del botón que corresponderá a la opción de


// "Resources"
res = new BotonImg( this );
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = [Link](getParameter( "[Link]" ) ).intValue();
[Link] = getImage( getCodeBase(),getParameter( "[Link]" ) );
[Link] = getParameter( "[Link]" );
[Link] = getParameter( "[Link]" );
[Link]();
}

// Aquí pintamos la imagen de fondo y le pasamos el control a cada uno de los


// botones para que controles la imagen que deben pintar en función de la
// acción que se realiza sobre ellos
public void paint( Graphics g ) {
[Link]( new Color( colFondo ) );
[Link]( 0,0,size().width,size().height );
[Link]( fondo,0,0,this );
[Link]( g );
[Link]( g );
[Link]( g );
[Link]( g );
[Link]( g );
}

// Ahora en los métodos que controlan los estados de los botones del ratón,
// pasamos el control a los botones, para que cambien la imagen que
// corresponde al botón sobre el que está actuando el ratón, ya sea solamente
// moviéndose sobre él o actuando con los botones sobre la zona que
// corresponde a ese botón
public boolean mouseUp( Event evt,int i,int j ) {
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
return( false );
}

public boolean mouseDown( Event evt,int i,int j ) {


[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
return( false );
}

public boolean mouseMove( Event evt,int i,int j ) {


[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
[Link]( evt,i,j );
return( false );
}

public MenuDeBotones() {}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 12-Sep-1996 15:39:38
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Calculadora extends Applet {


TextField pantallita;
public final int OP_NADA = 0;
public final int OP_SUMA = 1;
public final int OP_RESTA = 2;
public final int OP_MULT = 3;
public final int OP_DIV = 4;
public final int OP_IGUAL = 5;
public final int OP_BORRAR_C = 6;
public final int OP_BORRAR_AC = 7;
public final int PUNTO_DECIMAL = -1;

String cadDecimal;
int operador = OP_NADA;
boolean nuevoNumero = true;
boolean esDecimal = false;
double Total = 0.0;
boolean esConstante = false;
double numConstante = 0.0;
int opConstante = OP_NADA;

public void init() {


BotonCalculadora bot0,bot1,bot2,bot3,bot4,bot5,bot6,bot7,bot8,bot9;
BotonCalculadora botDecimal,botSuma,botResta;
BotonCalculadora botMult,botDiv,botIgual,botBorraC,botBorraAC;

// No utilizamos ningún la layout porque vamos a colocar


// los botones y el campo de texto para mostrar el resultado
// de las operaciones, en posiciones fijas
setLayout( null );
setFont( new Font( "Helvetica",[Link],14 ) );
setBackground( new Color( 0x66,0xA2,0xD4 ) );

// Pintamos los botones de los numeros


bot0 = new BotonCalculadora( "0",OP_NADA,0 );
add( bot0 );
[Link]( 8,144,96,24 );
bot1 = new BotonCalculadora( "1",OP_NADA,1 );
add( bot1 );
[Link]( 8,112,40,24 );
bot2 = new BotonCalculadora( "2",OP_NADA,2 );
add( bot2 );
[Link]( 64,112,40,24 );
bot3 = new BotonCalculadora( "3",OP_NADA,3 );
add( bot3 );
[Link]( 120,112,40,24 );
bot4 = new BotonCalculadora( "4",OP_NADA,4 );
add( bot4 );
[Link]( 8,80,40,24 );
bot5 = new BotonCalculadora( "5",OP_NADA,5 );
add( bot5 );
[Link]( 64,80,40,24 );
bot6 = new BotonCalculadora( "6",OP_NADA,6 );
add( bot6 );
[Link]( 120,80,40,24 );
bot7 = new BotonCalculadora( "7",OP_NADA,7 );
add( bot7 );
[Link]( 8,48,40,24 );
bot8 = new BotonCalculadora( "8",OP_NADA,8 );
add( bot8 );
[Link]( 64,48,40,24 );
bot9 = new BotonCalculadora( "9",OP_NADA,9 );
add( bot9 );
[Link]( 120,48,40,24 );

// Pintamos los botones que nos van a permitir realizar las


// operaciones soportadas poe esta mini-calculadora
botDecimal = new BotonCalculadora( "¸",OP_NADA,PUNTO_DECIMAL );
add( botDecimal );
[Link]( 120,144,40,24 );
botSuma = new BotonCalculadora( "+",OP_SUMA,0 );
add( botSuma );
[Link]( 176,112,40,56 );
botResta = new BotonCalculadora( "-",OP_RESTA,0 );
add( botResta );
[Link]( 232,112,40,24 );
botMult = new BotonCalculadora( "*",OP_MULT,0 );
add( botMult );
[Link]( 176,80,40,24 );
botDiv = new BotonCalculadora( "/",OP_DIV, 0);
add( botDiv );
[Link]( 176,48,40,24 );
botIgual = new BotonCalculadora( "=",OP_IGUAL,0 );
add( botIgual );
[Link]( 232,144,40,24 );
botBorraC = new BotonCalculadora( "C",OP_BORRAR_C,0 );
add( botBorraC );
[Link]( 232,48,40,24 );
botBorraAC = new BotonCalculadora( "AC",OP_BORRAR_AC,0 );
add( botBorraAC );
[Link]( 232,80,40,24 );

// Pintamos el campo de texto en que vamos a reflejar lo que se


// se va introduciendo y el resultado de las operaciones
pantallita = new TextField( "0",80 );
[Link]( false );
add( pantallita );
[Link]( 48,8,184,31 );
String unaDecima = ( new Double(0.1) ).toString();
cadDecimal =
[Link]( [Link]()-2 ).substring( 0,1 );
}

public static void main( String args[] ) {


Frame f = new Frame( "Calculadora Java" );
Calculadora c = new Calculadora();

[Link]();
[Link]( "Center",c );
[Link]();
[Link]( 395,181 );
[Link]();
}

public void anadir( int valor ) {


String digito;

// Controlamos el punto decimal, para que si es lo primero que se


// pulsa, desplazar un cero a la izquierda, y si se pulsa cuando
// ya estamos en un numero decimal, no hacerle caso
if( valor == PUNTO_DECIMAL )
if( !esDecimal )
{
if( nuevoNumero )
{
[Link]( "0" );
nuevoNumero = false;
}
esDecimal = true;
digito = cadDecimal;
}
else
return;
else
digito = ( new Integer(valor) ).toString();

// Si tenemos que presentar un numero nuevo, porque estemos ya en


// otra operacion, borramos antes la pantallaita
if( nuevoNumero )
{
[Link]( digito );
if( valor != 0 )
nuevoNumero = false;
}
else
[Link]( [Link]() + digito );

repaint();
}

// Ejecuta la operacion que indica el operador del boton que se


// haya pulsado
public void haceOperacion( int nuevoOperador ) {
double numero;

numero = ( new Double( [Link]() ) ).doubleValue();


switch( nuevoOperador )
{
case OP_SUMA:
case OP_RESTA:
case OP_MULT:
case OP_DIV:
if( nuevoNumero )
{
if( nuevoOperador == operador && !esConstante )
{
esConstante = true;
numConstante = numero;
opConstante = nuevoOperador;
}
else
esConstante = false;
}
else
esConstante = false;
case OP_IGUAL:
if( !nuevoNumero || esOperadorIgual( nuevoOperador ) )
{
if( esConstante )
{
Total = numConstante;
operador = opConstante;
}

// Controla los operadores de operaciones


// matematicas
switch( operador )
{
case OP_SUMA:
Total = Total + numero;
break;
case OP_RESTA:
Total = Total - numero;
break;
case OP_MULT:
Total = Total * numero;
break;
case OP_DIV:
Total = Total / numero;
break;
case OP_IGUAL:
case OP_NADA:
Total = numero;
break;
}

// Presenta el resultado del tecleo en la pantalla


[Link](( new Double(Total) ).toString());
}
operador = nuevoOperador;
nuevoNumero = true;
esDecimal = false;
break;
}

// Controla los operadores de borrado tanto el Clear como el


// AllClear
switch( nuevoOperador )
{
// Borra el numero y cancela la operacion en curso
// solamente
case OP_BORRAR_C:
numero = 0.0;
[Link]( "0" );
if( esOperadorIgual( operador ) )
Total = numero;
nuevoNumero = true;
esDecimal = false;
break;
// Borra todas las operaciones y numeros, lo deja
// todo a cero
case OP_BORRAR_AC:
[Link]( "0" );
operador = OP_NADA;
nuevoNumero = true;
esDecimal = false;
Total = 0.0;
esConstante = false;
break;
}
}

// Comprueba si es el operador igual, para presentar resultado


private protected boolean esOperadorIgual( int oper ) {
return( oper == OP_IGUAL );
}
}

// Esta clase se utiliza para pintar cada uno de los botones que van
// a conformar la calculadora
class BotonCalculadora extends Button {
int operador;
int bvalor;

BotonCalculadora( String texto, int oper, int valor ) {


super( texto );
operador = oper;
bvalor = valor;
}

public boolean action( Event evt, Object arg ) {


Calculadora par = ( Calculadora )getParent();

// Si no se tiene ninguna operacion matematica asociada, solamente


// se añade el numero a la pantallita, y si ya es una
// operacion, entonces se hace y se presenta el resultado
if( operador == par.OP_NADA )
[Link]( bvalor );
else
[Link]( operador );

return( true );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 14-Sep-1996 16:33:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Esta clase implementa un contador gráfico, tipo cuentakilómetros de


// coche. Admite que se le pasen tres parámetros desde la llamada al
// applet en la página html que lo incorpore, son:
// DIGITOS Número de dígitos del contador
// INTERVALO Tiempo a transcurrir entre cada incremento
// VALOR_INICIAL Cifra inicial desde la que empieza a contar
// Utiliza un fichero que contiene las imágenes de los dígitos y
// de ahí va extrayendo cada una de las figuras para componer el
// número que tenga que representar en pantalla
//
public class Contador extends Applet implements Runnable {
Thread thread = null;
MediaTracker tracker = null;
Image numeros;
int numero_ancho = 15; // Pixels de ancho de cada uno de los numeros
int numero_alto = 20; // Pixels de alto de cada uno de los numeros
int digitos;
int intervalo;
String valor;
int estado = 0;

public void init() {


String parametro;

// Creamos un objeto mediatracker para soportar el contador


tracker = new MediaTracker( this );

try {
// Cargamos la imagen que contiene los numeros que vamos a
// presentar en el contador
numeros = getImage( getCodeBase(),"[Link]" );
[Link]( numeros,0 );

// Numero de digitos de que consta el contador


parametro = getParameter( "DIGITOS" );
digitos = [Link]( parametro );

// Intervalo entre cada actualizacion del contador


parametro = getParameter( "INTERVALO" );
intervalo = [Link] ( parametro );

// Valor del contador cuando lo arrancamos


valor = getParameter( "VALOR_INICIAL" );
if( valor == null )
valor = [Link](
(long)( [Link]() *
(long)( [Link]( 10,digitos ) ) ) );
} catch( Exception e ) {
return;
}

// Ponemos el applet al tamaño más adecuado


resize( ( digitos * numero_ancho ),numero_alto );

// Creamos y arrancamos el thread que va a controla al


// contador
thread = new Thread( this );
[Link]();
}

public void stop() {


if( thread != null )
{
[Link]();
thread = null;
}
}

// Método principal del thread, donde se llama a la función de


// pintado, que es donde se componen las imágenes de los números
// para reflejar la cifra por donde anda el contador
public void run() {
// Una vez que se ha cargado la imagen de los número, seguimos
[Link]( true );

// repitamos y nos dormimos el intervalo de tiempo que se haya


// indicado
for( ;; )
{
repaint();

try {
[Link]( intervalo );
} catch( InterruptedException e ) {
;
}
}
}

// Cuando se pulsa el ratón, se para el contador y cuando se


// vuelva a pulsar, seguirá contando
public boolean mouseDown( Event e,int x,int y ) {
if( thread != null )
{
[Link]();
thread = null;
}
else
{
thread = new Thread( this );
[Link]();
}
return true;
}

// Controlamos algunas teclas, para poder manipular el contador


public boolean keyDown( Event e,int key ) {
switch( key )
{
case '+': // Va más rápido
intervalo -= 100;
if( intervalo < 10 )
intervalo = 10;
break;

case '-': // Va más lento


intervalo += 100;
break;

case '0': // Lo reseteamos


valor = [Link]( 0 );
estado = 0;
break;

default:
valor = [Link](
(long)( [Link]() * (long)( [Link]( 10,digitos ) ) ) );
estado = 0;
break;
}

return true;
}

// Aquí no borramos la pantalla, sólo pintamos encima


public void update( Graphics g ) {
paint( g );
}

// Pintamos el número
public void paint( Graphics g ) {
int i;
int digit;
boolean scroll;

if( [Link]() == false )


{
[Link]( [Link] );
[Link]( 0,0,(digitos * numero_ancho),numero_alto );
return;
}

int zeros = digitos - [Link]();


for( i=0; i < zeros; i++ )
{
Graphics gc = [Link]( i * numero_ancho,0,
numero_ancho,numero_alto );
[Link]( numeros,0,0,this );
[Link]();
}

scroll = true;

for( i=[Link]() - 1; i >= 0;i-- )


{
digit = [Link]( i ) - '0';

Graphics gc = [Link]( (zeros+i) * numero_ancho,0,


numero_ancho,numero_alto );

// Tenemos en cuenta cuando se va a cambiar de un número


// a otro para ir mostrando la mitad del anterior y la primera
// mitad del siguiente para dar la sensación de movimiento del
// display del contador
if( scroll )
{
switch( estado )
{
case 0:
if( digit == 0 )
[Link]( numeros,0,
-( (9 * numero_alto) + numero_alto / 2 ),this );
[Link]( numeros,0,
-( (digit * numero_alto) - numero_alto / 2 ),this );
break;

case 1:
[Link]( numeros,0,
-(digit * numero_alto),this );
break;

case 2:
[Link]( numeros,0,
-( (digit * numero_alto) + numero_alto / 2 ),this );
if( digit == 9 )
[Link]( numeros,0,
-( (0 * numero_alto) - numero_alto / 2 ),this );
break;
}
}
else
[Link]( numeros,0,-(digit * numero_alto),this );

[Link]();

if( digit != 9 )
scroll = false;
}

if( estado >= 2 )


{
estado = 0;
long l = [Link]( valor );
l++;
valor = [Link]( l );
}
estado++;
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 16-Dic-1996 17:13:51
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

public class EjPotenciometro extends Applet {


Button izda;
Button dcha;
Button todo;
TextField inds;
TextField inds1;
Potenciometro s;
Potenciometro s1;

public void init() {


setBackground( [Link] );
setLayout( null );

// Utilizamos el componente Grupo que ya tenemos desarrollado


// Para agrupar los componentes de esta demo. El primer
// Grupo agrupa a todos los elementos: barras, botones, textos
Grupo g = new Grupo( "Ejemplo de Potenciómetro" );
add( g );
[Link]( new Font( "Dialog",0,12 ) );
[Link]( insets().left+20,insets().top+20,520,250 );
[Link]( null );
// Creamos un potenciómetro vertical
s = new Potenciometro( 0,150,2 );
[Link]( s );
[Link]( 40,50,42,180 );
[Link]( 0 );
inds = new TextField( [Link]( [Link]()),4 );
[Link]( inds );
[Link]( 36,20,45,28 );
// Creamos otro potenciómetro, horizontal
s1 = new Potenciometro( 0,240,1 );
[Link]( s1 );
[Link]( 120,35,365,40 );
[Link]( 0 );
inds1 = new TextField( [Link]( [Link]()),4 );
[Link]( inds1 );
[Link]( 420,80,50,28 );

// Este otro grupo engloba a los botones que permiten posicionar


// las marcas por encima o debajo de la barra
Grupo g2 = new Grupo( "Posición Indicador" );
[Link]( g2 );
[Link]( 105,150,400,70 );
izda = new Button( "Izquierda/Arriba" );
[Link]( izda );
[Link]( 15,25,120,30 );
dcha = new Button( "Derecha/Abajo" );
[Link]( dcha );
[Link]( 145,25,110,30 );
todo = new Button( "Ambas Posiciones" );
[Link]( todo );
[Link]( 265,25,125,30 );
}

public boolean handleEvent( Event evt ) {


[Link]( "Target "+[Link] );
[Link]( " ID "+[Link] );
// Controlamos los eventos de los botones para posicionar
// las marcas y del propio potenciómetro para controlar
// la posicion del indicador y el valor en el texto
if( [Link] == izda && [Link] == 1001 )
{
[Link]( 1 );
[Link]();
[Link]( 1 );
[Link]();
return( true );
}
if( [Link] == dcha && [Link] == 1001 )
{
[Link]( 2 );
[Link]();
[Link]( 2 );
[Link]();
return( true );
}
if( [Link] == todo && [Link] == 1001 )
{
[Link]( 3 );
[Link]();
[Link]( 3 );
[Link]();
return( true );
}
if( [Link] == s && [Link] == 1001 )
{
[Link]( [Link]( [Link]() ) );
return( true );
}
if( [Link] == s1 && [Link] == 1001 )
{
[Link]( [Link]( [Link]() ) );
return( true );
}
switch( [Link] ) {
default:
return( false );
}
}
}

//----------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 16-Dic-1996 16:25:46
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class Potenciometro extends Canvas {


public static final int HORIZONTAL = 1;
public static final int VERTICAL = 2;
public static final int IZQUIERDA = 1;
public static final int DERECHA = 2;
public static final int SUBIR = 3;
public static final int BAJAR = 4;
public static final int SUPERIOR = 1;
public static final int INFERIOR = 2;
public static final int SUP_INF = 3;
boolean boolDrag;
int valor;
int Max;
int Min;
int x_offset;
int y_offset;
int hat_high;
int espacioMarca;
int posicion;
int linIncremento;
int pagIncremento;
int hat_offset;
int orientacion;
int posicionMarca;
Image offscreen;
static Font defFuente;

public Potenciometro( int min,int max,int orient ) {


this( min,max,orient,3 );
}

public Potenciometro( int min,int max,int orient,int posMarca ) {


boolDrag = false;
Max = 100;
hat_high = 12;
espacioMarca = 30;
linIncremento = 1;
pagIncremento = 30;
orientacion = 1;
posicionMarca = 3;
Max = max;
Min = min;
valor = Min;
posicionMarca = posMarca;
orientacion = orient;
setFont( defFuente );
}

// Método que utilizamos para fijar los marcadores en un valor


// determinado
// Aquí se encuentran todos los métodos de get() y set() que se
// utilizan para fijar y recuperar los valores de los parámetros
// que controlan al potenciómetro
public void setValor( int v ) {
Dimension d = size();
valor = v;
if( orientacion == 2 )
{
posicion = [Link]-hat_high - (valor-Min) *
([Link]-hat_high) / (Max-Min);
return;
}
posicion = [Link]-hat_high - (valor-Min) *
([Link]-hat_high) / (Max-Min);
}

public int getValor() {


return( valor );
}

public void setMaximo( int v ) {


Max = v;
}

public int getMaximo() {


return( Max );
}

public void setMinimo( int v ) {


Min = v;
}

public int getMinimo() {


return( Min );
}

public void setEspacioMarca( int f ) {


espacioMarca = f;
}

public int getEspacioMarca() {


return( espacioMarca );
}

public void setPosicionMarca( int p ) {


posicionMarca = p;
}

public int getPosicionMarca() {


return( posicionMarca );
}

public void setPagIncremento( int i ) {


pagIncremento = i;
}

public int getPagIncremento() {


return( pagIncremento );
}
public void setLinIncremento( int i ) {
linIncremento = i;
}

public int getLinIncremento() {


return( linIncremento );
}

public void setOrientacion( int o ) {


orientacion = o;
}

public int getOrientacion() {


return( orientacion );
}

// Repintamos el potenciómetro, sólo una de las posiciones


public void paint( Graphics g ) {
if( orientacion == 1 )
{
printHSlider( g );
return;
}
printVSlider( g );
}

// Pinta el potenciómetro vertical


public void printVSlider( Graphics g ) {
Dimension d = size();
x_offset = 17;
y_offset = 4;
[Link]( [Link] );
g.fill3DRect( x_offset,y_offset,4,[Link]-2*y_offset,false );
[Link]( [Link] );
[Link]( x_offset+1,y_offset+1,x_offset+1,[Link]-y_offset-2 );
[Link]( [Link] );
g.fill3DRect( 5,posicion,27,hat_high,true );
[Link]( getForeground() );

int delta = espacioMarca*[Link]/Max;


for( int y = hat_high/2; y < [Link]-hat_high/2; y += delta )
{
if( posicionMarca != 2 )
[Link]( 0,y,3,y );
if( posicionMarca != 1 )
[Link]( 33,y,36,y );
}

if( posicionMarca != 2 )
[Link]( 0,[Link]-hat_high/2,3,[Link]-hat_high/2 );
if( posicionMarca != 1 )
[Link]( 33,[Link]-hat_high/2,36,[Link]-hat_high/2 );
if( posicionMarca != 2 )
drawTriangulo( g,9,posicion+3,3,1,true );
if( posicionMarca != 1 )
drawTriangulo( g,27,posicion+3,3,2,true );
}

// Pinta el potenciómetro horizontal


public void printHSlider( Graphics g ) {
Dimension d = size();
y_offset = 17;
x_offset = 4;
[Link]( [Link] );
g.fill3DRect( x_offset,y_offset,[Link]-2*x_offset,4,false );
[Link]( [Link] );
[Link]( x_offset+1,y_offset+1,[Link]-x_offset-2,y_offset+1 );
[Link]( [Link] );
g.fill3DRect( posicion,5,hat_high,27,true );
[Link]( getForeground() );

int delta = espacioMarca*[Link]/Max;


for( int x=hat_high/2; x < [Link]-hat_high/2; x += delta )
{
if( posicionMarca != 2 )
[Link]( x,0,x,3 );
if( posicionMarca != 1 )
[Link]( x,33,x,36 );
}

if( posicionMarca != 2 )
[Link]( [Link]-hat_high/2,0,[Link]-hat_high/2,3 );
if( posicionMarca != 1 )
[Link]( [Link]-hat_high/2,33,[Link]-hat_high/2,36 );
if( posicionMarca != 2 )
drawTriangulo( g,posicion+3,9,3,3,true );
if( posicionMarca != 1 )
drawTriangulo( g,posicion+3,27,3,4,true );
}

public void update() {


Dimension d = size();

if( offscreen == null )


offscreen = createImage( [Link],[Link] );
if( offscreen == null )
return;

Graphics offg = [Link]();


Graphics g = getGraphics();
[Link]( 0,0,[Link],[Link] );
[Link]( getFont() );
[Link]( getBackground() );
[Link]( 0,0,[Link],[Link] );
[Link]( [Link]() );
paint( offg );
[Link]( 0,0,[Link],[Link] );
[Link]( offscreen,0,0,this );
}

// Ahora controlamos los eventos que nos llegan del ratón, que son
// el pique y el arrastre
public boolean onMouseDown( int x,int y ) {
Dimension d = size();

if( orientacion == 2 && y > posicion && y < posicion+hat_high )


{
hat_offset = y-posicion;
boolDrag = true;
return( true );
}
if( orientacion == 1 && x > posicion && x < posicion+hat_high )
{
hat_offset = x-posicion;
boolDrag = true;
return( true );
}
if( orientacion == 2 )
{
if( y < posicion )
posicion = (posicion > pagIncremento) ?
(posicion-pagIncremento) : 0;
else if( y > posicion )
posicion = (posicion < [Link]-hat_high-pagIncremento) ?
(posicion+pagIncremento) : ([Link]-hat_high);
valor = Min + (Max-Min) * ([Link]-hat_high-posicion) /
([Link]-hat_high);
}
if( orientacion == 1 )
{
if( x < posicion )
posicion = (posicion > pagIncremento) ?
(posicion-pagIncremento) : 0;
else if( x > posicion )
posicion = (posicion < [Link]-hat_high-pagIncremento) ?
(posicion+pagIncremento) : ([Link]-hat_high);
valor = Min + (Max-Min) * ([Link]-hat_high-posicion) /
([Link]-hat_high);
}
update();
return( true );
}

public boolean onMouseDrag( int x,int y ) {


Dimension d = size();

if( boolDrag && orientacion == 2 )


{
posicion = y-hat_offset;
if( posicion < 0 )
posicion = 0;
if( posicion > [Link]-hat_high )
posicion = [Link]-hat_high;
update();
}
if( boolDrag && orientacion == 1 )
{
posicion = x-hat_offset;
if( posicion < 0 )
posicion = 0;
if( posicion > [Link]-hat_high )
posicion = [Link]-hat_high;
update();
}
return( true );
}

public boolean handleEvent( Event evt ) {


Event evnt;

switch( [Link] ) {
case 501:
return( onMouseDown( evt.x,evt.y ) );
case 502:
evnt = new Event( this,1001,new Integer( valor ) );
break;
case 506:
return( onMouseDrag( evt.x,evt.y ) );
default:
return( false );
}
postEvent( evnt );
boolDrag = false;
return( true );
}

public void reshape( int x,int y,int w,int h ) {


[Link]( x,y,w,h );
offscreen = createImage( w,h );
update();
}

public Dimension preferredSize() {


return( minimumSize() );
}

public Dimension minimumSize() {


return( new Dimension( 40,40 ) );
}

// Pintamos un triangulito sobre el indicador, que apunta hacia


// donde se encuentra la escala que estamos usando
private void drawTriangulo( Graphics g,int x,int y,
int tam,int orient,boolean habil ) {
if( habil )
[Link]( [Link] );
else
[Link]( [Link] );
for( int i=0; i < tam; i++ )
{
switch( orient ) {
case 3:
[Link]( x+i,y-i,x+2*tam-i-1,y-i );
break;
case 4:
[Link]( x+i,y+i,x+2*tam-i-1,y+i );
break;
case 1:
[Link]( x-i,y+i,x-i,y+2*tam-i-1 );
break;
case 2:
[Link]( x+i,y+i,x+i,y+2*tam-i-1 );
break;
}
}
}

static {
defFuente = new Font( "Dialog",0,16);
}
}

//------------------------------------- Final del fichero [Link]


ARQUITECTURA Modelo/Vista/Controlador
La arquitectura MVC (Model/View/Controller) fue introducida como parte de la versión Smalltalk-80 del lenguaje de
programación Smalltalk. Fue diseñada para reducir el esfuerzo de programación necesario en la implementación de
sistemas múltiples y sincronizados de los mismos datos. Sus características principales son que el Modelo, las Vistas
y los Controladores se tratan como entidades separadas; esto hace que cualquier cambio producido en el Modelo se
refleje automáticamente en cada una de las Vistas.

Además del programa ejemplo que hemos presentado al principio y que posteriormente implementaremos, este
modelo de arquitectura se puede emplear en sistemas de representación gráfica de datos, como se ha citado, o en
sistemas CAD, en donde se presentan partes del diseño con diferente escala de aumento, en ventanas separadas.

En la figura siguiente, vemos la arquitectura MVC en su forma más general. Hay un Modelo, múltiples
Controladores que manipulan ese Modelo, y hay varias Vistas de los datos del Modelo, que cambian cuando cambia
el estado de ese Modelo.

Este modelo de arquitectura presenta varias ventajas:

● Hay una clara separación entre los componentes de un programa; lo cual nos permite implementarlos por
separado
● Hay un API muy bien definido; cualquiera que use el API, podrá reemplazar el Modelo, la Vista o el
Controlador, sin aparente dificultad.
● La conexión entre el Modelo y sus Vistas es dinámica; se produce en tiempo de ejecución, no en tiempo de
compilación.

Al incorporar el modelo de arquitectura MVC a un diseño, las piezas de un programa se pueden construir por
separado y luego unirlas en tiempo de ejecución. Si uno de los Componentes, posteriormente, se observa que
funciona mal, puede reemplazarse sin que las otras piezas se vean afectadas. Este escenario contrasta con la
aproximación monolítica típica de muchos programas Java. Todos tienen un Frame que contiene todos los elementos,
un controlador de eventos, un montón de cálculos y la presentación del resultado. Ante esta perspectiva, hacer un
cambio aquí no es nada trivial.

Definición de las partes


El Modelo es el objeto que representa los datos del programa. Maneja los datos y controla todas sus
transformaciones. El Modelo no tiene conocimiento específico de los Controladores o de las Vistas, ni siquiera
contiene referencias a ellos. Es el propio sistema el que tiene encomendada la responsabilidad de mantener enlaces
entre el Modelo y sus Vistas, y notificar a las Vistas cuando cambia el Modelo.

La Vista es el objeto que maneja la presentación visual de los datos representados por el Modelo. Genera una
representación visual del Modelo y muestra los datos al usuario. Interactúa con el Modelo a través de una referencia
al propio Modelo.

El Controlador es el objeto que proporciona significado a las ordenes del usuario, actuando sobre los datos
representados por el Modelo. Cuando se realiza algún cambio, entra en acción, bien sea por cambios en la
información del Modelo o por alteraciones de la Vista. Interactúa con el Modelo a través de una referencia al propio
Modelo.

Vamos a mostrar un ejemplo concreto. Consideremos como tal el sistema descrito en la introducción a este capítulo,
una pieza geométrica en tres dimensiones, que representamos en la figura siguiente:

En este caso, la pieza central de la escena en tres dimensiones es el Modelo. El Modelo es una descripción
matemática de los vértices y las caras que componen la escena. Los datos que describen cada vértice o cara pueden
modificarse (quizás como resultado de una acción del usuario, o una distorsión de la escena, o un algoritmo de
sombreado). Sin embargo, no tiene noción del punto de vista, método de presentación, perspectiva o fuente de luz. El
Modelo es una representación pura de los elementos que componen la escena.

La porción del programa que transforma los datos dentro del Modelo en una presentación gráfica es la Vista. La
Vista incorpora la visión del Modelo a la escena; es la representación gráfica de la escena desde un punto de vista
determinado, bajo condiciones de iluminación determinadas.

El Controlador sabe que puede hacer el Modelo e implementa el interface de usuario que permite iniciar la acción. En
este ejemplo, un panel de datos de entrada es lo único que se necesita, para permitir añadir, modificar o borrar
vértices o caras de la figura.

Tutorial de Java [Anterior] [Indice] [Siguiente]


OBSERVADOR Y OBSERVABLE
El lenguaje de programación Java proporciona soporte para la arquitectura MVC mediante dos clases:

● Observer: Es cualquier objeto que desee ser notificado cuando el estado de otro objeto sea alterado
● Observable: Es cualquier objeto cuyo estado puede representar interés y sobre el cual otro objeto ha
demostrado ese interés

Estas dos clases se pueden utilizar para muchas más cosas que la implementación de la arquitectura MVC. Serán
útiles en cualquier sistema en que se necesite que algunos objetos sean notificados cuando ocurran cambios en otros
objetos.

El Modelo es un subtipo de Observable y la Vista es un subtipo de Observer. Estas dos clases manejan
adecuadamente la función de notificación de cambios que necesita la arquitectura MVC. Proporcionan el mecanismo
por el cual las Vistas pueden ser notificadas automáticamente de los cambios producidos en el Modelo. Referencias
al objeto Modelo tanto en el Controlador como en la Vista permiten acceder a los datos de ese objeto Modelo.

Funciones Observer y Observable

Vamos a enumerar las funciones que intervienen en el control de Observador y Observable:

Observer

public void update( Observableobs,Object obj )

Llamada cuando se produce un cambio en el estado del objeto Observable

Observable

public void addObserver( Observer obs )

Añade un observador a la lista interna de observadores

public void deleteObserver( Observer obs )

Borra un observador de la lista interna de observadores

public void deleteObservers()

Borra todos los observadores de la lista interna

public int countObserver()


Devuelve el número de observadores en la lista interna

protected void setChanged()

Levanta el flag interno que indica que el Observable ha cambiado de estado

protected void clearChanged()

Baja el flag interno que indica que el Observable ha cambiado de estado

protected boolean hasChanged()

Devuelve un valor booleano indicando si el Observable ha cambiado de estado

public void notifyObservers()

Comprueba el flag interno para ver si el Observable ha cambiado de estado y lo notifica a todos los
observadores

public void notifyObservers( Object obj )

Comprueba el flag interno para ver si el Observable ha cambiado de estado y lo notifica a todos los
observadores. Les pasa el objeto especificado en la llamada para que lo usen los observadores en su
método notify().

Tutorial de Java [Anterior] [Indice] [Siguiente]


UTILIZAR OBSERVADOR Y OBSERVABLE
Vamos a describir en los siguientes apartados, como crear una nueva clase Observable y una nueva clase Observer
y como utilizar las dos conjuntamente.

Extender un Observable

Una nueva clase de objetos observables se crea extendiendo la clase Observable. Como la clase Observable ya
implementa todos los métodos necesarios para proporcionar el funcionamiento de tipo Observador/Observable, la
clase derivada solamente necesita proporcionar algún tipo de mecanismo que lo ajuste a su funcionamiento particular
y proporcionar acceso al estado interno del objeto Observable.

En la clase ValorObservable que mostramos a continuación, el estado interno del Modelo es capturado en el entero
n. A este valor se accede (y más importante todavía, se modifica) solamente a través de sus métodos públicos. Si el
valor cambia, el objeto invoca a su propio método setChanged() para indicar que el estado del Modelo ha cambiado.
Luego, invoca a su propio método notifyObservers() para actualizar a todos los observadores registrados.

import [Link];

public class ValorObservable extends Observable {


private int nValor = 0;

// Constructor al que indicamos el valor en que comenzamos y los


// limites inferior y superior que no deben sobrepasarse
public ValorObservable( int nValor,int nInferior,int nSuperior ) {
[Link] = nValor;
}

// Fija el valor que le pasamos y notifica a los observadores que


// estan pendientes del cambio de estado de los objetos de esta
// clase, que su etado se ha visto alterado
public void setValor(int nValor) {
[Link] = nValor;

setChanged();
notifyObservers();
}

// Devuelve el valor actual que tiene el objeto


public int getValor() {
return( nValor );
}
}
Implementar un Observador

Una nueva clase de objetos que observe los cambios en el estado de otro objeto se puede crear implementando la
interface Observer. Esta interface necesita un método update() que se debe proporcionar en la nueva clase. Este
método será llamado siempre que el Observable cambie de estado, que anuncia este cambio llamando a su método
notifyObservers(). El observador entonces, debería interrogar al objeto Observable para determinar su nuevo estado;
y, en el caso de la arquitectura MVC, ajustar su Vista adecuadamente.

En la clase ObservadorDeTexto, que muestra el código siguiente, el método notify() primero realiza una
comprobación para asegurarse de que el Observable que ha anunciado un cambio es el Observable que él esta
observando. Si lo es, entonces lee su estado e imprime el nuevo valor.

import [Link];
import [Link];

public class TextoObservador extends Frame implements Observer {


private ValorObservable vo = null;

public TextoObservador( ValorObservable vo ) {


[Link] = vo;
}

public void update( Observable obs,Object obj ) {


if( obs == vo )
[Link]( [Link]( [Link]() ) );
}
}

Usando Observador y Observable

Un programa indica a un objeto Observable que hay un objeto observador que debe ser notificado cuando se
produzca un cambio en su estado, llamando al método addObserver() del objeto Observable. Este método añade el
Observador a la lista de observadores que el objeto Observable ha de notificar cuando su estado se altere.

En el ejemplo siguiente, en donde mostramos la clase ControlValor, [Link], vemos como se usa el
método addObserver() para añadir una instancia de la clase TextoObservador a la lista que mantiene la clase
ValorObservable.

public class ControlValor {

// Constructor de la clase que nos permite crear los objetos de


// observador y observable
public ControlValor() {
ValorObservable vo = new ValorObservable( 100,0,500 );
TextoObservador to = new TextoObservador( vo );

[Link]( to );
}

public static void main( String args[] ) {


ControlValor m = new ControlValor();
}
}
En la siguiente secuencia, vamos a describir como se realiza la interacción entre un Observador y un objeto
Observable, durante la ejecución de un programa:

1. En primer lugar el usuario manipula un elemento del interface de usuario representado por el Controlador.
Este Controlador realiza un cambio en el Modelo a través de uno de sus métodos públicos de acceso; en
nuestro caso, llama a setValue().
2. El método público de acceso modifica el dato privado, ajusta el estado interno del Modelo y llama al método
setChanged() para indicar que su estado ha cambiado. Luego llama al método notifyObservers() para notificar
a los observadores que su estado no es el mismo. La llamada a este método puede realizarse en cualquier
lugar, incluso desde un bucle de actualización que se esté ejecutando en otro thread.
3. Se llama a los métodos update() de cada Observador, indicando que hay un cambio en el estado del objeto que
estaban observando. El Observador accede entonces a los datos del Modelo a través del método público del
Observable y actualiza las Vistas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


EJEMPLO DE APLICACION MVC
En el ejemplo siguiente, vemos como colaboran juntos Observador y Observable en la arquitectura MVC:

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

El Modelo de este ejemplo es muy simple. Su estado interno consta de un valor entero. Este valor, o estado, es
manipulado exclusivamente a través de métodos públicos de acceso. El código del modelo se encuentra
implementado en [Link].

Inicialmente, hemos escrito una clase simple de Vista/Controlador. La clase combina las características de una Vista
(presenta el valor que corresponde al estado actual del Modelo) y un Controlador (permite al usuario introducir un
nuevo valor para alterar el estado del Modelo). El código se encuentra en el fichero [Link]. Podemos
crear instancias de esta vista pulsando el botón superior que aparece en el applet.

A través de este diseño utilizando la arquitectura MVC (en lugar de colocar el código para que el Modelo, la Vista y
el Controlador de texto en una clase monolítica), el sistema puede ser fácilmente rediseñado para manejar otra Vista
y otro Controlador. En este caso, hemos visto una clase Vista/Controlador con una barra de desplazamiento. La
posición del marcador en la barra representa el valor actual que corresponde con el estado del Modelo y puede ser
alterado a través de movimientos del marcador sobre la barra por acción del usuario. El código de esta clase se
encuentra en [Link]. Se pueden crear instancias de esta clase pulsando el botón inferior del applet de
esta página.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 08:56:05
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link];

public class ValorObservable extends Observable {


private int nValor = 0;
private int nInferior = 0;
private int nSuperior = 0;

// Constructor al que indicamos el valor en que comenzamos y los


// limites inferior y superior que no deben sobrepasarse
public ValorObservable( int nValor,int nInferior,int nSuperior ) {
[Link] = nValor;
[Link] = nInferior;
[Link] = nSuperior;
}

// Fija el valor que le pasamos y notifica a los observadores que


// estan pendientes del cambio de estado de los objetos de esta
// clase, que su etado se ha visto alterado
public void setValor(int nValor) {
[Link] = nValor;

setChanged();
notifyObservers();
}

// Devuelve el valor actual que tiene el objeto


public int getValor() {
return( nValor );
}

// Devuelve el limite inferior del rango de valores en los que se ha


// de mover el objeto
public int getLimiteInferior() {
return( nInferior );
}

// Devuelve el limite superior del rango de valores en los que se ha


// de mover el objeto
public int getLimiteSuperior() {
return( nSuperior );
}
}
//----------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 09:24:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import [Link];

public class TextoObservador extends Frame implements Observer {


private ValorObservable vo = null;
private TextField tf = null;
private Label l = null;
private int nInferior = 0;
private int nSuperior = 0;

// Constructor en el que creamos una ventana donde poder introducir


// el valor numerico que represente la cantidad que corresponda
// al objeto observable
public TextoObservador( ValorObservable vo ) {
super("Observador de Texto");

[Link] = vo;
setLayout( new GridLayout( 0,1 ) );
nInferior = [Link]();
nSuperior = [Link]();

tf = new TextField( [Link]( [Link]() ) );


add( tf );

l = new Label();
add( l );

pack();
show();
}

// Controlamos el evento que proviene del campo de texto, cuando se


// introduce un valor numerico
public boolean action( Event evt,Object obj ) {
if( [Link] == tf )
{
int n = 0;
boolean bValido = false;

try {
n = [Link]( [Link]() );
bValido = true;
} catch( NumberFormatException nfe ) {
bValido = false;
}

// Comprobamos que no se sobrepasen los limites que hemos


// fijado
if( n < nInferior || n > nSuperior )
bValido = false;

if( bValido )
{
[Link]( n );
[Link]( "" );
}
else
[Link]( "Valor no valido - intentelo de nuevo" );

return( true );
}

return( false );
}

// Controlamos el cierre de la ventana, para eliminar el objeto


// que hemos creado antes de hacer desaparecer la ventana
public boolean handleEvent( Event evt ) {
if( [Link] == Event.WINDOW_DESTROY )
{
[Link]( this );
dispose();
return( true );
}

return( [Link]( evt ) );


}

// Actualizamos el valor del objeto que estamos observando en


// nuestro campo de texto, para reflejar el valor actual del
// objeto
public void update( Observable obs,Object obj ) {
if( obs == vo )
[Link]( [Link]( [Link]() ) );
}
}

//----------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Jun-1996 05:18:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import [Link];

public class BarraObservador extends Frame implements Observer {


private ValorObservable vo = null;
private Scrollbar sb = null;

// Constructor que presenta una ventanita con la barra de


// desplazamiento para poder ir alterando los valores del
// objeto observable
public BarraObservador( ValorObservable vo ) {
super( "Observador de Barra" );

[Link] = vo;
setLayout( new GridLayout( 0,1 ) );

sb = new Scrollbar( [Link],[Link](),10,


[Link](),[Link]() );
add( sb );
pack();
show();
}

// Manejamos los eventos que se producen al manipular la barra y


// al destruir la ventana
// Cuando desplazamos el marcador de la barra, vamos actualizando
// el valor del objeto observable y presentamos el valor que
// se ha adquirido
public boolean handleEvent( Event evt ) {
if( [Link] == Event.WINDOW_DESTROY )
{
[Link]( this );
dispose();
return( true );
}
else if( [Link] == Event.SCROLL_LINE_UP )
{
[Link]( [Link]() );
return( true );
}
else if( [Link] == Event.SCROLL_LINE_DOWN )
{
[Link]( [Link]() );
return( true );
}
else if( [Link] == Event.SCROLL_PAGE_UP )
{
[Link]( [Link]() );
return( true );
}
else if( [Link] == Event.SCROLL_PAGE_DOWN )
{
[Link]( [Link]() );
return( true );
}
else if( [Link] == Event.SCROLL_ABSOLUTE )
{
[Link]( [Link]() );
return( true );
}

return( [Link]( evt ) );


}

// Actualizamos el valor que corresponde al numero que actualmente


// tiene el objeto que estamos observando
public void update( Observable obs,Object obj ) {
if( obs == vo )
[Link]( [Link]() );
}
}

//----------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 01-Oct-1996 09:18:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

public class ControlValor {

// Constructor de la clase que nos permite crear los objetos de


// observador y observable
public ControlValor() {
ValorObservable vo = new ValorObservable( 100,0,500 );
TextoObservador to = new TextoObservador( vo );
BarraObservador bo = new BarraObservador( vo );

[Link]( to );
[Link]( bo );
}

public static void main( String args[] ) {


ControlValor m = new ControlValor();
}
}

//------------------------------------- Final del fichero [Link]


COMUNICACIONES EN UNIX
El sistema de Entrada/Salida de Unix sigue el paradigma que normalmente se designa como Abrir-Leer-Escribir-
Cerrar. Antes de que un proceso de usuario pueda realizar operaciones de entrada/salida, debe hacer una llamada a
Abrir (open) para indicar, y obtener permisos para su uso, el fichero o dispositivo que quiere utilizar. Una vez que el
objeto está abierto, el proceso de usuario realiza una o varias llamadas a Leer (read) y Escribir (write), para
conseguir leer y escribir datos. Leer coge datos desde el objeto y los transfiere al proceso de usuario, mientras que
Escribir transfiere datos desde el proceso de usuario al objeto. Una vez que todos estos intercambios de información
estén concluidos, el proceso de usuario llamará a Cerrar (close) para informar al sistema operativo que ha finalizado
la utilización del objeto que antes había abierto.

Cuando se incorporan las características a Unix de comunicación entre procesos (IPC) y el manejo de redes, la idea
fue implementar la interface con IPC similar a la que se estaba utilizando para la entrada/salida de ficheros, es decir,
siguiendo el paradigma del párrafo anterior. En Unix, un proceso tiene un conjunto de descriptores de entrada/salida
desde donde Leer y por donde Escribir. Estos descriptores pueden estar referidos a ficheros, dispositivos, o canales
de comunicaciones (sockets). El ciclo de vida de un descriptor, aplicado a un canal de comunicación (socket), está
determinado por tres fases (siguiendo el paradigma):

● Creación, apertura del socket


● Lectura y Escritura, recepción y envío de datospor el socket
● Destrucción, cierre del socket

La interface IPC en Unix-BSD está implementada sobre los protocolos de red TCP y UDP. Los destinatarios de los
mensajes se especifican como direcciones de socket; cada dirección de socket es un identificador de comunicación
que consiste en una dirección Internet y un número de puerto.

Las operaciones IPC se basan en pares de sockets. Se intercambian información transmitiendo datos a través de
mensajes que circulan entre un socket en un proceso y otro socket en otro proceso. Cuando los mensajes son
enviados, se encolan en el socket hasta que el protocolo de red los haya transmitido. Cuando llegan, los mensajes son
encolados en el socket de recepción hasta que el proceso que tiene que recibirlos haga las llamadas necesarias para
recoger esos datos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


SOCKETS
Los sockets son puntos finales de enlaces de comunicaciones entre procesos. Los procesos los tratan como
descriptores de ficheros, de forma que se pueden intercambiar datos con otros procesos transmitiendo y recibiendo a
través de sockets.

El tipo de sockets describe la forma en la que se transfiere información a través de ese socket.

Sockets Stream (TCP, Transmission Control Protocol)

Son un servicio orientado a conexión donde los datos se transfieren sin encuadrarlos en registros o bloques. Si se
rompe la conexión entre los procesos, éstos serán informados.

El protocolo de comunicaciones con streams es un protocolo orientado a conexión, ya que para establecer una
comunicación utilizando el protocolo TCP, hay que establecer en primer lugar una conexión entre un par de sockets.
Mientras uno de los sockets atiende peticiones de conexión (servidor), el otro solicita una conexión (cliente). Una vez
que los dos sockets estén conectados, se pueden utilizar para transmitir datos en ambas direcciones.

Sockets Datagrama (UDP, User Datagram Protocol)

Son un servicio de transporte sin conexión. Son más eficientes que TCP, pero no está garantizada la fiabilidad. Los
datos se envían y reciben en paquetes, cuya entrega no está garantizada. Los paquetes pueden ser duplicados,
perdidos o llegar en un orden diferente al que se envió.

El protocolo de comunicaciones con datagramas es un protocolo sin conexión, es decir, cada vez que se envíen
datagramas es necesario enviar el descriptor del socket local y la dirección del socket que debe recibir el datagrama.
Como se puede ver, hay que enviar datos adicionales cada vez que se realice una comunicación.

Sockets Raw

Son sockets que dan acceso directo a la capa de software de red subyacente o a protocolos de más bajo nivel. Se
utilizan sobre todo para la depuración del código de los protocolos.

Diferencias entre Sockets Stream y Datagrama

Ahora se nos presenta un problema, ¿qué protocolo, o tipo de sockets, debemos usar - UDP o TCP? La decisión
depende de la aplicación cliente/servidor que estemos escribiendo. Vamos a ver algunas diferencias entre los
protocolos para ayudar en la decisión.

En UDP, cada vez que se envía un datagrama, hay que enviar también el descriptor del socket local y la dirección del
socket que va a recibir el datagrama, luego éstos son más grandes que los TCP. Como el protocolo TCP está
orientado a conexión, tenemos que establecer esta conexión entre los dos sockets antes de nada, lo que implica un
cierto tiempo empleado en el establecimiento de la conexión, que no existe en UDP.

En UDP hay un límite de tamaño de los datagramas, establecido en 64 kilobytes, que se pueden enviar a una
localización determinada, mientras que TCP no tiene límite; una vez que se ha establecido la conexión, el par de
sockets funciona como los streams: todos los datos se leen inmediatamente, en el mismo orden en que se van
recibiendo.

UDP es un protocolo desordenado, no garantiza que los datagramas que se hayan enviado sean recibidos en el mismo
orden por el socket de recepción. Al contrario, TCP es un protocolo ordenado, garantiza que todos los paquetes que
se envíen serán recibidos en el socket destino en el mismo orden en que se han enviado.

Los datagramas son bloques de información del tipo lanzar y olvidar. Para la mayoría de los programas que utilicen
la red, el usar un flujo TCP en vez de un datagrama UDP es más sencillo y hay menos posibilidades de tener
problemas. Sin embargo, cuando se requiere un rendimiento óptimo, y está justificado el tiempo adicional que supone
realizar la verificación de los datos, los datagramas son un mecanismo realmente útil.

En resumen, TCP parece más indicado para la implementación de servicios de red como un control remoto (rlogin,
telnet) y transmisión de ficheros (ftp); que necesitan transmitir datos de longitud indefinida. UDP es menos complejo
y tiene una menor sobrecarga sobre la conexión; esto hace que sea el indicado en la implementación de aplicaciones
cliente/servidor en sistemas distribuidos montados sobre redes de área local.

Tutorial de Java [Anterior] [Indice] [Siguiente]


USO DE SOCKETS
Podemos pensar que un Servidor Internet es un conjunto de sockets que proporciona capacidades adicionales del
sistema, los llamados servicios.

Puertos y Servicios

Cada servicio está asociado a un puerto. Un puerto es una dirección numérica a través de la cual se procesa el
servicio. Sobre un sistema Unix, los servicios que proporciona ese sistema se indican en el fichero /etc/services, y
algunos ejemplos son:

daytime 13/udp
ftp 21/tcp
telnet 23/tcp telnet
smtp 25/tcp mail
http 80/tcp

La primera columna indica el nombre del servicio. La segunda columna indica el puerto y el protocolo que está
asociado al servicio. La tercera columna es un alias del servicio; por ejemplo, el servicio smtp, también conocido
como mail, es la implementación del servicio de correo electrónico.

Las comunicaciones de información relacionada con Web tienen lugar a través del puerto 80 mediante protocolo
TCP. Para emular esto en Java, usaremos la clase Socket. La fecha (daytime). Sin embargo, el servicio que coge la
fecha y la hora del sistema, está ligado al puerto 13 utilizando el protocolo UDP. Un servidor que lo emule en Java
usaría un objeto DatagramSocket.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE URL
La clase URL contiene contructores y métodos para la manipulación de URL (Universal Resource Locator): un objeto o
servicio en Internet. El protocolo TCP necesita dos tipos de información: la dirección IP y el número de puerto. Vamos a
ver como podemos recibir pues la página Web principal de nuestro buscador favorito al teclear:

[Link]

En primer lugar, Yahoo tiene registrado su nombre, permitiendo que se use [Link] como su dirección IP, o lo que es lo
mismo, cuando indicamos [Link] es como si hubiesemos indicado [Link], su dirección IP real.

La verdad es que la cosa es un poco más complicada que eso. Hay un servicio, el DNS (Domain Name Service), que
traslada [Link] a [Link], lo que nos permite teclear [Link], en lugar de tener que recordar su
dirección IP.

Si queremos obtener la dirección IP real de la red en que estamos corriendo, podemos realizar llamadas a los métodos
getLocalHost() y getAddress(). Primero, getLocalHost() nos devuelve un objeto iNetAddress, que si usamos con
getAddress() generará un array con los cuatro bytes de la dirección IP, por ejemplo:

InetAddress direccion = [Link]();


byte direccionIp[] = [Link]();

Si la dirección de la máquina en que estamos corriendo es [Link], entonces:

direccionIp[0] = 150
direccionIp[1] = 150
direccionIp[2] = 112
direccionIp[3] = 145

Una cosa interesante en este punto es que una red puede mapear muchas direcciones IP. Esto puede ser necesario para un
Servidor Web, como Yahoo, que tiene que soportar grandes cantidades de tráfico y necesita más de una dirección IP para
poder atender a todo ese tráfico. El nombre interno para la dirección [Link], por ejemplo, es [Link]. El
DNS puede trasladar una lista de direcciones IP asignadas a Yahoo en [Link]. Esto es una cualidad útil, pero por
ahora abre un agujero en cuestión de seguridad.

Ya conocemos la dirección IP, nos falta el número del puerto. Si no se indica nada, se utilizará el que se haya definido por
defecto en el fichero de configuración de los servicios del sistema. En Unix se indican en el fichero /etc/services, en
Windows-NT en el fichero services y en otros sistemas puede ser diferente.

El puerto habitual de los servicios Web es el 80, así que si no indicamos nada, entraremos en el servidor de Yahoo por el
puerto 80. Si tecleamos la URL siguiente en un navegador:

[Link]

también recibiremos la página principal de Yahoo. No hay nada que nos impida cambiar el puerto en el que residirá el
servidor Web; sin embargo, el uso del puerto 80 es casi estándar, porque elimina pulsaciones en el teclado y, además, las
direcciones URL son lo suficientemente difíciles de recordar como para añadirle encima el número del puerto.

Si necesitamos otro protocolo, como:

[Link]

el puerto se derivará de ese protocolo. Así el puerto FTP de Microsoft es el 21, según su fichero services. La primera
parte, antes de los dos puntos, de la URL, indica el protocolo que se quiere utilizar en la conexión con el servidor. El
protocolo http (HyperText Transmission Protocol), es el utilizado para manipular documentos Web. Y si no se especifica
ningún documento, muchos servidores están configurados para devolver un documento de nombre [Link].

Con todo esto, Java permite los siguientes cuatro constructores para la clase URL:

public URL( String spec ) throws MalformedURLException;


public URL( String protocol,String host,int port,String file ) throws
MalformedURLException;
public URL( String protocol,String host,String file ) throws MalformedURLException;
public URL( URL context,String spec ) throws MalformedURLException;

Así que podríamos especificar todos los componenetes del URL como en:

URL( "http","[Link]","80","[Link]" );

o dejar que los sistemas utilicen todos los valores por defecto que tienen definidos, como en:

URL( "[Link] );

y en los dos casos obtendríamos la visualización de la página principal de Yahoo en nuestro navegador.

Tutorial de Java [Anterior] [Indice] [Siguiente]


DOMINIOS DE COMUNICACIONES
El mecanismo de sockets está diseñado para ser todo lo genérico posible. El socket por sí mismo no contiene
información suficiente para describir la comunicación entre procesos. Los sockets operan dentro de dominios de
comunicación, entre ellos se define si los dos procesos que se comunican se encuentran en el mismo sistema o en
sistemas diferentes y cómo pueden ser direccionados.

Dominio Unix

Bajo Unix, hay dos dominios, uno para comunicaciones internas al sistema y otro para comunicaciones entre
sistemas.

Las comunicaciones intrasistema (entre dos procesos en el mismo sistema) ocurren (en una máquina Unix) en el
dominio Unix. Se permiten tanto los sockets stream como los datagrama. Los sockets de dominio Unix bajo Solaris
2.x se implementan sobre TLI (Transport Level Interface).

En el dominio Unix no se permiten sockets de tipo Raw.

Dominio Internet

Las comunicaciones intersistemas proporcionan acceso a TCP, ejecutando sobre IP (Internet Protocol). De la misma
forma que el dominio Unix, el dominio Internet permite tanto sockets stream como datagrama, pero además permite
sockets de tipo Raw.

Los sockets stream permiten a los procesos comunicarse a través de TCP. Una vez establecidas las conexiones, los
datos se pueden leer y escribir a/desde los sockets como un flujo (stream) de bytes. Algunas aplicaciones de servicios
TCP son:

● File Tranfer Protocol, FTP


● Simple Mail Transfer Protocol, SMTP
● TELNET, servicio de conexión de terminal remoto

Los sockets datagrama permiten a los procesos utilizar el protocolo UDP para comunicarse a y desde esos sockets
por medio de bloques. UDP es un protocolo no fiable y la entrega de los paquetes no está garantizada. Servicios UDP
son:

● Simple Network Management Protocol, SNMP


● Trivial File Transfer Protocol, TFTP (versión de FTP sin conexión)
● Versatile Message Transaction Protocol, VMTP (servicio fiable de entrega punto a punto de datagramas
independiente de TCP)

Los sockets raw proporcionan acceso al Internet Control Message Protocol, ICMP, y se utiliza para comunicarse
entre varias entidades IP.
Tutorial de Java [Anterior] [Indice] [Siguiente]
MODELO DE COMUNICACIONES CON JAVA
En Java, crear una conexión socket TCP/IP se realiza directamente con el paquete [Link]. A continuación
mostramos un diagrama de lo que ocurre en el lado del cliente y del servidor:

El modelo de sockets más simple es:

● El servidor establece un puerto y espera durante un cierto tiempo (timeout segundos), a que el cliente
establezca la conexión. Cuando el cliente solicite una conexión, el servidor abrirá la conexión socket con el
método accept().
● El cliente establece una conexión con la máquina host a través del puerto que se designe en puerto#
● El cliente y el servidor se comunican con manejadores InputStream y OutputStream

Hay una cuestión al respecto de los sockets, que viene impuesta por la implementación del sistema de seguridad de
Java. Actualmente, los applets sólo pueden establecer conexiones con el nodo desde el cual se transfirió su código.
Esto está implementado en el JDK y en el intérprete de Java de Netscape. Esto reduce en gran manera la flexibilidad
de las fuentes de datos disponibles para los applets. El problema si se permite que un applet se conecte a cualquier
máquina de la red, es que entonces se podrían utilizar los applets para inundar la red desde un ordenador con un
cliente Netscape del que no se sospecha y sin ninguna posibilidad de rastreo.

Tutorial de Java [Anterior] [Indice] [Siguiente]


APERTURA DE SOCKETS
Si estamos programando un cliente, el socket se abre de la forma:

Socket miCliente;
miCliente = new Socket( "maquina",numeroPuerto );

Donde maquina es el nombre de la máquina en donde estamos intentando abrir la conexión y numeroPuerto es
el puerto (un número) del servidor que está corriendo sobre el cual nos queremos conectar. Cuando se selecciona un
número de puerto, se debe tener en cuenta que los puertos en el rango 0-1023 están reservados para usuarios con
muchos privilegios (superusuarios o root). Estos puertos son los que utilizan los servicios estándar del sistema como
email, ftp o http. Para las aplicaciones que se desarrollen, asegurarse de seleccionar un puerto por encima del 1023.

En el ejemplo anterior no se usan excepciones; sin embargo, es una gran idea la captura de excepciones cuando se
está trabajando con sockets. El mismo ejemplo quedaría como:

Socket miCliente;
try {
miCliente = new Socket( "maquina",numeroPuerto );
} catch( IOException e ) {
[Link]( e );
}

Si estamos programando un servidor, la forma de apertura del socket es la que muestra el siguiente ejemplo:

Socket miServicio;
try {
miServicio = new ServerSocket( numeroPuerto );
} catch( IOException e ) {
[Link]( e );
}

A la hora de la implementación de un servidor también necesitamos crear un objeto socket desde el ServerSocket
para que esté atento a las conexiones que le puedan realizar clientes potenciales y poder aceptar esas conexiones:

Socket socketServicio = null;


try {
socketServicio = [Link]();
} catch( IOException e ) {
[Link]( e );
}
Tutorial de Java [Anterior] [Indice] [Siguiente]
CREACION DE STREAMS
Creación de Streams de Entrada

En la parte cliente de la aplicación, se puede utilizar la clase DataInputStream para crear un stream de entrada que
esté listo a recibir todas las respuestas que el servidor le envíe.

DataInputStream entrada;
try {
entrada = new DataInputStream( [Link]() );
} catch( IOException e ) {
[Link]( e );
}

La clase DataInputStream permite la lectura de líneas de texto y tipos de datos primitivos de Java de un modo
altamente portable; dispone de métodos para leer todos esos tipos como: read(), readChar(), readInt(), readDouble()
y readLine(). Deberemos utilizar la función que creamos necesaria dependiendo del tipo de dato que esperemos
recibir del servidor.

En el lado del servidor, también usaremos DataInputStream, pero en este caso para recibir las entradas que se
produzcan de los clientes que se hayan conectado:

DataInputStream entrada;
try {
entrada =
new DataInputStream( [Link]() );
} catch( IOException e ) {
[Link]( e );
}

Creación de Streams de Salida

En el lado del cliente, podemos crear un stream de salida para enviar información al socket del servidor utilizando las
clases PrintStream o DataOutputStream:

PrintStream salida;
try {
salida = new PrintStream( [Link]() );
} catch( IOException e ) {
[Link]( e );
}

La clase PrintStream tiene métodos para la representación textual de todos los datos primitivos de Java. Sus
métodos write y println() tienen una especial importancia en este aspecto. No obstante, para el envío de información
al servidor también podemos utilizar DataOutputStream:

DataOutputStream salida;
try {
salida = new DataOutputStream( [Link]() );
} catch( IOException e ) {
[Link]( e );
}

La clase DataOutputStream permite escribir cualquiera de los tipos primitivos de Java, muchos de sus métodos
escriben un tipo de dato primitivo en el stream de salida. De todos esos métodos, el más útil quizás sea writeBytes().

En el lado del servidor, podemos utilizar la clase PrintStream para enviar información al cliente:

PrintStream salida;
try {
salida = new PrintStream( [Link]() );
} catch( IOException e ) {
[Link]( e );
}

Pero también podemos utilizar la clase DataOutputStream como en el caso de envío de información desde el
cliente.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CIERRE DE SOCKETS
Siempre deberemos cerrar los canales de entrada y salida que se hayan abierto durante la ejecución de la aplicación.
En la parte del cliente:

try {
[Link]();
[Link]();
[Link]();
} catch( IOException e ) {
[Link]( e );
}

Y en la parte del servidor:

try {
[Link]();
[Link]();
[Link]();
[Link]();
} catch( IOException e ) {
[Link]( e );
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


MINIMO CLIENTE SMTP
Vamos a desarrollar un mínimo cliente SMTP (simple mail transfer protocol), de forma que podamos encapsular
todos los datos en la aplicación. El código es libre de modificación para las necesidades que sean; por ejemplo, una
modificación interesante sería que aceptase argumentos desde la línea de comandos y también capturase el texto del
mensaje desde la entrada estándar del sistema. Con estas modificaciones tendríamos casi la misma aplicación de
correo que utiliza Unix. Veamos el código de nuestro cliente, [Link]:

import [Link].*;
import [Link].*;

class smtpCliente {
public static void main( String args[] ) {
Socket s = null;
DataInputStream sIn = null;
DataOutputStream sOut = null;

// Abrimos una conexión con breogan en el puerto 25


// que es el correspondiente al protocolo smtp, e intentamos
// abrir los streams de entrada y salida
try {
s = new Socket( "breogan",25 );
sIn = new DataInputStream( [Link]() );
sOut = new DataOutputStream( [Link]() );
} catch( UnknownHostException e ) {
[Link]( "No conozco el host" );
} catch( IOException e ) {
[Link]( e );
}

// Si todo está inicializado correctamente, vamos a escribir


// algunos datos en el canal de salida que se ha establecido
// con el puerto del protocolo smtp del servidor
if( s != null && sIn != null && sOut != null )
{
try {
// Tenemos que respetar la especificación SMTP dada en
// RFC1822/3, de forma que lo que va en mayúsculas
// antes de los dos puntos tiene un significado especial
// en el protocolo
[Link]( "MAIL From: froufe@[Link]\n" );
[Link]( "RCPT To: froufe@[Link]\n" );
[Link]( "DATA\n" );
[Link]( "From: froufe@[Link]\n" );
[Link]( "Subject: Pruebas\n" );
// Ahora el cuerpo del mensaje
[Link]( "Hola, desde el Tutorial de Java\n" );
[Link]( "\n.\n" );

// Nos quedamos a la espera de recibir el "Ok" del


// servidor para saber que ha recibido el mensaje
// correctamente, momento en el cual cortamos
String respuesta;
while( ( respuesta = [Link]() ) != null )
{
[Link]( "Servidor: "+respuesta );
if( [Link]( "Ok" ) != -1 )
break;
}

// Cerramos todo lo que hemos abierto


[Link]();
[Link]();
[Link]();
} catch( UnknownHostException e ) {
[Link]( "Intentando conectar: "+e );
} catch( IOException e ) {
[Link]( e );
}
}
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


SERVIDOR DE ECO
En el siguiente ejemplo, vamos a desarrollar un servidor similar al que se ejecuta sobre el puerto 7 de las máquinas
Unix, el servidor echo. Básicamente, este servidor recibe texto desde un cliente y reenvía ese mismo texto al cliente.
Desde luego, este es el servidor más simple de los simples que se pueden escribir. El ejemplo que presentamos,
[Link], maneja solamente un cliente. Una modificación interesante sería adecuarlo para que aceptase
múltiples clientes simultáneos mediante el uso de threads.

import [Link].*;
import [Link].*;

class ecoServidor {
public static void main( String args[] ) {
ServerSocket s = null;
DataInputStream sIn;
PrintStream sOut;
Socket cliente = null;
String texto;

// Abrimos una conexión con breogan en el puerto 9999


// No podemos elegir un puerto por debajo del 1023 si no somos
// usuarios con los máximos privilegios (root)
try {
s = new ServerSocket( 9999 );
} catch( IOException e ) {
}

// Creamos el objeto desde el cual atenderemos y aceptaremos


// las conexiones de los clientes y abrimos los canales de
// comunicación de entrada y salida
try {
cliente = [Link]();
sIn = new DataInputStream( [Link]() );
sOut = new PrintStream( [Link]() );

// Cuando recibamos datos, se los devolvemos al cliente


// que los haya enviado
while( true )
{
texto = [Link]();
[Link]( texto );
}
} catch( IOException e ) {
[Link]( e );
}
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


CLIENTE/SERVIDOR TCP/IP
Mínimo Servidor TCP/IP

Veamos el código que presentamos en el siguiente ejemplo, [Link], donde desarrollamos un mínimo
servidor TCP/IP, para el cual desarrollaremos después su contrapartida cliente TCP/IP. La aplicación servidor
TCP/IP depende de una clase de comunicaciones proporcionada por Java: ServerSocket. Esta clase realiza la mayor
parte del trabajo de crear un servidor.

import [Link].*;
import [Link].*;
import [Link].*;

class minimoServidor {
public static void main( String args[] ) {
ServerSocket s = (ServerSocket)null;
Socket s1;
String cadena = "Tutorial de Java!";
int longCad;
OutputStream s1out;

// Establece el servidor en el socket 4321,


// acepta hasta 5 conexiones
try {
s = new ServerSocket( 4321,5 );
} catch( IOException e ) {
[Link]( e );
}

// Ejecuta un bucle infinito de listen/accept


while( true ) {
try {
// Espera para aceptar una conexión
s1 = [Link]();
// Obtiene un controlador de fichero de salida asociado
// con el socket
s1out = [Link]();

// Enviamos nuestro texto


longCad = [Link]();
for( int i=0; i < longCad; i++ )
[Link]( (int)[Link]( i ) );

// Cierra la conexión, pero no el socket del servidor


[Link]();
} catch( IOException e ) {
[Link]( e );
}
}
}
}

Mínimo Cliente TCP/IP

El lado cliente de una aplicación TCP/IP descansa en la clase Socket. De nuevo, mucho del trabajo necesario para
establecer la conexión lo ha realizado la clase Socket. Vamos a presentar ahora el código de nuestro cliente más
simple, [Link], que encaja con el servidor presentado antes. El trabajo que realiza este cliente es que
todo lo que recibe del servidor lo imprime por la salida estándar del sistema.

import [Link].*;
import [Link].*;
import [Link].*;

class minimoCliente {
public static void main( String args[] ) throws IOException {
int c;
Socket s;
InputStream sIn;

// Abrimos una conexión con breogan en el puerto 4321


try {
s = new Socket( "breogan",4321 );
} catch( IOException e ) {
[Link]( e );
}

// Obtenemos un controlador de fichero de entrada del socket y


// leemos esa entrada
sIn = [Link]();
while( ( c = [Link]() ) != -1 )
[Link]( (char)c );

// Cuando se alcance el fin de fichero, cerramos la conexión y


// abandonamos
[Link]();
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


SERVIDOR SIMPLE DE HTTP
Vamos a implementar un servidor de HTTP básico, sólo le permitiremos admitir operaciones GET y un rango
limitado de tipos MIME codificados. Los tipos MIME son los descriptores de tipo para contenido multimedia.
Esperamos que este ejemplo sirva como base para un entretenido ejercicio de ampliación y exploración porque, desde
luego, lo que no pretendemos es inquietar a los Consejos de Dirección de Microsoft o Netscape.

La aplicación va a crear un ServerSocket conectado al puerto 80, que en caso de no tener privilegios para su uso,
podemos cambiar, por ejemplo al 8080; y después entra en un bucle infinito. Dentro del bucle, espera dentro del
método accept() del ServerSocket hasta que se establece una conexión cliente. Después asigna un flujo de entrada y
salida al socket. A continuación lee la solicitud del cliente utilizando el método getRawRequest(), que devolverá un
null si hay un error de entrada/salida o el cliente corta la conexión. Luego se identifica el tipo de solicitud y se
gestiona mediante el método handlget() o handleUnsup(). Finalmente se cierran los sockets y se comienza de nuevo.

Cuando se ejecuta el programa completo, se escribe en pantalla lo que el navegador cliente envía al servidor. Aunque
se capturan varias condiciones de error, en la práctica no aparecen. El ampliar este servidor para que soporte una
carga de millones de visitas al día requiere bastante trabajo; no obstante, en el ordenador en que estoy escribiendo
esto, no se enlenteció demasiado con una carga de hasta diez entradas por segundo, lo que permitiría alrededor de un
millón de visitas al día. Se podría mejorar mediante el uso de threads y control de la memoria caché para gestionar
esas visitas, pero eso ya forma parte del ejercicio sobre el que se puede trabajar.

El código fuente de nuestro mini servidor de HTTP se encuentra en el fichero [Link], que reproducimos a
continuación:

import [Link].*;
import [Link].*;
import [Link].*;

// Clase de utilidades donde declaramos los tipos MIME y algunos gestores


// de los errores que se pueden generar en HTML
class HttpUtilidades {
final static String version = "1.0";
final static String mime_text_plain = "text/plain";
final static String mime_text_html = "text/html";
final static String mime_image_gif = "image/gif";
final static String mime_image_jpg = "image/jpg";
final static String mime_app_os = "application/octet-stream";
final static String CRLF = "\r\n";

// Método que convierte un objeto String en una matriz de bytes.


// Java gestiona las cadenas como objetos, por lo que es necesario
// convertir las matrices de bytes que se obtienen a Strings y
// viceversa
public static byte aBytes( String s )[] {
byte b[] = new byte[ [Link]() ];
[Link]( 0,[Link],b,0 );
return( b );
}

// Este método concatena dos matrices de bytes. El método


// arraycopy() asombra por su rapidez
public static byte concatenarBytes( byte a[],byte b[] )[] {
byte ret[] = new byte[ [Link]+[Link] ];
[Link]( a,0,ret,0,[Link] );
[Link]( b,0,ret,[Link],[Link] );
return( ret );
}

// Este método toma un tipo de contenido y una longitud, para


// devolver la matriz de bytes que contiene el mensaje de cabecera
// MIME con formato
public static byte cabMime( String ct,int tam )[] {
return( cabMime( 200,"OK",ct,tam ) );
}

// Es el mismo método anterior, pero permite un ajuste más fino


// del código que se devuelve y el mensaje de error de HTTP
public static byte cabMime(int codigo,String mensaje,String ct,
int tam )[] {
Date d = new Date();
return( aBytes( "HTTP/1.0 "+codigo+" "+mensaje+CRLF+
"Date: "+[Link]()+CRLF+
"Server: Java/"+version +CRLF+
"Content-type: "+ct+CRLF+
( tam > 0 ? "Content-length: "+tam+CRLF : "" )+CRLF ) );
}

// Este método construye un mensaje HTML con un formato decente


// para presentar una condición de error y lo devuelve como
// matriz de bytes
public static byte error( int codigo,String msg,String fname)[] {
String ret = "<BODY>"+CRLF+"<H1>"+codigo+" "+msg+"</H1>"+CRLF;

if( fname != null )


ret += "Error al buscar el URL: "+fname+CRLF;
ret += "</BODY>"+CRLF;
byte tmp[] = cabMime( codigo,msg,mime_text_html,0 );
return( concatenarBytes( tmp,aBytes( ret ) ) );
}

// Devuelve el tipo MIME que corresponde a un nombre de archivo dado


public static String mimeTypeString( String fichero ) {
String tipo;

if( [Link]( ".html" ) || [Link]( ".htm" ) )


tipo = mime_text_html;
else if( [Link]( ".class" ) )
tipo = mime_app_os;
else if( [Link]( ".gif" ) )
tipo = mime_image_gif;
else if( [Link]( ".jpg" ) )
tipo = mime_image_jpg;
else
tipo = mime_text_plain;
return( tipo );
}
}

// Esta clase sirve para que nos enteremos de lo que está haciendo
// nuestro servidor. En una implementación real, todos estos mensajes
// deberían registrarse en algún fichero
class HTTPlog {
public static void error( String entrada ) {
[Link]( "Error: "+entrada );
}

public static void peticion( String peticion ) {


[Link]( peticion );
}
}

// Esta es la clase principal de nuestro servidor Http


class TutHttp {
public static final int puerto = 80;
final static String docRaiz = "/html";
final static String fichIndice = "[Link]";
final static int buffer = 2048;
public static final int RT_GET=1;
public static final int RT_UNSUP=2;
public static final int RT_END=4;

// Indica que la petición no está soportada, por ejemplo POST y HEAD


private static void ctrlNoSop(String peticion,OutputStream sout) {
[Link]( "Peticion no soportada: "+peticion );
}

// Este método analiza gramaticalmente la solicitud enviada con el


// GET y la descompone en sus partes para extraer el nombre del
// archivo que se está solicitando. Entonces lee el fichero que
// se pide
private static void ctrlGet( String peticion,OutputStream sout ) {
int fsp = [Link]( ' ' );
int nsp = [Link]( ' ',fsp+1 );
String fich = [Link]( fsp+1,nsp );

fich = docRaiz+fich+( [Link]("/") ? fichIndice : "" );


try {
File f = new File( fich );
if( ![Link]() )
{
[Link]( [Link]( 404,
"No Encontrado",fich ) );
return;
}

if( ![Link]() )
{
[Link]( [Link]( 404,
"Permiso Denegado",fich ) );
return;
}

// Ahora lee el fichero que se ha solicitado


InputStream sin = new FileInputStream( f );
String cabmime = [Link]( fich );
int n = [Link]();
[Link]( [Link]( cabmime,n ) );
byte buf[] = new byte[buffer];
while( ( n = [Link]( buf ) ) >= 0 )
[Link]( buf,0,n );

[Link]();
} catch( IOException e ) {
[Link]( "Excepcion: "+e );
}
}

// Devuelve la cabecera de la solicitud completa del cliente al


// método main de nuestro servidor
private static String getPeticion( InputStream sin ) {
try {
byte buf[] = new byte[buffer];
boolean esCR = false;
int pos = 0;
int c;

while( ( c = [Link]() ) != -1 )
{
switch( c ) {
case '\r':
break;
case '\n':
if( esCR )
return( new String( buf,0,0,pos ) );
esCR = true;
// Continúa, se ha puesto el primer \n en la cadena
default:
if( c != '\n' )
esCR = false;
buf[pos++] = (byte)c;
}
}
} catch( IOException e ) {
[Link]( "Error de Recepcion" );
}
return( null );
}

private static int tipoPeticion( String peticion ) {


return( [Link]( true,0,"get ",0,4 ) ?
RT_GET : RT_UNSUP );
}

// Función principal de nuestro servidor, que se conecta al socket


// y se embucla indefinidamente
public static void main( String args[] ) throws Exception {
ServerSocket ss = new ServerSocket( puerto );
while( true )
{
String peticion;
Socket s = [Link]();
OutputStream sOut = [Link]();
InputStream sIn = [Link]();

if( ( peticion = getPeticion( sIn ) ) != null )


{
switch( tipoPeticion( peticion ) ) {
case RT_GET:
ctrlGet( peticion,sOut );
break;
case RT_UNSUP:
default:
ctrlNoSop( peticion,sOut );
break;
}
[Link]( peticion );
}
[Link]();
[Link]();
[Link]();
}
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


CLASES UTILES EN COMUNICACIONES
Vamos a exponer otras clases que resultan útiles cuando estamos desarrollando programas de comunicaciones, aparte
de las que ya se han visto. El problema es que la mayoría de estas clases se prestan a discusión, porque se encuentran
bajo el directorio sun. Esto quiere decir que son implementaciones Solaris y, por tanto, específicas del Unix Solaris.
Además su API no está garantizada, pudiendo cambiar. Pero, a pesar de todo, resultan muy interesantes y vamos a
comentar un grupo de ellas solamente que se encuentran en el paquete [Link]

Socket

Es el objeto básico en toda comunicación a través de Internet, bajo el protocolo TCP. Esta clase
proporciona métodos para la entrada/salida a través de streams que hacen la lectura y escritura a través
de sockets muy sencilla.

ServerSocket

Es un objeto utilizado en las aplicaciones servidor para escuchar las peticiones que realicen los clientes
conectados a ese servidor. Este objeto no realiza el servicio, sino que crea un objeto Socket en función
del cliente para realizar toda la comunicación a través de él.

DatagramSocket

La clase de sockets datagrama puede ser utilizada para implementar datagramas no fiables (sockets
UDP), no ordenados. Aunque la comunicación por estos sockets es muy rápida porque no hay que
perder tiempo estableciendo la conexión entre cliente y servidor.

DatagramPacket

Clase que representa un paquete datagrama conteniendo información de paquete, longitud de paquete,
direcciones Internet y números de puerto.

MulticastSocket

Clase utilizada para crear una versión multicast de las clase socket datagrama. Múltiples
clientes/servidores pueden transmitir a un grupo multicast (un grupo de direcciones IP compartiendo el
mismo número de puerto).

NetworkServer

Una clase creada para implementar métodos y variables utilizadas en la creación de un servidor
TCP/IP.

NetworkClient
Una clase creada para implementar métodos y variables utilizadas en la creación de un cliente TCP/IP.

SocketImpl

Es un Interface que nos permite crearnos nuestro propio modelo de comunicación. Tendremos que
implementar sus métodos cuando la usemos. Si vamos a desarrollar una aplicación con requerimientos
especiales de comunicaciones, como pueden se la implementación de un cortafuegos (TCP es un
protocolo no seguro), o acceder a equipos especiales (como un lector de código de barras o un GPS
diferencial), necesitaremos nuestra propia clase Socket.

Vamos a ver un ejemplo de utilización, presentando un sencillo ejemplo, [Link], de implementación de


sockets UDP utilizando la clase DatagramSocket.

import [Link].*;
import [Link].*;
import [Link].*;

// Implementación del servidor de datagramas UDP. Envía una cadena


// tras petición
//
class servidorUDP {
public static void main( String args[] ) {
DatagramSocket s = (DatagramSocket)null;
DatagramPacket enviap,recibep;
byte ibuffer[] = new byte[100];
String cadena = "Hola Tutorial de Java!\n";
InetAddress IP = (InetAddress)null;
int longitud = [Link]();
int puertoEnvio = 4321;
int puertoRecep = 4322;
int puertoRemoto;

// Intentamos conseguir la dirección IP del host


try {
IP = [Link]( "bregogan" );
} catch( UnknownHostException e ) {
[Link]( "No encuentro al host breogan" );
[Link]( -1 );
}

// Establecemos el servidor para escuchar en el socket 4322


try {
s = new DatagramSocket( puertoRecep );
} catch( SocketException e ) {
[Link]( "Error - "+[Link]() );
}

// Creamos un paquete de solicitud en el cliente


// y nos quedamos esperando a sus peticiones
recibep = new DatagramPacket( ibuffer,longitud );
try {
[Link]( recibep );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
}

// Creamos un paquete para enviar al cliente y lo enviamos


[Link]( 0,longitud,ibuffer,0 );
enviap = new DatagramPacket( ibuffer,longitud,IP,puertoEnvio );
try {
[Link]( enviap );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
[Link]( -1 );
}

// Cerramos el socket
[Link]();
}
}

Y también vamos a implementar el cliente, [Link], del socket UDP correspondiente al servidor que
acabamos de presentar:

import [Link].*;
import [Link].*;
import [Link].*;

// Implementación del cliente de datagramas UDP. Devuelve la salida


// de los servidores
//
class clienteUDP {
public static void main( String args[] ) {
int longitud = 100;
DatagramSocket s = (DatagramSocket)null;
DatagramPacket enviap,recibep;
byte ibuffer[] = new byte[100];
InetAddress IP = (InetAddress)null;
int puertoEnvio = 4321;
int puertoRecep = 4322;

// Abre una conexión y establece el cliente para recibir


// una petición en el socket 4321
try {
s = new DatagramSocket( puertoRecep );
} catch( SocketException e ) {
[Link]( "Error - "+[Link]() );
}

// Crea una petición para enviar bytes. Intenta conseguir


// la dirección IP del host
try {
IP = [Link]( "depserver" );
} catch( UnknownHostException e ) {
[Link]( "No encuentro el host depserver" );
[Link]( -1 );
}
// Envía una petición para que responda el servidor
try {
enviap = new DatagramPacket( ibuffer,[Link],
IP,4322 );
[Link]( enviap );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
}

// Consigue un controlador de fichero de entrada del socket y lee


// dicha entrada. Creamos un paquete descriptor para recibir el
// paquete UDP
recibep = new DatagramPacket( ibuffer,longitud );

// Espera a recibir un paquete


try {
[Link]( recibep );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
[Link]( -1 );
}

// Imprimimos los resultados de lo que conseguimos


[Link]( "Recibido: "+[Link]()+" bytes" );
String datos = new String( [Link](),0 );
[Link]( "Datos: "+datos );
[Link]( "Recibido por puerto: "+[Link]() );

// Cerramos la conexión y abandonamos


[Link]();
}
}

La salida que se producirá cuando ejecutemos primero el servidor y luego el cliente será la misma que reproducimos
a continuación:

%java clienteUDP
Recibido: 17 bytes
Datos: Hola Tutorial de Java!

Recibido por puerto: 4322

Tutorial de Java [Anterior] [Indice] [Siguiente]


EJECUTAR TCP/IP EN Windows '95
Las indicaciones que se proporcionan a continuación, van a permitirnos fijar los parámetros de Windows '95 para que
se puedan ejecutar programas cliente y servidor, sin necesidad de que el ordenador en el cual se está ejecutando
Windows '95 esté conectado a una red de área local. Esto puede resultar útil para mucha gente que está probando
Java en su casa y no dispone de red, o incluso para aquellos programadores o estudiosos que quieren probar sus
nuevos programas distribuidos pero no disponen de red o de Internet.

Advertencia: Si los siguientes parámetros se van a fijar en un ordenador portátil que en ocasiones sí se conecte a
una red, sería conveniente anotar los parámetros actuales de la configuración de Windows '95, para que sean
fácilmente recuperables cuando este ordenador se vuelva a conectar a la red.

Configuración del TCP/IP de Windows '95

Hay que seguir los pasos que vamos a relatar a continuación, suponemos que se está ejecutando la versión española
de Windows '95, en otras versiones puede que las opciones tengan nombre diferente:

1. En el Panel de Control, seleccionar Red


2. Picar Agregar, luego Protocolo y luego Agregar
3. Seleccionar Microsoft y luego TCP/IP y picar en Aceptar
4. En este momento probablemente se solicite la introducción de los discos de Windows '95, o del CD-ROM
5. Seleccionar la pestaña Configuración de la ventana Red
6. Seleccionar TCP/IP en la lista que aparece y picar Propiedades
7. Seleccionar la pestaña Dirección IP
❍ Crearse una dirección IP, como por ejemplo: [Link]

❍ Crearse una Máscara de subred, como: [Link]

8. Seleccionar la pestaña Configuración DNS y desactivar DNS


9. Los valores correspondientes a las otras cuatro pestañas pueden dejarse los que hay por defecto
10. Picar Aceptar
11. (Opcional) Seleccionar la pestaña Identificación de la ventana Red
12. (Opcional) Introducir un nombre para el ordenador, como por ejemplo: breogan
13. (Opcional) Picar Aceptar

Crear una entrada en la "red"

1. Editar el fichero [Link] que está en el directorio de Windows


2. Al final del fichero incorporar la dirección IP y el nombre del ordenador que se han introducido antes, en
nuestro caso: [Link] breogan
3. Asegurarse de que la dirección IP y el nombre coinciden con la dirección IP que se ha fijado en el paso 7a de
antes y que el nombre es el mismo que el indicado en el paso 12 anterior
4. Salvar el fichero con el nombre "hosts" y reiniciar Windows '95

Comprobación de la red
1. Abrir una sesión MS-DOS
2. Teclear "ping breogan"
3. Debería aparecer:

Pinging breogan [[Link]] with 32 bytes of data:


Reply from [Link]: bytes=32 time=1ms TTL=32
Reply from [Link]: bytes=32 time<10ms TTL=32
Reply from [Link]: bytes=32 time<10ms TTL=32
Reply from [Link]: bytes=32 time<10ms TTL=32

4. Teclear "tracert [Link]"


5. Debería aparecer:

Tracing route to [Link] over a maximum of 30 hops


1 <10 ms 1 ms <10 ms [Link]
Trace complete.

En este instante, si todo ha ido bien, el ordenador está listo para funcionar como si estuviera en red. Dos o más
programas que se comuniquen en red a través de sockets debería poder ejecutarse ahora dentro de los dominios del
ordenador que acabamos de configurar

Problemas más frecuentes

Los tres problemas que pueden presentarse cuando intentemos comprobar el funcionamiento correcto de la red
interna que acabamos de montar son:

Cuando hacemos "ping" obtenemos "Bad IP address breogan"

Intentar teclear "ping [Link]". Si ahora sí se obtiene réplica, la causa del problema es que el
los pasos 12 de la Configuración y 3 de la Creación de la entrada en la tabla de hosts, no se ha
introducido correctamente el nombre de la máquina. Comprobar esos pasos y que todo coincide.

El programa cliente o el servidor fallan al intentar el "connect"

La causa podría estar en que se produzca un fallo por fichero no encontrado en el directorio
Windows/System de las librerías [Link] o [Link]. Muchos programas que se
utilizan en Internet reemplazan estos ficheros cuando se instalan. Asegurarse de que están estos
ficheros y que son los originales que vienen con la distribución de Windows '95.

El programa servidor dice que no puede "bind" a un socket

Esto sucede porque tiene el DNS activado y no puede encontrar ese DNS o servidor de direcciones,
porque estamos solos en la red. Asegurarse de que en el paso 8 de la Configuración la opción de DNS
está deshabilitada.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 28-11-1996 04:08:24
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

class smtpCliente {
public static void main( String args[] ) {
Socket s = null;
DataInputStream sIn = null;
DataOutputStream sOut = null;

// Abrimos una conexión con breogan en el puerto 25


// que es el correspondiente al proticolo smtp, e intentamos
// abrir los streams de entrada y salida
try {
s = new Socket( "breogan",25 );
sIn = new DataInputStream( [Link]() );
sOut = new DataOutputStream( [Link]() );
} catch( UnknownHostException e ) {
[Link]( "No conozco el host" );
} catch( IOException e ) {
[Link]( e );
}

// Si todo está inicializado correctamente, vamos a escribir


// algunos datos en el canal de salida que se ha establecido
// con el puerto del protocolo smtp del servidor
if( s != null && sIn != null && sOut != null )
{
try {
// Tenemos que respetar la especificación SMTP dada en
// RFC1822/3, de forma que lo que va en mayúsculas
// antes de los dos puntos tiene un significado especial
// en el protocolo
[Link]( "MAIL From: froufe@[Link]\n" );
[Link]( "RCPT To: froufe@[Link]\n" );
[Link]( "DATA\n" );
[Link]( "From: froufe@[Link]\n" );
[Link]( "Subject: Pruebas\n" );
// Ahora el cuerpo del mensaje
[Link]( "Hola, desde el Tutorial de Java\n" );
[Link]( "\n.\n" );

// Nos quedamos a la espera de recibir el "Ok" del


// servidor para saber que ha recibido el mensaje
// correctamente, momento en el cual cortamos

String respuesta;
while( ( respuesta = [Link]() ) != null )
{
[Link]( "Servidor: "+respuesta );
if( [Link]( "Ok" ) != -1 )
break;
}

// Cerramos todo lo que hemos abierto


[Link]();
[Link]();
[Link]();
} catch( UnknownHostException e ) {
[Link]( "Intentando conectar: "+e );
} catch( IOException e ) {
[Link]( e );
}
}
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 28-11-1996 04:46:13
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

class ecoServidor {
public static void main( String args[] ) {
ServerSocket s = null;
DataInputStream sIn;
PrintStream sOut;
Socket cliente = null;
String texto;

// Abrimos una conexión con breogan en el puerto 9999


// No podemos elegir un puerto por debajo del 1023 si no somos
// usuarios con los máximos privilegios (root)
try {
s = new ServerSocket( 9999 );
} catch( IOException e ) {
[Link]( e );
}

// Creamos el objeto desde el cual atenderemos y aceptaremos


// las conexiones de los clientes y abrimos los canales de
// comunicación de entrada y salida
try {
cliente = [Link]();
sIn = new DataInputStream( [Link]() );
sOut = new PrintStream( [Link]() );

// Cuando recibamos datos, se los devolvemos al cliente


// que los haya enviado
while( true )
{
texto = [Link]();
[Link]( texto );
}
} catch( IOException e ) {
[Link]( e );
}
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 14:58:27
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;

class minimoServidor {
public static void main( String args[] ) {
ServerSocket s = (ServerSocket)null;
Socket s1;
String cadena = "Hola Tutorial de Java!";
int longCad;
OutputStream s1out;

// Establece el servidor en el socket 4321,


// acepta hasta 5 conexiones
try {
s = new ServerSocket( 4321,5 );
} catch( IOException e ) {
;
}

// Ejecuta un bucle infinito de listen/accept


while( true ) {
try {
// Espera para aceptar una conexión
s1 = [Link]();
// Obtiene un controlador de fichero de salida asociado con
// el socket
s1out = [Link]();

// Enviamos nuestro texto


longCad = [Link]();
for( int i=0; i < longCad; i++ )
[Link]( (int)[Link]( i ) );

// Cierra la conexión, pero no el socket del servidor


[Link]();
} catch( IOException e ) {
;
}
}
}
}

//------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-09-1996 15:13:24
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;

class minimoCliente {
public static void main( String args[] ) throws IOException {
int c;
Socket s;
InputStream sIn;

// Abrimos una conexión con depserver en el puerto 4321


s = new Socket( "breogan",4321 );

// Obtenemos un controlador de fichero de entrada del socket y


// leemos esa entrada
sIn = [Link]();
while( ( c = [Link]() ) != -1 )
[Link]( (char)c );

// Cuando se alcance el fin de fichero, cerramos la conexión y


// abandonamos
[Link]();
}
}

//------------------------------------- Final del fichero [Link]


// // [Link] // Copyright (c) 1996, Agustin Froufe // Todos los derechos reservados. // // No se
asume ninguna responsabilidad por el uso o alteracion de este // software. Este software se proporciona
COMO ES, sin garantia de ningun // tipo de su funcionamiento y en ningun caso sera el autor
responsable de // daños o perjuicios que se deriven del mal uso del software, aun cuando // este haya
sido notificado de la posibilidad de dicho daño. // // Compilador: javac 1.0 // Autor: Agustin Froufe //
Creacion: 01-Dic-1996 18:34:15 // //-------------------------------------------------------------------------- //
Esta informacion no es necesariamente definitiva y est sujeta a cambios // que pueden ser
incorporados en cualquier momento, sin avisar. //-----------------------------------------------------------------
--------- import [Link].*; import [Link].*; import [Link].*; // Clase de utilidades donde declaramos
los tipos MIME y algunos gestores de // los errores que se pueden generar en HTML class
HttpUtilidades { final static String version = "1.0"; final static String mime_text_plain = "text/plain";
final static String mime_text_html = "text/html"; final static String mime_image_gif = "image/gif";
final static String mime_image_jpg = "image/jpg"; final static String mime_app_os =
"application/octet-stream"; final static String CRLF = "\r\n"; // Método que convierte un objeto String
en una matriz de bytes. // Java gestiona las cadenas como objetos, por lo que es necesario // convertir
las matrices de bytes que se obtienen a Strings y // viceversa public static byte aBytes( String s )[] {
byte b[] = new byte[ [Link]() ]; [Link]( 0,[Link],b,0 ); return( b ); } // Este método concatena
dos matrices de bytes. El método // arraycopy() asombra por su rapidez public static byte
concatenarBytes( byte a[],byte b[] )[] { byte ret[] = new byte[ [Link]+[Link] ]; [Link](
a,0,ret,0,[Link] ); [Link]( b,0,ret,[Link],[Link] ); return( ret ); } // Este método toma un
tipo de contenido y una longitud, para // devolver la matriz de bytes que contiene el mensaje de
cabecera // MIME con formato public static byte cabMime( String ct,int tam )[] { return( cabMime(
200,"OK",ct,tam ) ); } // Es el mismo método anterior, pero permite un ajuste más fino // del código
que se devuelve y el mensaje de error de HTTP public static byte cabMime(int codigo,String
mensaje,String ct, int tam )[] { Date d = new Date(); return( aBytes( "HTTP/1.0 "+codigo+"
"+mensaje+CRLF+ "Date: "+[Link]()+CRLF+ "Server: Java/"+version +CRLF+ "Content-
type: "+ct+CRLF+ ( tam > 0 ? "Content-length: "+tam+CRLF : "" )+CRLF ) ); } // Este método
construye un mensaje HTML con un formato decente // para presentar una condición de error y lo
devuelve como // matriz de bytes public static byte error( int codigo,String msg,String fname)[] {
String ret = ""+CRLF+"

"+codigo +" "+msg+"


"+CRLF; if( fname != null ) ret += "Error al buscar el URL: "+fname+CRLF; ret += ""+CRLF; byte
tmp[] = cabMime( codigo,msg,mime_text_html,0 ); return( concatenarBytes( tmp,aBytes( ret ) ) ); } //
Devuelve el tipo MIME que corresponde a un nombre de archivo dado public static String
mimeTypeString( String fichero ) { String tipo; if( [Link]( ".html" ) || [Link](
".htm" ) ) tipo = mime_text_html; else if( [Link]( ".class" ) ) tipo = mime_app_os; else if(
[Link]( ".gif" ) ) tipo = mime_image_gif; else if( [Link]( ".jpg" ) ) tipo =
mime_image_jpg; else tipo = mime_text_plain; return( tipo ); } } // Esta clase sirve para que nos
enteremos de lo que está haciendo // nuestro servidor. En una implementación real, todos estos
mensajes // deberían registrarse en algún fichero class HTTPlog { public static void error( String
entrada ) { [Link]( "Error: "+entrada ); } public static void peticion( String peticion ) {
[Link]( peticion ); } } // Esta es la clase principal de nuestro servidor Http class TutHttp {
public static final int puerto = 80; final static String docRaiz = "/html"; final static String fichIndice =
"[Link]"; final static int buffer = 2048; public static final int RT_GET=1; public static final int
RT_UNSUP=2; public static final int RT_END=4; // Indica que la petición no está soportada, por
ejemplo POST y HEAD private static void ctrlNoSop(String peticion,OutputStream sout) {
[Link]( "Peticion no soportada: "+peticion ); } // Este método analiza gramaticalmente la
solicitud enviada con el // GET y la descompone en sus partes para extraer el nombre del // archivo que
se está solicitando. Entonces lee el fichero que // se pide private static void ctrlGet( String
peticion,OutputStream sout ) { int fsp = [Link]( ' ' ); int nsp = [Link]( ' ',fsp+1 );
String fich = [Link]( fsp+1,nsp ); fich = docRaiz+fich+( [Link]("/") ? fichIndice : ""
); try { File f = new File( fich ); if( ![Link]() ) { [Link]( [Link]( 404, "No
Encontrado",fich ) ); return; } if( ![Link]() ) { [Link]( [Link]( 404, "Permiso
Denegado",fich ) ); return; } // Ahora lee el fichero que se ha solicitado InputStream sin = new
FileInputStream( f ); String cabmime = [Link]( fich ); int n = [Link]();
[Link]( [Link]( cabmime,n ) ); byte buf[] = new byte[buffer]; while( ( n =
[Link]( buf ) ) >= 0 ) [Link]( buf,0,n ); [Link](); } catch( IOException e ) { [Link](
"Excepcion: "+e ); } } // Devuelve la cabecera de la solicitud completa del cliente al // método main de
nuestro servidor private static String getPeticion( InputStream sin ) { try { byte buf[] = new
byte[buffer]; boolean esCR = false; int pos = 0; int c; while( ( c = [Link]() ) != -1 ) { switch( c ) {
case '\r': break; case '\n': if( esCR ) return( new String( buf,0,0,pos ) ); esCR = true; // Continúa, se ha
puesto el primer \n en la cadena default: if( c != '\n' ) esCR = false; buf[pos++] = (byte)c; } } } catch(
IOException e ) { [Link]( "Error de Recepcion" ); } return( null ); } private static int
tipoPeticion( String peticion ) { return( [Link]( true,0,"get ",0,4 ) ? RT_GET :
RT_UNSUP ); } // Función principal de nuestro servidor, que se conecta al socket // y se embucla
indefinidamente public static void main( String args[] ) throws Exception { ServerSocket ss = new
ServerSocket( puerto ); while( true ) { String peticion; Socket s = [Link](); OutputStream sOut =
[Link](); InputStream sIn = [Link](); if( ( peticion = getPeticion( sIn ) ) != null )
{ switch( tipoPeticion( peticion ) ) { case RT_GET: ctrlGet( peticion,sOut ); break; case RT_UNSUP:
default: ctrlNoSop( peticion,sOut ); break; } [Link]( peticion ); } [Link](); [Link]();
[Link](); } } } //------------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 15:42:04
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;

// Implementación del servidor de datagramas UDP. Envía una cadena


// tras petición
//
class servidorUDP {
public static void main( String args[] ) {
DatagramSocket s = (DatagramSocket)null;
DatagramPacket enviap,recibep;
byte ibuffer[] = new byte[100];
String cadena = "Hola Tutorial de java!\n";
InetAddress IP = (InetAddress)null;
int longitud = [Link]();
int puertoEnvio = 4321;
int puertoRecep = 4322;
int puertoRemoto;

// Intentamos conseguir la dirección IP del host


try {
IP = [Link]( "breogan" );
} catch( UnknownHostException e ) {
[Link]( "No encuentro el host breogan" );
[Link]( -1 );
}

// Establecemos el servidor para escuchar en el socket 4322


try {
s = new DatagramSocket( puertoRecep );
} catch( SocketException e ) {
[Link]( "Error - "+[Link]() );
}

// Creamos un paquete de solicitud en el cliente


// y nos quedamos esperando a sus peticiones
recibep = new DatagramPacket( ibuffer,longitud );
try {
[Link]( recibep );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
}

// Creamos un paquete para enviar al cliente y lo enviamos


[Link]( 0,longitud,ibuffer,0 );
enviap = new DatagramPacket( ibuffer,longitud,IP,puertoEnvio );
try {
[Link]( enviap );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
[Link]( -1 );
}

// Cerramos el socket
[Link]();
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 15:07:49
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;

// Implementación del cliente de datagramas UDP. Devuelve la salida


// de los servidores
//
class clienteUDP {
public static void main( String args[] ) {
int longitud = 100;
DatagramSocket s = (DatagramSocket)null;
DatagramPacket enviap,recibep;
byte ibuffer[] = new byte[100];
InetAddress IP = (InetAddress)null;
int puertoEnvio = 4321;
int puertoRecep = 4322;

// Abre una conexión y establece el cliente para recibir


// una petición en el socket 4321
try {
s = new DatagramSocket( puertoRecep );
} catch( SocketException e ) {
[Link]( "Error - "+[Link]() );
}

// Crea una petición para enviar bytes. Intenta conseguir


// la dirección IP del host
try {
IP = [Link]( "breogan" );
} catch( UnknownHostException e ) {
[Link]( "No encuentro el host breogan" );
[Link]( -1 );
}

// Envía una petición para que responda el servidor


try {
enviap = new DatagramPacket( ibuffer,[Link],IP,4322 );
[Link]( enviap );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
}

// Consigue un controlador de fichero de entrada del socket y lee


// dicha entrada. Creamos un paquete descriptor para recibir el
// paquete UDP
recibep = new DatagramPacket( ibuffer,longitud );
// Espera a recibir un paquete
try {
[Link]( recibep );
} catch( IOException e ) {
[Link]( "Error - "+[Link]() );
[Link]( -1 );
}

// Imprimimos los resultados de lo que conseguimos


[Link]( "Recibido: "+[Link]()+" bytes" );
String datos = new String( [Link](),0 );
[Link]( "Datos: "+datos );
[Link]( "Recibido por el puerto: "+[Link]() );

// Cerramos la conexión y abandonamos


[Link]();
}
}

//---------------------------------------- Final del fichero [Link]


STREAMS DE ENTRADA
Hay muchas clases dedicadas a la obtención de entrada desde un fichero. Este es el esquema de la jerarquía de clases
de entrada por fichero:

Objetos FileInputStream

Los objetos FileInputStream típicamente representan ficheros de texto accedidos en orden secuencial, byte a byte.
Con FileInputStream, se puede elegir acceder a un byte, varios bytes o al fichero completo.

Apertura de un FileInputStream

Para abrir un FileInputStream sobre un fichero, se le da al constructor un String o un objeto File:

FileInputStream mi FicheroSt;
miFicheroSt = new FileInputStream( "/etc/kk" );

También se puede utilizar:

File miFichero FileInputStream miFicheroSt;


miFichero = new File( "/etc/kk" );
miFicheroSt = new FileInputStream(
miFichero );

Lectura de un FileInputStream

Una vez abierto el FileInputStream, se puede leer de él. El método read() tiene muchas opciones:

int read();
Lee un byte y devuelve -1 al final del stream.

int read( byte b[] );

Llena todo el array, si es posible. Devuelve el número de bytes leídos o -1 si se alcanzó el final del
stream.

int read( byte b[],int offset,int longitud );

Lee longitud bytes en b comenzando por b[offset]. Devuelve el número de bytes leídos o -1 si se
alcanzó el final del stream.

Cierre de FileInputStream

Cuando se termina con un fichero, existen dos opciones para cerrarlo: explícitamente, o implícitamente cuando se
recicla el objeto (el garbage collector se encarga de ello).

Para cerrarlo explícitamente, se utiliza el método close():

[Link]();

Ejemplo: Visualización de un fichero

Si la configuración de la seguridad de Java permite el acceso a ficheros, se puede ver el contenido de un fichero en un
objeto TextArea. El código siguiente contiene los elementos necesarios para mostrar un fichero:

FileInputStream fis;
TextArea ta;

public void init() {


byte b[] = new byte[1024];
int i;

// El buffer de lectura se debe hacer lo suficientemente grande


// o esperar a saber el tamaño del fichero
String s;

try {
fis = new FileInputStream( "/etc/kk" );
} catch( FileNotFoundException e ) {
/* Hacer algo */
}

try {
i = [Link]( b );
} catch( IOException e ) {
/* Hacer algo */
}

s = new String( b,0 );


ta = new TextArea( s,5,40 );
add( ta );
}

Hemos desarrollado un ejemplo, [Link], en el que partimos de un fichero agenda que dispone de los datos que
nosotros deseamos de nuestros amigos, como son: nombre, teléfono y dirección. Si tecleamos un nombre, buscará en
el fichero de datos si existe ese nombre y presentará la información que se haya introducido. Para probar, intentar que
aparezca la información de Pepe.

Objetos DataInputStream

Los objetos DataInputStream se comportan como los FileInputStream. Los streams de datos pueden leer cualquiera
de las variables de tipo nativo, como floats, ints o chars. Generalmente se utilizan DataInputStream con ficheros
binarios.

Apertura y cierre de DataInputStream

Para abrir y cerrar un objeto DataInputStream, se utilizan los mismos métodos que para FileInputStream:

DataInputStream miDStream;
FileInputStream miFStream;

// Obtiene un controlador de fichero


miFStream = new FileInputStream "/etc/[Link]" );
//Encadena un fichero de entrada de datos
miDStream = new DataInputStream( miFStream );

// Ahora se pueden utilizar los dos streams de entrada para


// acceder al fichero (si se quiere...)
[Link]( b );
i = [Link]();

// Cierra el fichero de datos explícitamente


//Siempre se cierra primero el fichero stream de mayor nivel
[Link]();
[Link]();

Lectura de un DataInputStream

Al acceder a un fichero como DataInputStream, se pueden utilizar los mismos métodos read() de los objetos
FileInputStream. No obstante, también se tiene acceso a otros métodos diseñados para leer cada uno de los tipos de
datos:

byte readByte()
int readUnsignedByte()
short readShort()
int readUnsignedShort()
char readChar()
int readInt()
long readLong()
float readFloat()
double readDouble()
String readLine()
Cada método leerá un objeto del tipo pedido.

Para el método String readLine(), se marca el final de la cadena con \n, \r, \r\n o con EOF.

Para leer un long, por ejemplo:

long numeroSerie;
...
numeroSerie = [Link]();

Streams de entrada de URLs

Además del acceso a ficheros, Java proporciona la posibilidad de acceder a URLs como una forma de acceder a
objetos a través de la red. Se utiliza implícitamente un objeto URL al acceder a sonidos e imágenes, con el método
getDocumentBase() en los applets:

String imagenFich = new String( "imagenes/[Link]" );


imagenes[0] = getImage( getDocumentBase(),imagenFich );

No obstante, se puede proporcionar directamente un URL, si se quiere:

URL imagenSrc;
imagenSrc = new URL( "[Link] );
imagenes[0] = getImage( imagenSrc,"imagenes/[Link]" );

Apertura de un Stream de entrada de URL

También se puede abrir un stream de entrada a partir de un URL. Por ejemplo, se puede utilizar un fichero de datos
para un applet:

ImputStream is;
byte buffer[] = new byte[24];
is = new URL( getDocumentBase(),datos).openStream();

Ahora se puede utilizar is para leer información de la misma forma que se hace con un objeto FileInputStream:

[Link]( buffer,0,[Link] );

NOTA: Debe tenerse muy en cuenta que algunos usuarios pueden haber configurado la seguridad de sus
navegadores para que los applets no accedan a ficheros.

Tutorial de Java [Anterior] [Indice] [Siguiente]


STREAMS DE SALIDA
La contrapartida necesaria de la lectura de datos es la escritura de datos. Como con los Streams de entrada, las clases
de salida están ordenadas jerárquicamente:

Examinaremos las clases FileOutputStream y DataOutputStream para complementar los streams de entrada que
se han visto. En los ficheros fuente del directorio $JAVA_HOME/src/java/io se puede ver el uso y métodos de
estas clases, así como de los streams de entrada ($JAVA_HOME es el directorio donde se haya instalado el Java
Development Kit, en sistemas UNIX).

Objetos FileOutputStream

Los objetos FileOutputStream son útiles para la escritura de ficheros de texto. Como con los ficheros de entrada,
primero se necesita abrir el fichero para luego escribir en él.

Apertura de un FileOutputStream

Para abrir un objeto FileOutputStream, se tienen las mismas posibilidades que para abrir un fichero stream de
entrada. Se le da al constructor un String o un objeto File.

FileOutputStream miFicheroSt;
miFicheroSt = new FileOutputStream( "/etc/kk" );

Como con los streams de entrada, también se puede utilizar:

File miFichero FileOutputStream miFicheroSt;

miFichero = new File( "/etc/kk" );


miFicheroSt = new FileOutputStream( miFichero );

Escritura en un FileOutputStream

Una vez abierto el fichero, se pueden escribir bytes de datos utilizando el método write(). Como con el método read()
de los streams de entrada, tenemos tres posibilidades:

void write( int b );

Escribe un byte.

void write( byte b[] );

Escribe todo el array, si es posible.

void write( byte b[],int offset,int longitud );

Escribe longitud bytes en b comenzando por b[offset].

Cierre de FileOutputStream

Cerrar un stream de salida es similar a cerrar streams de entrada. Se puede utilizar el método explícito:

[Link]();

O, se puede dejar que el sistema cierre el fichero cuando se recicle miFicheroSt.

Ejemplo: Almacenamiento de Información

Este programa, [Link], pregunta al usuario una lista de nombres y números de teléfono. Cada nombre y
número se añade a un fichero situado en una localización fija. Para indicar que se ha introducido toda la lista, el
usuario especifica "Fin" ante la solicitud de entrada del nombre.

Una vez que el usuario ha terminado de teclear la lista, el programa creará un fichero de salida que se mostrará en
pantalla o se imprimirá. Por ejemplo:

95-4751232,Juanito
564878,Luisa
123456,Pepe
347698,Antonio
91-3547621,Maria

El código fuente del programa es el siguiente:

import [Link].*;

class Telefonos {
static FileOutputStream fos;
public static final int longLinea = 81;

public static void main( String args[] ) throws IOException {


byte tfno[] = new byte[longLinea];
byte nombre[] = new byte[longLinea];

fos = new FileOutputStream( "[Link]" );


while( true )
{
[Link]( "Teclee un nombre ('Fin' termina)" );
leeLinea( nombre );
if( "fin".equalsIgnoreCase( new String( nombre,0,0,3 ) ) )
break;

[Link]( "Teclee el numero de telefono" );


leeLinea( tfno );
for( int i=0; tfno[i] != 0; i++ )
[Link]( tfno[i] );
[Link]( ',' );
for( int i=0; nombre[i] != 0; i++ )
[Link]( nombre[i] );
[Link]( '\n' );
}
[Link]();
}

private static void leeLinea( byte linea[] ) throws IOException {


int b = 0;
int i = 0;

while( (i < ( longLinea-1) ) &&


( ( b = [Link]() ) != '\n' ) )
linea[i++] = (byte)b;
linea[i] = (byte)0;
}
}

Streams de salida con buffer

Si se trabaja con gran cantidad de datos, o se escriben muchos elementos pequeños, será una buena idea utilizar un
stream de salida con buffer. Los streams con buffer ofrecen los mismos métodos de la clase FileOutputStream, pero
toda salida se almacena en un buffer. Cuando se llena el buffer, se envía a disco con una única operación de escritura;
o, en caso necesario, se puede enviar el buffer a disco en cualquier momento.

Creación de Streams de salida con buffer

Para crear un stream BufferedOutput, primero se necesita un stream FileOutput normal; entonces se le añade un
buffer al stream:

FileOutputStream miFileStream;
BufferdOutpurStream miBufferStream;
// Obtiene un controlador de fichero
miFileStream = new FileOutputStream( "/tmp/kk" );
// Encadena un stream de salida con buffer
miBufferStream = new BufferedOutputStream( miFileStream );

Volcado y Cierre de Streams de salida con buffer

Al contrario que los streams FileOutput, cada escritura al buffer no se corresponde con una escritura en disco. A
menos que se llene el buffer antes de que termine el programa, cuando se quiera volcar el buffer explícitamente se
debe hacer mediante una llamada a flush():
// Se fuerza el volcado del buffer a disco
[Link]();
// Cerramos el fichero de datos. Siempre se ha de cerrar primero el
// fichero stream de mayor nivel
[Link]();
[Link]();

Streams DataOutput

Java también implementa una clase de salida complementaria a la clase DataInputStream. Con la clase
DataOutputStream, se pueden escribir datos binarios en un fichero.

Apertura y cierre de objetos DataOutputStream

Para abrir y cerrar objetos DataOutputStream, se utilizan los mismos métodos que para los objetos FileOutputStream:

DataOutputStream miDataStream;
FileOutputStream miFileStream;
BufferedOutputStream miBufferStream;

// Obtiene un controlador de fichero


miFileStream = new FileOutputStream( "/tmp/kk" );
// Encadena un stream de salida con buffer (por eficiencia)
miBufferStream = new BufferedOutputStream( miFileStream );
// Encadena un fichero de salida de datos
miDataStream = new DataOutputStream( miBufferStream );

// Ahora se pueden utilizar los dos streams de entrada para


// acceder al fichero (si se quiere)
[Link]( b );
[Link]( i );

// Cierra el fichero de datos explícitamente. Siempre se cierra


// primero el fichero stream de mayor nivel
[Link]();
[Link]();
[Link]();

Escritura en un objeto DataOutputStream

Cada uno de los métodos write() accesibles por los FileOutputStream también lo son a través de los
DataOutputStream. También encontrará métodos complementarios a los de DataInputStream:

void writeBoolean( boolean b );


void writeByte( int i );
void writeShort( int i );
void writeChar( int i );
void writeInt( int i );
void writeFloat( float f );
void writeDouble( double d );
void writeBytes( String s );
void writeChars( string s );
Para las cadenas, se tienen dos posibilidades: bytes y caracteres. Hay que recordar que los bytes son objetos de 8 bits
y los caracteres lo son de 16 bits. Si nuestras cadenas utilizan caracteres Unicode, debemos escribirlas con
writeChars().

Contabilidad de la salida

Otra función necesaria durante la salida es el método size(). Este método simplemente devuelve el número total de
bytes escritos en el fichero. Se puede utilizar size() para ajustar el tamaño de un fichero a múltiplo de cuatro. Por
ejemplo, de la forma siguiente:

. . .
int numBytes = [Link]() % 4;
for( int i=0; i < numBytes; i++ )
[Link]( 0 );
. . .

Tutorial de Java [Anterior] [Indice] [Siguiente]


FICHEROS DE ACCESO ALEATORIO
A menudo, no se desea leer un fichero de principio a fin; sino acceder al fichero como una base de datos, donde se
salta de un registro a otro; cada uno en diferentes partes del fichero. Java proporciona una clase RandomAccessFile
para este tipo de entrada/salida.

Creación de un Fichero de Acceso Aleatorio

Hay dos posibilidades para abrir un fichero de acceso aleatorio:

Con el nombre del fichero:

miRAFile = new RandomAccessFile( String nombre,String modo );

Con un objeto File:

miRAFile = new RandomAccessFile( File fichero,String modo );

El argumento modo determina si se tiene acceso de sólo lectura (r) o de lectura/escritura (r/w). Por ejemplo, se
puede abrir un fichero de una base de datos para actualización:

RandomAccessFile miRAFile;
miRAFile = new RandomAccessFile( "/tmp/[Link]","rw" );

Acceso a la Información

Los objetos RandomAccessFile esperan información de lectura/escritura de la misma manera que los objetos
DataInput/DataOutput. Se tiene acceso a todas las operaciones read() y write() de las clases DataInputStream y
DataOutputStream.

También se tienen muchos métodos para moverse dentro de un fichero:

long getFilePointer();

Devuelve la posición actual del puntero del fichero

void seek( long pos );

Coloca el puntero del fichero en una posición determinada. La posición se da como un desplazamiento en bytes desde
el comienzo del fichero. La posición 0 marca el comienzo de ese fichero.
long length();

Devuelve la longitud del fichero. La posición length() marca el final de ese fichero.

Actualización de Información

Se pueden utilizar ficheros de acceso aleatorio para añadir información a ficheros existentes:

miRAFile = new RandomAccessFile( "/tmp/[Link]","rw" );


[Link]( [Link]() );
// Cualquier write() que hagamos a partir de este punto del código
// añadirá información al fichero

Vamos a ver un pequeño ejemplo, [Link], que añade


una cadena a un fichero existente:

import [Link].*;

// Cada vez que ejecutemos este programita, se incorporara una nueva


// linea al fichero de log que se crea la primera vez que se ejecuta
//
class Log {
public static void main( String args[] ) throws IOException {
RandomAccessFile miRAFile;
String s = "Informacion a incorporar\nTutorial de Java\n";

// Abrimos el fichero de acceso aleatorio


miRAFile = new RandomAccessFile( "/tmp/[Link]","rw" );
// Nos vamos al final del fichero
[Link]( [Link]() );
// Incorporamos la cadena al fichero
[Link]( s );
// Cerramos el fichero
[Link]();
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Sep-1996 11:24:56
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Cada vez que ejecutemos este programita, se incorporara una nueva


// linea al fichero de log que se crea la primera vez que se ejecuta
//
class Log {
public static void main( String args[] ) throws IOException {
RandomAccessFile miRAFile;
String s = "Informacion a incorporar\nTutorial de Java\n";

// Abrimos el fichero de acceso aleatorio


miRAFile = new RandomAccessFile( "/tmp/[Link]","rw" );
// Nos vamos al final del fichero
[Link]( [Link]() );
// Incorporamos la cadena al fichero
[Link]( s );
// Cerramos el fichero
[Link]();
}
}

//----------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 06-Oct-1996 09:48:03
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

class Direccion {
protected String nombre;
protected String telefono;
protected String direccion;

Direccion( String n,String t,String d ) {


nombre = n;
telefono = t;
direccion = d;
}

public String getNombre() {


return( nombre );
}

public String getTelefono() {


return( telefono );
}

public String getDireccion() {


return( direccion );
}

public void print() {


[Link]( nombre+"\n "+telefono+"\n "+
direccion );
}
}

class DireccionArray {
protected Direccion lista[];
final int max = 128;
int tamano = 0;

DireccionArray() {
lista = new Direccion[max];
}

void printDireccion( String nombre ) {


for(int i=0; i < tamano; i++ )
{
if( lista[i].getNombre().indexOf( nombre ) != -1 )
lista[i].print();
}
}

void addDireccion( Direccion direccion ) {


if( tamano == max )
[Link]( 1 );
lista[tamano++] = direccion;
}
}

public class Agenda {


DireccionArray lista;
FileInputStream agFichero;
final int longLinea = 32;

public static void main( String argv[] ) {


Agenda agenda = new Agenda();
[Link]();
}

Agenda() {
lista = cargaDirecciones();
}

void bucle() {
String nombre;

[Link]( "Introduzca un nombre o <Enter>" );


try {
while( !"".equals( nombre = leeEntrada( [Link] ) ) )
{
[Link]( nombre );
[Link](
"Introduzca un nombre o <Enter>" );
}
} catch( Exception e ) {
;
}
}

String leeEntrada( InputStream entrada ) throws IOException {


byte chars[] = new byte[longLinea];
int contador = 0;

while( contador < longLinea &&


( chars[contador++] = (byte)[Link]() ) != '\n' )
if( chars[contador-1] == -1 )
return( null );

return( new String( chars,0,0,contador-1 ) );


}

Direccion cargaDireccion() throws IOException {


String nombre = leeEntrada( agFichero );
if( nombre == null )
return( null );

String telefono = leeEntrada( agFichero );


String direccion = leeEntrada( agFichero ) + "\n " +
leeEntrada( agFichero ) + "\n " +
leeEntrada( agFichero );

return( new Direccion( nombre,telefono,direccion ) );


}

DireccionArray cargaDirecciones() {
DireccionArray lista = new DireccionArray();
Direccion nuevaDireccion;

try {
agFichero = new FileInputStream( "agenda" );
} catch( FileNotFoundException e ) {
[Link]( "No hay fichero de Agenda" );
return( lista );
}

while( true ) {
try {
nuevaDireccion = cargaDireccion();
if( nuevaDireccion == null )
return( lista );
[Link]( nuevaDireccion );
} catch( Exception e ) {
[Link]( "Error cargando Agenda " );
[Link]( 1 );
}
}
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Oct-1996 06:43:16
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

class Telefonos {
static FileOutputStream fos;
public static final int longLinea = 81;

public static void main( String args[] ) throws IOException {


byte tfno[] = new byte[longLinea];
byte nombre[] = new byte[longLinea];

fos = new FileOutputStream( "[Link]" );


while( true )
{
[Link]( "Teclee un nombre ('Fin' termina)" );
leeLinea( nombre );
if( "fin".equalsIgnoreCase( new String( nombre,0,0,3 ) ) )
break;

[Link]( "Teclee el numero de telefono" );


leeLinea( tfno );
for( int i=0; tfno[i] != 0; i++ )
[Link]( tfno[i] );
[Link]( ',' );
for( int i=0; nombre[i] != 0; i++ )
[Link]( nombre[i] );
[Link]( '\n' );
}
[Link]();
}

private static void leeLinea( byte linea[] ) throws IOException {


int b = 0;
int i = 0;

while( (i < ( longLinea-1) ) &&


( ( b = [Link]() ) != '\n' ) )
linea[i++] = (byte)b;
linea[i] = (byte)0;
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Oct-1996 06:01:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

class InfoFichero {

public static void main( String args[] ) throws IOException {


if( [Link] > 0 )
{
for( int i=0; i < [Link]; i++ )
{
File f = new File( args[i] );
[Link]( "Nombre: "+[Link]() );
[Link]( "Camino: "+[Link]() );
if( [Link]() )
{
[Link]( "Fichero existente " );
[Link]( ([Link]() ?
" y se puede Leer" : "" ) );
[Link]( ([Link]() ?
" y se puese Escribir" : "" ) );
[Link]( "." );
[Link]( "La longitud del fichero son "+
[Link]()+" bytes" );
}
else
[Link]( "El fichero no existe." );
}
}
else
[Link]( "Debe indicar un fichero." );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Oct-1996 06:13:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

class miType {
public static void main( String args[] ) throws IOException {
int c;
int contador = 0;

while( (c = [Link]() ) != '\n' )


{
contador++;
[Link]( (char)c );
}
[Link](); // Línea en blanco
[Link]( "Contados "+ contador +" bytes en total." );
}
}

//-------------------------------------------- Final del fichero [Link]


ESCRIBIR CODIGO JAVA
En primer lugar, debemos crear una clase Java, HolaMundo, que declare un método nativo. También debemos crear
el programa principal que cree el objeto HolaMundo y llame al método nativo.

Las siguientes líneas de código definen la clase HolaMundo, que consta de un método y un segmento estático de
código:

class HolaMundo {
public native void presentaSaludo();
static {
[Link]( "hola" );
}
}

Podemos decir que la implementación del método presentaSaludo() de la clase HolaMundo está escrito en otro
lenguaje, porque la palabra reservada native aparece como parte de la definición del método. Esta definición,
proporciona solamente la definición para presentaSaludo() y no porporciona ninguna implementación para él. La
implementación la proporcionaremos desde un fichero fuente separado, escrito en lenguaje C.

La definición para presentaSaludo() también indica que el método es un método público, no acepta argumentos y no
devuelve ningún valor. Al igual que cualquier otro método, los métodos nativos deben estar definidos dentro de una
clase Java.

El código C que implementa el método presentaSaludo() debe ser compilado en una librería dinámica y cargado en la
clase Java que lo necesite. Esta carga, mapea la implementación del método nativo sobre su definición.

El siguiente bloque de código carga la librería dinámica, en este caso hola. El sistema Java ejecutará un bloque de
código estático de la clase cuando la cargue.

Todo el código anterior forma parte del fichero [Link], que contiene la clase HolaMundo. En un fichero
separado, [Link], vamos a crear una aplicación Java que instancie a la clase HolaMundo y llame al método
nativo presentaSaludo().

class Main {
public static void main( String args[] ) {
new HolaMundo().presentaSaludo();
}
}

Como se puede observar, llamamos al método nativo del mismo modo que a cualquier otro método Java; añadimos el
nombre del método al final del nombre del objeto con un punto ("."). El conjunto de paréntesis que sigue al nombre
del método encierra los argumentos que se le pasen. En este caso, el método presentaSaludo() no recibe ningún tipo
de argumento.

Compilar el Código Java

Utilizaremos ahora el compilador javac para compilar el código Java que hemos desarrollado.

Compilaremos los dos ficheros fuentes de código Java que hemos creado, tecleando los siguientes comandos:

> javac [Link]


> javac [Link]

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR EL FICHERO DE CABECERA
Ahora debemos utilizar la aplicación javah para conseguir el fichero de cabecera .h. El fichero de cabecera define
una estructura que representa la clase HolaMundo sobre código C y proporciona la definición de una función C para
la implementación del método nativo presentaSaludo() definido en ese clase.

Ejecutamos javah sobre la clase HolaMundo, con el siguiente comando:

> javah HolaMundo

Por defecto, javah creará el nuevo fichero .h en el mismo directorio en que se encuentra el fichero .class, obtenido al
compilar con javac el código fuente Java correspondiente a la clase. El fichero que creará, será un fichero de
cabecera del mismo nombre que la clase y con extensión .h. Por ejemplo, el comando anterior habrá creado el fichero
HolaMundo.h, cuyo contenido será el siguiente:

/* DO NOT EDIT THIS FILE - it is machine generated */


#include <native.h>
/* Header for class HolaMundo */

#ifndef _Included_HolaMundo
#define _Included_HolaMundo

typedef struct ClassHolaMundo {


char PAD; /* ANSI C requires structures to have a least one member */
} ClassHolaMundo;
HandleTo(HolaMundo);

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HolaMundo_presentaSaludo(struct HHolaMundo *);
#ifdef __cplusplus
}
#endif
#endif

Este fichero de cabecera contiene la definición de una estructura llamada ClassHolaMundo. Los miembros de esta
estructura son paralelos a los miembros de la clase Java correspondiente; es decir, los campos en la estructura
corresponden a las variables de la clase. Pero como HolaMundo no tiene ninguna variable, la estructura se encuentra
vacía. Se pueden utilizar los miembros de la estructura para referenciar a variables instanciadas de la clase desde las
funciones C.

Además de la estructura C similar a la clase Java, vemos que la llamada de la función C está declarada como:
extern void HolaMundo_presentaSaludo( struct HHolaMundo *);

Esta es la definición de la función C que deberemos escribir para implementar el método nativo presentaSaludo() de
la clase HolaMundo. Debemos utilizar esa definición cuando lo implementemos. Si HolaMundo llamase a otros
métodos nativos, las definiciones de las funciones también aparecerían aquí.

El nombre de la función C que implementa el método nativo está derivado del nombre del paquete, el nombre de la
clase y el nombre del método nativo. Así, el método nativo presentaSaludo() dentro de la clase HolaMundo es
HolaMundo_presentaSaludo(). En este ejemplo, no hay nombre de paquete porque HolaMundo se considera
englobado dentro del paquete por defecto.

La función C acepta un parámetro, aunque el método nativo definido en la clase Java no acepte ninguno. Se puede
pensar en este parámetro como si fuese la variable this de C++. En nuestro caso, ignoramos el parámetro this.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR EL FICHERO DE STUBS
Volvemos a utilizar la aplicación javah para crear el fichero de stubs, que contiene todas las declaraciones de
métodos, con sus llamadas y argumentos, listos para que nosotros rellenemos el cuerpo de los métodos con los
algoritmos que necesitemos implementar. Proporciona la unión entre la clase Java y su estructura C paralela.

Para generar este fichero, debemos indicar el parámetro .stubs al ejecutar la aplicación javah sobre la clase
HolaMundo, de la siguiente forma:

> javah -stubs HolaMundo

Del mismo modo que se generaba el fichero .h; el nombre del fichero de stubs será el nombre de la clase con la
extensión .c. En nuestro ejemplo, será HolaMundo.c, y su contenido será el siguiente:

/* DO NOT EDIT THIS FILE - it is machine generated */


#include <StubPreamble.h>

/* Stubs for class HolaMundo */


/* SYMBOL: "HolaMundo/presentaSaludo()V",
Java_HolaMundo_presentaSaludo_stub */
__declspec(dllexport) stack_item
*Java_HolaMundo_presentaSaludo_stub(stack_item *_P_,struct execenv *_EE_) {
extern void HolaMundo_presentaSaludo(void *);
(void) HolaMundo_presentaSaludo(_P_[0].p);
return _P_;
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


ESCRIBIR LA FUNCION C
Escribiremos la función C para el método nativo en un fichero fuente de código C. La implementación será una
función habitual C, que luego integraremos con la clase Java. La definición de la función C debe ser la misma que la
que se ha generado con javah en el fichero HolaMundo.h.

La implementación que proponemos la guardaremos en el fichero HolaImp.c, y contendrá las siguientes línea de
código:

#include <StubPreamble.h>
#include "HolaMundo.h>
#include <stdio.h>

void HolaMundo_presentaSaludo( struct HHolaMundo *this ) {


printf( "Hola Mundo, desde el Tutorial de Java\n" );
return;
}

Como se puede ver, la implementación no puede ser más sencilla: hace una llamada a la función printf() para
presentar el saludo y sale.

En el código se incluyen tres ficheros de cabecera:

● StubsPreamble.h

Proporciona la información para que el código C pueda interactuar con el sistema Java. Cuando se
escriben métodos nativos, siempre habrá que incluir este fichero en el código fuente C.

● HolaMundo.h

Es el fichero de cabecera que hemos generado para nuestra clase. Contiene la estructura C que
representa la clase Java para la que estamos escribiendo el método nativo y la definición de la función
para ese método nativo.

● stdio.h

Es necesario incluirlo porque utilizamos la función printf() de la librería estándar de C, cuya


declaración se encuentra en este fichero de cabecera.
Tutorial de Java [Anterior] [Indice] [Siguiente]
CREAR LA LIBRERIA DINAMICA
Utilizaremos el compilador C para compilar el fichero .h, el fichero de stubs y el fichero fuente .c; para crear una
librería dinámica. Para crearla, utilizaremos el compilador C de nuestro sistema, haciendo que los ficheros
HolaMundo.c y HolaImp.c generen una librería dinámica de nombre hola, que será la que el sistema Java cargue
cuando ejecute la aplicación que estamos construyendo.

Vamos a ver cómo generamos esta librería en Unix y en Windows '95.

Unix

Teclearemos el siguiente comando:

% cc -G HolaMundo.c HolaImp.c -o [Link]

En caso de que no encuentre el compilador los ficheros de cabecera, se puede utilizar el flag -I para indicarle el
camino de búsqueda, por ejemplo:

% cc -G -I$JAVA_HOME/include HolaMundo.c HolaImp.c -o [Link]

donde $JAVA_HOME es el directorio donde se ha instalado la versión actual del Java Development Kit.

Windows '95

El comando a utilizar en este caso es el siguiente:

c:\>cl HolaMundo.c HolaImp.c -[Link] -MD -LD [Link]

Este comando funciona con Microsoft Visual C++ 2.x y posteriores. Si queremos indicar al compilador donde se
encuentran los ficheros de cabecera y las librerías, tendremos que fijar dos variables de entorno:

c:\>SET INCLUDE=%JAVAHOME%\include;%INCLUDE%
c:\>SET LIB=%JAVAHOME%\lib;%LIB%

donde %JAVAHOME% es el directorio donde se ha instalado la versión actual del Java Development Kit.

Tutorial de Java [Anterior] [Indice] [Siguiente]


EJECUTAR EL PROGRAMA
Y, por fin, utilizaremos el intérprete de Java, java, para ejecutar el programa que hemos construido siguiendo todos
los pasos anteriormente descritos. Si tecleamos el comando:

> java Main

obtendremos el resultado siguiente:

% Hola Mundo, desde el Tutorial de Java

Si no aparece este mensaje de saludo y lo que aparece en pantalla son expresiones como UnsatisfiedLinkError, es
porque no tenemos fijado correctamente el camino de la librería dinámica que hemos generado. Este camino es la
lista de directorios que el sistema Java utilizará para buscar las librerías que debe cargar. Debemos asegurarnos de
que el directorio donde se encuentra nuestra librería hola recién creada, figura entre ellos.

Si fijamos el camino correcto y ejecutamos de nuevo el programa, veremos que ahora sí obtenemos el mensaje de
saludo que esperábamos.

Con ello, hemos visto como integrar código C en programas Java. Quedan muchas cuestiones por medio, como la
equivalencia de tipos entre Java y C, el paso de parámetros, el manejo de cadenas, etc. Pero eso supondría entrar en
mucha más profundidad dentro de Java de la que aquí pretendemos (por ahora).

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 01-Oct-1996 09:06:29
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class HolaMundo {
public native void presentaSaludo();

static {
[Link]( "hola" );
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 01-Oct-1996 09:09:03
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class Main {
public static void Main( String args[] ) {
new HolaMundo().presentaSaludo();
}
}

//---------------------------------------------- Final del fichero [Link]


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <native.h>
/* Header for class HolaMundo */

#ifndef _Included_HolaMundo
#define _Included_HolaMundo

typedef struct ClassHolaMundo {


char PAD; /* ANSI C requires structures to have a least one member */
} ClassHolaMundo;
HandleTo(HolaMundo);

#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HolaMundo_presentaSaludo(struct HHolaMundo *);
#ifdef __cplusplus
}
#endif
#endif
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <StubPreamble.h>

/* Stubs for class HolaMundo */


/* SYMBOL: "HolaMundo/presentaSaludo()V", Java_HolaMundo_presentaSaludo_stub */
__declspec(dllexport) stack_item *Java_HolaMundo_presentaSaludo_stub(stack_item *_P_,struct
execenv *_EE_) {
extern void HolaMundo_presentaSaludo(void *);
(void) HolaMundo_presentaSaludo(_P_[0].p);
return _P_;
}
/*
// HolaImp.c
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: Microsoft Visual C++ 4.2
// Autor: Agustin Froufe
// Creacion: 01-Oct-1996 09:12:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------
*/

#include <StubPreamble.h>
#include "HolaMundo.h"
#include <stdio.h>

void HolaMundo_presentaSaludo( struct HolaMundo *this ) {


printf( "Hola Mundo, desde el Tutorial de Java\n" );
return;
}

/*------------------------------------------- Final del fichero HolaImp.c */


FLUJO EN PROGRAMAS
Programas de flujo único

Un programa de flujo único o mono-hilvanado (single-thread) utiliza un único flujo de control (thread) para controlar
su ejecución. Muchos programas no necesitan la potencia o utilidad de múltiples flujos de control. Sin necesidad de
especificar explícitamente que se quiere un único flujo de control, muchos de los applets y aplicaciones son de flujo
único.

Por ejemplo, en nuestra aplicación estándar de saludo:

public class HolaMundo {


static public void main( String args[] ) {
[Link]( "Hola Mundo!" );
}
}

Aquí, cuando se llama a main(), la aplicación imprime el mensaje y termina. Esto ocurre dentro de un único thread.

Programas de flujo múltiple

En nuestra aplicación de saludo, no vemos el thread que ejecuta nuestro programa. Sin embargo, Java posibilita la
creación y control de threads explícitamente. La utilización de threads en Java, permite una enorme flexibilidad a los
programadores a la hora de plantearse el desarrollo de aplicaciones. La simplicidad para crear, configurar y ejecutar
threads, permite que se puedan implementar muy poderosas y portables aplicaciones/applets que no se puede con
otros lenguajes de tercera generación. En un lenguaje orientado a Internet como es Java, esta herramienta es vital.

Si se ha utilizado un navegador con soporte Java, ya se habrá visto el uso de múltiples threads en Java. Habrá
observado que dos applet se pueden ejecutar al mismo tiempo, o que puede desplazar la página del navegador
mientras el applet continúa ejecutándose. Esto no significa que el applet utilice múltiples threads, sino que el
navegador es multithreaded.

Las aplicaciones (y applets) multithreaded utilizan muchos contextos de ejecución para cumplir su trabajo. Hacen uso
del hecho de que muchas tareas contienen subtareas distintas e independientes. Se puede utilizar un thread para cada
subtarea.

Mientras que los programas de flujo único pueden realizar su tarea ejecutando las subtareas secuencialmente, un
programa multithreaded permite que cada thread comience y termine tan pronto como sea posible. Este
comportamiento presenta una mejor respuesta a la entrada en tiempo real.

Vamos a modificar nuestro programa de saludo creando tres threads individuales, que imprimen cada uno de ellos su
propio mensaje de saludo, [Link]:
// Definimos unos sencillos threads. Se detendrán un rato
// antes de imprimir sus nombres y retardos

class TestTh extends Thread {


private String nombre;
private int retardo;

// Constructor para almacenar nuestro nombre


// y el retardo
public TestTh( String s,int d ) {
nombre = s;
retardo = d;
}

// El metodo run() es similar al main(), pero para


// threads. Cuando run() termina el thread muere
public void run() {
// Retasamos la ejecución el tiempo especificado
try {
sleep( retardo );
} catch( InterruptedException e ) {
;
}

// Ahora imprimimos el nombre


[Link]( "Hola Mundo! "+nombre+" "+retardo );
}
}

public class MultiHola {


public static void main( String args[] ) {
TestTh t1,t2,t3;

// Creamos los threads


t1 = new TestTh( "Thread 1",(int)([Link]()*2000) );
t2 = new TestTh( "Thread 2",(int)([Link]()*2000) );
t3 = new TestTh( "Thread 3",(int)([Link]()*2000) );

// Arrancamos los threads


[Link]();
[Link]();
[Link]();
}
}

Y ya mßs como espectáculo que otra cosa, aunque también podemos tomarlo por el lado ilustrativo, vemos a
continuación la elecución del applet [Link] que muestra un montón de círculos, cada uno de ellos ejecutándose
en un thread diferente y con distinta prioridad cada uno de ellos. La clase Circulo es la que se utiliza para lanzarla
todas las veces que se quiere, de tal forma que cada uno de los círculos presentes en el applet son instancias de la
misma clase Circulo.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREACION Y CONTROL DE THREADS
Creación de un Thread

Hay dos modos de conseguir threads en Java. Una es implementando la interface Runnable, la otra es extender la
clase Thread.

La implementación de la interface Runnable es la forma habitual de crear threads. Las interfaces proporcionan al
programador una forma de agrupar el trabajo de infraestructura de una clase. Se utilizan para diseñar los
requerimientos comunes al conjunto de clases a implementar. La interface define el trabajo y la clase, o clases, que
implementan la interface realizan ese trabajo. Los diferentes grupos de clases que implementen la interface tendrán
que seguir las mismas reglas de funcionamiento.

Hay una cuantas diferencias entre interface y clase. Primero, una interface solamente puede contener métodos
abstractos y/o variables estáticas y finales (constantes). Las clases, por otro lado, pueden implementar métodos y
contener variables que no sean constantes. Segundo, una interface no puede implementar cualquier método. Una
clase que implemente una interface debe implementar todos los métodos definidos en esa interface. Una interface
tiene la posibilidad de poder extenderse de otras interfaces y, al contrario que las clases, puede extenderse de
múltiples interfaces. Además, una interface no puede ser instanciada con el operador new; por ejemplo, la siguiente
sentencia no está permitida:

Runnable a = new Runnable(); // No se permite

El primer método de crear un thread es simplemente extender la clase Thread:

class MiThread extends Thread {


public void run() {
. . .
}

El ejemplo anterior crea una nueva clase MiThread que extiende la clase Thread y sobrecarga el método
[Link]() por su propia implementación. El método run() es donde se realizará todo el trabajo de la clase.
Extendiendo la clase Thread, se pueden heredar los métodos y variables de la clase padre. En este caso, solamente se
puede extender o derivar una vez de la clase padre. Esta limitación de Java puede ser superada a través de la
implementación de Runnable:

public class MiThread implements Runnable {


Thread t;
public void run() {
// Ejecución del thread una vez creado
}
}
En este caso necesitamos crear una instancia de Thread antes de que el sistema pueda ejecutar el proceso como un
thread. Además, el método abstracto run() está definido en la interface Runnable tiene que ser implementado. La
única diferencia entre los dos métodos es que este último es mucho más flexible. En el ejemplo anterior, todavía
tenemos oportunidad de extender la clase MiThread, si fuese necesario. La mayoría de las clases creadas que
necesiten ejecutarse como un thread , implementarán la interface Runnable, ya que probablemente extenderán
alguna de su funcionalidad a otras clases.

No pensar que la interface Runnable está haciendo alguna cosa cuando la tarea se está ejecutando. Solamente
contiene métodos abstractos, con lo cual es una clase para dar idea sobre el diseño de la clase Thread. De hecho, si
vemos los fuentes de Java, podremos comprobar que solamente contiene un método abstracto:

package [Link];
public interface Runnable {
public abstract void run() ;
}

Y esto es todo lo que hay sobre la interface Runnable. Como se ve, una interface sólo proporciona un diseño para las
clases que vayan a ser implementadas. En el caso de Runnable, fuerza a la definición del método run(), por lo tanto,
la mayor parte del trabajo se hace en la clase Thread. Un vistazo un poco más profundo a la definición de la clase
Thread nos da idea de lo que realmente está pasando:

public class Thread implements Runnable {


...
public void run() {
if( tarea != null )
[Link]() ;
}
}
...
}

De este trocito de código se desprende que la clase Thread también implemente la interface Runnable. [Link]()
se asegura de que la clase con que trabaja (la clase que va a ejecutarse como un thread) no sea nula y ejecuta el
método run() de esa clase. Cuando esto suceda, el método run() de la clase hará que corra como un thread.

Arranque de un Thread

Las aplicaciones ejecutan main() tras arrancar. Esta es la razón de que main() sea el lugar natural para crear y
arrancar otros threads. La línea de código:

t1 = new TestTh( "Thread 1",(int)([Link]()*2000) );

crea un nuevo thread. Los dos argumentos pasados representan el nombre del thread y el tiempo que queremos que
espere antes de imprimir el mensaje.

Al tener control directo sobre los threads, tenemos que arrancarlos explícitamente. En nuestro ejemplo con:

[Link]();

start(), en realidad es un método oculto en el thread que llama al método run().


Manipulación de un Thread

Si todo fue bien en la creación del thread, t1 debería contener un thread válido, que controlaremos en el método
run().

Una vez dentro de run(), podemos comenzar las sentencias de ejecución como en otros programas. run() sirve como
rutina main() para los threads; cuando run() termina, también lo hace el thread. Todo lo que queramos que haga el
thread ha de estar dentro de run(), por eso cuando decimos que un método es Runnable, nos obliga a escribir un
método run().

En este ejemplo, intentamos inmediatamente esperar durante una cantidad de tiempo aleatoria (pasada a través del
constructor):

sleep( retardo );

El método sleep() simplemente le dice al thread que duerma durante los milisegundos especificados. Se debería
utilizar sleep() cuando se pretenda retrasar la ejecución del thread. sleep() no consume recursos del sistema mientras
el thread duerme. De esta forma otros threads pueden seguir funcionando. Una vez hecho el retardo, se imprime el
mensaje "Hola Mundo!" con el nombre del thread y el retardo.

Suspensión de un Thread

Puede resultar útil suspender la ejecución de un thread sin marcar un límite de tiempo. Si, por ejemplo, está
construyendo un applet con un thread de animación, querrá permitir al usuario la opción de detener la animación
hasta que quiera continuar. No se trata de terminar la animación, sino desactivarla. Para este tipo de control de thread
se puede utilizar el método suspend().

[Link]();

Este método no detiene la ejecución permanentemente. El thread es suspendido indefinidamente y para volver a
activarlo de nuevo necesitamos realizar una invocación al método resume():

[Link]();

Parada de un Thread

El último elemento de control que se necesita sobre threads es el método stop(). Se utiliza para terminar la ejecución
de un thread:

[Link]();

Esta llamada no destruye el thread, sino que detiene su ejecución. La ejecución no se puede reanudar ya con
[Link](). Cuando se desasignen las variables que se usan en el thread, el objeto thread (creado con new) quedará
marcado para eliminarlo y el garbage collector se encargará de liberar la memoria que utilizaba.

En nuestro ejemplo, no necesitamos detener explícitamente el thread. Simplemente se le deja terminar. Los
programas más complejos necesitarán un control sobre cada uno de los threads que lancen, el método stop() puede
utilizarse en esas situaciones.

Si se necesita, se puede comprobar si un thread está vivo o no; considerando vivo un thread que ha comenzado y no
ha sido detenido.

[Link]();

Este método devolverá true en caso de que el thread t1 esté vivo, es decir, ya se haya llamado a su método run() y
no haya sido parado con un stop() ni haya terminado el método run() en su ejecución.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ARRANCAR Y PARAR THREADS
Ahora que ya hemos visto por encima como se arrancan, paran y manipulan threads, vamos a mostrar un ejemplo un
poco más gráfico, se trata de un contador, cuyo código ([Link]) es el siguiente:

import [Link].*;
import [Link];

public class App1Thread extends Applet implements Runnable {


Thread t;
int contador;

public void init() {


contador = 0;
t = new Thread( this );
[Link]();
}

public void run() {


while( true )
{
contador++;
repaint();
try {
[Link]( 10 );
} catch( InterruptedException e ) {
;
};
}
}

public boolean mouseDown( Event evt,int x,int y ) {


[Link]();
return( true );
}

public void paint( Graphics g ) {


[Link]( [Link]( contador ),10,10 );
[Link]( "Contador = "+contador );
}

public void stop() {


[Link]();
}
}
Este applet arranca un contador en 0 y lo incrementa, presentando su salida tanto en la pantalla gráfica como en la
consola. Una primera ojeada al código puede dar la impresión de que el programa empezará a contar y presentará
cada número, pero no es así. Una revisión más profunda del flujo de ejecución del applet, nos revelará su verdadera
identidad.

En este caso, la clase App1Thread está forzada a implementar Runnable sobre la clase Applet que extiende. Como
en todos los applets, el método init() es el primero que se ejecuta. En init(), la variable contador se inicializa a
cero y se crea una nueva instancia de la clase Thread. Pasándole this al constructor de Thread, el nuevo thread ya
conocerá al objeto que va a correr. En este caso this es una referencia a App1Thread. Después de que hayamos
creado el thread, necesitamos arrancarlo. La llamada a start(), llamará a su vez al método run() de nuestra clase, es
decir, a [Link](). La llamada a start() retornará con éxito y el thread comenzará a ejecutarse en ese instante.
Observar que el método run() es un bucle infinito. Es infinito porque una vez que se sale de él, la ejecución del
thread se detiene. En este método se incrementará la variable contador, se duerme 10 milisegundos y envía una
petición de refresco del nuevo valor al applet.

Es muy importante dormirse en algún lugar del thread, porque sino, el thread consumirá todo el tiempo de la CPU
para su proceso y no permitirá que entren otros métodos de otros threads a ejecutarse. Otra forma de detener la
ejecución del thread es hacer una llamada al método stop(). En el contador, el thread se detiene cuando se pulsa el
ratón mientras el cursor se encuentre sobre el applet. Dependiendo de la velocidad del ordenador, se presentarán los
números consecutivos o no, porque el incremento de la variable contador es independiente del refresco en
pantalla. El applet no se refresca a cada petición que se le hace, sino que el sistema operativo encolará las peticiones
y las que sean sucesivas las convertirán en un único refresco. Así, mientras los refescos se van encolando, la variable
contador se estará todavía incrementando, pero no se visualiza en pantalla.

Tutorial de Java [Anterior] [Indice] [Siguiente]


SUSPENDER Y REANUDAR THREADS
Una vez que se para un thread, ya no se puede rearrancar con el comando start(), debido a que stop() concluirá la
ejecución del thread. Por ello, en ver de parar el thread, lo que podemos hacer es dormirlo, llamando al método
sleep(). El thread estará suspendido un cierto tiempo y luego reanudará su ejecución cuando el límite fijado se
alcance. Pero esto no es útil cuando se necesite que el thread reanude su ejecución ante la presencia de ciertos
eventos. En estos casos, el método suspend() permite que cese la ejecución del thread y el método resume() permite
que un método suspendido reanude su ejecución. En la siguiente versión de nuestra clase contador,
[Link], modificamos el applet para que utilice los métodos suspend() y resume():

public class App2Thread extends Applet implements Runnable {


Thread t;
int contador;
boolean suspendido;

...

public boolean mouseDown( Event evt,int x,int y ) {


if( suspendido )
[Link]();
else
[Link]();
suspendido = !suspendido;

return( true );
}
...

Para controlar el estado del applet, hemos introducido la variable suspendido. Diferenciar los distintos estados de
ejecución del applet es importante porque algunos métodos pueden generar excepciones si se llaman desde un estado
erróneo. Por ejemplo, si el applet ha sido arrancado y se detiene con stop(), si se intenta ejecutar el método start(), se
generará una excepción IllegalThreadStateException.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ESTADOS DE UN THREAD
Durante el ciclo de vida de un thread, éste se puede encontrar en diferentes estados. La figura siguiente muestra estos
estados y los métodos que provocan el paso de un estado a otro. Este diagrama no es una máquina de estados finita,
pero es lo que más se aproxima al funcionamiento real de un thread .

Nuevo Thread

La siguiente sentencia crea un nuevo thread pero no lo arranca, lo deja en el estado de "Nuevo Thread":

Thread MiThread = new MiClaseThread();

Cuando un thread está en este estado, es simplemente un objeto Thread vacío. El sistema no ha destinado ningún
recurso para él. Desde este estado solamente puede arrancarse llamando al método start(), o detenerse
definitivamente, llamando al método stop(); la llamada a cualquier otro método carece de sentido y lo único que
provocará será la generación de una excepción de tipo IllegalThreadStateException.

Ejecutable

Ahora veamos las dos línea de código que se presentan a continuación:

Thread MiThread = new MiClaseThread();


[Link]();

La llamada al método start() creará los recursos del sistema necesarios para que el thread puede ejecutarse, lo
incorpora a la lista de procesos disponibles para ejecución del sistema y llama al método run() del thread. En este
momento nos encontramos en el estado "Ejecutable" del diagrama. Y este estado es Ejecutable y no En Ejecución,
porque cuando el thread está aquí no esta corriendo. Muchos ordenadores tienen solamente un procesador lo que hace
imposible que todos los threads estén corriendo al mismo tiempo. Java implementa un tipo de scheduling o lista de
procesos, que permite que el procesador sea compartido entre todos los procesos o threads que se encuentran en la
lista. Sin embargo, para nuestros propósitos, y en la mayoría de los casos, se puede considerar que este estado es
realmente un estado "En Ejecución", porque la impresión que produce ante nosotros es que todos los procesos se
ejecutan al mismo tiempo.

Cuando el thread se encuentra en este estado, todas las instrucciones de código que se encuentren dentro del bloque
declarado para el método run(), se ejecutarán secuencialmente.

Parado

El thread entra en estado "Parado" cuando alguien llama al método suspend(), cuando se llama al método sleep(),
cuando el thread está bloqueado en un proceso de entrada/salida o cuando el thread utiliza su método wait() para
esperar a que se cumpla una determinada condición. Cuando ocurra cualquiera de las cuatro cosas anteriores, el
thread estará Parado.

Por ejemplo, en el trozo de código siguiente:

Thread MiThread = new MiClaseThread();


[Link]();
try {
[Link]( 10000 );
} catch( InterruptedException e ) {
;
}

la línea de código que llama al método sleep():

[Link]( 10000 );

hace que el thread se duerma durante 10 segundos. Durante ese tiempo, incluso aunque el procesador estuviese
totalmente libre, MiThread no correría. Después de esos 10 segundos. MiThread volvería a estar en estado
"Ejecutable" y ahora sí que el procesador podría hacerle caso cuando se encuentre disponible.

Para cada una de los cuatro modos de entrada en estado Parado, hay una forma específica de volver a estado
Ejecutable. Cada forma de recuperar ese estado es exclusiva; por ejemplo, si el thread ha sido puesto a dormir, una
vez transcurridos los milisegundos que se especifiquen, él solo se despierta y vuelve a estar en estado Ejecutable.
Llamar al método resume() mientras esté el thread durmiendo no serviría para nada.

Los métodos de recuperación del estado Ejecutable, en función de la forma de llegar al estado Parado del thread, son
los siguientes:

● Si un thread está dormido, pasado el lapso de tiempo


● Si un thread está suspendido, luego de una llamada al método resume()
● Si un thread está bloqueado en una entrada/salida, una vez que el comando E/S concluya su ejecución
● Si un thread está esperando por una condición, cada vez que la variable que controla esa condición varíe debe
llamarse a notify() o notifyAll()

Muerto
Un thread se puede morir de dos formas: por causas naturales o porque lo maten (con stop()). Un thread muere
normalmente cuando concluye de forma habitual su método run(). Por ejemplo, en el siguiente trozo de código, el
bucle while es un bucle finito -realiza la iteración 20 veces y termina-:

public void run() {


int i=0;
while( i < 20 )
{
i++;
[Link]( "i = "+i );
}
}

Un thread que contenga a este método run(), morirá naturalmente después de que se complete el bucle y run()
concluya.

También se puede matar en cualquier momento un thread, invocando a su método stop(). En el trozo de código
siguiente:

Thread MiThread = new MiClaseThread();


[Link]();
try {
[Link]( 10000 );
} catch( InterruptedException e ) {
;
}
[Link]();

se crea y arranca el thread MiThread, lo dormimos durante 10 segundos y en el momento de despertarse, la llamada
a su método stop(), lo mata.

El método stop() envía un objeto ThreadDeath al thread que quiere detener. Así, cuando un thread es parado de este
modo, muere asíncronamente. El thread morirá en el momento en que reciba la excepción ThreadDeath.

Los applets utilizarán el método stop() para matar a todos sus threads cuando el navegador con soporte Java en el que
se están ejecutando le indica al applet que se detengan, por ejemplo, cuando se minimiza la ventana del navegador o
cuando se cambia de página.

El método isAlive()

La interface de programación de la clase Thread incluye el método isAlive(), que devuelve true si el thread ha sido
arrancado (con start()) y no ha sido detenido (con stop()). Por ello, si el método isAlive() devuelve false, sabemos que
estamos ante un "Nuevo Thread" o ante un thread "Muerto". Si nos devuelve true, sabemos que el thread se
encuentra en estado "Ejecutable" o "Parado". No se puede diferenciar entre "Nuevo Thread" y "Muerto", ni entre un
thread "Ejecutable" o "Parado".

Tutorial de Java [Anterior] [Indice] [Siguiente]


SCHEDULING
Java tiene un Scheduler, una lista de procesos, que monitoriza todos los threads que se están ejecutando en todos los
programas y decide cuales deben ejecutarse y cuales deben encontrarse preparados para su ejecución. Hay dos
características de los threads que el scheduler identifica en este proceso de decisión. Una, la más importante, es la
prioridad del thread; la otra, es el indicador de demonio. La regla básica del scheduler es que si solamente hay
threads demonio ejecutándose, la Máquina Virtual Java (JVM) concluirá. Los nuevos threads heredan la prioridad y
el indicador de demonio de los threads que los han creado. El scheduler determina qué threads deberán ejecutarse
comprobando la prioridad de todos los threads, aquellos con prioridad más alta dispondrán del procesador antes de
los que tienen prioridad más baja.

El scheduler puede seguir dos patrones, preemptivo y no-preemptivo. Los schedulers preemtivos proporcionan un
segmento de tiempo a todos los threads que están corriendo en el sistema. El scheduler decide cual será el siguiente
thread a ejecutarse y llama a resume() para darle vida durante un período fijo de tiempo. Cuando el thread ha estado
en ejecución ese período de tiempo, se llama a suspend() y el siguiente thread en la lista de procesos será relanzado
(resume()). Los schedulers no-preemtivos deciden que thread debe correr y lo ejecutan hasta que concluye. El thread
tiene control total sobre el sistema mientras esté en ejecución. El método yield() es la forma en que un thread fuerza
al scheduler a comenzar la ejecución de otro thread que esté esperando. Dependiendo del sistema en que esté
corriendo Java, el scheduler será preemtivo o no-preemptivo.

En el siguiente ejemplo, [Link], mostramos la ejecución de dos threads con diferentes prioridades. Un
thread se ejecuta a prioridad más baja que el otro. Los threads incrementarán sus contadores hasta que el thread que
tiene prioridad más alta alcance al contador que corresponde a la tarea con ejecución más lenta.

Tutorial de Java [Anterior] [Indice] [Siguiente]


PRIORIDADES, DEMONIOS...
Prioridades

El scheduler determina el thread que debe ejecutarse en función de la prioridad asignada a cada uno de ellos. El rango
de prioridades oscila entre 1 y 10. La prioridad por defecto de un thread es Thread.NORM_PRIORITY, que tiene
asignado un valor de 5. Hay otras dos variables estáticas disponibles, que son Thread.MIN_PRORITY, fijada a 1, y
Thread.MAX_PRIORITY, aque tiene un valor de 10. El método getPriority() puede utilizarse para conocer el valor
actual de la prioridad de un thread.

Threads Demonio

Los threads demonio también se llaman servicios, porque se ejecutan, normalmente, con prioridad baja y
proporcionan un servicio básico a un programa o programas cuando la actividad de la máquina es reducida. Un
ejemplo de thread demonio que está ejecutándose continuamente es el recolector de basura (garbage collector). Este
thread, proporcionado por la Máquina Virtual Java, comprueba las variables de los programas a las que no se accede
nunca y libera estos recursos, devolviéndolos al sistema. Un thread puede fijar su indicador de demonio pasando un
valor true al método setDaemon(). Si se pasa false a este método, el thread será devuelto por el sistema como un
thread de usuario. No obstante, esto último debe realizarse antes de que se arranque el thread (start()).

Diferencia de threads con fork()

fork() en Unix crea un proceso hijo que tiene su propia copia de datos y código del padre. Esto funciona
correctamente si estamos sobrados de memoria y disponemos de una CPU poderosa, y siempre que mantengamos el
número de procesos hijos dentro de un límite manejable, porque se hace un uso intensivo de los recursos del sistema.
Los applets Java no pueden lanzar ningún proceso en el cliente, porque eso sería una fuente de inseguridad y no está
permitido. Las aplicaciones y los applets deben utilizar threads.

La multi-tarea pre-emptiva tiene sus problemas. Un thread puede interrumpir a otro en cualquier momento, de ahí lo
de pre-emptive. Imaginarse lo que pasaría si un thread está escribiendo en un array, mientras otro thread lo
interrumpe y comienza a escribir en el mismo array. Los lenguajes como C y C++ necesitan de las funciones lock() y
unlock() para antes y después de leer o escribir datos. Java también funciona de este modo, pero oculta el bloqueo de
datos bajo la sentencia synchronized:

synchronized int MiMetodo();

Otro área en que los threads son muy útiles es en los interfaces de usuario. Permiten incrementar la respuesta del
ordenador ante el usuario cuando se encuentra realizando complicados cálculos y no puede atender a la entrada de
usuario. Estos cálculos se pueden realizar en segundo plano, o realizar varios en primer plano (música y animaciones)
sin que se dé apariencia de pérdida de rendimiento.
Tutorial de Java [Anterior] [Indice] [Siguiente]
EJEMPLO DE ANIMACION

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Este es un ejemplo de un applet, [Link], que crea un thread de animación que nos presenta el globo
terráqueo en rotación. Aquí podemos ver que estamos creando un thread de sí mismo, concurrencia. Además,
[Link]() llama al start() del thread, no del applet, que automáticamente llamará a run():

import [Link].*;
import [Link];

public class Animacion extends Applet implements Runnable {


Image imagenes[];
MediaTracker tracker;
int indice = 0;
Thread animacion;

int maxAncho,maxAlto;
Image offScrImage; // Componente off-screen para doble buffering
Graphics offScrGC;

// Nos indicará si ya se puede pintar


boolean cargado = false;

// Inicializamos el applet, establecemos su tamaño y


// cargamos las imágenes
public void init() {
// Establecemos el supervisor de imágenes
tracker = new MediaTracker( this );
// Fijamos el tamaño del applet
maxAncho = 100;
maxAlto = 100;
imagenes = new Image[36];

// Establecemos el doble buffer y dimensionamos el applet


try {
offScrImage = createImage( maxAncho,maxAlto );
offScrGC = [Link]();
[Link]( [Link] );
[Link]( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
} catch( Exception e ) {
[Link]();
}

// Cargamos las imágenes en un array


for( int i=0; i < 36; i++ )
{
String fichero =
new String( "Tierra"+[Link](i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),fichero );
// Registramos las imágenes con el tracker
[Link]( imagenes[i],i );
}

try {
// Utilizamos el tracker para comprobar que todas las
// imágenes están cargadas
[Link]();
} catch( InterruptedException e ) {
;
}
cargado = true;
}

// Pintamos el fotograma que corresponda


public void paint( Graphics g ) {
if( cargado )
[Link]( offScrImage,0,0,this );
}

// Arrancamos y establecemos la primera imagen


public void start() {
if( [Link]( indice ) )
[Link]( imagenes[indice],0,0,this );
animacion = new Thread( this );
[Link]();
}

// Aquí hacemos el trabajo de animación


// Muestra una imagen, para, muestra la siguiente...
public void run() {
// Obtiene el identificador del thread
Thread thActual = [Link]();

// Nos aseguramos de que se ejecuta cuando estamos en un


// thread y además es el actual
while( animacion != null && animacion == thActual )
{
if( [Link]( indice ) )
{
// Obtenemos la siguiente imagen
[Link]( imagenes[indice],0,0,this );
indice++;
// Volvemos al principio y seguimos, para el bucle
if( indice >= [Link] )
indice = 0;
}

// Ralentizamos la animación para que parezca normal


try {
[Link]( 200 );
} catch( InterruptedException e ) {
;
}
// Pintamos el siguiente fotograma
repaint();
}
}
}

En el ejemplo podemos observar más cosas. La variable thActual es propia de cada thread que se lance, y la
variable animacion la estarán viendo todos los threads. No hay duplicidad de procesos, sino que todos comparten
las mismas variables; cada thread, sin embargo, tiene su pila local de variables, que no comparte con nadie y que son
las que están declaradas dentro de las llaves del método run().

La excepción InterruptedExcepcion salta en el caso en que se haya tenido al thread parado más tiempo del debido. Es
imprescindible recoger esta excepción cuando se están implementando threads, tanto es así, que en el caso de no
recogerla, el compilador generará un error.

Tutorial de Java [Anterior] [Indice] [Siguiente]


COMUNICACION ENTRE THREADS
Otra clave para el éxito y la ventaja de la utilización de múltiples threads en una aplicación, o aplicación
multithreaded, es que pueden comunicarse entre sí. Se pueden diseñar threads para utilizar objetos comunes, que cada
thread puede manipular independientemente de los otros threads.

El ejemplo clásico de comunicación de threads es un modelo productor/consumidor. Un thread produce una salida,
que otro thread usa (consume), sea lo que sea esa salida. Vamos entonces a crear un productor, que será un thread
que irá sacando caracteres por su salida; crearemos también un consumidor que ira recogiendo los caracteres que
vaya sacando el productor y un monitor que controlará el proceso de sincronización entre los threads. Funcionará
como una tubería, insertando el productor caracteres en un extremos y leyéndolos el consumidor en el otro, con el
monitor siendo la propia tubería.

Productor

El productor extenderá la clase Thread, y su código es el siguiente:

class Productor extends Thread {


private Tuberia tuberia;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

public Productor( Tuberia t ) {


// Mantiene una copia propia del objeto compartido
tuberia = t;
}

public void run() {


char c;

// Mete 10 letras en la tubería


for( int i=0; i < 10; i++ )
{
c = [Link]( (int)([Link]()*26 ) );
[Link]( c );
// Imprime un registro con lo añadido
[Link]( "Lanzado "+c+" a la tuberia." );
// Espera un poco antes de añadir más letras
try {
sleep( (int)([Link]() * 100 ) );
} catch( InterruptedException e ) {
;
}
}
}
}

Notar que creamos una instancia de la clase Tuberia, y que se utiliza el método [Link]() para que se vaya
construyendo la tubería, en principio de 10 caracteres.

Consumidor

Veamos ahora el código del consumidor, que también extenderá la clase Thread:

class Consumidor extends Thread {


private Tuberia tuberia;

public Consumidor( Tuberia t ) {


// Mantiene una copia propia del objeto compartido
tuberia = t;
}

public void run() {


char c;

// Consume 10 letras de la tubería


for( int i=0; i < 10; i++ )
{
c = [Link]();
// Imprime las letras retiradas
[Link]( "Recogido el caracter "+c );
// Espera un poco antes de coger más letras
try {
sleep( (int)([Link]() * 2000 ) );
} catch( InterruptedException e ) {
;
}
}
}
}

En este caso, como en el del productor, contamos con un método en la clase Tuberia, [Link](), para
manejar la información.

Monitor

Una vez vistos el productor de la información y el consumidor, nos queda por ver qué es lo que hace la clase
Tuberia.

Lo que realiza la clase Tuberia, es una función de supervisión de las transacciones entre los dos threads, el productor
y el consumidor. Los monitores, en general, son piezas muy importantes de las aplicaciones multithreaded, porque
mantienen el flujo de comunicación entre los threads.

class Tuberia {
private char buffer[] = new char[6];
private int siguiente = 0;
// Flags para saber el estado del buffer
private boolean estaLlena = false;
private boolean estaVacia = true;

// Método para retirar letras del buffer


public synchronized char recoger() {
// No se puede consumir si el buffer está vacío
while( estaVacia == true )
{
try {
wait(); // Se sale cuando estaVacia cambia a false
} catch( InterruptedException e ) {
;
}
}
// Decrementa la cuenta, ya que va a consumir una letra
siguiente--;
// Comprueba si se retiró la última letra
if( siguiente == 0 )
estaVacia = true;
// El buffer no puede estar lleno, porque acabamos de consumir
estaLlena = false;
notify();

// Devuelve la letra al thread consumidor


return( buffer[siguiente] );
}

// Método para añadir letras al buffer


public synchronized void lanzar( char c ) {
// Espera hasta que haya sitio para otra letra
while( estaLlena == true )
{
try {
wait(); // Se sale cuando estaLlena cambia a false
} catch( InterruptedException e ) {
;
}
}
// Añade una letra en el primer lugar disponible
buffer[siguiente] = c;
// Cambia al siguiente lugar disponible
siguiente++;
// Comprueba si el buffer está lleno
if( siguiente == 6 )
estaLlena = true;
estaVacia = false;
notify();
}
}

En la clase Tuberia vemos dos características importantes: los miembros dato (buffer[]) son privados, y los
métodos de acceso (lanzar() y recoger()) son sincronizados.

Aquí vemos que la variable estaVacia es un semáforo, como los de toda la vida. La naturaleza privada de los
datos evita que el productor y el consumidor accedan directamente a éstos. Si se permitiese el acceso directo de
ambos threads a los datos, se podrían producir problemas; por ejemplo, si el consumidor intenta retirar datos de un
buffer vacío, obtendrá excepciones innecesarias, o se bloqueará el proceso.

Los métodos sincronizados de acceso impiden que los productores y consumidores corrompan un objeto compartido.
Mientras el productor está añadiendo una letra a la tubería, el consumidor no la puede retirar y viceversa. Esta
sincronización es vital para mantener la integridad de cualquier objeto compartido. No sería lo mismo sincronizar la
clase en vez de los métodos, porque esto significaría que nadie puede acceder a las variables de la clase en paralelo,
mientras que al sincronizar los métodos, sí pueden acceder a todas las variables que están fuera de los métodos que
pertenecen a la clase.

Se pueden sincronizar incluso variables, para realizar alguna acción determinada sobre ellas, por ejemplo:

sincronized( p ) {
// aquí se colocaría el código
// los threads que estén intentando acceder a p se pararán
// y generarán una InterruptedException
}

El método notify() al final de cada método de acceso avisa a cualquier proceso que esté esperando por el objeto,
entonces el proceso que ha estado esperando intentará acceder de nuevo al objeto. En el método wait() hacemos que
el thread se quede a la espera de que le llegue un notify(), ya sea enviado por el thread o por el sistema.

Ahora que ya tenemos un productor, un consumidor y un objeto compartido, necesitamos una aplicación que
arranque los threads y que consiga que todos hablen con el mismo objeto que están compartiendo. Esto es lo que hace
el siguiente trozo de código, del fuente [Link]:

class TubTest {
public static void main( String args[] ) {
Tuberia t = new Tuberia();
Productor p = new Productor( t );
Consumidor c = new Consumidor( t );

[Link]();
[Link]();
}
}

Compilando y ejecutando esta aplicación, podremos observar nuestro modelo el pleno funcionamiento.

Monitorización del Productor


Los programas productor/consumidor a menudo emplean monitorización remota, que permite al consumidor observar
el thread del productor interaccionando con un usuario o con otra parte del sistema. Por ejemplo, en una red, un
grupo de threads productores podrían trabajar cada uno en una workstation. Los productores imprimirían
documentos, almacenando una entrada en un registro (log). Un consumidor (o múltiples consumidores) podría
procesar el registro y realizar durante la noche un informe de la actividad de impresión del día anterior.

Otro ejemplo, a pequeña escala podría ser el uso de varias ventanas en una workstation. Una ventana se puede usar
para la entrada de información (el productor), y otra ventana reaccionaría a esa información (el consumidor).

Peer, es un observador general del sistema.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 09-Sep-1996 05:32:54
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class Productor extends Thread {


private Tuberia tuberia;
private String alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

public Productor( Tuberia t ) {


// Mantiene una copia propia del objeto compartido
tuberia = t;
}

public void run() {


char c;

// Mete 10 letras en la tubería


for( int i=0; i < 10; i++ )
{
c = [Link]( (int)([Link]()*26 ) );
[Link]( c );
// Imprime un registro con lo añadido
[Link]( "Lanzado "+c+" a la tuberia." );
// Espera un poco antes de añadir más letras
try {
sleep( (int)([Link]() * 100 ) );
} catch( InterruptedException e ) {
;
}
}
}
}

class Consumidor extends Thread {


private Tuberia tuberia;

public Consumidor( Tuberia t ) {


// Mantiene una copia propia del objeto compartido
tuberia = t;
}

public void run() {


char c;

// Consume 10 letras de la tubería


for( int i=0; i < 10; i++ )
{
c = [Link]();
// Imprime las letras retiradas
[Link]( "Recogido el caracter "+c );
// Espera un poco antes de coger más letras
try {
sleep( (int)([Link]() * 2000 ) );
} catch( InterruptedException e ) {
;
}
}
}
}

class Tuberia {
private char buffer[] = new char[6];
private int siguiente = 0;
// Flags para saber el estado del buffer
private boolean estaLlena = false;
private boolean estaVacia = true;

// Método para retirar letras del buffer


public synchronized char recoger() {
// No se puede consumir si el buffer está vacío
while( estaVacia == true )
{
try {
wait(); // Se sale cuando estaVacia cambia a false
} catch( InterruptedException e ) {
;
}
}
// Decrementa la cuenta, ya que va a consumir una letra
siguiente--;
// Comprueba si se retiró la última letra
if( siguiente == 0 )
estaVacia = true;
// El buffer no puede estar lleno, porque acabamos de consumir
estaLlena = false;
notify();

// Devuelve la letra al thread consumidor


return( buffer[siguiente] );
}

// Método para añadir letras al buffer


public synchronized void lanzar( char c ) {
// Espera hasta que haya sitio para otra letra
while( estaLlena == true )
{
try {
wait(); // Se sale cuando estaLlena cambia a false
} catch( InterruptedException e ) {
;
}
}
// Añade una letra en el primer lugar disponible
buffer[siguiente] = c;
// Cambia al siguiente lugar disponible
siguiente++;
// Comprueba si el buffer está lleno
if( siguiente == 6 )
estaLlena = true;
estaVacia = false;
notify();
}
}
class TubTest extends [Link]{
public static void main( String args[] ) {
Tuberia t = new Tuberia();
Productor p = new Productor( t );
Consumidor c = new Consumidor( t );

[Link]();
[Link]();
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 18-Sep-1996 05:51:27
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

// Definimos unos sencillos threads. Se detendrán un rato


// antes de imprimir sus nombres y retardos
//
class TestTh extends Thread {
private String nombre;
private int retardo;

// Constructor para almacenar nuestro nombre


// y el retardo
public TestTh( String s,int d ) {
nombre = s;
retardo = d;
}

// El metodo run() es similar al main(), pero para


// threads. Cuando run() termina el thread muere
public void run() {
// Retasamos la ejecución el tiempo especificado
try {
sleep( retardo );
} catch( InterruptedException e ) {
;
}

// Ahora imprimimos el nombre


[Link]( "Hola Mundo! "+nombre+" "+retardo );
}
}

public class MultiHola {


public static void main( String args[] ) {
TestTh t1,t2,t3;

// Creamos los threads


t1 = new TestTh( "Thread 1",(int)([Link]()*2000) );
t2 = new TestTh( "Thread 2",(int)([Link]()*2000) );
t3 = new TestTh( "Thread 3",(int)([Link]()*2000) );

// Arrancamos los threads


[Link]();
[Link]();
[Link]();
}
}
//----------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 04-Jun-1996 06:26:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import [Link];
import [Link];

// Es un applet muy simple para demostrar el multithreading


// Crea círculos, corriendo cada uno en su propio thread
// que se irá agrandando y disminuyendo más o menos
// rápidamente
public class Figuras extends Applet {
public int Ancho = 400;
public int Alto = 100;
public int Numero = 15;
public final int minTam = 10;
public final int maxTam = 50;
public final int minNaptime = 1;
public final int maxNaptime = 500;

public final Color colores[] = {


[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link]
};

public final Color bg = [Link];


boolean thSuspendida = false;
Image im;
Graphics offscreen;
Random rand;
Circulo circulos[] = new Circulo[Numero];

public void init() {


resize( Ancho,Alto );
rand = new Random( (long)[Link]() );
try {
im = createImage( Ancho,Alto );
offscreen = [Link]();
} catch( Exception e ) {
offscreen = null;
}
}

// Creamos cada figura con algunos parámetros aleatorios y


// arrancamos su thread
public void start() {
for( int i=0; i < Numero; i++ )
{
if( circulos[i] == null )
{
circulos[i] = new Circulo( this,
(int)( (double)Ancho * [Link]() ),
(int)((double)Alto * [Link]() ),
minTam +
(int)( (double)(maxTam-minTam) * [Link]() ),
minNaptime +
(int)( (double)(maxNaptime-minNaptime) * [Link]() ),
colores[(int)( (double)[Link] * [Link]() )],
bg );
circulos[i].start();
}
}
repaint();
}

// Cuando detengamos el applet, paramos todos los threads


public void stop() {
for( int i=0; i < Numero; i++ )
circulos[i].stop();
}

// Sobrecargamos el metodo update para reducir el flasheo


public void update( Graphics g ) {
paint( g );
}

// Utilizamos también el doble-buffer para reducir el flasheo


// de la imagen en la pantalla
public void paint( Graphics g ) {
if( offscreen != null )
{
paintApplet( offscreen );
[Link]( im,0,0,this );
}
else
paintApplet( g );
}

// Llamamos al metodo paint de cada una de las figuras


public void paintApplet( Graphics g ) {
[Link]( bg );
[Link]( 0,0,Ancho,Alto );
for( int i=0; i < Numero; i++ )
circulos[i].paint( g );
}

// Respondiendo al ratón, suspendemos o resumimos el


// thread de cada una de la figuras
public boolean mouseDown( Event evt,int x,int y ) {
if( thSuspendida )
{
for( int i=0; i < Numero; i++ )
circulos[i].[Link]();
}
else
{
for( int i=0; i < Numero; i++ )
circulos[i].[Link]();
}
thSuspendida = !thSuspendida;

return( true );
}
}

// Implementamos un círculo. Cada figura llamará a su metodo


// paint asíncronamente cuando le llegue el momento de
// aumentar o disminuir su dimensión
class Circulo implements Runnable {
static int threadNum = 1;
private Color color = null;
private Color bg = [Link];
private int naptime = 500;
private int tamano = 50;
private int factorCrecer = 1;
private int ox = 0; /* posición dentro del frame */
private int oy = 0;
private Graphics graphics;
private int actual;
private int anterior;
private boolean creciendo = false;
public Thread thread = null;
Figuras applet;

public Circulo( Figuras applet,int x,int y,int s,int n,


Color c,Color bg ) {
[Link] = applet;
ox = x;
oy = y;
tamano = s;
naptime = n;
color = c;
if( color == null )
color = [Link];
actual = anterior = s;
}

public void run() {


[Link]( Thread.MIN_PRIORITY+1 );
while( thread != null )
{
anterior = actual;
if( creciendo )
actual += factorCrecer;
else
actual -= factorCrecer;

if( actual == tamano || actual == 0 )


creciendo = !creciendo;

try {
[Link]( naptime );
} catch( InterruptedException e )
{
;
}
[Link]();
}
thread = null;
}

public void start() {


if( thread == null )
{
thread = new Thread( this,[Link]( threadNum++ ) );
[Link]();
}
}

public void stop() {


thread = null;
}

// Borramos la antigua posición y pintamos la nueva


public void paint( Graphics g ) {
int antMedio = (int)( anterior/2 );
int actMedio = (int)( actual/2 );

[Link]( bg );
[Link]( ox-antMedio,oy-antMedio,anterior,anterior );

[Link]( color);
[Link]( ox-actMedio,oy-actMedio,actual,actual );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 14-Sep-1996 16:15:56
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class App1Thread extends Applet implements Runnable {


Thread t;
int contador;

// Creamos el thread y lo arrancamos


public void init() {
contador = 0;
t = new Thread( this );
[Link]();
}

// Corazón del applet, incrementa el contador, lo pinta en la


// pantalla y tiene su tiempo de espera, tanto para incrementar
// de nuevo el contador como para dejar tiempo a la CPU para que
// atienda a otros applets o aplicacionesque pudiesen convivir
public void run() {
while( true )
{
contador++;
repaint();
// Forzosamente tenemos que capturar este interrupción
try {
[Link]( 10 );
} catch( InterruptedException e ) {
;
};
}
}

// Detenemos el proceso cuando se pulsa el ratón dentro del


// dominio del applet
public boolean mouseDown( Event evt,int x,int y ) {
[Link]();
return( true );
}

// Actualizamos un contador en la ventana del applet y otro en


// la consola
public void paint( Graphics g ) {
[Link]( [Link]( contador ),10,10 );
[Link]( "Contador= "+contador );
}

// Paramos el applet
public void stop() {
[Link]();
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 14-Sep-1996 16:25:15
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class App2Thread extends Applet implements Runnable {


Thread t;
int contador;
boolean suspendido;

// Creamos el applet y lo arrancamos


public void init() {
contador = 0;
suspendido = false;
t = new Thread( this );
[Link]();
}

// Corazón del applet, incrementa el contador, lo pinta en la


// pantalla y tiene su tiempo de espera, tanto para incrementar
// de nuevo el contador como para dejar tiempo a la CPU para que
// atienda a otros applets o aplicacionesque pudiesen convivir
public void run() {
while( true )
{
contador++;
repaint();
try {
[Link]( 10 );
} catch( InterruptedException e ) {
;
};
}
}

// En este caso, cuando pulsamos el ratón si el thread estaba


// suspendido, recuperamos su ejecución, y si estaba corriendo
// lo suspendemos.
// El estado se controla a través de una variable booleana
public boolean mouseDown( Event evt,int x,int y ) {
if( suspendido )
[Link]();
else
[Link]();
suspendido = !suspendido;
return( true );
}

// Actualizamos un contador en la ventana del applet y otro en


// la consola
public void paint( Graphics g ) {
[Link]( [Link]( contador ),10,10 );
[Link]( "Contador= "+contador );
}

// Paramos el applet
public void stop() {
[Link]();
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 14-Sep-1996 18:34:35
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// En este applet se crean dos threads que incrementan un contador, se


// proporcionan distintas prioridades a cada uno y se para cuando los
// dos coinciden
//
public class SchThread extends Applet {
Contar alto,bajo;

public void init() {


// Creamos un thread en 200, ya adelantado
bajo = new Contar( 200 );
// El otro comienza desde cero
alto = new Contar( 0 );
// Al que comienza en 200 le asignamos prioridad mínima
[Link]( Thread.MIN_PRIORITY );
// Y al otro máxima
[Link]( Thread.MAX_PRIORITY );
[Link]( "Prioridad alta es "+[Link]() );
[Link]( "Prioridad baja es "+[Link]() );
}

// Arrancamos los dos threads, y vamos repintando hasta que el thread


// que tiene prioridad más alta alcanza o supera al que tiene prioridad
// más baja, pero empezó a contar más alto
public void start() {
[Link]();
[Link]();
while( [Link]() < [Link]() )
repaint();
repaint();
[Link]();
[Link]();
}

// Vamos pintando los incrementos que realizan ambos threads


public void paint( Graphics g ) {
[Link]( "bajo = "+[Link]()+
" alto = "+[Link](),10,10 );
[Link]( "bajo = "+[Link]()+
" alto = "+[Link]() );
}
// Para parar la ejecución de los threads
public void stop() {
[Link]();
[Link]();
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Sep-1996 04:10:25
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Animacion extends Applet implements Runnable {


Image imagenes[];
MediaTracker tracker;
int indice = 0;
Thread animacion;

int maxAncho,maxAlto;
Image offScrImage; // Componente off-screen para doble buffering
Graphics offScrGC;

// Nos indicará si ya se puede pintar


boolean cargado = false;

// Inicializamos el applet, establecemos su tamaño y


// cargamos las imágenes
public void init() {
// Establecemos el supervisor de imágenes
tracker = new MediaTracker( this );
// Fijamos el tamaño del applet
maxAncho = 100;
maxAlto = 100;
imagenes = new Image[18];

// Establecemos el doble buffer y dimensionamos el applet


try {
offScrImage = createImage( maxAncho,maxAlto );
offScrGC = [Link]();
[Link]( [Link] );
[Link]( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
} catch( Exception e ) {
[Link]();
}

// Cargamos las imágenes en un array


for( int i=0; i < 18; i++ )
{
String fichero =
new String( "Tierra"+[Link](i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),fichero );
// Registramos las imágenes con el tracker
[Link]( imagenes[i],i );
showStatus( "Cargando Imagen: "+fichero );
}
showStatus( "" );

try {
// Utilizamos el tracker para comprobar que todas las
// imágenes están cargadas
[Link]();
} catch( InterruptedException e ) {
;
}
cargado = true;
}

// Pintamos el fotograma que corresponda


public void paint( Graphics g ) {
if( cargado )
[Link]( offScrImage,0,0,this );
}

// Arrancamos y establecemos la primera imagen


public void start() {
if( [Link]( indice ) )
[Link]( imagenes[indice],0,0,this );
animacion = new Thread( this );
[Link]();
}

// Aquí hacemos el trabajo de animación


// Muestra una imagen, para, muestra la siguiente...
public void run() {
// Obtiene el identificador del thread
Thread thActual = [Link]();

// Nos aseguramos de que se ejecuta cuando estamos en un thread


// y además es el actual
while( animacion != null && animacion == thActual )
{
if( [Link]( indice ) )
{
// Obtenemos la siguiente imagen
[Link]( imagenes[indice],0,0,this );
indice++;
// Volvemos al principio y seguimos, para el bucle
if( indice >= [Link] )
indice = 0;
}

// Ralentizamos la animación para que parezca normal


try {
[Link]( 200 );
} catch( InterruptedException e ) {
;
}
// Pintamos el siguiente fotograma
repaint();
}
}
}

//----------------------------------------- Final del fichero [Link]


MANEJO DE EXCEPCIONES
Vamos a mostrar como se utilizan las excepciones, reconvirtiendo nuestro applet de saludo a partir de la versión
iterativa de [Link]:

import [Link].*;
import [Link];

public class HolaIte extends Applet {


private int i = 0;
private String Saludos[] = {
"Hola Mundo!",
"HOLA Mundo!",
"HOLA MUNDO!!"
};

public void paint( Graphics g ) {


[Link]( Saludos[i],25,25 );
i++;
}
}

Normalmente, un programa termina con un mensaje de error cuando se lanza una excepción. Sin embargo, Java tiene
mecanismos para excepciones que permiten ver qué excepción se ha producido e intentar recuperarse de ella.

Vamos a reescribir el método paint() de nuestra versión iterativa del saludo:

public void paint( Graphics g ) {


try {
[Link]( Saludos[i],25,25 );
} catch( ArrayIndexOutOfBoundsException e ) {
[Link]( "Saludos desbordado",25,25 );
} catch( Exception e ) {
// Cualquier otra excepción
[Link]( [Link]() );
} finally {
[Link]( "Esto se imprime siempre!" );
}
i++;
}

La palabra clave finally define un bloque de código que se quiere que sea ejecutado siempre, de acuerdo a si se
capturó la excepción o no. En el ejemplo anterior, la salida en la consola, con i=4 sería:
Saludos desbordado
¡Esto se imprime siempre!

Tutorial de Java [Anterior] [Indice] [Siguiente]


GENERAR EXCEPCIONES EN JAVA
Cuando se produce un error se debería generar, o lanzar, una excepción. Para que un método en Java, pueda lanzar
excepciones, hay que indicarlo expresamente.

void MetodoAsesino() throws NullPointerException,CaidaException

Se pueden definir excepciones propias, no hay por qué limitarse a las predefinidas; bastará con extender la clase
Exception y proporcionar la funcionalidad extra que requiera el tratamiento de esa excepción.

También pueden producirse excepciones no de forma explícita como en el caso anterior, sino de forma implícita
cuando se realiza alguna acción ilegal o no válida.

Las excepciones, pues, pueden originarse de dos modos: el programa hace algo ilegal (caso normal), o el programa
explícitamente genera una excepción ejecutando la sentencia throw (caso menos normal). La sentencia throw tiene la
siguiente forma:

throw ObtejoExcepction;

El objeto ObjetoException es un objeto de una clase que extiende la clase Exception.

El siguiente código de ejemplo origina una excepción de división por cero:

class melon {
public static void main( String[] a ) {
int i=0, j=0, k;

k = i/j; // Origina un error de division-by-zero


}
}

Si compilamos y ejecutamos esta aplicación Java, obtendremos la siguiente salida por pantalla:

> javac [Link]


> java melon
[Link]: / by zero
at [Link]([Link])

Las excepciones predefinidas, como ArithmeticException, se conocen como excepciones runtime. Actualmente,
como todas las excepciones son eventos runtime, sería mejor llamarlas excepciones irrecuperables. Esto contrasta
con las excepciones que generamos explícitamente, que suelen ser mucho menos severas y en la mayoría de los casos
podemos recuperarnos de ellas. Por ejemplo, si un fichero no puede abrirse, preguntamos al usuario que nos indique
otro fichero; o si una estructura de datos se encuentra completa, podremos sobreescribir algún elemento que ya no se
necesite.

Tutorial de Java [Anterior] [Indice] [Siguiente]


EXCEPCIONES PREDEFINIDAS
Las excepciones predefinidas y su jerarquía de clases es la que se muestra en la figura:
Los nombres de las excepciones indican la condición de error que representan. Las siguientes son las excepciones
predefinidas más frecuentes que se pueden encontrar:

ArithmeticException

Las excepciones aritméticas son típicamente el resultado de una división por 0:

int i = 12 / 0;

NullPointerException

Se produce cuando se intenta acceder a una variable o método antes de ser definido:

class Hola extends Applet {


Image img;

paint( Graphics g ) {
[Link]( img,25,25,this );
}
}

IncompatibleClassChangeException

El intento de cambiar una clase afectada por referencias en otros objetos, específicamente cuando esos
objetos todavía no han sido recompilados.

ClassCastException

El intento de convertir un objeto a otra clase que no es válida.

y = (Prueba)x; // donde
x no es de tipo Prueba

NegativeArraySizeException

Puede ocurrir si hay un error aritmético al intentar cambiar el tamaño de un array.

OutOfMemoryException

¡No debería producirse nunca! El intento de crear un objeto con el operador new ha fallado por falta de
memoria. Y siempre tendría que haber memoria suficiente porque el garbage collector se encarga de
proporcionarla al ir liberando objetos que no se usan y devolviendo memoria al sistema.

NoClassDefFoundException

Se referenció una clase que el sistema es incapaz de encontrar.

ArrayIndexOutOfBoundsException
Es la excepción que más frecuentemente se produce. Se genera al intentar acceder a un elemento de un
array más allá de los límites definidos inicialmente para ese array.

UnsatisfiedLinkException

Se hizo el intento de acceder a un método nativo que no existe. Aquí no existe un método [Link]

class A {
native void kk();
}

y se llama a [Link](), cuando debería llamar a [Link]().

InternalException

Este error se reserva para eventos que no deberían ocurrir. Por definición, el usuario nunca debería ver
este error y esta excepción no debería lanzarse.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR EXCEPCIONES PROPIAS
También podemos lanzar nuestras propias excepciones, extendiendo la clase [Link]. Por ejemplo,
consideremos un programa cliente/servidor. El código cliente se intenta conectar al servidor, y durante 5 segundos se
espera a que conteste el servidor. Si el servidor no responde, el servidor lanzaría la excepción de time-out:

class ServerTimeOutException extends Exception {}

public void conectame( String nombreServidor ) throws Exception {


int exito;
int puerto = 80;

exito = open( nombreServidor,puerto );


if( exito == -1 )
throw ServerTimeOutException;
}

Si se quieren capturar las propias excepciones, se deberá utilizar la sentencia try:

public void encuentraServidor() {


...
try {
conectame( servidorDefecto );
catch( ServerTimeOutException e ) {
[Link](
"Time-out del Servidor, intentando alternativa",
5,5 );
conectame( servidorAlterno );
}
...
}

Cualquier método que lance una excepción también debe capturarla, o declararla como parte de la interface del
método. Cabe preguntarse entonces, el porqué de lanzar una excepción si hay que capturarla en el mismo método. La
respuesta es que las excepciones no simplifican el trabajo del control de errores. Tienen la ventaja de que se puede
tener muy localizado el control de errores y no tenemos que controlar millones de valores de retorno, pero no van
más allá.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CAPTURAR EXCEPCIONES
Las excepciones lanzadas por un método que pueda hacerlo deben recoger en bloque try/catch o try/finally.

int valor;
try {
for( x=0,valor = 100; x < 100; x ++ )
valor /= x;
}
catch( ArithmeticException e ) {
[Link]( "Matemáticas locas!" );
}
catch( Exception e ) {
[Link]( "Se ha producido un error" );
}

try

Es el bloque de código donde se prevé que se genere una excepción. Es como si dijésemos "intenta estas sentencias y
mira a ver si se produce una excepción". El bloque try tiene que ir seguido, al menos, por una cláusula catch o una
cláusula finally

catch

Es el código que se ejecuta cuando se produce la excepción. Es como si dijésemos "controlo cualquier excepción que
coincida con mi argumento". En este bloque tendremos que asegurarnos de colocar código que no genere
excepciones. Se pueden colocar sentencias catch sucesivas, cada una controlando una excepción diferente. No
debería intentarse capturar todas las excepciones con una sola cláusula, como esta:

catch( Excepcion e ) { ...

Esto representaría un uso demasiado general, podrían llegar muchas más excepciones de las esperadas. En este caso
es mejor dejar que la excepción se propague hacia arriba y dar un mensaje de error al usuario.

Se pueden controlar grupos de excepciones, es decir, que se pueden controlar, a través del argumento, excepciones
semejantes. Por ejemplo:

class Limites extends Exception {}


class demasiadoCalor extends Limites {}
class demasiadoFrio extends Limites {}
class demasiadoRapido extends Limites {}
class demasiadoCansado extends Limites {}
.
.
.
try {
if( temp > 40 )
throw( new demasiadoCalor() );
if( dormir < 8 )
throw( new demasiado Cansado() );
} catch( Limites lim ) {
if( lim instanceof demasiadoCalor )
{
[Link]( "Capturada excesivo calor!" );
return;
}
if( lim instanceof demasiadoCansado )
{
[Link]( "Capturada excesivo cansancio!" );
return;
}
} finally
[Link]( "En la clausula finally" );

La cláusula catch comprueba los argumentos en el mismo orden en que aparezcan en el programa. Si hay alguno que
coincida, se ejecuta el bloque. El operador instanceof se utiliza para identificar exactamente cual ha sido la identidad
de la excepción.

finally

Es el bloque de código que se ejecuta siempre, haya o no excepción. Hay una cierta controversia entre su utilidad,
pero, por ejemplo, podría servir para hacer un log o un seguimiento de lo que está pasando, porque como se ejecuta
siempre puede dejarnos grabado si se producen excepciones y nos hemos recuperado de ellas o no.

Este bloque finally puede ser útil cuando no hay ninguna excepción. Es un trozo de código que se ejecuta
independientemente de lo que se haga en el bloque try.

Cuando vamos a tratar una excepción, se nos plantea el problema de qué acciones vamos a tomar. En la mayoría de
los casos, bastará con presentar una indicación de error al usuario y un mensaje avisándolo de que se ha producido un
error y que decida si quiere o no continuar con la ejecución del programa.

Por ejemplo, podríamos disponer de un diálogo como el que se presenta en el código siguiente:

public class DialogoError extends Dialog {


DialogoError( Frame padre ) {
super( padre,true );
setLayout( new BorderLayout() );

// Presentamos un panel con continuar o salir


Panel p = new Panel();
[Link]( new Button( "¿Continuar?" ) );
[Link]( new Button( "Salir" ) );

add( "Center",new Label(


"Se ha producido un error. ¿Continuar?" ) )
add( "South",p );
}

public boolean action( Event evt,Object obj ) {


if( "Salir".equals( obj ) )
{
dispose();
[Link]( 1 );
}
return false;
}
}

Y la invocación, desde algún lugar en que se suponga que se generarán errores, podría ser como sigue:

try {
// Código peligroso
}
catch( AlgunaExcepcion e ) {
VentanaError = new DialogoError( this );
[Link]();
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


PROPAGACION DE EXCEPCIONES
La cláusula catch comprueba los argumentos en el mismo orden en que aparezcan en el programa. Si hay alguno que
coincida, se ejecuta el bloque y sigue el flujo de control por el bloque finally (si lo hay) y concluye el control de la
excepción.

Si ninguna de las cláusulas catch coincide con la excepción que se ha producido, entonces se ejecutará el código de la
cláusula finally (en caso de que la haya). Lo que ocurre en este caso, es exactamente lo mismo que si la sentencia que
lanza la excepción no se encontrase encerrada en el bloque try.

El flujo de control abandona este método y retorna prematuramente al método que lo llamó. Si la llamada estaba
dentro del ámbito de una sentencia try, entonces se vuelve a intentar el control de la excepción, y así continuamente.

Veamos lo que sucede cuando una excepción no es tratada en la rutina en donde se produce. El sistema Java busca un
bloque try..catch más allá de la llamada, pero dentro del método que lo trajo aquí. Si la excepción se propaga de todas
formas hasta lo alto de la pila de llamadas sin encontrar un controlador específico para la excepción, entonces la
ejecución se detendrá dando un mensaje. Es decir, podemos suponer que Java nos está proporcionando un bloque
catch por defecto, que imprime un mensaje de error y sale.

No hay ninguna sobrecarga en el sistema por incorporar sentencias try al código. La sobrecarga se produce cuando se
genera la excepción.

Hemos dicho ya que un método debe capturar las excepciones que genera, o en todo caso, declararlas como parte de
su llamada, indicando a todo el mundo que es capaz de generar excepciones. Esto debe ser así para que cualquiera
que escriba una llamada a ese método esté avisado de que le puede llegar una excepción, en lugar del valor de retorno
normal. Esto permite al programador que llama a ese método, elegir entre controlar la excepción o propagarla hacia
arriba en la pila de llamadas. La siguiente línea de código muestra la forma general en que un método declara
excepciones que se pueden propagar fuera de él:

tipo_de_retorno( parametros ) throws e1,e2,e3 { }

Los nombres e1,e2,... deben ser nombres de excepciones, es decir, cualquier tipo que sea asignable al tipo
predefinido Throwable. Observar que, como en la llamada al método se especifica el tipo de retorno, se está
especificando el tipo de excepción que puede generar (en lugar de un objeto exception).

He aquí un ejemplo, tomado del sistema Java de entrada/salida:

byte readByte() throws IOException;


short readShort() throws IOException;
char readChar() throws IOException;

void writeByte( int v ) throws IOException;


void writeShort( int v ) throws IOException;
void writeChar( int v ) throws IOException;

Lo más interesante aquí es que la rutina que lee un char, puede devolver un char; no el entero que se requiere en C. C
necesita que se devuelva un int, para poder pasar cualquier valor a un char, y además un valor extra (-1) para indicar
que se ha alcanzado el final del fichero. Algunas de las rutinas Java lanzan una excepción cuando se alcanza el fin del
fichero.

En el siguiente diagrama se muestra gráficamente cómo se propaga la excepción que se genera en el código, a través
de la pila de llamadas durante la ejecución del código:

Cuando se crea una nueva excepción, derivando de una clase Exception ya existente, se puede cambiar el mensaje
que lleva asociado. La cadena de texto puede ser recuperada a través de un método. Normalmente, el texto del
mensaje proporcionará información para resolver el problema o sugerirá una acción alternativa. Por ejemplo:

class SinGasolina extends Exception {


SinGasolina( String s ) { // constructor
super( s );
}
....

// Cuando se use, aparecerá algo como esto


try {
if( j < 1 )
throw new SinGasolina( "Usando deposito de reserva" );
} catch( SinGasolina e ) {
[Link]( [Link]() );
}
Esto, en tiempo de ejecución originaría la siguiente salida por pantalla:

> Usando deposito de reserva

Otro método que es heredado de la superclase Throwable es printStackTrace(). Invocando a este método sobre una
excepción se volcará a pantalla todas las llamadas hasta el momento en donde se generó la excepción (no donde se
maneje la excepción). Por ejemplo:

// Capturando una excepción en un método


class testcap {
static int slice0[] = { 0,1,2,3,4 };

public static void main( String a[] ) {


try {
uno();
} catch( Exception e ) {
[Link]( "Captura de la excepcion en main()" );
[Link]();
}
}

static void uno() {


try {
slice0[-1] = 4;
} catch( NullPointerException e ) {
[Link]( "Captura una excepcion diferente" );
}
}
}

Cuando se ejecute ese código, en pantalla observaremos la siguiente salida:

> Captura de la excepcion en main()


> [Link]: -1
at [Link]([Link])
at [Link]([Link])

Con todo el manejo de excepciones podemos concluir que proporciona un método más seguro para el control de
errores, además de representar una excelente herramienta para organizar en sitios concretos todo el manejo de los
errores y, además, que podemos proporcionar mensajes de error más decentes al usuario indicando qué es lo que ha
fallado y por qué, e incluso podemos, a veces, recuperarnos de los errores.

La degradación que se produce en la ejecución de programas con manejo de excepciones está ampliamente
compensada por las ventajas que representa en cuanto a seguridad de funcionamiento de esos mismos programas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 06:03:59
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class HolaIte extends Applet {


private int i = 0;
private String Saludos[] = {
"Hola Mundo!",
"HOLA Mundo!",
"HOLA MUNDO!!"
};

public void paint( Graphics g ) {


try {
[Link]( Saludos[i],25,25 );
} catch( ArrayIndexOutOfBoundsException e ) {
[Link]( "Saludos desbordado",25,25 );
} catch( Exception e ) {
// Cualquier otra excepción
[Link]( [Link]() );
} finally {
[Link]( "Esto se imprime siempre!" );
}
i++;
}
}

//------------------------------------------- Final del fichero [Link]


LINEAS
Si se necesita dibujar una línea, se puede utilizar el método

[Link]( x1,y1,ancho,alto );

donde g es una instancia de la clase Graphics. [Link](..) también sería legal ya que graphics es también
una instancia de Graphics. Graphics es una clase abstracta por lo que no se pueden crear objetos de esta clase, es
decir, la siguiente sentencia es totalmente ilegal:

g = new Graphics();

porque no se puede utilizar new para obtener g.

En el código de la aplicación [Link], podemos observar el uso del método de dibujar líneas. Es el más
simple de todos los métodos gráficos, que pinta una línea recta de un pixel de ancho entre el punto inicial que se
indica y el final, calculado en función del ancho y alto de la región donde se pinta. En el siguiente applet,
[Link], podemos ver el método drawLine() en funcionamiento:

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


RECTANGULOS
Los rectángulos, al igual que los óvalos, se definen por un punto de inicio de coordenadas x e y y el ancho y el
alto de la caja que circunscribirá a la figura.

Para dibujar un rectángulo en pantalla, basta con llamar al método drawRect() indicando la posición en que deseamos
colocar la esquina superior-izquierda del rectángulo y su ancho y alto. Por ejemplo, el código siguiente, [Link],
pinta un rectángulo alrededor del applet que lo contiene:

import [Link].*;
import [Link];

public class Rect1 extends Applet {


int ancho,alto;

public void init() {


Dimension d = size(); // devuelve el tamaño del applet
ancho = [Link];
alto = [Link];

repaint();
}

public void paint( Graphics g ) {


[Link]( 0,0,ancho-1,alto-1 );
}
}

En este caso hemos tenido que utilizar ancho-1 y alto-1, para que fuese visible todo el rectángulo y no
solamente la mitad, por causa de la referencia de coordenadas que utiliza Java con respecto a la pantalla.

El método drawRect() pinta un rectángulo abierto, si queremos un rectángulo relleno, tendremos que invocar al
método fillRect(), que tiene idéntica sintaxis. El código siguiente, [Link], pinta un rectángulo relleno en el centro
del applet que lo contiene:

import [Link].*;
import [Link];

public class Rect2 extends Applet {


int apAncho;
int apAlto;
int x,y,ancho,alto;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
ancho = apAncho/3;
alto = apAlto/3;
x = (apAncho - ancho)/2;
y = (apAlto - alto)/2;

repaint();
}

public void paint( Graphics g ) {


[Link]( 0,0,apAncho-1,apAlto-1 );
[Link]( x,y,ancho-1,alto-1 );
}
}

Si queremos pintar un montón de rectángulos en posiciones y de tamaños aleatorios, al estilo de Mondrian, también
podemos hacerlo. Para ello utilizaremos el método [Link]() de la clase Math. Este método devuelve un doble
entre 0.0 y 1.0. El método aleatorio() sería:

private int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)( retornoMath * rango ) );
}

Este método fuerza a que el resultado sea un entero en el rango que nosotros indiquemos. El casting o moldeo se
realiza de double a int. El casting en Java es mucho más seguro que en C u otros lenguajes que permiten castings
arbitrarios. En Java solamente se pueden realizar castings que tengan sentido, por ejemplo entre un float y un int; y
no podrían realizarse un casting, por ejemplo entre un int y un String.

Vamos también a pintar los rectángulos en diferentes colores, utilizando el método setColor() de la clase Graphics.
El AWT predefine suficientes colores, con lo cual, además de pintar un rectángulo aleatorio, lo mostraremos en un
color aleatorio. En el código, [Link], que mostramos, se pinta un rectángulo con tamaño, posición y color
aleatorios:

import [Link].*;
import [Link];

public class Rect3 extends Applet {


int apAncho,apAlto;
int x,y,ancho,alto;
Color color;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
x = aleatorio( apAncho );
y = aleatorio( apAlto );
ancho = aleatorio( apAncho - x );
alto = aleatorio( apAlto - y );
color = new Color(
aleatorio(255),aleatorio(255),aleatorio(255) );

repaint();
}

public void paint( Graphics g ) {


[Link]( color );
[Link]( 0,0,apAncho-1,apAlto-1 );
[Link]( x,y,ancho-1,alto-1 );
}

private int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)( retornoMath * rango ) );
}
}

Si se carga repetidas veces el applet, aparecerán diferentes rectángulos, con distintos colores y en distintas
posiciones, así que vamos a automatizar ese proceso y a complicar del todo el ejemplo, permitiendo que se pinten
multitud de rectángulos coloreados. Debido a que cada uno de los rectángulos va a ser diferente, tendremos que
mover los cálculos de posición, tamaño y color de cada rectángulo al método paint(). Además, vamos a permitir
especificar en el fichero HTML que lance el applet, el número de rectángulos que se van a dibujar. Para ello
fijaremos un número por defecto y en caso de que se incluya el número de rectángulos como parámetro de la
invocación al applet, utilizaremos este último. He aquí el código, [Link], que realiza todo esto:

import [Link].*;
import [Link];

public class Rect4 extends Applet {


int apAncho,apAlto;
int x,y,ancho,alto;
Color color;
int numRect = 100;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];

String s = getParameter( "Numero" );


if( s != null )
numRect = [Link]( s ).intValue();

repaint();
}

public void paint( Graphics g ) {


[Link]( [Link] );
[Link]( 0,0,apAncho-1,apAlto-1 );

for( int i=0; i < numRect; i++ )


{
x = aleatorio( apAncho );
y = aleatorio( apAlto );
ancho = aleatorio( apAncho - x );
alto = aleatorio( apAlto - y );
color = new Color( aleatorio(255),aleatorio(255),
aleatorio(255) );

[Link]( color );
[Link]( x,y,ancho-1,alto-1 );
}
}

private int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)( retornoMath * rango ) );
}
}

Los rectángulos redondeados necesitan dos parámetros adicionales, con respecto al método habitual, para controlar el
arco con que se redondearán las esquinas del rectángulo. El método que pinta rectángulos tridimensionales todavía
necesitan un parámetro más que indica si el rectángulo estará sobresaliendo o hundiéndose en la pantalla. En el applet
siguiente, [Link], podemos ver y manipular los valores que pueden tomar estos métodos:

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


CIRCULOS, ELIPSES
Los m‰todos definidos en Java para la realizaci•n de c•rculos y elipses, al igual que en la mayor•a de los lenguajes,
reciben como parßmetros las coordenadas de la esquina superior-izquierda y el ancho y alto de la caja en la que se
circunscribe el c•rculos o la elipse.

En el ejemplo siguiente, [Link], podemos ver la r‰plica de la aplicaci•n conocida por los usuarios de Motif, en la
que los ojos siguen los movimientos del rat•n cuando se encuentra dentro del campo del applet.

Su navegador no entiende la marca <APPLET>, la siguiente imagen muestra la visualización de la


ejecución del applet en pantalla

import [Link].*;
import [Link];

public class Ojos extends Applet {


int Mx = -1;
int My = -1;
int OjoR1;
int OjoR2;
int Ancho;
int Alto;
int OjoIzq;
int OjoDch;
int OjoPY;
Color Pupila = [Link];
Color Iris = [Link]();
Color Orbita = [Link];
Image Imagen;
Graphics OjoCG;
public void init() {
setBackground( [Link] );
Dimension d = size();

// Fijamos las variables que nos van a posicionar los


// ojos sobre el applet
OjoIzq = [Link] >> 2;
OjoDch = OjoIzq * 3;
OjoPY = [Link] >> 2;

OjoR2 = [Link] >> 4;


OjoR1 = [Link] >> 5;
Ancho = ( [Link] >> 3 ) + OjoR1;
Alto = Ancho >> 1;
}

public void update( Graphics g ) {


paint( g );
}

// Funcion auxiliar, para que no se desmanden los valores


// y no se los salgan los ojos de las orbitas
int swap( int i,int c ) {
if( i > c )
i = c;
else if( i < -c )
i = -c;
return( i );
}

// Pintamos el ojo sobre el applet


void pintaOjo( Graphics g,int x ) {
// Fijamos los desplazamientos, las nuevas posiciones de
// referencia, en funcion de la posicion del cursor del
// raton, determinada por Mx y My
int dx = x-Mx;
int dy = OjoPY-My;

// Pintamos el ojo solamente bordeado, es decir, cerrado


if( dx < Ancho && dx > -Ancho && dy < Alto && dy > -Alto )
{
[Link]( getBackground() );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );
[Link]( getBackground().brighter() );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );
}
else
{
// Pintamos el hueco del ojo, por el que se movera el iris
[Link]( Orbita );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );
int y = OjoPY;
dx = swap( dx >> 3,OjoR1 << 1 );
dy = swap( dy >> 5,OjoR1 >> 1 );
if( Mx >= 0 && My >= 0 )
{
x -= dx;
y -= dy;
}

// Pintamos el iris, sobre el que se movera la pupila


[Link]( Iris );
[Link]( x-OjoR2,y-OjoR2,OjoR2 << 1,OjoR2 << 1 );
if( Mx >= 0 && My >= 0 )
{
x -= ( dx >> 1 );
y -= dy;
}

// Pintamos la pupila dentro del iris


[Link]( Pupila );
[Link]( x-OjoR1,y-OjoR1,OjoR1 << 1,OjoR1 << 1 );
}
}

public void paint( Graphics g ) {


Dimension d = size();

// La primera vez que se llama a este metodo, todavia no


// hay nada, asi que creamos el soporte de los ojos
if( Imagen == null || OjoCG == null )
{
Imagen = createImage( [Link],[Link] >> 1 );
OjoCG = [Link]();
}

// Pintamos los ojos


[Link]( getBackground() );
[Link]( 0,0,[Link],[Link] );
pintaOjo( OjoCG,OjoIzq );
pintaOjo( OjoCG,OjoDch );
[Link]( Imagen,0,0,this );
}

// Cuando movemos el cursos dentro del applet, recibimos las


// coordenadas y repintamos el ojo
public boolean mouseMove( Event evt,int x,int y ) {
Mx = x;
My = y;
repaint();

return true;
}
// Si nos llega el evento de que el raton se ha salido del applet
// ponemos los todo en el centro, con los ojos espantados,
// como si se hubiese visto al diablo
public boolean mouseExit( Event evt,int x,int y ) {
Mx = My = -1;
repaint();

return true;
}
}

Cada uno de los métodos que nos permiten representar en pantalla elipses y arcos, requieren como parámetros las
coordenadas del punto central del óvalo o arco y el ancho y alto, en valor positivo, del rectángulo que circunscribe al
óvalo o al arco, como hemos dicho. Para pintar arcos, necesitamos dos parámetros adicionales, un ángulo de inicio y
un ángulo para el arco; de este modo especificamos el inicio del arco y en tamaño del arco en grados (no en
radianes). En la figura que sigue mostramos cómo se tiene en cuanta el ángulo a la hora de las especificación de
ángulos en los valores de los parámetros a pasar a los métodos drawArc() y fillArc().

El applet siguiente, [Link], nos permite manipular el comportamiento de estos métodos ante los valores que
indiquemos en los parámetros que aceptan:

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


POLIGONOS
Los polígonos son figuras creadas a partir de una secuencia de segmentos. Cada método que permite dibujar
polígonos necesita como parámetros las coordenadas de los puntos donde termina cada uno de los segmentos que
constituyen el polígono. Estos puntos se pueden especificar como dos arrays paralelos de enteros, uno conteniendo
las coordenadas x de los puntos y otro las coordenadas y; o mediante una instancia de la clase Polygon. Esta clase
proporciona el método addPoint(), que permite ir construyendo el polígono punto a punto.

El applet, [Link], que aparece seguidamente permite ver los métodos de dibujo de polígonos en acción.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Tutorial de Java [Anterior] [Indice] [Siguiente]


FUNCIONES GRAFICAS
A través de líneas también se pueden realizar figuras más complicadas que resulten de la representación gráfica de
funciones matemáticas. No pretendemos entrar en complicadas disquisiciones matemáticas, sino presentar algunas de
las particularidades de los gráficos y Java. Vamos a presentar el código siguiente, [Link], que pintará la curva
de la función seno de izquierda a derecha de la ventana:

import [Link].*;
import [Link];

public class Grafico1 extends Applet {


int x0,xN,y0,yN;

public void init() {


Dimension d = size();

x0 = y0 = 0;
xN = [Link]-1;
yN = [Link]-1;
}

public void paint( Graphics g ) {


for( int x=x0; x < xN; x++ )
[Link]( x,(int)(yN*[Link](x)),
x+1,(int)(yN*[Link](x+1)) );
}
}

El corazón del funcionamiento del applet se encuentra en el bucle incluido en el método paint():

for( int x=x0; x < xN; x++ )


[Link]( x,(int)(yN*[Link](x)),x+1,(int)(yN*[Link](x+1)));

El bucle va desplazándose a través de cada pixel de la pantalla en el eje x, y en cada una de las posiciones, calcula el
seno para ese pixel. También calcula el seno del pixel siguiente y pinta una línea que une esos dos puntos. Debido a
que el seno de un número real está siempre comprendido entre 1 y -1, escalamos el valor de y con yN. Y por fin
hacemos un casting de los valores del seno en el eje y porque son flotantes fundamentalmente y el método
drawLine() necesita enteros.

El applet anterior funciona correctamente, pero adolece de dos dos problemas: Primero, los senos son operaciones en
coma flotante, luego para que el applet tenga realmente utilidad necesitamos utilizar números en coma flotante.
Segundo, el sistema de coordenadas que maneja el applet va desde el punto (0,0), de la esquina superior-izquierda
hasta la inferior-derecha. Pero el sistema normal de coordenadas Cartesianas empieza a contar desde la esquina
inferior-izquierda. Lo que haremos será mover el origen al centro del applet y transformar las coordenadas del eje y
para que vayan en las direcciones adecuadas.

La solución a los dos problemas anteriores puede tomar un montón de caminos diferentes, sin embargo, la clave se
encuentra en separar los datos de lo que es la pantalla. Es decir, vamos a realizar nuestros cálculos matemáticos
suponiendo que estamos en el espacio de un rectángulo en coordenadas cartesianas y, por otro lado, tomaremos a la
pantalla como un rectángulo de puntos de ancho y tamaño fijos. Así podremos realizar los cálculos en el plano de los
ejes cartesianos y presentarlos en el espacio reducido de la ventana del applet. Necesitaremos pues, un método para
convertir un punto de la ventana del applet en un punto en el mundo cartesiano, y otro que haga la función contraria.
El código siguiente, [Link], hace todo esto:

import [Link].*;
import [Link];

public class GraficoSeno extends Applet {


int x0,xN,y0,yN;
double xmin,xmax,ymin,ymax;
int apAncho,apAlto;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];

x0 = y0 = 0;
xN = apAncho-1;
yN = apAlto-1;
xmin = -10.0;
xmax = 10.0;
ymin = -1.0;
ymax = 1.0;
}

public void paint( Graphics g ) {


double x1,y1,x2,y2;
int j1,j2;

j1 = ValorY( 0 );
for( int i=0; i < apAncho; i++ )
{
j2 = ValorY( i+1 );
[Link]( i,j1,i+1,j2 );
j1 = j2;
}
}

private int ValorY( int valor ) {


double x,y;
int retorno;

// Cartesianas equivalentes al punto de la pantalla


x = (valor * (xmax-xmin) / (apAncho-1)) + xmin;
// Calculamos el seno de ese punto
y = [Link]( x );
// Escalamos la coordenada y dentro de los limites de la ventana
retorno = (int)( (y-ymin) * (apAlto-1) / (ymax-ymin) );
// Reconvertinos el valor cartesiano a punto de pantalla
retorno = apAlto - retorno;

return( retorno );
}
}

Ejecutando este applet, podremos observar que lo que se presenta ya se parece muchísimo más a la imagen que todos
conocemos de la onda senoidal.

Tutorial de Java [Anterior] [Indice] [Siguiente]


FRACTALES
No vamos aquí a proporcionar una clase maestra sobre fractales, sino que vamos a mostrar que Java también se
puede emplear para la implementación de algunos ejemplos clásicos de la geometría de fractales. Vamos a realizar
por uno sencillito, en el que se trata de un conjunto definido por todos los números reales entre cero y uno, inclusive.
Entonces, eliminamos el tercio central de ese conjunto, es decir, todo lo que se encuentre entre el primer tercio y el
último, ambos exclusive.

Para visualizar lo anterior vamos a utilizar segmentos de línea. Eliminaremos el tercio medio del segmento, es decir,
nos quedaremos con el segmento que va desde el inicio del segmento hasta el segundo noveno, y entre el séptimo
noveno y el final; y continuaremos este proceso indefinidamente.

La verdad es que parece un poco confusa la explicación, pero si una imagen vale más que mil palabras, un buen
programa Java vale más que mil imágenes. Por ello, aquí esta el código Java, [Link], que muestra sucesivas
líneas en que se demuestra la explicación del párrafo anterior.

import [Link].*;
import [Link];
import [Link];

public class Tercio extendsApplet {


int apAncho,apAlto;
Vector finPuntos = new Vector();

public void init() {


apAncho = size().width;
apAlto = size().height;

[Link]( new Float( 0.0f ) );


[Link]( new Float( 1.0f ) );
}

public void paint( Graphics g ) {


float x1,x2;
Float tmpFloat;

for( int i=0; i < apAncho; i+=5 )


{
// Pintamos las lineas
for( int j=0; j < [Link](); j+=2 )
{
tmpFloat = (Float)[Link]( j );
x1 = [Link]();
tmpFloat = (Float)[Link]( j+1 );
x2 = [Link]();
[Link]( [Link]( x1*apAncho ),i,
[Link]( x2*apAncho),i );
}
// Eliminamos el tercio medio de las lineas
BorraSegmentos();
// Comprobamos que no nos salimos de la pantalla
tmpFloat = (Float)[Link]( 0 );
x1 = [Link]();
tmpFloat = (Float)[Link]( 1 );
x2 = [Link]();
if( [Link]( x1*apAncho ) == [Link]( x2*apAncho ) )
break;
}
}

private void BorraSegmentos() {


int indice = 0;
int fin = [Link]();

for( int i=0; i < fin; i+=2 )


{
BorraTercioMedio( indice,indice+1 );
indice += 4;
}
}

private void BorraTercioMedio( int izqda,int dcha ) {


float gap;
float x1,x2;
Float tmpFloat1,tmpFloat2;

tmpFloat1 = (Float)[Link]( izqda );


tmpFloat2 = (Float)[Link]( dcha );
gap = [Link]() - [Link]();
x1 = [Link]() + gap/3.0f;
x2 = [Link]() - gap/3.0f;
[Link]( new Float( x2 ),dcha );
[Link]( new Float( x1 ),dcha );
}
}

Aquí vemos el resultado de la ejecución del applet. ¿Está claro? Desde luego no es la representación más perfecta del
conjunto, debido a que tenemos que manejar puntos de tamaño finito en lugar de puntos matemáticos genuinos.
Dependiendo de lo larga que sea la ventana del applet, probablemente sólo se vean entre seis y doce interacciones
antes de necesitar de que los pixels se vuelvan fraccionarios.
Es de hacer notar que en este programa Java hemos utilizado el objeto Vector. Debido a que Java no dispone de
punteros, este objeto y la clase asociada, disponen de los métodos necesarios para poder implementar una lista
enlazada, que es lo que nosotros hemos utilizado.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LINEAS FLOTANTES
El ejemplo de las líneas flotantes es más difícil de describir que su código. Se ejecuta sobre un bucle infinito y son
líneas que se están moviendo continuamente por la ventana que ocupa el applet, rebotando en los bordes y
moviéndose continuamente. El código del fichero [Link], es el que contiene las sentencias que crean el applet
que se visualiza a continuación. Repasar el código delalgoritmo para entenderlo, que es bastante simple.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

import [Link].*;
import [Link];

public class Lineas extends Applet {


int LINEAS = 25;
int gSup = 3;
int gInf = 3;
int gIzq = 2;
int gDch = 6;
int apAncho,apAlto;
int gLineas[][] = new int[LINEAS][4];

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
}

public void start() {


gLineas[0][0] = aleatorio( apAncho );
gLineas[0][1] = aleatorio( apAlto );
gLineas[0][2] = aleatorio( apAncho );
gLineas[0][3] = aleatorio( apAlto );

for( int i=1; i < LINEAS; i++ )


{
CopiaLinea( i,i-1 );
RecalcLinea( i );
}
repaint();
}

public void paint( Graphics g ) {


while( true )
{
for( int i=LINEAS-1; i > 0; i-- )
CopiaLinea( i,i-1 );
RecalcLinea( 0 );
[Link]( [Link] );
[Link](
gLineas[0][0],gLineas[0][1],
gLineas[0][2],gLineas[0][3] );
[Link]( getBackground() );
[Link]( gLineas[LINEAS-1][0],gLineas[LINEAS-1][1],
gLineas[LINEAS-1][2],gLineas[LINEAS-1][3] );
}
}

private void CopiaLinea( int desde,int hasta ) {


for( int i=0; i < 4; i++ )
gLineas[desde][i] = gLineas[hasta][i];
}

public int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)(retornoMath * rango) );
}

private void RecalcLinea( int i ) {


gLineas[i][1] += gSup;
if( (gLineas[i][1] < 0 ) || (gLineas[i][1] > apAlto) )
{
gSup *= -1;
gLineas[i][1] += 2*gSup;
}

gLineas[i][3] += gInf;
if( (gLineas[i][3] < 0 ) || (gLineas[i][3] > apAlto) )
{
gInf *= -1;
gLineas[i][3] += 2*gInf;
}

gLineas[i][0] += gIzq;
if( (gLineas[i][0] < 0 ) || (gLineas[i][0] > apAncho) )
{
gIzq *= -1;
gLineas[i][0] += 2*gIzq;
}

gLineas[i][2] += gDch;
if( (gLineas[i][2] < 0 ) || (gLineas[i][2] > apAncho) )
{
gDch *= -1;
gLineas[i][2] += 2*gDch;
}
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


METODOS PARA IMAGENES
Los objetos Graphics pueden mostrar imágenes a través del método:

drawImage( Image img,int x,int y,ImageObserver observador );

Hay que tener en cuenta que el método drawImage() necesita un objeto Image y un objeto ImageObserver. Podemos
cargar una imagen desde un fichero de dibujo (actualmente sólo se soportan formatos GIF y JPEG) con el método
getImage():

Image img = getImage( getDocumentBase(),"[Link]" );

La forma de invocar al método getImage() es indicando un URL donde se encuentre el fichero que contiene la
imagen que queremos presentar y el nombre de ese fichero:

getImage( URL directorioImagen,String ficheroImagen );

Un URL común para el método getImage() es el directorio donde está el fichero HTML. Se puede acceder a esa
localización a través del método getDocumentBase() de la clase Applet, como ya se ha indicado.

Normalmente, se realiza el getImage() en el método init() del applet y se muestra la imagen cargada en el método
paint(), tal como se muestra en el ejemplo siguiente:

public void init() {


img = getImage( getDocumentBase(),"[Link]" );
}

public void paint( Graphics g ) {


[Link]( img,x,y,this );
}

En el applet [Link], podemos ver el ejemplo completo. Su ponemos en él la existencia del fichero
"Imagenes/[Link]":

import [Link].*;
import [Link];
import [Link];

public class Imagen extends Applet {


Imagen pepe;

public void init() {


pepe = getImage( getDocumentBase(),"Imagenes/[Link]" );
}

public void paint( Graphics g ) {


[Link]( pepe,25,25,this );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


DOBLE-BUFFERING DE GRAFICOS
Al mostrar gráficos con las técnicas estándar, las imágenes suelen aparecer a trozos o con parpadeo. Las aplicaciones
Java permiten que los programas dibujen en memoria, para luego ir mostrando la imagen completa de forma suave.

Este es el proceso conocido como doble-buffering, y tiene dos ventajas fundamentales sobre el proceso normal de
pintar o dibujar directamente sobre la pantalla:

Primero, el usuario ve aparecer de golpe la imagen en la pantalla. Mientras el usuario está viendo esa imagen, el
programa está generando la siguiente para mostrarla de golpe a continuación, y así una y otra vez.

Segundo, la técnica de doble-buffering involucra un objeto Image, que se puede pasar directamente a varios métodos.
Esta capacidad para manipular objetos Image permite descomponer las rutinas de dibujo en componentes
funcionales, en lugar de un enorme método paint().

No obstante, el doble-buffering sólo debe usarse para animaciones gráficas, no como método normal. Lo usual en
otras aplicaciones sería repintar la zona que interese solamente.

Contextos gráficos

Para entender el doble-buffering, primero se necesita comprender qué es un contexto gráfico. Un contexto gráfico es
simplemente una estructura de datos que el sistema sabe utilizar como tablero de dibujo, es decir, es la zona en que se
va a pintar. Ya hemos visto y utilizado contextos gráfico en las declaraciones del método paint():

public void paint( Graphics g ) {

El objeto Graphics g es el contexto gráfico. Se utiliza g para realizar todo el dibujo en el applet. Por ejemplo:

[Link]( "¡Hola!",25,25 );
[Link]( 15,15,50,10 );

Entonces, Java traduce todo lo que se dibuja en g en imágenes sobre la pantalla. Para realizar doble-buffering, se
necesita pues, primero crear un contexto gráfico que no es presentado inmediatamente en la pantalla.

Creación de Contextos Gráficos

Crear contextos gráficos tiene dos pasos: Crear una imagen vacía con las dimensiones adecuadas y obtener un objeto
Graphics de esa imagen. El objeto Graphics que se construye en el segundo paso realiza la función de contexto
gráfico.

Por ejemplo, [Link]:


import [Link].*;
import [Link];

public class CGrafico extends Applet {


Image dobleBuffer;
Graphics miCG;

public void init() {


// Inicializa el doble buffer
dobleBuffer = createImage( 300,300 );
miCG = [Link]();

// Construye un área gráfica de trabajo


miCG .setColor( [Link] );
[Link]( 0,0,300,300 );
resize( 500,450 );
}

Podemos utilizar miCG para dibujar cualquier cosa. Las imágenes se trazarán en doble buffer. Cuando el dibujo esté
terminado, se puede presentar el doble buffer en pantalla:

public void paint( Graphics g ) {


// Sólo se tiene que presentar la imagen del buffer
[Link]( dobleBuffer,0,0,this );
}

Utilización de Contextos Gráficos

Una vez definido un contexto gráfico, podemos usarlo en cualquier parte de nuestro programa. Por ejemplo, podemos
repartir la responsabilidad para dibujar sobre varias funciones:

public void titulo() {


// Obtiene la fuente de texto actual y la guardamos
Font f = [Link]();

// Seleccionamos otra fuente para el título


[Link]( new Font( "TimesRoman".[Link],36 ) );
[Link]( "Ejemplo de Espiral",15,50 );
[Link]( "Círculos",15,90 );
// Recuperamos la fuente original
[Link]( f );
}

public void espiral() {


int x,y;

// Dibujamos circulos en los lados horizontales


y = 100;
for( x=100; x <= 200; x+=10 )
{
[Link]( x,y,20,20 );
[Link]( x,y+100,20,20 );
}
// Ahora en los verticales
x = 100;
for( y=100; y <= 200; y+=10 )
{
[Link]( x,y,20,20 );
[Link]( x+100,y,20,20 );
}
}

public void start() {


// Hace el dibujo off-line
titulo();
espiral();
// Ahora muestra la imagen de golpe
repaint();
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


NUEVAS CLASES PARA DIBUJO
La descomposición funcional de los métodos para dibujo proporcionados por el doble-buffering se pueden extender a
otras clases. Por ejemplo, se puede diseñar una clase especializada en un tipo de salida (gráficos, informes, CAD,
etc.). Pasándole el contexto gráfico como argumento al constructor, la nueva clase podrá construir la imagen. Esta
clase puede ser reutilizada en cualquier otro applet que lo necesite. Por ejemplo, el código del fichero fuente
[Link] siguiente muestra la clase Espiral. El applet espiral crea y usa un objeto Espiral. La representación
en pantalla se construye enteramente en la nueva clase:

import [Link].*;
import [Link];

// Clase de ejemplo para dibujar en contextos gráficos


class Espiral {
// Al ser privada, las variables son sólo accesibles por esta clase
private int iniX,iniY,iniAncho,iniAlto;
private int incremento;
private Graphics cg;

// constructor. crea una referencia local al buffer gráfico y define


// el azul como color de los objetos que se dibujen sobre ella
public Espiral( Graphics g ) {
cg = g;
[Link]( [Link] );
}

// Establece el tamaño y posición iniciales de la espiral


public void setTamInicial( int x,int y,int w,int h ) {
iniX = x;
iniY = y;
iniAncho = w;
iniAlto = h;
}

// Establece el incremento para espaciar los giros


public void setTamEspiral( int inc ) {
incremento = inc;
}

// Construye la espiral
public void creaEspiral() {
int cX = iniX;
int cY = iniY;

// Dibuja líneas por pares, cubriéndose entre sí para formar la


// espiral cuadrada hasta alcanzar el tamaño del incremento
while( iniAncho > incremento && iniAlto > incremnto )
{
[Link]( cX,cY,(cX+iniAncho),cY );
[Link]( (cX+iniAncho),Cy,(cX+iniAncho),(cY+iniAlto) );
cX += iniAncho;
cY += iniAlto;
iniAncho -= incremento;
iniAlto -= incremento;

[Link]( cX,cY,(cX-iniAncho),cY );
[Link]( (cX-iniAncho),Cy,(cX-iniAncho),(cY-iniAlto) );
cX -= iniAncho;
cY -= iniAlto;
iniAncho -= incremento;
iniAlto -= incremento;
}
}
}

// Esta es la llamada a la clase desde un Applet Html


public class EspiralTest extends Applet {
Image buffer;
Espiral spiral;
boolean cargado = false;

synchronized public void init() {


// crea un buffer donde dibujar
buffer = createImage( 300,300 );
// crea una nueva espiral
spiral = new Espiral( [Link]() );
// establece el punto inicial y dimensiones
[Link]( 10,10,200,200 );
// establece el incremento
[Link]( 10 );
// construye la espiral
[Link]();
}

synchronized public void paint( Graphics g ) {


[Link]( buffer,25,25,this );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE MediaTracker
Si nuestro applet tiene que tratar con imágenes almacenadas en ficheros gif/jpeg, tendremos que recurrir a la clase
MediaTracker. Esta clase proporciona muchos métodos para manejar objetos multimedia y grupos de objetos.

Manejo de Imágenes para Animación

Combinando MediaTracker con la técnica de doble-buffering, se pueden conseguir animaciones. Estos son algunos
métodos de MediaTracker útiles para ver gráficos

void addImage( Image img,int id )

Marca la imagen como parte de un grupo de identificadores id.

boolean checkID( int id )

Comprueba las imágenes pertenecientes al grupo id. Devuelve true si han sido cargadas todas, o false
en otro caso (no carga los ficheros que falten). Se utiliza para saber cuando se han cargado todas las
imágenes que componen una animación, antes de echarla a andar sobre la pantalla.

boolean checkID( int id,boolean load )

Comprueba las imágenes pertenecientes al grupo id. Devuelve true si han sido cargadas todas, o false
en otro caso. Carga las imágenes que falten si load es true.

boolean checkAll( boolean load )

Comprueba todas las imágenes. Devuelve true si todas están cargadas, o false en otro caso. Carga las
imágenes que falten si load es true.

void waitForID( int id )

Espera a que se carguen todas las imágenes del grupo id.

void waitForAll()

Espera a que se carguen todas las imágenes.

Se debería utilizar addImage() con cada imagen que necesite un applet. MediaTracker sólo supervisa imágenes
asociadas mediante el método addImage().

Si se quiere saber si un determinado gráfico ha sido cargado, se pueden utilizar los métodos check. Si se quiere que
un gráfico sea cargado antes de hacer cualquier otra cosa, usar los métodos waitFor. El uso de estos métodos es
especialmente útil ya que cuando realizamos la carga de una imagen con getImage(), esta carga se realiza en un
thread aparte del de nuestro applet, con lo cual, aunque la imagen se encuentre en el otro lado del mundo, getImage()
devuelve inmediatamente el control con lo cual podemos comenzar la ejecución de la animación, sin haberse cargado
todavía todas las imágenes.

Creación de un Objeto MediaTracker

Los objetos MediaTracker necesitan saber qué ImageObserver verá las imágenes que se están supervisando. Para los
applets, el ImageObserver es el propio applet:

miTracker = new MediaTracker( this );

Ahora ya se puede usar el objeto miTracker para manejar todas las imágenes de este applet.

Ejemplo de animación

Veamos ahora un ejemplo de animación, [Link]. Utilizaremos MediaTracker para asegurarnos de que se cargan
todas las imágenes. De este modo, cuando se ejecute la animación, no se verá parpadeo o que falta algún fotograma.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:

Y el código siguiente es el que corresponde a la animación anterior:

import [Link].*;
import [Link];

public class Taza extends Applet {


Image Images[];
MediaTracker tracker;
int index = 0;
int maxAncho,maxAlto;

// Componentes off-screen para el doble buffering


Image offScrImage;
Graphics offScrCG;
boolean cargado = false;

// Inicializa el applet. Establece el tamaño y carga las imágenes


public void init() {
// Establece el supervisor de imágenes y dimensiones
tracker = new MediaTracker( this );
maxAncho = 78;
maxAlto = 128;
imagenes = new Image[6];

// Establece el doble buffer y cambia el tamaño del applet


try {
offScrImage = createImage( maxAnho,maxAlto );
offScrCG = [Link]();
[Link]( [Link] );
[Link]( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
}
catch( exception e ) {
[Link]();
}

// Carga las imágenes en un array


for( int i=0; i < 33; i++ )
{
String imageFich =
new String( "taza"+[Link](i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),imageFich );
// Pasamos esta imagen al tracker
[Link]( imagenes[i],i );
}

try {
// Utilizamos el tracker para asegurar que se
// cargaran todas las imágenes
[Link]();
}
catch( InterruptedException e ) {
}
cargado = true;
}

// Pinta el fotograma actual


public void paint( Graphics g ) {
if( cargado )
{
// Copia del doble buffer a la pantalla
[Link]( offScrImage,0,0,this );
// Hacemos una pausa y cogemos la siguiente imagen
timerloop();
}
}

// Establecemos la primera imagen


public void start() {
index = 0;

if( [Link]( index ) )


// Pintamos en el doble buffer
[Link]( imagenes[index],0,0,this );
}

// Actualiza los fotogramas para que avance la animación


public void timerloop() {
// Se asegura que la imagen esté presente y la mete en el buffer
if( [Link]( index ) )
{
// Borra el fondo y obtiene la siguiente imagen
[Link]( 0,0,100,100 );
[Link]( imagenes[index],0,0,this );
index++;

// Vuelve al principio de la animación


if( index <= [Link] )
index = 0;
}
// Bucle de retardo
for( int retardo=0; retardo < 200000; retardo++ );
// Dibujamos el siguiente fotograma
repaint();
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


SONIDO EN JAVA
Java también posee métodos predefinidos para reproducir sonido. El ordenador remoto no necesita tener un
reproductor de audio; Java realizará la reproducción (evidentemente, el ordenador remoto, en donde se ejecuta el
applet, necesitará disponer de hardware de sonido).

Reproducción de sonido

La forma más fácil de reproducir sonido es a través del método play():

play( URL directorioSonido,String ficheroSonido );

o, simplemente:

play( URL unURLdeSonido );

Un URL común para el método play() es el directorio donde está el fichero HTML. Se puede acceder a esa
localización a través del método getDocumentBase() de la clase Applet:

play( getDocumentBase(),"[Link]" );

para que esto funcione, el fichero de la clase y el fichero [Link] deberían estar en el mismo directorio.

En el applet [Link], podemos ver el ejemplo completo. Su ponemos en él la existencia del fichero
sonidos/[Link]:

import [Link];
import [Link];

public class Sonido extends Applet {

public void paint( Graphics g ) {


[Link]( "Prueba de Sonido",25,25 );
play( getDocumentBase(),"sonidos/[Link]" );
}
}

Reproducción Repetitiva

Se puede manejar el sonido como si de imágenes se tratara. Se pueden cargar y reproducir más tarde.

Para cargar un clip de sonido, se utiliza el método getAudioClip():


AudoClip sonido;
sonido = getAudioClip( getDocumentBase(),"[Link]" );

Una vez que se carga el clip de sonido, se pueden utilizar tres métodos:

[Link]();

para reproducir el clip de sonido.

[Link]();

para iniciar la reproducción del clip de sonido y que entre en un blucle de reproducción, es decir, en
una repetición automática del clip.

[Link]();

para detener el clip de sonido que se encuentre en ese instante en reproducción.

Veamos como en el applet [Link] utilizamos estos métodos para repetir automáticamente una pista de audio.

import [Link];
import [Link];

public class Bucle extends Applet {


AudioClip sonido;

public void init() {


sonido = getAudioClip( getDocumentBase(),"sonidos/[Link]" );
}

public void paint( Graphics g ) {


[Link]( "Prueba de Repetición",25,25 );
}

public void start() {


[Link]();
}

public void stop() {


[Link]();
}
}

Y, finalmente, el applet [Link], nos permite a través de una interface basada en botones, poder controlar
la reproducción de audioclips. El checkbox de carga se usa como indicador para saber cuando el fichero que contiene
el clip de sonido a reproducir, se encuentra ya cargado en el sistema.

Tu navegador no entiende la marca <APPLET>. La imagen siguiente es la reproducción de la


apariencia del applet en pantalla:
Tutorial de Java [Anterior] [Indice] [Siguiente]
ENTRADA POR RATON
Una de las características más útiles que ofrece Java es el soporte directo de la interactividad. La aplicación puede
reaccionar a los cambios producidos en el ratón, por ejemplo, sin necesidad de escribir ninguna línea de código para
su control, solamente indicando qué se quiere hacer cuando el ratón haga algo.

El evento más común en el ratón es el click. Este evento es gobernado por dos métodos: mouseDown() (botón
pulsado) y mouseUp() (botón soltado). Ambos métodos son parte de la clase Applet, pero se necesita definir sus
acciones asociadas, de la misma forma que se realiza con init() o con paint().

public boolean mouseDown( Event evt,int x,int y ) {


/* ratón pulsado en x,y */
/* hacer algo */
}

public boolean mouseUp( Event evt,int x,int y ) {


/* ratón soltado en x,y */
/* hacer algo */
}

Para ambos métodos, las coordenadas x e y de la posición en que ha ocurrido el evento son relativas a la esquina
superior izquierda del applet.

En el applet [Link], se muestra la utilización del ratón para recibir las coordenadas en donde se ha pulsado el
ratón, y será en esa posición donde se repinte el saludo habitual:

import [Link].*;
import [Link];

public class Raton extends Applet {


int ratonX = 25;
int ratonY = 25;

public void paint( Graphics g ) {


[Link]( "Hola Mundo!",ratonX,ratonY );
}

public boolean mouseDown( Event evt,int x, int y ) {


ratonX = x;
ratonY = y;
repaint();
return true;
}
}
Tutorial de Java [Anterior] [Indice] [Siguiente]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:18:34
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Raton extends Applet {


int ratonX = 25;
int ratonY = 25;

// Pintamos el saludo donde se haya pulsado el ratón


public void paint( Graphics g ) {
[Link]( "Hola Mundo!",ratonX,ratonY );
}

// Solo gestionamos este evento, casando las coordenadas del


// ratón para presentar el mensaje
public boolean mouseDown( Event evt,int x, int y ) {
ratonX = x;
ratonY = y;
repaint();
return true;
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Jul-1996 19:53:09
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class Cuadrados extends Frame {


float xA,yA,xB,yB,xC,yC,xD,yD;
float xA1,yA1,xB1,yB1,xC1,yC1,xD1,yD1;
float p,q,r;
int xcentro,ycentro;

static final int HOR_TAMANO = 300;


static final int VER_TAMANO = 300;

public Cuadrados() {
q = (float)0.05;
p = 1 - q;
r = (float)0.95 * ( HOR_TAMANO/2 );

xcentro = HOR_TAMANO / 2;
ycentro = VER_TAMANO / 2;

resize( HOR_TAMANO,VER_TAMANO );
show();
}

public void paint( Graphics g ) {


xA = xD = xcentro - r;
xB = xC = xcentro + r;
yA = yB = ycentro - r;
yC = yD = ycentro + r;

for( int i=0; i < 20; i++ )


{
[Link]( (int)xA,(int)yA,(int)xB,(int)yB );
[Link]( (int)xB,(int)yB,(int)xC,(int)yC );
[Link]( (int)xC,(int)yC,(int)xD,(int)yD );
[Link]( (int)xD,(int)yD,(int)xA,(int)yA );
xA1 = p*xA + q*xB;
yA1 = p*yA + q*yB;
xB1 = p*xB + q*xC;
yB1 = p*yB + q*yC;
xC1 = p*xC + q*xD;
yC1 = p*yC + q*yD;
xD1 = p*xD + q*xA;
yD1 = p*yD + q*yA;

xA = xA1; xB = xB1; xC = xC1; xD = xD1;


yA = yA1; yB = yB1; yC = yC1; yD = yD1;
}
}

public boolean mouseDown( Event evt,int x,int y ) {


repaint();
return true;
}

public static void main( String args[] ) {


new Cuadrados();
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Dec-1996 13:14:24
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class FigLinea extends Applet implements Figura {


private TextField tfx1,tfy1,tfx2,tfy2;

private TutCanvas tc;

public void init() {


setBackground( [Link] );
setLayout( new BorderLayout() );

Panel p = new Panel();


[Link]( new FlowLayout( [Link],0,0 ) );

[Link]( new Label( "drawLine( ") );


[Link]( tfx1 = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfy1 = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfx2 = new TextField(3) );
[Link]( new Label( ",") );
[Link]( tfy2 = new TextField(3) );
[Link]( new Label( " )" ) );
add( "North",p );

// En la zona central colocamos nuestro canvas para ir


// pintando la líneas que correspondan a los datos
// que se introduzcan
tc = new TutCanvas( this );
add( "Center",tc );

// En la parte inferior colocamos un botón para que cuando


// lo pique el usuario se pinte la línea que corresponda a
// los parámetros de los campos de texto
p = new Panel();
[Link]( new Button( " Pintar " ) );
add( "South",p );

[Link]( "10" );
[Link]( "10" );
[Link]( "100" );
[Link]( "100" );
}

// Este método se encarga de recoger los valores numéricos que


// se introduzcan en los campos de texto. Si se meten letras
// o cualquier cosa rara, toma como valor 0
private int parseTextField( TextField tf ) {
int n;

try {
n = [Link]( [Link]() );
} catch( NumberFormatException nfe ) {
[Link]( "0" );
n = 0;
}
return( n );
}

// Sobrecargamos el método de pintura de nuestra interface


// Figura, que como es la que implementa la clase TutCanvas,
// hará que nos aparezca en pantalla la imagen correspondiente
// a la línea que indiquen los parámetros fijados
public void paintCallback( Graphics g ) {
int x1 = parseTextField( tfx1 );
int y1 = parseTextField( tfy1 );
int x2 = parseTextField( tfx2 );
int y2 = parseTextField( tfy2 );

[Link]( x1,y1,x2,y2 );
}

// Controlamos el evento de repintado de la línea


public boolean action( Event evt,Object obj ) {
if( [Link]( " Pintar " ) )
{
[Link]();
return( true );
}
return( false );
}

public Dimension preferredSize() {


return new Dimension( 500,200 );
}

// Función para cuando queramos ejecutar esta aplicación de forma


// individual, en solitario
public static void main( String args[] ){
Frame f = new Frame( "Líneas" );

FigLinea fl = new FigLinea();


[Link]();
[Link]( "Center",fl );
[Link]();
[Link]();
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 04:12:15
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Rect1 extends Applet {


int ancho,alto;

public void init() {


Dimension d = size(); // devuelve el tamaño del applet
ancho = [Link];
alto = [Link];

repaint();
}

public void paint( Graphics g ) {


[Link]( 0,0,ancho-1,alto-1 );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 04:13:47
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Rect2 extends Applet {


int apAncho;
int apAlto;
int x,y,ancho,alto;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
ancho = apAncho/3;
alto = apAlto/3;
x = (apAncho - ancho)/2;
y = (apAlto - alto)/2;

repaint();
}

public void paint( Graphics g ) {


[Link]( 0,0,apAncho-1,apAlto-1 );
[Link]( x,y,ancho-1,alto-1 );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 04:13:47
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Rect3 extends Applet {


int apAncho,apAlto;
int x,y,ancho,alto;
Color color;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
x = aleatorio( apAncho );
y = aleatorio( apAlto );
ancho = aleatorio( apAncho - x );
alto = aleatorio( apAlto - y );
color = new Color(
aleatorio(255),aleatorio(255),aleatorio(255) );

repaint();
}

public void paint( Graphics g ) {


[Link]( color );
[Link]( 0,0,apAncho-1,apAlto-1 );
[Link]( x,y,ancho-1,alto-1 );
}

private int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)( retornoMath * rango ) );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 04:15:51
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Rect4 extends Applet {


int apAncho,apAlto;
int x,y,ancho,alto;
Color color;
int numRect = 100;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];

String s = getParameter( "Numero" );


if( s != null )
numRect = [Link]( s ).intValue();

repaint();
}

public void paint( Graphics g ) {


[Link]( [Link] );
[Link]( 0,0,apAncho-1,apAlto-1 );

for( int i=0; i < numRect; i++ )


{
x = aleatorio( apAncho );
y = aleatorio( apAlto );
ancho = aleatorio( apAncho - x );
alto = aleatorio( apAlto - y );
color = new Color( aleatorio(255),aleatorio(255),
aleatorio(255) );

[Link]( color );
[Link]( x,y,ancho-1,alto-1 );
}
}

private int aleatorio( int rango ) {


double retornoMath;

retornoMath = [Link]();
return( (int)( retornoMath * rango ) );
}
}
//--------------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Dec-1996 13:45:29
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class FigRectangulo extends Applet implements Figura {


private TextField tfx,tfy,tfw,tfh,tfaw,tfah;
private TextField tfdrx,tfdry,tfdrw,tfdrh;
private TextField tffrx,tffry,tffrw,tffrh;
private TextField tfrrx,tfrry,tfrrw,tfrrh,tfrraw,tfrrah;
private TextField tffrrx,tffrry,tffrrw,tffrrh,tffrraw,tffrrah;
private TextField tf3rx,tf3ry,tf3rw,tf3rh;
private TextField tff3rx,tff3ry,tff3rw,tff3rh;
private Choice ch3r,chf3r,ch3;
private Panel p;
private CardLayout cl;
private TutCanvas tc;
private Choice ch;

public void init() {


setBackground( [Link] );
setLayout( new BorderLayout() );

// Vamos a utilizar un CardLayout para ir cambiando las


// presentaciones de los métodos y los parametros que se
// van a introducir en función del tipo de figura que se
// seleccione. Esto lo colocamos en la zona superior del
// BorderLayout que gestiona el applet al completo
// Para cada una de las primitivas, creamos un FlowLayout
// que nos permite colocar los campos de texto para la
// entrada de los parámetros que necesita esa primitiva
Panel p1;
p = new Panel();
[Link]( cl = new CardLayout() );
[Link]( "Rectángulo",p1 = new Panel() );
[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "drawRect(" ) );
[Link]( tfdrx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdrw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdrh = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Rectángulo Relleno",p1 = new Panel() );


[Link](new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fillRect(" ) );
[Link]( tffrx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrh = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Rectángulo Redondeado",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "drawRoundRect(" ) );
[Link]( tfrrx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfrry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfrrw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfrrh = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfrraw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfrrah = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Rectángulo Redondeado Relleno", p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fillRoundRect(" ) );
[Link]( tffrrx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrrw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrrh = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrraw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffrrah = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Rectángulo 3D",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "draw3DRect(" ) );
[Link]( tf3rx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tf3ry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tf3rw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tf3rh = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( ch3r = new Choice() );
[Link]( "true" );
[Link]( "false" );
[Link]( new Label( " )" ) );

[Link]( "Rectángulo 3D Relleno",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fill3DRect(" ) );
[Link]( tff3rx = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tff3ry = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tff3rw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tff3rh = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( chf3r = new Choice() );
[Link]( "true" );
[Link]( "false" );
[Link]( new Label( " )" ) );
add( "North",p );

// En la zona central colocamos nuestro canvas para ir


// pintando las primitivas que correspondan a las selecciones
// que se introduzcan
tc = new TutCanvas( this );
add( "Center",tc );

// En la parte inferior colocamos un botón para que cuando


// lo pique el usuario se pinte la figura y una caja de
// selección para que nos indique la figura que quiere
// ver en pantalla
p1 = new Panel();
[Link](new Button( " Pintar " ) );
ch = new Choice();
[Link]( "Rectángulo" );
[Link]( "Rectángulo Relleno" );
[Link]( "Rectángulo Redondeado" );
[Link]( "Rectángulo Redondeado Relleno" );
[Link]( "Rectángulo 3D" );
[Link]( "Rectángulo 3D Relleno" );
[Link]( ch );
add( "South",p1 );

tfx = tfdrx;
tfy = tfdry;
tfw = tfdrw;
tfh = tfdrh;
tfaw = tfrraw;
tfah = tfrrah;
ch3 = ch3r;

[Link]( "10" );
[Link]( "10" );
[Link]( "100" );
[Link]( "100" );
[Link]( "10" );
[Link]( "10" );
[Link]( "true" );
}

// Este método se encarga de recoger los valores numéricos que


// se introduzcan en los campos de texto. Si se meten letras
// o cualquier cosa rara, toma como valor 0
private int parseTextField( TextField tf ) {
int n;

try {
n = [Link]( [Link]() );
} catch( NumberFormatException nfe ) {
[Link]( "0" );
n = 0;
}
return( n );
}

// Sobrecargamos el método de pintura de nuestra interface


// Figura, que como es la que implementa la clase TutCanvas,
// hara que nos aparezca en pantalla la imagen correspondiente
// a la figura geométrica que queremos pintar
public void paintCallback( Graphics g ) {
int x = parseTextField( tfx );
int y = parseTextField( tfy );
int w = parseTextField( tfw );
int h = parseTextField( tfh );
int aw = parseTextField( tfaw );
int ah = parseTextField( tfah );
boolean b = [Link]().equals( "true" );

if( [Link]().equals( "Rectángulo" ) )


[Link]( x,y,w,h );
else if( [Link]().equals( "Rectángulo Relleno" ) )
[Link]( x,y,w,h );
else if( [Link]().equals( "Rectángulo Redondeado" ) )
[Link]( x,y,w,h,aw,ah );
else if( [Link]().equals( "Rectángulo Redondeado Relleno" ) )
[Link]( x,y,w,h,aw,ah );
else if( [Link]().equals( "Rectángulo 3D" ) )
g.draw3DRect( x,y,w,h,b );
else if( [Link]().equals( "Rectángulo 3D Relleno" ) )
g.fill3DRect( x,y,w,h,b );
}

// Control de las opciones que seleccione el usuario, tanto


// para repintar lo que haya introducido como para la selección
// de la figura que quiere presentar
public boolean action( Event evt,Object obj ) {
if( [Link]( " Pintar " ) )
{
[Link]();
return( true );
}
else if( [Link]("Rectángulo" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tfdrx;
tfy = tfdry;
tfw = tfdrw;
tfh = tfdrh;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Rectágulo Relleno" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tffrx;
tfy = tffry;
tfw = tffrw;
tfh = tffrh;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Rectágulo Redondeado" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tfrrx;
tfy = tfrry;
tfw = tfrrw;
tfh = tfrrh;
tfaw = tfrraw;
tfah = tfrrah;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Rectágulo Redondeado Relleno" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tffrrx;
tfy = tffrry;
tfw = tffrrw;
tfh = tffrrh;
tfaw = tffrraw;
tfah = tffrrah;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Rectágulo 3D" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tf3rx;
tfy = tf3ry;
tfw = tf3rw;
tfh = tf3rh;
ch3 = ch3r;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Rectángulo 3D Relleno" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tff3rx;
tfy = tff3ry;
tfw = tff3rw;
tfh = tff3rh;
ch3 = chf3r;

[Link]( p,(String)obj );
[Link]();
return( true );
}
return( false );
}

public Dimension preferredSize() {


return( new Dimension( 500,200 ) );
}

// Función para cuando queramos ejecutar esta aplicación de forma


// individual, en solitario
public static void main( String args[] ) {
Frame f = new Frame( "Rectángulos" );

FigRectangulo fr = new FigRectangulo();


[Link]();
[Link]( "Center",fr );
[Link]();
[Link]();
}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 23-Ago-1996 06:26:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Ojos extends Applet {


int Mx = -1;
int My = -1;
int OjoR1;
int OjoR2;
int Ancho;
int Alto;
int OjoIzq;
int OjoDch;
int OjoPY;
Color Pupila = [Link];
Color Iris = [Link]();
Color Orbita = [Link];
Image Imagen;
Graphics OjoCG;

public void init() {


setBackground( [Link] );
Dimension d = size();

// Fijamos las variables que nos van a posicionar los


// ojos sobre el applet
OjoIzq = [Link] >> 2;
OjoDch = OjoIzq * 3;
OjoPY = [Link] >> 2;

OjoR2 = [Link] >> 4;


OjoR1 = [Link] >> 5;
Ancho = ( [Link] >> 3 ) + OjoR1;
Alto = Ancho >> 1;
}

public void update( Graphics g ) {


paint( g );
}

// Funcion auxiliar, para que no se desmanden los valores


// y no se los salgan los ojos de las orbitas
int swap( int i,int c ) {
if( i > c )
i = c;
else if( i < -c )
i = -c;
return( i );
}

// Pintamos el ojo sobre el applet


void pintaOjo( Graphics g,int x ) {
// Fijamos los desplazamientos, las nuevas posiciones de
// referencia, en funcion de la posicion del cursor del
// raton, determinada por Mx y My
int dx = x-Mx;
int dy = OjoPY-My;

// Pintamos el ojo solamente bordeado, es decir, cerrado


if( dx < Ancho && dx > -Ancho && dy < Alto && dy > -Alto )
{
[Link]( getBackground() );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );
[Link]( getBackground().brighter() );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );
}
else
{
// Pintamos el hueco del ojo, por el que se movera el iris
[Link]( Orbita );
[Link]( x-Ancho,OjoPY-Alto,Ancho << 1,Alto << 1 );

int y = OjoPY;
dx = swap( dx >> 3,OjoR1 << 1 );
dy = swap( dy >> 5,OjoR1 >> 1 );
if( Mx >= 0 && My >= 0 )
{
x -= dx;
y -= dy;
}

// Pintamos el iris, sobre el que se movera la pupila


[Link]( Iris );
[Link]( x-OjoR2,y-OjoR2,OjoR2 << 1,OjoR2 << 1 );
if( Mx >= 0 && My >= 0 )
{
x -= ( dx >> 1 );
y -= dy;
}

// Pintamos la pupila dentro del iris


[Link]( Pupila );
[Link]( x-OjoR1,y-OjoR1,OjoR1 << 1,OjoR1 << 1 );
}
}

public void paint( Graphics g ) {


Dimension d = size();

// La primera vez que se llama a este metodo, todavia no


// hay nada, asi que creamos el soporte de los ojos
if( Imagen == null || OjoCG == null )
{
Imagen = createImage( [Link],[Link] >> 1 );
OjoCG = [Link]();
}

// Pintamos los ojos


[Link]( getBackground() );
[Link]( 0,0,[Link],[Link] );
pintaOjo( OjoCG,OjoIzq );
pintaOjo( OjoCG,OjoDch );
[Link]( Imagen,0,0,this );
}

// Cuando movemos el cursos dentro del applet, recibimos las


// coordenadas y repintamos el ojo
public boolean mouseMove( Event evt,int x,int y ) {
Mx = x;
My = y;
repaint();

return true;
}

// Si nos llega el evento de que el raton se ha salido del applet


// ponemos los todo en el centro, con los ojos espantados,
// como si se hubiese visto al diablo
public boolean mouseExit( Event evt,int x,int y ) {
Mx = My = -1;
repaint();

return true;
}
}

//---------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Dec-1996 13:02:51
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class FigElipse extends Applet implements Figura {


private TextField tfx,tfy,tfw,tfh,tfsa,tfaa;
private TextField tfdox,tfdoy,tfdow,tfdoh;
private TextField tffox,tffoy,tffow,tffoh;
private TextField tfdax,tfday,tfdaw,tfdah,tfdasa,tfdaaa;
private TextField tffax,tffay,tffaw,tffah,tffasa,tffaaa;
private Panel p;
private CardLayout cl;
private TutCanvas tc;
private Choice ch;

public void init() {


// Fijamos el fondo del applet igual que el de la página
setBackground( [Link] );
setLayout( new BorderLayout() );

// Vamos a utilizar un CardLayout para ir cambiando las


// presentaciones de los métodos y los parámetros que se
// van a introducir en función del tipo de figura que se
// seleccione. Esto lo colocamos en la zona superior del
// BorderLayout que gestiona el applet al completo
Panel p1;
p = new Panel();
[Link]( cl = new CardLayout() );

[Link]( "Elipse",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "drawOval( " ) );
[Link]( tfdox = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdoy = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdow = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdoh = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Elipse Rellena",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fillOval (" ) );
[Link]( tffox = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffoy = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffow = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffoh = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Arco",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "drawArc( " ) );
[Link]( tfdax = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfday = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdaw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdah = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdasa = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tfdaaa = new TextField(3) );
[Link]( new Label( " )" ) );

[Link]( "Arco Relleno",p1 = new Panel() );


[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fillArc( " ) );
[Link]( tffax = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffay = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffaw = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffah = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffasa = new TextField(3) );
[Link]( new Label( "," ) );
[Link]( tffaaa = new TextField(3) );
[Link]( new Label( " )" ) );
add( "North",p );

// En la zona central colocamos nuestro canvas para ir


// pintando las primitivas que correspondan a las selecciones
// que se introduzcan
tc = new TutCanvas( this );
add( "Center",tc );

// En la parte inferior colocamos un botón para que cuando


// lo pique el usuario se pinte la figura y una caja de
// selección para que nos indique la figura que quiere
// ver en pantalla
p1 = new Panel();
[Link]( new Button( " Pintar " ) );
ch = new Choice();
[Link]( "Elipse" );
[Link]( "Elipse Rellena" );
[Link]( "Arco" );
[Link]( "Arco Relleno" );
[Link]( ch );
add( "South",p1 );

tfx = tfdox;
tfy = tfdoy;
tfw = tfdow;
tfh = tfdoh;
tfsa = tfdasa;
tfaa = tfdaaa;
[Link]( "10" );
[Link]( "10" );
[Link]( "100" );
[Link]( "100" );
[Link]( "90" );
[Link]( "110" );
}

// Este método se encarga de recoger los valores numéricos que


// se introduzcan en los campos de texto. Si se meten letras
// o cualquier cosa rara, toma como valor 0
private int parseTextField( TextField tf ) {
int n;

try {
n = [Link]( [Link]() );
} catch( NumberFormatException nfe ) {
[Link]( "0" );
n = 0;
}
return( n );
}

// Sobrecargamos el metodo de pintura de nuestra interface


// Figura, que como es la que implementa la clase TutCanvas,
// hará que nos aparezca en pantalla la imagen correspondiente
// a la figura geométrica que queremos pintar
public void paintCallback( Graphics g ) {
int x = parseTextField( tfx );
int y = parseTextField( tfy );
int w = parseTextField( tfw );
int h = parseTextField( tfh );
int sa = parseTextField( tfsa );
int aa = parseTextField( tfaa );

if( [Link]().equals( "Elipse" ) )


[Link]( x,y,w,h );
else if( [Link]().equals( "Elipse Rellena" ) )
[Link]( x,y,w,h );
else if( [Link]().equals( "Arco" ) )
[Link]( x,y,w,h,sa,aa );
else if( [Link]().equals( "Arco Relleno" ) )
[Link]( x,y,w,h,sa,aa );
}

// Control de las opciones que seleccione el usuario, tanto


// para repintar lo que haya introducido como para la selección
// de la figura que quiere presentar
public boolean action( Event evt,Object obj ) {
if( [Link]( " Pintar " ) )
{
[Link]();
return( true );
}
else if( [Link]( "Elipse" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tfdox;
tfy = tfdoy;
tfw = tfdow;
tfh = tfdoh;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Elipse Rellena" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tffox;
tfy = tffoy;
tfw = tffow;
tfh = tffoh;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Arco" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tfdax;
tfy = tfday;
tfw = tfdaw;
tfh = tfdah;
tfsa = tfdasa;
tfaa = tfdaaa;

[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Arco Relleno" ) )
{
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
[Link]( [Link]() );
tfx = tffax;
tfy = tffay;
tfw = tffaw;
tfh = tffah;
tfsa = tffasa;
tfaa = tffaaa;

[Link]( p,(String)obj );
[Link]();
return( true );
}
return( false );
}

public Dimension preferredSize() {


return new Dimension( 500,200 );
}

// Función para cuando queramos ejecutar esta aplicación de forma


// individual, en solitario
public static void main( String args[] ) {
Frame f = new Frame( "Elipses y Arcos" );

FigElipse fo = new FigElipse();


[Link]();
[Link]( "Center", fo );
[Link]();
[Link]();
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Dec-1996 13:22:51
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class FigPoligono extends Applet implements Figura {


private Panel p;
private CardLayout cl;
private TutCanvas tc;
private Choice ch;

public void init() {


setBackground( [Link] );
setLayout( new BorderLayout() );

// Vamos a utilizar un CardLayout para ir cambiando las


// presentaciones de los métodos y los parámetros que se
// van a introducir en función del tipo de figura que se
// seleccione. Esto lo colocamos en la zona superior del
// BorderLayout que gestiona el applet al completo
// En este caso, no dejamos que se introduzcan valores de
// parámetros, sino que pintamos un polígono predeterminado y
// sólo dejamos al usuario que seleccione entre si quiere
// ver el polígono relleno o no
Panel p1;
p = new Panel();
[Link]( cl = new CardLayout() );
[Link]( "Pol•gono",p1 = new Panel() );
[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "drawPolygon ( ... )" ) );
[Link]( "Pol•gono Relleno",p1 = new Panel() );
[Link]( new FlowLayout( [Link],0,0 ) );
[Link]( new Label( "fillPolygon( ... )" ) );
add( "North",p );

// En la zona central colocamos nuestro canvas para ir


// pintando las primitivas que correspondan a las selecciones
// que se introduzcan
tc = new TutCanvas( this );
add( "Center",tc );

// En la parte inferior colocamos un botón para que cuando


// lo pique el usuario se pinte la figura y una caja de
// selección para que nos indique la figura que quiere
// ver en pantalla
p1 = new Panel();
[Link]( new Button( " Pintar " ) );
ch = new Choice();
[Link]( "Polígono" );
[Link]( "Polígono Relleno" );
[Link]( ch );
add( "South",p1 );
}

// Sobrecargamos el método de pintura de nuestra interface


// Figura, que como es la que implementa la clase TutCanvas,
// hara que nos aparezca en pantalla la imagen correspondiente
// a la figura geométrica que queremos pintar
public void paintCallback( Graphics g ) {
Polygon pg = new Polygon();

[Link]( 220,30 );
[Link]( 300,35 );
[Link]( 320,95 );
[Link]( 275,70 );
[Link]( 210,100 );
[Link]( 180,50 );

if( [Link]().equals( "Polígono" ) )


[Link]( pg );
else if( [Link]().equals( "Polígono Relleno" ) )
[Link]( pg );
}

// Control de las opciones que seleccione el usuario, tanto


// para repintar lo que haya introducido como para la selección
// de la figura que quiere presentar
public boolean action( Event evt,Object obj ) {
if( [Link]( " Pintar " ) )
{
[Link]();
return( true );
}
else if( [Link]( "Polígono" ) )
{
[Link]( p,(String)obj );
[Link]();
return( true );
}
else if( [Link]( "Polígono Relleno" ) )
{
[Link]( p,(String)obj );
[Link]();
return( true );
}
return( false );
}

public Dimension preferredSize() {


return new Dimension( 500,200 );
}

// Función para cuando queramos ejecutar esta aplicación de forma


// individual, en solitario
public static void main( String args[] ) {
Frame f = new Frame( "Polígonos" );

FigPoligono fp = new FigPoligono();


[Link]();
[Link]( "Center",fp );
[Link]();
[Link]();
}
}
//-------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 17-Sep-1996 04:17:34
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Grafico1 extends Applet {


int x0,xN,y0,yN;

public void init() {


Dimension d = size();

x0 = y0 = 0;
xN = [Link]-1;
yN = [Link]-1;
}

public void paint( Graphics g ) {


for( int x=x0; x < xN; x++ )
[Link]( x,(int)(yN*[Link](x)),
x+1,(int)(yN*[Link](x+1)) );
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 21:41:14
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class GraficoSeno extends Applet {


int x0,xN,y0,yN;
double xmin,xmax,ymin,ymax;
int apAncho,apAlto;

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];

x0 = y0 = 0;
xN = apAncho-1;
yN = apAlto-1;
xmin = -10.0;
xmax = 10.0;
ymin = -1.0;
ymax = 1.0;
}

// Pinta la línea entre los puntos que se toman en cada


// segmento de cálculo de la función
public void paint( Graphics g ) {
double x1,y1,x2,y2;
int j1,j2;

j1 = ValorY( 0 );
for( int i=0; i < apAncho; i++ )
{
j2 = ValorY( i+1 );
[Link]( i,j1,i+1,j2 );
j1 = j2;
}
}

private int ValorY( int valor ) {


double x,y;
int retorno;

// Cartesianas equivalentes al punto de la pantalla


x = (valor * (xmax-xmin) / (apAncho-1)) + xmin;
// Calculamos el seno de ese punto
y = [Link]( x );
// Escalamos la coordenada y dentro de los limites de la ventana
retorno = (int)( (y-ymin) * (apAlto-1) / (ymax-ymin) );
// Reconvertinos el valor cartesiano a punto de pantalla
retorno = apAlto - retorno;

return( retorno );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 23:15:04
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
import [Link];

public class Tercio extends Applet {


int apAncho,apAlto;
Vector finPuntos = new Vector();

public void init() {


apAncho = size().width;
apAlto = size().height;

[Link]( new Float( 0.0f ) );


[Link]( new Float( 1.0f ) );
}

public void paint( Graphics g ) {


float x1,x2;
Float tmpFloat;

for( int i=0; i < apAncho; i+=5 )


{
// Pintamos las lineas
for( int j=0; j < [Link](); j+=2 )
{
tmpFloat = (Float)[Link]( j );
x1 = [Link]();
tmpFloat = (Float)[Link]( j+1 );
x2 = [Link]();
[Link]( [Link]( x1*apAncho ),i,
[Link]( x2*apAncho),i );
}
// Eliminamos el tercio medio de las lineas
BorraSegmentos();
// Comprobamos que no nos salimos de la pantalla
tmpFloat = (Float)[Link]( 0 );
x1 = [Link]();
tmpFloat = (Float)[Link]( 1 );
x2 = [Link]();
if( [Link]( x1*apAncho ) == [Link]( x2*apAncho ) )
break;
}
}

private void BorraSegmentos() {


int indice = 0;
int fin = [Link]();

for( int i=0; i < fin; i+=2 )


{
BorraTercioMedio( indice,indice+1 );
indice += 4;
}
}

private void BorraTercioMedio( int izqda,int dcha ) {


float gap;
float x1,x2;
Float tmpFloat1,tmpFloat2;

tmpFloat1 = (Float)[Link]( izqda );


tmpFloat2 = (Float)[Link]( dcha );
gap = [Link]() - [Link]();
x1 = [Link]() + gap/3.0f;
x2 = [Link]() - gap/3.0f;
[Link]( new Float( x2 ),dcha );
[Link]( new Float( x1 ),dcha );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 21:55:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Lineas extends Applet {


int LINEAS = 25;
int gSup = 3;
int gInf = 3;
int gIzq = 2;
int gDch = 6;
int apAncho,apAlto;
int gLineas[][] = new int[LINEAS][4];

public void init() {


Dimension d = size();
apAncho = [Link];
apAlto = [Link];
}

// Arranque del thread, donde se inicializa en un punto cualquiera


// Y se lanzan los cálculos
public void start() {
gLineas[0][0] = aleatorio( apAncho );
gLineas[0][1] = aleatorio( apAlto );
gLineas[0][2] = aleatorio( apAncho );
gLineas[0][3] = aleatorio( apAlto );

for( int i=1; i < LINEAS; i++ )


{
CopiaLinea( i,i-1 );
RecalcLinea( i );
}
repaint();
}

// Primero copia las líneas para pasar a las siguiente posiciones


// recalcula y pinta de nuevo, con ello se da siempre la sensación
// de continuidad y no dan saltos entre cada vez que se pinta
public void paint( Graphics g ) {
while( true )
{
for( int i=LINEAS-1; i > 0; i-- )
CopiaLinea( i,i-1 );
RecalcLinea( 0 );
[Link]( [Link] );
[Link]( gLineas[0][0],gLineas[0][1],
gLineas[0][2],gLineas[0][3] );
[Link]( getBackground() );
[Link]( gLineas[LINEAS-1][0],gLineas[LINEAS-1][1],
gLineas[LINEAS-1][2],gLineas[LINEAS-1][3] );
}
}

// Copia la línea dentro del array de vectores


private void CopiaLinea( int desde,int hasta ) {
for( int i=0; i < 4; i++ )
gLineas[desde][i] = gLineas[hasta][i];
}

// Devuelve un número pseudo-aleatorio


public int aleatorio( int rango ) {
double retornoMath;

retornoMath = [Link]();
return( (int)(retornoMath * rango) );
}

// Recalcula la posición en que se va a encontrar cada una de


// las líneas en la siguiente secuencia
private void RecalcLinea( int i ) {
gLineas[i][1] += gSup;
if( (gLineas[i][1] < 0 ) || (gLineas[i][1] > apAlto) )
{
gSup *= -1;
gLineas[i][1] += 2*gSup;
}

gLineas[i][3] += gInf;
if( (gLineas[i][3] < 0 ) || (gLineas[i][3] > apAlto) )
{
gInf *= -1;
gLineas[i][3] += 2*gInf;
}

gLineas[i][0] += gIzq;
if( (gLineas[i][0] < 0 ) || (gLineas[i][0] > apAncho) )
{
gIzq *= -1;
gLineas[i][0] += 2*gIzq;
}

gLineas[i][2] += gDch;
if( (gLineas[i][2] < 0 ) || (gLineas[i][2] > apAncho) )
{
gDch *= -1;
gLineas[i][2] += 2*gDch;
}
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:05:32
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Imagen extends Applet {


Image pepe;

// Coge la imagen de Disco


public void init() {
pepe = getImage( getDocumentBase(),"[Link]" );
}

// Y la pinta en la pantalla, con un borde de 5 pixels en la


// parte superior e izquierda
public void paint( Graphics g ) {
[Link]( pepe,5,5,this );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:09:41
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class CGrafico extends Applet {


Image dobleBuffer;
Graphics miCG;

public void init() {


// Inicializa el doble buffer
dobleBuffer = createImage( 300,300 );
miCG = [Link]();

// Construye un área gráfica de trabajo


[Link]( [Link] );
[Link]( 0,0,300,300 );
resize( 500,450 );
}

public void paint( Graphics g ) {


// Sólo se tiene que presentar la imagen del buffer
[Link]( dobleBuffer,0,0,this );
}

public void titulo() {


// Obtiene la fuente de texto actual y la guardamos
Font f = [Link]();
// Seleccionamos otro color y otra fuente para el título
[Link]( [Link] );
[Link]( new Font( "TimesRoman",[Link],20 ) );
[Link]( "Ejemplo de Cuadrado",15,50 );
[Link]( "con Círculos",15,70 );
// Recuperamos la fuente original
[Link]( f );
}

public void cuadrado() {


int x,y;

// Seleccionamos otro color para el cuadrado


[Link]( [Link] );

// Dibujamos circulos en los lados horizontales


y = 100;
for( x=100; x <= 200; x+=10 )
{
[Link]( x,y,20,20 );
[Link]( x,y+100,20,20 );
}
// Ahora en los verticales
x = 100;
for( y=100; y <= 200; y+=10 )
{
[Link]( x,y,20,20 );
[Link]( x+100,y,20,20 );
}
}

public void start() {


// Hace el dibujo off-line
titulo();
cuadrado();
// Ahora muestra la imagen de golpe
repaint();
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:01:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase de ejemplo para dibujar en contextos gráficos


class Espiral {
// Al ser privada, las variables son sólo accesibles por esta clase
private int iniX,iniY,iniAncho,iniAlto;
private int incremento;
private Graphics cg;

// constructor. crea una referencia local al buffer gráfico y define


// el azul como color de los objetos que se dibujen sobre ella
public Espiral( Graphics g ) {
cg = g;
[Link]( [Link] );
}

// Establece el tamaño y posición iniciales de la espiral


public void setTamInicial( int x,int y,int w,int h ) {
iniX = x;
iniY = y;
iniAncho = w;
iniAlto = h;
}

// Establece el incremento para espaciar los giros


public void setTamEspiral( int inc ) {
incremento = inc;
}

// Construye la espiral
public void creaEspiral() {
int cX = iniX;
int cY = iniY;

// Dibuja líneas por pares, cubriéndose entre sí para formar la


// espiral cuadrada hasta alcanzar el tamaño del incremento
while( iniAncho > incremento && iniAlto > incremento )
{
[Link]( cX,cY,(cX+iniAncho),cY );
[Link]( (cX+iniAncho),cY,(cX+iniAncho),(cY+iniAlto) );
cX += iniAncho;
cY += iniAlto;
iniAncho -= incremento;
iniAlto -= incremento;
[Link]( cX,cY,(cX-iniAncho),cY );
[Link]( (cX-iniAncho),cY,(cX-iniAncho),(cY-iniAlto) );
cX -= iniAncho;
cY -= iniAlto;
iniAncho -= incremento;
iniAlto -= incremento;
}
}
}

// Esta es la llamada a la clase desde un Applet Html


public class EspiralTest extends Applet {
Image buffer;
Espiral spiral;
boolean cargado = false;

synchronized public void init() {


// crea un buffer donde dibujar
buffer = createImage( 300,300 );
// crea una nueva espiral
spiral = new Espiral( [Link]() );
// establece el punto inicial y dimensiones
[Link]( 10,10,200,200 );
// establece el incremento
[Link]( 10 );
// construye la espiral
[Link]();
}

synchronized public void paint( Graphics g ) {


[Link]( buffer,25,25,this );
}
}

//-------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:12:14
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Taza extends Applet {


Image imagenes[];
MediaTracker tracker;
int index = 0;
int maxAncho,maxAlto;

// Componentes off-screen para el doble buffering


Image offScrImage;
Graphics offScrCG;
boolean cargado = false;

// Inicializa el applet. Establece el tamaño y carga las imágenes


public void init() {
// Establece el supervisor de imágenes y dimensiones
tracker = new MediaTracker( this );
maxAncho = 78;
maxAlto = 128;
imagenes = new Image[6];

// Establece el doble buffer y cambia el tamaño del applet


try {
offScrImage = createImage( maxAncho,maxAlto );
offScrCG = [Link]();
[Link]( [Link] );
[Link]( 0,0,maxAncho,maxAlto );
resize( maxAncho,maxAlto );
} catch( Exception e ) {
[Link]();
}

// Carga las imágenes en un array


for( int i=0; i < 6; i++ )
{
String imageFich =
new String( "taza"+[Link](i+1)+".gif" );
imagenes[i] = getImage( getDocumentBase(),imageFich );
// Pasamos esta imagen al tracker
[Link]( imagenes[i],i );
}

try {
// Utilizamos el tracker para asegurar que se cargarán
// todas las imágenes
[Link]();
} catch( InterruptedException e ) {
}
cargado = true;
}

// Pinta el fotograma actual


public void paint( Graphics g ) {
if( cargado )
{
// Copia del doble buffer a la pantalla
[Link]( offScrImage,0,0,this );
// Hacemos una pausa y cogemos la siguiente imagen
timerloop();
}
}

// Establecemos la primera imagen


public void start() {
index = 0;

if( [Link]( index ) )


// Pintamos en el doble buffer
[Link]( imagenes[index],0,0,this );
}

// Actualiza los fotogramas para que avance la animación


public void timerloop() {
// Se asegura que la imagen esté presente y la mete en el buffer
if( [Link]( index ) )
{
// Obtiene la siguiente imagen
[Link]( imagenes[index],0,0,this );
index++;

// Vuelve al principio de la animación


if( index >= [Link] )
index = 0;
}
// Bucle de retardo
for( int retardo=0; retardo < 200000; retardo++ );
// Dibujamos el siguiente fotograma
repaint();
}
}

//---------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:12:14
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link];
import [Link];

public class Sonido extends Applet {

// Ejecuta el fichero de sonido que se especifica


public void paint( Graphics g ) {
[Link]( "Prueba de Sonido",25,25 );
play( getDocumentBase(),"[Link]" );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Ago-1996 19:15:54
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

public class Bucle extends Applet {


AudioClip sonido;

// Cogemos el fichero de sonido y lo converitmos en clip


public void init() {
sonido = getAudioClip( getDocumentBase(),"Imagenes/[Link]" );
}

// Pintamos en el applet para que se vea que funciona


public void paint( Graphics g ) {
[Link]( "Prueba de Repetición",25,25 );
}

// Arrancamos el applet y dejamos que el fichero de sonido se


// repita indefinidamente, hasta que llegue el evento de stop
public void start() {
[Link]();
}

// Detenemos la música. Aquí se entra, por ejemplo, cuando se


// cierra la ventana en donde se está ejecutando el applet
public void stop() {
[Link]();
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Sep-1996 06:26:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;

// Este applet presenta tres botones para controla el sonido que se emite.
// Permite que se indique este sonido en el parámetro SONIDO cuando se
// llama desde una página html
//
public class ControlSonido extends Applet implements Runnable {
int ancho = 260;
int alto = 40;

String ficheroSonido;
AudioClip sonido = null;
Button reproducir = null;
Button repeticion = null;
Button parar = null;
Checkbox carga = null;
Event pendiente = null;
Thread thrd = null;
boolean cargando = false;

// Inicializacion del applet


public synchronized void init() {
Dimension d = size();
resize( [Link],[Link] );

// Recogemos el nombre del fichero de sonido que se quiere


// reproducir y que se pasa como parametro al applet
// Si no se indica nada, reproduce el de defecto
ficheroSonido = getParameter( "SONIDO" );
if( ficheroSonido == null )
ficheroSonido = "[Link]";

// Incorporamos al applet los tres botones de control de la


// reproduccion
reproducir = new Button( "Reproducir" );
add( reproducir );
repeticion = new Button( "Repetir" );
add( repeticion );
parar = new Button( "Detener" );
add( parar );

// Incorporamos el checkbox de carga, que si ya esta cargando


// el thread el fichero de sonido, aparece marcada
carga = new Checkbox( "Cargar" );
if( cargando )
[Link]( true );
add( carga );
}

public boolean mouseEnter( Event evt,int x,int y ) {


// Cuando el raton entre en los dominios del applet, en la
// barra de status aparecera en nombre del fichero que se
// esta reproduciendo
showStatus( ficheroSonido );

return( true );
}

public boolean mouseExit( Event evt,int x,int y ) {


// Vaciamos la linea de status cuando sale el raton del applet
showStatus( null );

return( true );
}

// Cuando pulsemos una tecla, se detiene el sonido y matamos


// todo
public synchronized boolean keyDown( Event evt,int key ) {
// Paramos la reproduccion del sonido
if( sonido != null )
[Link]();
// Matamos el thread
if( thrd != null )
[Link]();
// Desmarcamos el checkbox
[Link]( false );
// Reinicializamos variables
sonido = null;
pendiente = null;
thrd = null;
cargando = false;
cargaSonido( null );

return( true );
}

// Controlamos las acciones de los botones del applet


public boolean action( Event evt,Object obj ) {
if( [Link] == null )
return( true );
if( [Link]( reproducir ) )
{
if( !cargaSonido( evt ) )
{
showStatus( "Reproduciendo " + ficheroSonido );
[Link]();
}
}
else if( [Link]( repeticion ) )
{
if( !cargaSonido( evt ) )
{
showStatus( "Repitiendo " + ficheroSonido );
[Link]();
}
}
else if( [Link]( parar ) )
{
pendiente = null;
if( sonido != null )
{
showStatus( "Parando " + ficheroSonido );
[Link]();
}
}
else if( [Link]( carga ) )
cargaSonido( null );

return( true );
}

// Carga el fichero de sonido, creando un thread para que lo haga


synchronized boolean cargaSonido( Event evt ) {
[Link]( true );
if( !cargando )
{
cargando = true;
if( sonido == null )
{
showStatus( "Cargando " + ficheroSonido );
if( evt != null )
pendiente = evt;
thrd = new Thread( this );
[Link]();
return( true );
}
}
if( sonido == null )
{
if( evt != null )
pendiente = evt;
showStatus( "Sigue cargando " + ficheroSonido );
return( true );
}
return( false );
}

public void run() {


// Cargamos el ficehro de sonido
sonido = getAudioClip( getDocumentBase(),ficheroSonido );
showStatus( "Cargado " + ficheroSonido );
// Quitamos el checkbox indicador
remove( carga );
repaint();
// Si estabamos pendientes de la carga del fichero de sonido
// lanzamos un evento indicando que ya esta listo
if( pendiente != null )
action( pendiente,this );
// Ya no esta pendiente la carga del fichero, y el thread
// encargado de esa carga ya ha cumplido su mision
pendiente = null;
thrd = null;
}

public synchronized void stop() {


// Si ya habiamos cargado el fichero de sonido, detenemos
// la musica
if( sonido != null )
[Link]();

// Si esta todavia en activo el thread encargado de la carga del


// fichero de sonido, detenemos la carga y volvemos el
// checkbox indicador a su estado vacio
if( thrd != null )
{
[Link]();
[Link]( false );
sonido = null;
pendiente = null;
thrd = null;
cargando = false;
}
}
}

//------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 02-Dec-1996 12:56:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Esta clase selecciona un color de un array predefinido


class SeleccionColor {
private int i=0;

// Array con los colores para poder manipular la zona


// que se repintara
private Color rgc[] = {
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link],
[Link]
};

// Vamos cogiendo los colores que se suceden en el


// array
public Color generaColor() {
i = i < [Link] ? i : 0;
return( rgc[i++] );
}
}

// Clase que utilizamos para crearnos nuestros propios paneles


// de forma que podemos declarar un color para ellos y así ver
// más claramente el cambio de colores que se produce en cada
// uno de los repintados que hace el sistema
class TutPanel extends Panel {
private String str;
private TextArea ta;
private SeleccionColor sc;

// Constructor de nuestro Panel


public TutPanel( String str,TextArea ta ) {
super();
[Link] = str;
[Link] = ta;
sc = new SeleccionColor();
}
public Insets insets() {
return( new Insets( 5,5,5,5 ) );
}

public void paint( Graphics g ) {


// Indica el panel sobre el que se está repintando
[Link]( "Panel \""+str+"\" pintando...\n" );

// Repinta el rectángulo con el color que le corresponda


// del array para la visualización y después pinta el
// borde del rectángulo en negro para que se vean los
// límites
[Link]( [Link]() );
[Link]( 0,0,size().width-1,size().height-1 );
[Link]( [Link] );
[Link]( 0,0,size().width-1,size().height-1 );
}
}

// Esta es la clase base del ejemplo


public class EjemploGraf extends Applet {
private TextArea ta;
private SeleccionColor sc;

// Creamos todos los Componentes que forman la ventana,


// incorporando los Paneles y botones
public void init() {
ta = new TextArea();
sc = new SeleccionColor();

// Fijamos el layout que vamos a utilizar para posicionar


// los componentes sobre el
setLayout( new BorderLayout() );
add( "North",new Button( "Repintar Solamente el Panel" ) );
add( "Center",ta );

TutPanel p1 = new TutPanel( "1",ta );


TutPanel p2 = new TutPanel( "2",ta );
[Link]( new TutPanel( "2A",ta ) );
[Link]( new TutPanel( "2B",ta ) );
[Link]( p2 );
add( "South",p1 );
}

public Dimension preferredSize() {


return( new Dimension( 400,230 ) );
}

public Insets insets() {


return( new Insets( 5,5,5,5 ) );
}

// Esta es la madre del cordero, llegue el evento que llegue,


// hacemos un repintado del applet, y ya se encargará el AWT de
// repintar la zona que corresponda, que al cambiar nosotros
// el color con que va a hacerlo, veremos un repintado
// multicolor, ya que en cada pasada utilizará un color
// diferente
public boolean action( Event evt,Object obj) {
repaint();
return( true );
}

// Metodo correspondiente al applet en si mismo


public void paint( Graphics g ) {
[Link]( "Applet pintando...\n" );
// Repinta el rectángulo con el color que le corresponda
// del array para la visualización y después pinta el
// borde del rectángulo en negro para que se vean los
// límites
[Link]( [Link]() );
[Link]( 0,0,size().width-1,size().height-1 );
[Link]( [Link] );
[Link]( 0,0,size().width-1,size().height-1 );
}

// Metodo main() para cuando ejecutamos este código como


// aplicación independiente
public static void main( String args[] ) {
Frame f = new Frame( "Ejemplo de Paint" );

EjemploGraf ej = new EjemploGraf();


[Link]();
[Link]( "Center",ej );
[Link]();
[Link]();
}
}

//--------------------------------------- Final del fichero [Link]


INTERFACE DE USUARIO
La interface de usuario es la parte del programa que permite a éste interactuar con el usuario. Las interfaces de
usuario pueden adoptar muchas formas, que van desde la simple línea de comandos hasta las interfaces gráficas que
proporcionan las aplicaciones más modernas.

La interface de usuario es el aspecto más importante de cualquier aplicación. Una aplicación sin un interfaz fácil,
impide que los usuarios saquen el máximo rendimiento del programa. Java proporciona los elementos básicos para
construir decentes interfaces de usuario a través del AWT.

Al nivel más bajo, el sistema operativo transmite información desde el ratón y el teclado como dispositivos de
entrada al programa. El AWT fue diseñado pensando en que el programador no tuviese que preocuparse de detalles
como controlar el movimiento del ratón o leer el teclado, ni tampoco atender a detalles como la escritura en pantalla.
El AWT constituye una librería de clases orientada a objeto para cubrir estos recursos y servicios de bajo nivel.

Debido a que el lenguaje de programación Java es independiente de la plataforma en que se ejecuten sus
aplicaciones, el AWT también es independiente de la plataforma en que se ejecute. El AWT proporciona un conjunto
de herramientas para la construcción de interfaces gráficas que tienen una apariencia y se comportan de forma
semejante en todas las plataformas en que se ejecute. Los elementos de interface proporcionados por el AWT están
implementados utilizando toolkits nativos de las plataformas, preservando una apariencia semejante a todas las
aplicaciones que se creen para esa plataforma. Este es un punto fuerte del AWT, pero también tiene la desventaja de
que una interface gráfica diseñada para una plataforma, puede no visualizarse correctamente en otra diferente.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ESTRUCTURA DEL AWT
La estructura de la versión actual del AWT podemos resumirla en los puntos que exponemos a continuación:

● Los Contenedores contienen Componentes, que son los controles básicos


● No se usan posiciones fijas de los Componentes, sino que están situados a través de una disposición
controlada (layouts)
● El común denominador de más bajo nivel se acerca al teclado, ratón y manejo de eventos
● Alto nivel de abstracción respecto al entorno de ventanas en que se ejecute la aplicación (no hay áreas cliente,
ni llamadas a X, ni hWnds, etc.)
● La arquitectura de la aplicación es dependiente del entorno de ventanas, en vez de tener un tamaño fijo
● Es bastante dependiente de la máquina en que se ejecuta la aplicación (no puede asumir que un diálogo tendrá
el mismo tamaño en cada máquina)
● Carece de un formato de recursos. No se puede separar el código de lo que es propiamente interface. No hay
ningún diseñador de interfaces (todavía)

Tutorial de Java [Anterior] [Indice] [Siguiente]


COMPONENTES Y CONTENEDORES
Una interface gráfica está construida en base a elementos gráficos básicos, los Componentes. Típicos ejemplos de
estos Componentes son los botones, barras de desplazamiento, etiquetas, listas, cajas de selección o campos de texto.
Los Componentes permiten al usuario interactuar con la aplicación y proporcionar información desde el programa al
usuario sobre el estado del programa. En el AWT, todos los Componentes de la interface de usuario son instancias de
la clase Component o uno de sus subtipos.

Los Componentes no se encuentran aislados, sino agrupados dentro de Contenedores. Los Contenedores contienen y
organizan la situación de los Componentes; además, los Contenedores son en sí mismos Componentes y como tales
pueden ser situados dentro de otros Contenedores. También contienen el código necesario para el control de eventos,
cambiar la forma del cursor o modificar el icono de la aplicación. En el AWT, todos los Contenedores son instancias
de la clase Container o uno de sus subtipos.

En la imagen siguiente presentamos una interface de usuario muy simple, con la apariencia que presenta cuando se
visualiza bajo Windows '95.

Los Componentes deben circunscribirse dentro del Contenedor que los contiene. Esto hace que el anidamiento de
Componentes (incluyendo Contenedores) en Contenedores crean árboles de elementos, comenzando con un
Contenedor en la raiz del árbol y expandiéndolo en sus ramas. A continuación presentamos el árbol que representa la
interface que corresponde con la aplicación gráfica generada anteriormente.
Tutorial de Java [Anterior] [Indice] [Siguiente]
TIPOS DE COMPONENTES
En el árbol siguiente mostramos la relación que existe entre todas las clases que proporciona AWT para la creación
de interfaces de usuario, presentando la jerarquía de Clases e Interfaces:

Clases:

● BorderLayout
● CardLayout
● CheckboxGroup
● Color
● Component
❍ Button

❍ Canvas

❍ Checkbox

❍ Choice

❍ Container

■ Panel

■ Window

■ Dialog

■ Frame

❍ Label

❍ List

❍ Scrollbar

❍ TextComponent

■ TextArea

■ TextField

❍ Dimension

❍ Event

❍ FileDialog

❍ FlowLayout

❍ Font

❍ FontMetrics

❍ Graphics

❍ GridLayout

❍ GridBagConstraints

❍ GridBagLayout

❍ Image

❍ Insets

❍ MediaTracker

❍ MenuComponent
■ MenuBar
■ MenuItem
■ CheckboxMenuItem

■ Menu

❍ Point
❍ Polygon
❍ Rectangle
❍ Toolkit

Interfaces:

● LayoutManager
● MenuContainer

En la figura siguiente reproducimos la ventana generada por el código de la aplicación [Link] que
muestra todos los Componentes que proporciona el AWT. Vamos a ver en detalle estos Componentes, pero aquí
podemos observar ya la estética que presentan en su conjunto. La ventana es necesaria porque el programa incluye un
menú, y los menús solamente pueden utilizarse en ventanas. El código contiene un método main() para poder
ejecutarlo como una aplicación independiente.

Tutorial de Java [Anterior] [Indice] [Siguiente]


COMPONENTES
Component es una clase abstracta que representa todo lo que tiene una posición, un tamaño, puede ser pintado en
pantalla y puede recibir eventos.

Los Objetos derivados de la clase Component que se incluyen en el Abstract Window Toolkit son los que aparecen a
continuación:

● Button
● Canvas
● Checkbox
● Choice
● Container
❍ Panel

❍ Window

■ Dialog

■ Frame

● Label
● List
● Scrollbar
● TextComponent
❍ TextArea

❍ TextField

Vamos a ver un poco más en detalle los Componentes que nos proporciona el AWT para incorporar a la creación de
la interface con el usuario.

Tutorial de Java [Anterior] [Indice] [Siguiente]


BOTONES
Veremos ejemplos de cómo se añaden botones a un panel para la interacción del usuario con la aplicación, pero antes
vamos a ver la creación de botones como objetos.

Se pueden crear objetos Button con el operador new:

Button boton;

boton = new Button( "Botón");

La cadena utilizada en la creación del botón aparecerá en el botón cuando se visualice en pantalla. Esta cadena
también se devolverá para utilizarla como identificación del botón cuando ocurra un evento.

Eventos Button

Cada vez que el usuario pulsa un botón, se produce un evento, de la misma forma que se produce un evento cuando
se aprieta el botón del ratón. Los eventos de pulsación de un botón se pueden capturar sobrecargando el método
action():

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Button )
[Link]( (String)obj );
else
[Link]( "Evento No-Button" );
}

La distinción entre todos los botones existentes se puede hacer utilizando el objeto destino pasado por el objeto Event
y comparándolo con los objetos botón que hemos dispuesto en nuestro interface:

import [Link].*;
import [Link];

public class Botones extends Applet {


Button b1,b2,b3;

public void init() {


b1 = new Button( "Botón B1" );
b2 = new Button( "Botón B2" );
b3 = new Button( "Botón B3" );

[Link]( b1 );
[Link]( b2 );
[Link]( b3 );
}

public boolean action( Event evt,Object obj ) {


if( [Link]( b1 ) )
[Link]( "Se ha pulsado el boton B1" );
if( [Link]( b2 ) )
[Link]( "Se ha pulsado el boton B2" );
if( [Link]( b3 ) )
[Link]( "Se ha pulsado el boton B3" );

return true;
}
}

En el applet anterior, [Link], observamos que se imprime el texto asociado al botón que hayamos pulsado.

Botones de Pulsación

Los botones presentados en el applet son los botones de pulsación estándar; no obstante, para variar la representación
en pantalla y para conseguir una interfaz más limpia, AWT ofrece a los programadores otros tipos de botones.

Botones de Lista

Los botones de selección en una lista (Choice) permiten el rápido acceso a una lista de elementos. Por ejemplo,
podríamos implementar una selección de colores y mantenerla en un botón Choice:

import [Link].*;
import [Link];

public class BotonSeleccion extends Applet {


Choice Selector;

public void init() {


Selector = new Choice();

[Link]( "Rojo" );
[Link]( "Verde" );
[Link]( "Azul" );

add( Selector );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Choice )
{
String color = (String)obj;

[Link]( "El color elegido es el " + color );


}

return true;
}
}

En este ejemplo, [Link], la cadena proporcionada al método addItem() será devuelta en el argumento
Object de un evento Choice, por ello en el manejador del botón de selección, comprobamos en primer lugar que se
trate efectivamente de un evento generado en un botón de tipo Choice.

Botones de Marcación

Los botones de comprobación (Checkbox) se utilizan frecuentemente como botones de estado. Proporcionan
información del tipo Sí o No (true o false). El estado del botón se devuelve en el argumento Object de los eventos
Checkbox; el argumento es de tipo booleano: verdadero (true) si la caja se ha seleccionado y falso (false) en otro
caso.

Tanto el nombre como el estado se devuelven en el argumento del evento, aunque se pueden obtener a través de los
métodos getLabel() y getState() del objeto Checkbox.

import [Link].*;
import [Link];

public class BotonComprobacion extends Applet {


Checkbox Relleno;

public void init() {


Relleno = new Checkbox( "Relleno");

add( Relleno );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Checkbox )
[Link]( "CheckBox: " + [Link]() );

return true;
}
}

El sencillo ejemplo anterior, [Link], muestra los cambios que se producen en el estado del botón
cuando la caja está o no seleccionada.

Botones de Selección

Los botones de comprobación se pueden agrupar para formar una interfaz de botón de radio (CheckboxGroup), que
son agrupaciones de botones Checkbox en las que siempre hay un único botón activo.
import [Link].*;
import [Link];

public class BotonRadio extends Applet {


CheckboxGroup Radio;

public void init() {


Radio = new CheckboxGroup();

add( new Checkbox( "Primero",Radio,true) );


add( new Checkbox( "Segundo",Radio,false) );
add( new Checkbox( "Tercero",Radio,false) );
}
}

En el ejemplo anterior, [Link], observamos que siempre hay un botón activo entre los que conforman el
interfaz de comprobación que se ha implementado.

Botones Autocontenidos

La naturaleza orientada a objetos de Java nos da la posibilidad de crear botones completamente autocontenidos. En
este tipo de botón, se construye el manejador de eventos dentro de la propia clase extendida de botón. Se pueden
añadir estos botones a la aplicación, sin tener que preocuparse de los eventos que pudieran generar.

En el ejemplo siguiente, [Link], creamos el botón que muestra la figura, un botón que genera el texto
"Boton Aceptar" por la salida estándar:

import [Link].*;
import [Link];

class BotonAceptar extends Button {

public BotonAceptar() {
setLabel( "Aceptar" );
}

public boolean action( Event evt,Object obj ) {


[Link]( "Boton Aceptar" );
return true;
}
}

public class BotonAuto extends Applet {


BotonAceptar boton;

public void init() {


boton = new BotonAceptar();
add( boton );
}
}

Es de hacer notar que no hay un método action() en la clase applet BotonAuto, la clase BotonAceptar manejará sus
eventos. Si se hubiesen colocado otros objetos en el applet, se podría haber usado un método action() para tratar los
eventos de esos objetos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ETIQUETAS
Las etiquetas (Label) proporcionan una forma de colocar texto estático en un panel, para mostrar información que no
varía, normalmente, al usuario.

El applet [Link] presenta dos textos en pantalla, tal como aparece en la figura siguiente:

import [Link].*;
import [Link];

public class Etiqueta extends Applet {

public void init() {


Label etiq1 = new Label( "Hola Java!" );
Label etiq2 = new Label( "Otra Etiqueta" );

setLayout( new FlowLayout( [Link],10,10) );


add( etiq1 );
add( etiq2 );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


LISTAS
Las listas (List) aparecen en los interfaces de usuario para facilitar a los operadores la manipulación de muchos
elementos. Se crean utilizando métodos similares a los de los botones Choice. La lista es visible todo el tiempo,
utilizándose una barra de desplazamiento para visualizar los elementos que no caben en el área que aparece en la
pantalla.

El ejemplo siguiente, [Link], crea una lista que muestra cuatro líneas a la vez y no permite selección múltiple.

import [Link].*;
import [Link];

public class Lista extends Applet {

public void init() {


List l = new List( 4,false );

[Link]( "Mercurio" );
[Link]( "Venus" );
[Link]( "Tierra" );
[Link]( "Marte" );
[Link]( "Jupiter" );
[Link]( "Saturno" );
[Link]( "Neptuno" );
[Link]( "Urano" );
[Link]( "Pluton" );
add( l );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof List )
[Link]( "Entrada de la Lista: " + obj );

return true;
}
}

Para acceder a los elementos seleccionados se utilizan los métodos getSelectedItem() o getSelectedItems(). Para listas
de selección simple, cualquier selección con doble-click en la lista disparará el método action() de la misma forma
que con los eventos de selección en menús.

En el applet siguiente, [Link], se permite al usuario seleccionar varios elementos de los que constituyen la
lista. En la figura se muestra la apariencia de una selección múltiple en este applet.

import [Link].*;
import [Link];

public class ListaMult extends Applet {


List lm = new List( 6,true );

public void init() {


Button boton = new Button( "Aceptar" );

[Link]( "Mercurio" );
[Link]( "Venus" );
[Link]( "Tierra" );
[Link]( "Marte" );
[Link]( "Jupiter" );
[Link]( "Saturno" );
[Link]( "Neptuno" );
[Link]( "Urano" );
[Link]( "Pluton" );
add( lm );
add( boton );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Button )
{
if( "Aceptar".equals( obj ) )
{
String seleccion[];

seleccion = [Link]();
for( int i=0; i < [Link]; i++ )
[Link]( seleccion[i] );
}
}

return true;
}
}

En este caso de la selección múltiple en una lista, utilizamos un evento externo para disparar las acciones asociadas a
la lista. En el ejemplo, hemos incluido un botón para generar el evento que hace que el applet recoja los elementos
que hay seleccionados en la lista.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CAMPOS DE TEXTO
Para la entrada directa de datos se suelen utilizar los campos de texto, que aparecen en pantalla como pequeñas cajas
que permiten al usuario la entrada por teclado.

Los campos de texto (TextField) se pueden crear vacíos, vacíos con una longitud determinada, rellenos con texto
predefinido y rellenos con texto predefinido y una longitud determinada. El applet siguiente, [Link],
genera cuatro campos de texto con cada una de las características anteriores. La imagen muestra los distintos tipos de
campos.

import [Link].*;
import [Link];

public class CampoTexto extends Applet {


TextField tf1,tf2,tf3,tf4;

public void init() {


// Campo de texto vacío
tf1 = new TextField();
// Campo de texto vacío con 20 columnas
tf2 = new TextField( 20 );
// Texto predefinido
tf3 = new TextField( "Hola" );
// Texto predefinido en 30 columnas
tf4 = new TextField( "Hola",30 );
add( tf1 );
add( tf2 );
add( tf3 );
add( tf4 );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof TextField )
{
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 1: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 2: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 3: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 4: " +
[Link]() );
}
return true;
}
}

Cuando el usuario teclea un retorno de carro en un campo de texto, se genera un evento TextField, que al igual que
con los otros Componentes del AWT podemos capturar con el método action(), tal como se demuestra en el ejemplo.

Tutorial de Java [Anterior] [Indice] [Siguiente]


AREAS DE TEXTO
Java, a través del AWT, permite incorporar texto multilínea dentro de zonas de texto (TextArea). Los objetos
TextArea se utilizan para elementos de texto que ocupan más de una línea, como puede ser la presentación tanto de
texto editable como de sólo lectura.

Para crear una área de texto se pueden utilizar cuatro formas análogas a las que se han descrito en la creación de
Campos de Texto. Pero además, para las áreas de texto hay que especificar el número de columnas.

Se puede permitir que el usuario edite el texto con el método setEditable() de la misma forma que se hacía en el
TextField. En la figura aparece la representación del applet [Link], que presenta dos áreas de texto, una
vacía y editable y otra con un texto predefinido y no editable.

import [Link].*;
import [Link];

public class AreaTexto extends Applet {


TextArea t1,t2;

public void init() {


Button boton = new Button( "Aceptar" );

t1 = new TextArea();
t2 = new TextArea( "Tutorial de Java",5,40 );
[Link]( false );

add( t1 );
add( t2 );
add( boton );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Button )
{
if( "Aceptar".equals( obj ) )
{
String texto = [Link]();

[Link]( texto );
}
}

return true;
}
}

Para acceder al texto actual de una zona de texto se utiliza el método getText(), tal como muestra el código anterior.
Las áreas de texto no generan eventos por sí solas, por lo que hay que utilizar eventos externos, para saber cuando
tenemos que acceder a la información contenida en el TextArea. En este caso hemos utilizado un botón que generará
un evento al pulsarlo que hará que se recoja el texto que haya escrito en el área de texto que constituye el applet.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CANVAS
Si tenemos un applet que trabaja con imágenes directamente, ya sea un applet gráfico o de dibujo, los lienzos o zonas
de dibujo (Canvas) resultan muy útiles.

Los Canvas son un Componente básico que captura eventos de exposición (expose), de ratón y demás eventos
relacionados. La clase base Canvas no responde a estos eventos, pero se puede extender esa clase base creando
subclases en las que controlemos eseos eventos.

Al permitir saltarse el manejo normal de eventos, y junto con los métodos de representación gráfica, los canvas
simplifican la producción de applets que necesitan una única funcionalidad para distintas áreas. Por ejemplo, el
applet [Link], contiene un manejador de eventos que controla el evento mouseDown en el canvas. Si el evento
no se genera en el canvas, se le pasa al applet que lo tratará como un evento de ratón normal.

import [Link].*;
import [Link];

public class Lienzo extends Applet {


Button boton;

public void init() {


setLayout( new BorderLayout( 15,15 ) );
boton = new Button( "Test" );
MiCanvas canv = new MiCanvas( 100,100 );

add( "Center",canv );
add( "South",boton );
}

public boolean action( Event evt,Object obj ) {


[Link]( "Evento: " + obj );
return true;
}

public boolean mouseDown( Event evt,int x, int y ) {


[Link]( "Raton: ("+x+","+y+")" );
return true;
}
}

class MiCanvas extends Canvas {


private int ancho;
private int alto;

public MiCanvas( int anc,int alt ) {


ancho = anc;
alto = alt;

reshape( 0,0,anc,alt );
}

public void paint( Graphics g ) {


[Link]( [Link] );
[Link]( 0,0,ancho,alto );
}

public boolean mouseDown( Event evt,int x, int y ) {


if( x < ancho && y < alto )
{
[Link]( "Raton en Canvas: ("+x+","+y+")" );
return true;
}
return false;
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


BARRAS DE DESPLAZAMIENTO
En determinados applets que necesiten realizar el ajuste de valores lineales en pantalla, resulta útil el uso de barras de
desplazamiento (Scrollbar). Las barras de desplazamiento proporcionan una forma de trabajar con rangos de valores
o de áreas como el Componente TextArea, que proporciona dos barras de desplazamiento automáticamente.

Si queremos implementar un selector de color, como en el applet [Link], podemos utilizar una barra de
desplazamiento para cada uno de los colores primarios.

import [Link].*;
import [Link];

public class Slider extends Applet {


Scrollbar rojo,verde,azul;

public void init() {


rojo = new Scrollbar( [Link],0,1,0,255 );
verde = new Scrollbar( [Link],0,1,0,255 );
azul = new Scrollbar( [Link],0,1,0,255 );

add( rojo );
add( verde );
add( azul );
}
}

Este tipo de interfaz proporciona al usuario un punto de referencia visual de un rango y al mismo tiempo la forma de
cambiar los valores. Por ello, las barras de desplazamiento son Componentes un poco más complejos que los demás,
reflejándose esta complejidad en sus constructores. Al crearlos hay que indicar su orientación, su valor inicial, los
valores mínimo y máximo que puede alcanzar y el porcentaje de rango que estará visible.

También podríamos utilizar una barra de desplazamiento para un rango de valores de color, tal como se muestra en el
ejemplo [Link].
import [Link].*;
import [Link];

public class Ranger extends Applet {


Scrollbar rango;

public void init() {


rango = new Scrollbar( [Link],0,64,0,255 );

add( rango );
}
}

Como se puede ver, el ancho de la barra es mayor, en relación al Scrollbar. En este caso, maxValue representa el
valor máximo para el lado izquierdo de la barra. Si se quieren representar 64 colores simultáneamente, es decir [0-
63] a [192-255], maxValue debería ser 192.

Igual que otros Componentes, las barras de desplazamiento generan eventos; pero al contrario que en el resto, se
tiene que utilizar el método handleEvent() directamente, en lugar del método action(). El destino del evento será un
objeto de la clase Scrollbar, a partir de éste se obtiene la posición de la barra de desplazamiento.

Como se habrá podido observar en los applets anteriores, las barras de desplazamiento no disponen de un display o
zona donde se muestren directamente los valores asociados a los desplazamientos. Al contrario, si se desea eso, es
necesario añadir explícitamente una caja de texto, tal como se muestra en el ejemplo [Link].

import [Link].*;
import [Link];

public class RangoRojo extends Applet {


Scrollbar rango;
TextField valor;
Label etiqueta;

public void init() {


rango = new Scrollbar( [Link],0,1,0,255 );
valor = new TextField( "0",5 );
etiqueta = new Label( "Rojo (0-255)" );

setLayout( new GridLayout( 1,3 ) );


[Link]( false );

add( etiqueta );
add( rango );
add( valor );
}
public boolean handleEvent( Event evt ) {
if( [Link] instanceof Scrollbar )
{
[Link](
[Link]( ((Scrollbar)[Link]).getValue() ) );
return true;
}

return [Link]( evt );


}
}

Ese era el código del applet que construye la ventana de la figura y actualiza el campo de texto asociado. No
implementa ninguna otra acción o evento.

Tutorial de Java [Anterior] [Indice] [Siguiente]


DISEÑO DE COMPONENTES PROPIOS
También podemos atrevernos en el diseño de Componentes propios. Deberán ser una subclase de Canvas o Panel.
Para mostrarlos en pantalla deberemos sobreescribir los métodos paint(), update(), minimumSize() y preferredSize() y
para controlar los eventos tendremos que sobreescribir el método handleEvent().

Para que podamos reusarlos, tenemos que poner cuidado en el diseño, implementando métodos get y set, lanzando
excepciones cuando proceda y permitiendo el acceso a los campos de que disponga nuestro Componente.

Veamos un ejemplo, [Link], en que a partir de la clase Canvas, creamos un separador que será una línea
vertical u horizontal simulando tres dimensiones.

import [Link].*;

public class Separador extends Canvas {


public final static int HORIZONTAL = 0;
public final static int VERTICAL = 1;

int orientacion;
Dimension sepTama,sepDim;

public Separador( int lon,int thick,int orient ) {


orientacion = orient;
if( orient == HORIZONTAL )
sepTama = new Dimension( lon,thick );
else
sepTama = new Dimension( thick,lon );
}

public int getOrientacion() {


return orientacion;
}

public void setOrientacion( int orient) {


if( orient > VERTICAL || orient < HORIZONTAL )
throw new IllegalArgumentException( "Orientación ilegal" );

if( orientacion != orient )


{
orientacion = orient;
sepDim = new Dimension( [Link],[Link] );
invalidate();
}
}
public Dimension preferredSize() {
return sepDim;
}

public Dimension minimumSize() {


return sepDim;
}

public void paint( Graphics g ) {


int x1,y1,x2,y2;
Rectangle bbox = bounds();
Color c = getBackground();
Color brillo = [Link]();
Color oscuro = [Link]();

if( orientacion == HORIZONTAL )


{
x1 = 0;
x2 = [Link] - 1;
y1 = y2 = [Link]/2 - 1;
}
else
{
x1 = x2 = [Link]/2 - 1;
y1 = 0;
y2 = [Link] - 1;
}

[Link]( oscuro );
[Link]( x1,y1,x2,y2 );

[Link]( brillo );
if( orientacion == HORIZONTAL )
[Link]( x1,y1+1,x2,y2+1 );
else
[Link]( x1+1,y1,x2+1,y2 );
}
}

El código que mostramos a continuación [Link], muestra un ejemplo de uso de nuestro separador recién
creado:

import [Link].*;
import [Link];

public class EjSeparador extends Applet {


public final static int HORIZONTAL = 0;
public final static int VERTICAL = 1;

public void init() {


setLayout( new BorderLayout() );

TextField texto1 = new TextField( "Hola",20 );


TextField texto2 = new TextField( "que tal",20 );
Separador raya = new Separador( 8,2,HORIZONTAL );

add( "North",texto1 );
add( "Center",raya );
add( "South",texto2 );
}
}

Y ahora podemos complicar nuestro Componente, o utilizarlo como base para el desarrollo de otros más complejos.
Por ejemplo, vamos a implementar un Componente de Grupo, que extenderemos de la clase Panel y que la
utilizaremos para enmarcar a otros Componentes, tal como se utiliza en otros entornos de ventanas. En el código
fuente de la implementación del Componente, [Link], podemos observar que las acciones seguidas son
exactamente las mismas que en el caso anterior: sobreescribir los métodos que necesitamos y punto.

import [Link].*;

public class Grupo extends Panel {


String Rotulo;
int altoTexto;
int longTexto;
int offset;
static Font defFuente;
FontMetrics metFuente;

public Grupo( String titulo ) {


altoTexto = 20;
longTexto = 20;
offset = 10;
Rotulo = titulo;
setLayout( null );
metFuente = getFontMetrics( defFuente );
}

public void paint( Graphics g ) {


Dimension d = size();
Font fuente = getFont();
if( fuente != null )
metFuente = getFontMetrics( fuente );

longTexto = [Link]( Rotulo );


altoTexto = [Link]();
[Link]( [Link] );
[Link]( 0, altoTexto/2,[Link]-3,[Link]-altoTexto/2-3 );
[Link]( [Link] );
[Link]( 1,altoTexto/2+1,[Link]-3,[Link]-altoTexto/2-3 );
[Link]( getBackground() );
[Link]( offset,altoTexto/2,offset+longTexto+12,altoTexto/2 );
[Link]( offset,altoTexto/2+1,offset+longTexto+12,altoTexto/2+1 );
[Link]( getForeground() );
[Link]( Rotulo,offset+6,altoTexto-3 );
}

public boolean handleEvent( Event evt ) {


return( [Link]( evt ) );
}

public Dimension preferredSize() {


return( minimumSize() );
}

public Dimension minimumSize() {


return( new Dimension( 100,100 ) );
}

static {
defFuente = new Font( "Dialog",0,12 );
}
}

Un ejemplo de uso, lo podremos observar compilando y ejecutando el código que se puestra a continuación,
[Link]:

import [Link].*;
import [Link]

public class EjGrupo extends Applet {


Label etiq;
Button izqda;
Button dcha;
Button todo;

public void init() {


setBackground( [Link] );
setLayout( null );

Grupo g = new Grupo( "Etiqueta" );


add( g );
[Link]( new Font("Dialog",0,14 ) );
[Link]( insets().left + 10,insets().top + 20,290,40 );
[Link]( new FlowLayout( [Link],10,10 ) );
etiq = new Label( "Hola Java!" );
[Link]( etiq );

Grupo g2 = new Grupo( "Botones" );


add( g2 );
[Link]( insets().left+10,80,290,60 );
izqda = new Button( "Bot•n 1" );
[Link]( izqda );
[Link]( 20,20,70,30 );
dcha = new Button( "Bot•n 2" );
[Link]( dcha );
[Link]( 110,20,70,30 );
todo = new Button( "Bot•n 3" );
[Link]( todo );
[Link]( 200,20,70,30 );
}
}
Tutorial de Java [Anterior] [Indice] [Siguiente]
CONTENEDORES
Container es una clase abstracta derivada de Component, que representa a cualquier componente que pueda
contener otros componentes. Se trata, en esencia, de añadir a la clase Component la funcionalidad de adición,
sustracción, recuperación, control y organización de otros componentes.

El AWT proporciona cuatro clases de Contenedores:

● Window
● Frame
● Dialog
● Panel

Además de estos Contenedores, la clase Applet también es un Contenedor, es un subtipo de la clase Panel y puede
tener Componentes.

Window

Es una superficie de pantalla de alto nivel (una ventana). Una instancia de la clase Window no puede estar enlazada
o embebida en otro Contenedor. Una instancia de esta clase no tiene ni título ni borde.

Frame

Es una superficie de pantalla de alto nivel (una ventana) con borde y título. Una instancia de la clase Frame puede
tener una barra de menú. Una instancia de esta clase es mucho más aparente y más semejante a lo que nosotros
entendemos por ventana.

Dialog

Es una superficie de pantalla de alto nivel (una ventana) con borde y título. Una instancia de la clase Dialog no puede
existir sin una instancia asociada de la clase Frame.

Panel

Es un Contenedor genérico de Componentes. Una instancia de la clase Panel, simplemente proporciona un


Contenedor al que ir añadiendo Componentes.

Crear un Contenedor

Antes de poder incorporar Componentes a la interface de usuario que se desea implementar, el programador debe
crear un Contenedor. Cuando se construye una aplicación, el programador debe crear en primer lugar una instancia
de la clase Window o de la clase Frame. Cuando lo que se construye es un applet, ya existe un Frame (la ventana del
navegador). Debido a que la clase Applet está derivada de la clase Panel, el programador puede ir añadiendo
Componentes directamente a la instancia que se crea de la clase Applet.

En el siguiente ejemplo se crea un Frame vacío. El título del Frame, que corresponderá al título de la ventana, se fija
en la llamada al constructor. Un Frame inicialmente está invisible, para poder verlo es necesario invocar al método
show():

import [Link].*;

public class Ejemplo1 {


public static void main( String args[] ) {
Frame f = new Frame( "Ejemplo 1" );

[Link]();
}
}

En el código de ejemplo que sigue, extendemos el código anterior para que la nueva clase sea una subclase de la
clase Panel. En el método main() de esta nueva clase se crea una instancia de ella y se le incorpora un objeto Frame
llamando al método add(). El resultado de ambos ejemplos es idéntico a efectos de apariencia en pantalla:

import [Link].*;

public class Ejemplo2 extends Panel {


public static void main( String args[] ) {
Frame f = new Frame( "Ejemplo 2" );
Ejemplo2 ej = new Ejemplo2();

[Link]( "Center",ej );
[Link]();
[Link]();
}
}

Derivando la nueva clase directamente de la clase Applet en vez de Panel, nuestro ejemplo puede ahora ejecutarse
tanto como una aplicación solitaria como dentro de una página HTML en un navegador. El código siguiente muestra
esta circunstancia:

import [Link].*;

public class Ejemplo3 extends [Link] {


public static void main( String args[] ) {
Frame f = new Frame( "Ejemplo 3" );
Ejemplo3 ej = new Ejemplo3();

[Link]( "Center",ej );
[Link]();
[Link]();
}
}
Un objeto Window, y en algunos casos incluso un objeto Dialog, pueden reemplazar al objeto Frame. Son
Contenedores válidos y los Componentes se añaden en ellos del mismo modo que se haría sobre un Frame.

Añadir Componentes a un Contenedor

Para que la interface sea útil, no debe estar compuesta solamente por Contenedores, éstos deben tener Componentes
en su interior. Los Componentes se añaden al Contenedor invocando al método add() del Contenedor. Este método
tiene tres formas de llamada que dependen del manejador de composición o layout manager que se vaya a utilizar
sobre el Contenedor.

En el código siguiente, incorporamos dos botones al código del último ejemplo. La creación se realiza en el método
init() porque éste siempre es llamado automáticamente al inicializarse el applet. De todos modos, al inciarse la
ejecución se crean los botones, ya que el método init() es llamado tanto por el navegador como por el método main():

import [Link].*;

public class Ejemplo4 extends [Link] {


public void init() {
add( new Button( "Uno" ) );
add( new Button( "Dos" ) );
}

public static void main( String args[] ) {


Frame f = new Frame( "Ejemplo 4" );
Ejemplo4 ej = new Ejemplo4();

[Link]();

[Link]( "Center",ej );
[Link]();
[Link]();
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREACION DE APLICACIONES CON AWT
Para crear una aplicación utilizando AWT, vamos a ver en principio cómo podemos generar el interface de esa
aplicación, mostrando los distintos elementos del AWT, posteriormente volveremos hacia la implementación de la
aplicación.

Interface

● Crear el Marco de la aplicación (Frame)


● Inicializar Fuentes, Colores, Layouts y demás recursos
● Crear menús y Barras de Menús
● Crear los controles, diálogos, ventanas, etc.

Implementación

● Incorporar controladores de eventos


● Incorporar funcionalidad (threads, red, etc.)
● Incorporar un controlador de errores (excepciones)

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR EL MARCO DE LA APLICACION
El Contenedor de los Componentes es el Frame. También es la ventana principal de la aplicación, lo que hace que
para cambiar el icono o el cursor de la aplicación no sea necesario crear métodos nativos; al ser la ventana un Frame,
ya contiene el entorno básico para la funcionalidad de la ventana principal.

Vamos a empezar a crear una aplicación básica, a la que iremos incorporando Componentes. Quizás vayamos un
poco de prisa en las explicaciones que siguen; no preocuparse, ya que lo que no quede claro ahora, lo estará más
tarde. El problema es que para poder profundizar sobre algunos aspectos de Java, necesitamos conocer otros previos,
así que proporcionaremos un ligero conocimiento sobre algunas características de Java y del AWT, para que nos
permitan entrar a fondo en otras; y ya conociendo estas últimas, volveremos sobre las primeras. Un poco lioso, pero
imprescindible.

En el archivo [Link], se encuentra el código completo de la aplicación que vamos ir construyendo a lo


largo de este repaso general por las características de que dispone el AWT.

Comenzaremos el desarrollo de nuestra aplicación básica con AWT a partir del código que mostramos a
continuación:

import [Link].*;

public class AplicacionAWT extends Frame {


static final int HOR_TAMANO = 300;
static final int VER_TAMANO = 200;

public AplicacionAWT() {
super( "Aplicación Java con AWT" );

pack();
resize( HOR_TAMANO,VER_TAMANO );
show();
}

public static void main( String args[] ) {


new AplicacionAWT();
}
}

La clase anterior es un Frame, ya que extiende esa clase y hereda todas sus características. Tiene un método, el
constructor, que no admite parámetros.

Además, se hace una llamada explícita al constructor super, es decir, al constructor de la clase padre, para pasarle
como parámetro la cadena que figurará como el título de la ventana.
La llamada a show() es necesaria, ya que por defecto, los Contenedores del AWT se crean ocultos y hay que
mostrarlos explícitamente. La llamada a pack() hace que los Componentes se ajusten a sus tamaños correctos en
función del Contenedor en que se encuentren situados.

La ejecución de la aplicación mostrará la siguiente ventana en pantalla:

Los atributos fundamentales de la ventana anterior son:

● Marco de 300x200 pixels


● No tiene barra de menú
● No tiene ningún Componente
● Título "Aplicación Java con AWT"
● Color de fondo por defecto
● Layout por defecto
● Fondo de la ventana vacío

Tutorial de Java [Anterior] [Indice] [Siguiente]


INICIALIZAR FUENTES, COLORES Y RECURSOS
Vamos a ir alterando los recursos de la ventana de la aplicación Java que estamos desarrollando con el AWT, para ir
incorporando y visualizando los distintos Componentes que proporciona AWT. Insertemos algunas líneas de código
en el constructor para inicializar la aplicación:

● Cambiemos el font de caracteres a Times Roman de 12 puntos

setFont( new Font( "TimesRoman",[Link],12 ) );

● Fijemos los colores de la ventana para que el fondo sea Blanco y el texto resalte en Negro

setBackground( [Link] );
setForeground( [Link] );

● Seleccionemos como disposición de los Componentes el BorderLayout para este Contenedor

setLayout( new BorderLayout() );

● Incorporemos gráficos. Usamos métodos definidos en la clase Graphics; por ejemplo, reproduzcamos el título
de la ventana en medio con una fuente Time Roman de 24 puntos en color Azul. Es necesario utilizar new con
Font ya que en Java, todo son objetos y no podríamos utilizar un nuevo font de caracteres sin antes haberlo
creado

public void paint( Graphics g ) {


[Link]( new Font( "TimesRoman",[Link],24 ) );
[Link]( [Link] );
[Link]( getTitle(),30,50 );
}

● Incorporemos en la parte inferior de la ventana dos botones: Aceptar y Cancelar

Panel p = new Panel();


[Link]( new Button( "Aceptar" ) );
[Link]( new Button( "Cancelar" ) );
add( "South",p );

Los Componentes se incorporan al Contenedor a través de los dos métodos add() que hay definidos:

add( Component c );
add( String s,Component c );
Los Componentes también se podían haber insertado en el Frame, organizándolos en una cierta forma, teniendo en
cuenta que su manejador de composición es un BorderLayout. Por ejemplo:

add( "South",new Button( "Aceptar ) );


add( "South",new Button( "Cancelar" ) );

Hemos utilizado un Panel y no el segundo método, porque es más útil el organizar los Componentes en pequeñas
secciones. Así, con nuestro código podemos considerar al Panel como una entidad separada del Frame, lo cual
permitiría cambiar el fondo, layout, fuente, etc. del Panel sin necesidad de tocar el Frame.

Si ejecutamos de nuevo la aplicación con los cambios que hemos introducido, aparecerá ante nosotros la ventana que
se muestra a continuación.

Si intentásemos en esta aplicación cerrar la ventana, no sucede nada. Cuando se intenta cerrar la ventana, el sistema
envía un evento que no se está tratando. Incorporemos pues un controlador de eventos y empecemos tratando el
evento WINDOW_DESTROY, generado cuando se intenta cerrar la ventana:

public boolean handleEvent( Event evt ) {


switch( [Link] ) {
case Event.WINDOW_DESTROY:
{
[Link]( 0 );
return true;
}
default:
return false;
}
}

Si ahora ejecutamos de nuevo la aplicación y cerramos la ventana... Efectivamente se cierra, tal como se suponía.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR MENUS Y BARRAS DE MENUS
En la actual versión del AWT que se proporciona con el JDK, sólo se permite crear menús a través de código, ya que
Java todavía no dispone de un formato de recursos y tampoco hay un diseñador como pueden ser AppStudio, Delphi
o X-Designer; aunque terminará habiendo uno, con seguridad.

No hay ningún método para diseñar una buena interface, todo depende del programador. Los menús son el centro de
la aplicación. La diferencia entre una aplicación útil y otra que es totalmente frustrante radica en la organización de
los menús, pero eso, las reglas del diseño de un buen árbol de menús, no están claras. Hay un montón de libros acerca
de la ergonomía y de cómo se debe implementar la interacción con el usuario. Lo cierto es que por cada uno que
defienda una idea, seguro que hay otro que defiende la contraria. Todavía no hay un acuerdo para crear un estándar,
con cada Window Manager se publica una guía de estilo diferente. Así que, vamos a explicar lo básico, sin que se
deba tomar como dogma de fe, para que luego cada uno haga lo que mejor le parezca.

La interface MenuContainer solamente se puede implementar sobre un Frame. Un applet que desee tener un menú,
debe crear un Frame en primer lugar. El código de la función que vamos a ver, crea una barra de menús y se llama
desde el constructor del Frame. La función es private porque no queremos que se pueda llamar desde ninguna otra
clase.

private void InicializaMenus() {


mbarra = new MenuBar();
Menu m = new Menu( "Archivo" );
[Link]( new MenuItem( "Nuevo") );
[Link]( new MenuItem( "Abrir") );
[Link]( new MenuItem( "Guardar") );
[Link]( new MenuItem( "Guardar como") );
[Link]( new MenuItem( "Imprimir") );
[Link]();
[Link]( new MenuItem( "Salir") );
[Link]( m );

m = new Menu( "Ayuda" );


[Link]( new MenuItem( "Ayuda!" ) );
[Link]();
[Link]( new MenuItem( "Acerca de..." ) );
[Link]( m );

setMenuBar( mbarra );
}

El menú que crea esta función tendrá la apariencia que muestra la figura siguiente:
Los eventos generados por las opciones de un menú se manejan del mismo modo que los Botones, Listas, etc. En el
caso de menús, es el evento ACTION_EVENT de la clase [Link] el que se genera y en [Link] se
nos indica la opción seleccionada.

case Event.ACTION_EVENT:
{
if( [Link] instanceof MenuItem )
{
if( "Nuevo".equals( [Link] ) )
AplicacionAWT aAwt = new AplicacionAWT();;
if( "Abrir".equals( [Link] ) )
[Link]( "Opcion -Abrir-" );
if( "Guardar".equals( [Link] ) )
[Link]( "Opcion -Guardar-" );
if( "Guardar como".equals( [Link] ) )
[Link]( "Opcion -Guardar como-" );
if( "Imprimir".equals( [Link] ) )
[Link]( "Opcion -Imprimir-" );
if( "Salir".equals( [Link] ) )
[Link]( 0 );
if( "Ayuda!".equals( [Link] ) )
[Link]( "No hay ayuda" );
if( "Acerca de".equals( [Link] ) )
[Link]( "Opcion -Acerca de-" );
}
}

En el código anterior hemos tratado los eventos del menú. Para más seguridad, aunque no sea estrictamente
necesario, lo primero que hacemos es asegurarnos de que el objeto [Link] es realmente un objeto MenuItem, es
decir, procede de la barra de menús; y después comprobamos la opción que se ha seleccionado.

Como todo, también se puede rizar el rizo y conseguir reproducir los sistemas de menús que estamos acostumbrados
a ver en las aplicaciones que manejamos habitualmente. Un ejemplo de ello son los menús en cascada, semejantes al
que muestra la figura y que ha sido generado mediante la aplicación [Link].
Básicamente se utiliza la técnica ya descrita, pero en vez de crear un nuevo MenuItem se crea un nuevo Menu, lo que
origina el menú en cascada.

No obstante, y volviendo al diseño de interfaces, no debe abusarse de este tipo de menús, porque pueden crear mucha
más confusión al usuario. Siempre se debe tener en mente que los usuarios tienen que navegar habitualmente por una
gran cantidad de menús en las más diversas aplicaciones, por lo que no debemos esconderles demasiado las opciones
que les pueden interesar.

Tutorial de Java [Anterior] [Indice] [Siguiente]


DIALOGOS Y VENTANAS
Una Ventana genérica, Window, puede utilizarse simplemente para que sea la clase padre de otras clases y se puede
intercambiar por un Diálogo, Dialog, sin pérdida de funcionalidad. No se puede decir lo mismo de un Frame.

Se podría crear un menú pop-up con una Ventana, pero lo cierto es que en esta versión del JDK hay un montón de
bugs y no merece la pena el enfrascarse en el intento. No obstante, hay ciertos métodos que están en la clase Window
y que no están presentes en otras clases que pueden resultar interesantes y necesitar una Ventana si queremos
emplearlos. Son:

● getToolkit()
● getWarningString()
● pack()
● toBack()
● toFront()

Un Diálogo es una subclase de Window, que puede tener un borde y ser modal, es decir, no permite hacer nada al
usuario hasta que responda al diálogo. Esto es lo que se usa en las cajas de diálogo "Acerca de...", en la selección en
listas, cuando se pide una entrada numérica, etc.

El código Java que se expone a continuación, implementa el diálogo Acerca de para la aplicación. Esta clase se crea
oculta y necesitaremos llamar al método show() de la propia clase para hacerla visible.

class AboutDialog extends Dialog {


static int HOR_TAMANO = 300;
static int VER_TAMANO = 150;

public AboutDialog( Frame parent ) {


super( parent,"Acerca de...",true );
[Link]( false );
setBackground( [Link] );
setLayout( new BorderLayout() );

Panel p = new Panel();


[Link]( new Button( "Aceptar" ) );
add( "South",p );
resize( HOR_TAMANO,VER_TAMANO );
}

public void paint( Graphics g ) {


[Link]( [Link] );
[Link]( "Aplicación Java con AWT",
HOR_TAMANO/4,VER_TAMANO/3 );
[Link]( "Versión 1.00",
HOR_TAMANO/3+15,VER_TAMANO/3+20 );
}

public boolean handleEvent( Event evt ) {


switch( [Link] ) {
case Event.ACTION_EVENT:
{
if( "Aceptar".equals( [Link] ) )
{
hide();
return true;
}
}
default:
return false;
}
}
}

La ventana que aparece en pantalla generada por la clase anterior es la que muestra la figura:

Las aplicaciones independientes deberían heredar tomando como padre la ventana principal de esa aplicación. Así
pueden implementar la interface MenuContainer y proporcionar menús.

No hay razón aparente para que sea una subclase de la clase Frame, pero si se quiere proporcionar funcionalidad
extra, sí debería serlo, en vez de serlo de su padre: Window. Esto es así porque Frame implementa la interface
MenuContainer, con lo cual tiene la posibilidad de proporcionar menús y cambiar el cursor, el icono de la aplicación,
etc.

Un ejemplo más complicado de aplicación gráfica basada en el AWT es el convertidor de decimal a


binario/octal/hexadecimal/base36, [Link], cuya presentación en pantalla es la que muestra la figura
siguiente.
En la construcción de esta nueva aplicación se utilizan elementos que se presentan en profundidad en secciones
posteriores de este Tutorial.

Tutorial de Java [Anterior] [Indice] [Siguiente]


PANELES
La clase Panel es el más simple de los Contenedores de Componentes gráficos. En realidad, se trataba de crear una
clase no-abstracta (Container sí lo es) que sirviera de base a los applet y a otras pequeñas aplicaciones. La clase
Panel consta de dos métodos propios: el constructor, cuyo fin es crear un nuevo Panel con un LayoutManager de tipo
FlowLayout (el de defecto), y el método addNotify() que, sobrecargando la función del mismo nombre en la clase
Container, llama al método createPanel() del Toolkit adecuado, creando así un PanelPeer. El AWT enviará así al
Panel (y por tanto al applet) todos los eventos que sobre él ocurran. Esto que puede parecer un poco rebuscado,
obedece al esquema arquitectónico del AWT; se trata del bien conocido esquema de separación
interface/implementación que establece por un lado una clase de interface y por otro distintas clases de
implementación para cada una de las plataformas elegidas.

El uso de Paneles permite que las aplicaciones puedan utilizar múltiples layouts, es decir, que la disposición de los
componentes sobre la ventana de visualización pueda modificarse con mucha flexibilidad. Permite que cada
Contenedor pueda tener su propio esquema de fuentes de caracteres, color de fondo, zona de diálogo, etc.

Podemos, por ejemplo, crear una barra de herramientas para la zona superior de la ventana de la aplicación o
incorporarle una zona de estado en la zona inferior de la ventana para mostrar información útil al usuario. Para ello
vamos a implementar dos Paneles:

class BarraHerram extends Panel {


public BarraHerram() {
setLayout( new FlowLayout() );
add( new Button( "Abrir" ) );
add( new Button( "Guardar" ) );
add( new Button( "Cerrar" ) );

Choice c = new Choice();


[Link]( "Times Roman" );
[Link]( "Helvetica" );
[Link]( "System" );
add( c );
add( new Button( "Ayuda" ) );
}
}

class BarraEstado extends Panel {


Label texto;
Label mas_texto;

public BarraEstado() {
setLayout( new FlowLayout() );
add( texto = new Label( "Creada la barra de estado" ) );
add( mas_texto = new Label( "Información adicional" ) );
}

public void verEstado( String informacion ) {


[Link]( informacion );
}
}

Ahora, para dar funcionalidad, debemos crear los objetos correspondientes a la barra de herramientas y a la barra de
estado con new; al contrario que en C++, en Java todos los objetos deben ser creados con el operador new:

add( "North",tb = new ToolBar() );


add( "South",sb = new StatusBar() );

También vamos a incorporar un nuevo evento a nuestro controlador, para que maneje los eventos de tipo
ACTION_EVENT que le llegarán cuando se pulsen los botones de la barra de herramientas o se realice alguna
selección, etc.

case Event.ACTION_EVENT:
{
[Link]( [Link]() );
return true;
}

Cuando la aplicación reciba este tipo de evento, alterará el contenido de la barra de estado para mostrar la
información de la selección realizada o el botón pulsado.

Al final, la apariencia de la aplicación en pantalla es la que presenta la figura anterior.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LAYOUTS
Los layout managers o manejadores de composición, en traducción literal, ayudan a adaptar los diversos
Componentes que se desean incorporar a un Panel, es decir, especifican la apariencia que tendrán los Componentes a
la hora de colocarlos sobre un Contenedor. Java dispone de varios, en la actual versión, tal como se muestra en la
imagen:

¿Por qué Java proporciona estos esquemas predefinidos de disposición de componentes? La razón es simple:
imaginemos que deseamos agrupar objetos de distinto tamaño en celdas de una rejilla virtual: si confiados en nuestro
conocimiento de un sistema gráfico determinado, codificamos a mano tal disposición, deberemos preveer el
redimensionamiento del applet, su repintado cuando sea cubierto por otra ventana, etc., además de todas las
cuestiones relacionadas con un posible cambio de plataforma (uno nunca sabe a donde van a ir a parar los propios
hijos, o los applets).

Sigamos imaginando, ahora, que un hábil equipo de desarrollo ha previsto las disposiciones gráficas más usadas y ha
creado un gestor para cada una de tales configuraciones, que se ocupará, de forma transparente para nosotros, de
todas esas cuitas de formatos. Bien, pues estos gestores son instancias de las distintas clases derivadas de Layout
Manager y que se utilizan en el applet que genera la figura siguiente, donde se muestran los diferentes tipos de
layouts que proporciona el AWT.

En el applet que genera la figura siguiente, se utilizan los diferentes tipos de layouts que proporciona el AWT.
El ejemplo [Link], ilustra el uso de paneles, listas, barras de desplazamiento, botones, selectores, campos de
texto, áreas de texto y varios tipos de layouts.

En el tratamiento de los Layouts se utiliza un método de validación, de forma que los Componentes son marcados
como no válidos cuando un cambio de estado afecta a la geometría o cuando el Contenedor tiene un hijo incorporado
o eliminado. La validación se realiza automáticamente cuando se llama a pack() o show(). Los Componentes visibles
marcados como no válidos no se validan automáticamente.

En el ejemplo de control de eventos que se muestra a continuación, la llamada a validate() hace que se realicen en un
bloque, en un solo paso, todos los cálculos necesarios para la validación del layout.

public boolean action( Event evt,Object obj ) {


if( [Link]( "Cambia Font" ) )
{
[Link]( nuevoFont );
[Link]( nuevoFont );
[Link]( nuevoFont );
[Link]( nuevoFont );

validate();
return true;
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


FlowLayout
Es el más simple y el que se utiliza por defecto en todos los Paneles si no se fuerza el uso de alguno de los otros. Los
Componentes añadidos a un Panel con FlowLayout se encadenan en forma de lista. La cadena es horizontal, de
izquierda a derecha, y se puede seleccionar el espaciado entre cada Componente.

Por ejemplo, podemos poner un grupo de botones con la composición por defecto que proporciona FlowLayout:

import [Link].*;
import [Link];

public class AwtFlow extends Applet {


Button boton1,boton2,boton3;

public void init() {


boton1 = new Button( "Aceptar" );
boton2 = new Button( "Abrir" );
boton3 = new Button( "Cerrar" );

add( boton1 );
add( boton2 );
add( boton3 );
}
}

Este código, [Link], construye tres botones con un pequeño espacio de separación entre ellos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


BorderLayout
La composición BorderLayout (de borde) proporciona un esquema más complejo de colocación de los Componentes
en un panel. La composición utiliza cinco zonas para colocar los Componentes sobre ellas: Norte, Sur, Este, Oeste y
Centro. Es el layout o composición que se utilizan por defecto Frame y Dialog.

El Norte ocupa la parte superior del panel, el Este ocupa el lado derecho, Sur la zona inferior y Oeste el lado
izquierdo. Centro representa el resto que queda, una vez que se hayan rellenado las otras cuatro partes.

Con BorderLayout se podrían representar botones de dirección:

import [Link].*;
import [Link];

public class AwtBord extends Applet {


Button botonN,botonS,botonE,botonO,botonC;

public void init() {


setLayout( new BorderLayout() );

botonN = new Button( "Norte" );


botonS = new Button( "Sur" );
botonE = new Button( "Este" );
botonO = new Button( "Oeste" );
botonC = new Button( "Centro" );

add( "North",botonN );
add( "South",botonS );
add( "East",botonE );
add( "West",botonO );
add( "Center",botonC );
}
}
Este es el código, [Link], que genera el applet de botones de dirección:

Tutorial de Java [Anterior] [Indice] [Siguiente]


GridLayout
La composición GridLayout proporciona gran flexibilidad para situar Componentes. El layout se crea con un número
de filas y columnas y los Componentes van dentro de las celdas de la tabla así definida.

En la figura siguiente se muestra un panel que usa este tipo de composición para posicionar seis botones en su
interior, con tres filas y dos columnas que crearán las seis celdas necesarias para albergar los botones:

import [Link].*;
import [Link];

public class AwtGrid extends Applet {


Button boton1,boton2,boton3,boton4,boton5,boton6;

public void init() {


setLayout( new GridLayout( 3,2 ) );

boton1 = new Button( "1" );


boton2 = new Button( "2" );
boton3 = new Button( "3" );
boton4 = new Button( "4" );
boton5 = new Button( "5" );
boton6 = new Button( "6" );

add( boton1 );
add( boton2 );
add( boton3 );
add( boton4 );
add( boton5 );
add( boton6 );
}
}

Este es el código, [Link], que genera la imagen del ejemplo.


Tutorial de Java [Anterior] [Indice] [Siguiente]
GridBagLayout
Es igual que la composición de GridLayout, con la diferencia que los Componentes no necesitan tener el mismo
tamaño. Es quizá el layout más sofisticado y versátil de los que actualmente soporta AWT.

En la figura siguiente vemos la imagen generada por un panel que usa el GridBagLayout para soportar diez botones
en su interior:

import [Link].*;
import [Link];

public class AwtGBag extends Applet {

public void init() {


GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();

setLayout( gridbag );
[Link] = [Link];
[Link] = 1.0;
Button boton0 = new Button( "Botón 0" );
[Link]( boton0,gbc );
add( boton0 );
Button boton1 = new Button( "Botón 1" );
[Link]( boton1,gbc );
add( boton1 );
Button boton2 = new Button( "Botón 2" );
[Link]( boton2,gbc );
add( boton2 );

[Link] = [Link];
Button boton3 = new Button( "Botón 3" );
[Link]( boton3,gbc );
add( boton3 );

[Link] = 0.0;
Button boton4 = new Button( "Botón 4" );
[Link]( boton4,gbc );
add( boton4 );

[Link] = [Link];
Button boton5 = new Button( "Botón 5" );
[Link]( boton5,gbc );
add( boton5 );

[Link] = [Link];
Button boton6 = new Button( "Botón 6" );
[Link]( boton6,gbc );
add( boton6 );

[Link] = 1;
[Link] = 2;
[Link] = 1.0;
Button boton7 = new Button( "Botón 7" );
[Link]( boton7,gbc );
add( boton7 );

[Link] = 0.0;
[Link] = [Link];
[Link] = 1;
Button boton8 = new Button( "Botón 8" );
[Link]( boton8,gbc );
add( boton8 );
Button boton9 = new Button( "Botón 9" );
[Link]( boton9,gbc );
add( boton9 );
}
}

Este es el código, [Link], que utilizamos para generar la imagen del ejemplo.

Para aprovechar de verdad todas las posibilidades que ofrece este layout, hay que pintar antes en papel como van a
estar posicionados los Componentes; utilizar gridx, gridy, gridwidth y gridheight en vez de
[Link], porque en el proceso de validación del layout pueden quedar todos los
Componentes en posición indeseable. Además, se deberían crear métodos de conveniencia para hacer más fácil el
posicionamiento de los Componentes. En el ejemplo siguiente, [Link], creamos el método de
conveniencia addComponente() para la incorporación de nuevos Componentes al layout, lo que hace más sencillo el
manejo de los Constraints:

import [Link].*;
import [Link];

public class AwtGBagConv extends Applet {


GridBagLayout gridbag = new GridBagLayout();

void addComponente( Component comp,int gridx,int gridy,


int gridw,int gridh ) {
GridBagConstraints gbc = new GridBagConstraints();
[Link] = gridx;
[Link] = gridy;
[Link] = gridw;
[Link] = gridh;
[Link]( comp,gbc );
add( comp );
}

public void init() {


setLayout( gridbag );
addComponente( new Label( "Nombre:" ),0,0,1,1 );
addComponente( new TextField( 12 ),1,0,2,1 );
addComponente( new TextArea( 5,20 ),0,1,2,2 );
addComponente( new Checkbox( "Sí?" ),2,1,1,1 );
addComponente( new List(),2,2,1,1 );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


CardLayout
Este es el tipo de composición que se utiliza cuando se necesita una zona de la ventana que permita colocar distintos
Componentes en esa misma zona. Este layout suele ir asociado con botones de lista (Choice), de tal modo que cada
selección determina el panel (grupo de componentes) que se presentarán.

En la figura siguiente mostramos el efecto de la selección sobre la apriencia de la ventana que contiene el panel con
la composición CardLayout:

import [Link].*;
import [Link];

public class AwtCard extends Applet {


Panel card;
final static String PanelBoton = "Panel con Botones";
final static String PanelTexto = "Panel con Campo de Texto";

public void init() {


setLayout( new BorderLayout() );

Panel ac = new Panel();


Choice c = new Choice();

[Link]( PanelBoton );
[Link]( PanelTexto );
[Link]( c );
add( "North",ac );

card = new Panel();


[Link]( new CardLayout() );

Panel p1 = new Panel();


[Link]( new Button( "Botón 1" ) );
[Link]( new Button( "Botón 2" ) );
[Link]( new Button( "Botón 3" ) );
Panel p2 = new Panel();
[Link]( new TextField( "Texto",20 ) );

[Link]( PanelBoton,p1 );
[Link]( PanelTexto,p2 );
add( "Center",card );
}

public boolean action( Event evt,Object arg ) {


if( [Link] instanceof Choice )
{
( (CardLayout)[Link]() ).show( card,(String)arg );
return true;
}
return false;
}
}

Este es el código, [Link], que hemos utilizado para generar las dos imágenes que muestran el funcionamiento
de la composición CardLayout.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CREAR UN LAYOUT
Se puede crear un Layout personalizado en base a la interface LayoutManager. Hay que redefinir los cinco métodos
que utiliza este interface, lo cual puede no resultar sencillo, así que en lo posible se deben utilizar los métodos de
colocación de componentes que proporciona AWT, fundamentalmente en el momento en que parezca que ninguno de
los Layouts que hemos visto satisface nuestras exigencias, deberíamos volver a comprobar que el GridBagLayout,
que es el más flexible, de verdad no cumple nuestros requerimientos.

No obstante, vamos a implementar un layout propio, [Link], para poder colocar los Componentes en
posiciones absolutas del panel que contenga a este layout. Derivamos nuestro nuevo layout de LayoutManager y
redefinimos los cinco métodos de la clase para que podamos posicionar los Componentes.

import [Link].*;

public class MiLayout implements LayoutManager {

public MiLayout() {
}

public void addLayoutComponent( String name,Component comp ) {


}

public void removeLayoutComponent( Component comp ) {


}

public Dimension preferredLayoutSize( Container parent ) {


Insets insets = [Link]();
int numero = [Link]();
int ancho = 0;
int alto = 0;

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();
Point p = [Link]();
if( ( p.x + [Link] ) > ancho )
ancho = p.x + [Link];
if( ( p.y + [Link] ) > alto )
alto = p.y + [Link];
}
return new Dimension( [Link] + [Link] + ancho,
[Link] + [Link] + alto );
}
public Dimension minimumLayoutSize( Container parent ) {
Insets insets = [Link]();
int numero = [Link]();
int ancho = 0;
int alto = 0;

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();
Point p = [Link]();
if( ( p.x + [Link] ) > ancho )
ancho = p.x + [Link];
if( ( p.y + [Link] ) > alto )
alto = p.y + [Link];
}
return new Dimension( [Link] + [Link] + ancho,
[Link] + [Link] + alto );
}

public void layoutContainer( Container parent ) {


int numero = [Link]();

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();
[Link]( [Link],[Link] );
}
}
}

Y ahora vamos a ver un ejemplo en que utilicemos nuestro Layout. Posicionaremos tres botones en el panel y un
campo de texto con una etiqueta precediéndolo. La apriencia que tendrá en pantalla será la que se muestra en la
figura:

import [Link].*;
import [Link];

public class AwtLibre extends Applet {


Button boton1,boton2,boton3;
Label etiqueta;
TextField texto;

public void init() {


setLayout( new MiLayout() );

boton1 = new Button( "Aceptar" );


boton2 = new Button( "Abrir" );
boton3 = new Button( "Cerrar" );
etiqueta = new Label( "Texto" );
texto = new TextField( "",20 );

add( boton1 );
add( boton2 );
add( boton3 );
add( etiqueta );
add( texto );

[Link]( 0,10 );
[Link]( 70,10 );
[Link]( 30,40 );
[Link]( 75,70 );
[Link]( 120,70 );
}
}

Este código, [Link], es el que genera la imagen anterior creando un applet que utiliza nuestro recién creado
layout.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CONTROL DE EVENTOS
En el pasado, un programa que quisiera saber lo que estaba haciendo el usuario, debía recoger la información él
mismo. En la práctica, esto significaba que una vez inicializado, el programa entraba en un gran bucle en el que
continuamente se bloqueaba para comprobar que el usuario estuviese haciendo algo interesante (por ejemplo, pulsar
un botón, pulsar una tecla, mover una barra o mover el ratón) y tomar las acciones oportunas. Esta técnica se conoce
como polling.

El polling funciona, pero se vuelve demasiado difícil de manejar con las aplicaciones modernas por dos razones
fundamentales: Primero, el uso de polling tiende a colocar todo el código de control de eventos en una única
localización (dentro de un gran bucle); segundo, las interacciones dentro del gran bucle tienden a ser muy complejas.
Además, el polling necesita que el programa esté ejecutando el bucle, consumiendo tiempo de CPU, mientras está
esperando a que el usuario se decida a hacer algo, lo que supone un gran despilfarro de recursos.

El AWT resuelve estos problemas abrazando un paradigma diferente, en el que están basados todos los sistemas
modernos de ventanas: la orientación a eventos. Dentro del AWT, todas las acciones que pueda realizar el usuario
caen dentro de un gran saco que son los eventos. Un evento describe, con suficiente detalle, una acción particular del
usuario. En lugar de que el programa activamente recoja todos los eventos generados por el usuario, el sistema Java
avisa al programa cuando se produce un evento interesante.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Event
Un contenedor soltado en un entorno gráfico se convierte en rápido receptor de eventos de todo tipo, singularmente
de los relacionados con el movimiento del ratón, pulsaciones de teclas, creación/movimiento/destrucción de partes
gráficas y, por último, los referidos a acciones del usuario respecto de componentes (elección de un menú, pulsación
de un botón, etc.).

La clase Event es el jugador principal en el juego de los eventos. Intenta capturar las características fundamentales de
todos los eventos que genera el usuario. Los datos miembro de la clase Event son los que se indican a continuación:

id - El tipo de evento que se ha producido

target - Componente sobre el que se ha producido el evento

x, y - Las coordenadas en donde se ha producido el evento relativas al Componente que actualmente está procesando
ese evento. El origen se toma en la esquina superior izquierda del Componente

key - Para eventos de teclado, es la tecla que se ha pulsado. Su valor será el valor Unicode del carácter que representa
la tecla. Otros valores que puede tomas son los de las teclas especiales como INICIO, FIN, F1, F2, etc.

when - Instante en que se ha producido el evento

modifiers - La combinación aritmética del estado en que se encuentran las teclas modificadoras Mays, Alt, Ctrl.

clickCount - El número de clicks de ratón consecutivos. Sólo tiene importancia en los eventos MOUSE_DOWN

arg - Es un argumento dependiente del evento. Para objetos Button, este objeto arg es un objeto String que contiene
la etiqueta de texto del botón

evt - El siguiente evento en una lista encadenada de eventos

Una instancia de la clase Event será creada por el sistema Java cada vez que se genere un evento. Es posible, sin
embargo, que un programa cree y envíe eventos a los Componentes a través de su método postEvent().

Tutorial de Java [Anterior] [Indice] [Siguiente]


TIPOS DE EVENTOS
Los eventos se catalogan por su naturaleza, que se indicará en el miembro id de su estructura. Los grandes grupos de
eventos son:

Eventos de Ventana

Son los que se generan en respuesta a los cambios de una ventana un frame o un dialogo.

● WINDOW_DESTROY
● WINDOW_EXPOSE
● WINDOW_ICONIFY
● WINDOW_DEICONIFY
● WINDOW_MOVED

Eventos de Teclado

Son generados en respuesta a cuando el usuario pulsa y suelta una tecla mientras un Componente tiene el foco de
entrada.

● KEY_PRESS
● KEY_RELEASE
● KEY_ACTION
● KEY_ACTION_RELEASE

Eventos de Ratón

Son los eventos generados por acciones sobre el ratón dentro de los límites de un Componente.

● MOUSE_DOWN
● MOUSE_UP
● MOUSE_MOVE
● MOUSE_ENTER
● MOUSE_EXIT
● MOUSE_DRAG

Eventos de Barras

Son los eventos generados como respuesta a la manipulación de barras de desplazamiento (scrollbars).

● SCROLL_LINE_UP
● SCROLL_LINE_DOWN
● SCROLL_PAGE_UP
● SCROLL_PAGE_DOWN
● SCROLL_ABSOLUTE

Eventos de Lista

Son los eventos generados al seleccionar elementos de una lista.

● LIST_SELECT
● LIST_DESELECT

Eventos Varios

Son los eventos generados en función de diversas acciones.

● ACTION_EVENT
● LOAD_FILE
● SAVE_FILE
● GOT_FOCUS
● LOST_FOCUS

El applet [Link] está diseñado para observar los eventos que se producen sobre él. Cada vez que se genera
un evento, el applet responde imprimiendo el evento que ha capturado en la línea de comandos desde donde se ha
lanzado el applet.

Una vez que se haya compilado el código y cargado el applet en el appletviewer o en un navegador con soporte Java,
jugar un poco con el applet. Mover el cursor dentro del applet, picar con el ratón, picar y arrastrar, teclear algo,
cambiar el tamaño de la ventana y taparla y destaparla con otra. Las acciones anteriores harán que en la ventana en
donde se haya lanzado el appletviewer, o en la consola Java en caso de Netscape, vayan apareciendo los textos que
indican los eventos que está recibiendo el applet.

Lo cierto es que el uso de [Link]() en un applet es algo que no debería utilizarse, e incluso
puede llegar a no funcionar en algunos sistemas, pero tenía la ventaja de ser la forma más fácil de ver los eventos. No
obstante, vamos a reescribir el código del applet utilizando una Lista.

Una Lista es una lista de cadenas o Strings definidas en [Link]. Crearemos una lista de 25 líneas y no
permitiremos selección múltiple, que son los dos parámetros que necesita el constructor del objeto List. El código
[Link] que se muestra a continuación corresponde al anterior ejemplo un poco modificado.

import [Link].*;
import [Link];

public class EventosList extends Applet {


List lista;

public void init() {


lista = new List( 25,false );
add( lista );
[Link]( "Evento init" );
}
public void start() {
[Link]( "Evento start" );
}

public void destroy() {


[Link]( "Evento destroy" );
}

public void paint( Graphics g ) {


[Link]( "Evento paint" );
}

public void update( Graphics g ) {


[Link]( "Evento update" );
}

public boolean mouseUp( Event evt,int x, int y ) {


[Link]( "Evento mouseUp en ("+x+","+y+")" );
return false;
}

public boolean mouseDown( Event evt,int x, int y ) {


[Link]( "Evento mouseDown en ("+x+","+y+")" );
return false;
}

public boolean mouseDrag( Event evt,int x, int y ) {


[Link]( "Evento mouseDrag en ("+x+","+y+")" );
return false;
}

public boolean mouseMove( Event evt,int x, int y ) {


[Link]( "Evento mouseMove en ("+x+","+y+")" );
return false;
}

public boolean mouseEnter( Event evt,int x, int y ) {


[Link]( "Evento mouseEnter en ("+x+","+y+")" );
return false;
}

public boolean mouseExit( Event evt,int x, int y ) {


[Link]( "Evento mouseExit" );
return false;
}

public boolean keyDown( Event evt,int x ) {


[Link]( "Evento keyDown,carácter "+(char)x );
return true;
}

public void getFocus() {


[Link]( "Evento getFocus" );
}
public void gotFocus() {
[Link]( "Evento gotFocus" );
}

public void lostFocus() {


[Link]( "Evento lostFocus" );
}
}

El applet [Link] muestra los datos que componen cada evento que se produce. Hemos incorporado un
botón y una lista, tal como se puede apreciar en la figura, para poder generar diferentes eventos.

Moviendo el ratón o actuando sobre los dos Componentes, botón y lista, podemos observar los datos que el sistema
Java envía en la recolección de esos eventos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


GENERACION Y PROPAGACION DE EVENTOS
Tomemos el applet, [Link], que aparece en la figura siguiente. Consta de dos instancias de la clase Button,
embebidas dentro de una instancia de la clase Panel. Esta instancia está a su vez embebida dentro de otra instancia de
la clase Panel. Esta última instancia de la clase Panel está situada junto a una instancia de la clase TextArea, y
ambas están embebidas dentro de una instancia de la clase Applet.

La figura siguiente presenta los elementos que conforman este applet en forma de árbol, con el TextArea y Button
como hojas y la instancia de Applet como raiz.

Cuando un usuario interactúa con el applet, el sistema Java crea una instancia de la clase Event y rellena sus datos
miembro con la información necesaria para describir la acción. Es en ese momento cuando el sistema Java permite al
applet controlar el evento. Este control comienza por el Componente que recibe inicialmente el evento (por ejemplo,
el botón que ha sido pulsado) y se desplaza hacia arriba en el árbol de Componentes, componente a componente,
hasta que alcanza al Contenedor de la raíz del árbol. Durante este camino, cada Componente tiene oportunidad de
ignorar el evento o reaccionar ante él en una (o más) de las forma siguientes:

● Modificar los datos miembros de la instancia de Event


● Entrar en acción y realizar cálculos basados en la información contenida en el evento
● Indicar al sistema Java que el evento no debería propagarse más arriba en el árbol

El sistema Java pasa información del evento a un Componente a través del método handleEvent() del Componente.
Todos los métodos handleEvent() deben ser de la forma:

public boolean handleEvent( Event evt )

Un controlador de eventos solamente necesita una información: una referencia a la instancia de la clase Event que
contiene la información del evento que se ha producido.

El valor devuelto por el método handleEvent() es importante. Indica al sistema Java si el evento ha sido o no
completamente controlado por el controlador. Un valor true indica que el evento ha sido controlado y que su
propagación debe detenerse. Un valor false indica que el evento ha sido ignorado, o que no ha sido controlado en su
totalidad y debe continuar su propagación hacia arriba en el árbol de Componentes.

Veamos la descripción de una acción con el applet de la figura anterior. El usuario pulsa el botón "Uno". El sistema
run-time del lenguaje Java capturará la información sobre el evento (el número de clicks, la localización del click, la
hora en que se ha producido la pulsación y el Componente que ha recibido el click) y empaqueta todos esos datos en
una instancia de la clase Event. El sistema Java comienza entonces por el Componente que ha sido pulsado (en este
caso, el botón "Uno") y, a través de una llamada al método handleEvent() del Componente, ofrece a éste la
posibilidad de reaccionar ante el evento. Si el Componente no controla el evento, o no lo hace completamente
(indicado por un valor de retorno false), el sistema Java presentará la instancia de Event al siguiente Componente por
encima en el árbol (en este caso, una instancia de la clase Panel). El sistema Java continúa de este mismo modo hasta
que el evento es controlado en su totalidad o ya no hay Componentes a los que informar. En la figura siguiente
mostramos el camino recorrido por el evento en su intento de que algún Componente lo controle.

Cada Componente del applet añade una línea al objeto TextArea indicando que ha recibido un evento. Luego permite
que el evento se propague al siguiente Componente.

El código del controlador de eventos usado en el ejemplo es el que muestran las siguientes líneas:

public boolean handleEvent( Event evt) {


if( [Link] == Event.ACTION_EVENT )
[Link]( "Panel " + str + " recibe action...\n" );
else if( [Link] == Event.MOUSE_DOWN )
[Link]( "Panel " + str + " recibe mouse_down...\n" );

return [Link]( evt );


}

Tutorial de Java [Anterior] [Indice] [Siguiente]


METODOS DE CONTROL DE EVENTOS
El método handleEvent() es un lugar para que el programador pueda insertar código para controlar los eventos. A
veces, sin embargo, un Componente solamente estará interesado en eventos de un cierto tipo (por ejemplo, eventos
del ratón). En estos casos, el programador puede colocar el código en un método de ayuda, en lugar de colocarlo en
el método handleEvent().

No hay métodos de ayuda para ciertos tipos de eventos, aquí está la lista de los que están disponibles para los
programadores:

action( Event evt,Object obj )


gotFocus( Event evt,Object obj )
lostFocus( Event evt,Object obj )
mouseEnter( Event evt,int x,int y )
mouseExit( Event evt,int x,int y )
mouseMove( Event evt,int x,int y )
mouseUp( Event evt,int x,int y )
mouseDown( Event evt,int x,int y )
mouseDrag( Event evt,int x,int y )
keyDown( Event evt,int key )
keyUp( Event evt,int key )

false indicará que el método de ayuda no maneja el evento.

La implementación del método handleEvent() proporcionada por la clase Component invoca a cada método de
ayuda. Por esta razón, es importante que las implementaciones redefinidas del método handleEvent() en clases
derivadas, siempre finalicen con la sentencia:

return( [Link]( evt ) );

El siguiente trozo de código ilustra esta regla.

public boolean handleEvent( Event evt ) {


if( [Link] instanceof MiBoton )
{
// Hace algo...
return true;
}

return( [Link]( evt ) );


}
No seguir esta regla tan simple hará que no se invoquen adecuadamente los métodos de ayuda. El applet
[Link], que controla los eventos de ratón exclusivamente a través de código insertado en sus métodos de
ayuda; va dibujando una línea (rubber band) entre el último punto donde se ha producido un click de ratón y la
posición actual del cursor.

Tutorial de Java [Anterior] [Indice] [Siguiente]


ACTION_EVENT
Algunos de los eventos que más frecuentemente tendremos que controlar son los siguientes:

ACTION_EVENT
MOUSE_DOWN
KEY_PRESS
WINDOW_DESTROY

En la documentación de la clase Event se encuentra toda la lista de eventos que cualquier aplicación puede necesitar
manejar y su documentación; como ejemplo de uso vamos a detenernos en el primero de ellos, ACTION_EVENT.

Como ejemplo del manejo de eventos vamos a ver este evento que se provoca al pulsar un botón, seleccionar un
menú, etc. Para su control podemos manejarlo en el método handleEvent() o en el método action().

Los dos métodos anteriores pertenecen a la clase Component por lo que todas las clases derivadas de ésta
contendrán estos dos métodos y se pueden sobrecargar para que se ajuste su funcionamiento a lo que requiere nuestra
aplicación.

Veamos el siguiente ejemplo, en que se controla este evento a través del método handleEvent(), que es el método
general de manejo de eventos:

public boolean handleEvent( Event evt ) {


switch( [Link] ) {
case Event.ACTION_EVENT:
// [Link] contiene la etiqueta del botón pulsado
// o el item del menú que se ha seleccionado
if( ( "Pulsado "+n+" veces" ).equals( [Link] ) )
return( true );
default:
return( false );
}
}

Pero en este caso, cuando se produce este evento se llama al método action(), que sería:

public boolean action( Event evt,Object arg ) {


if( ( "Pulsado "+n+" veces" ).equals( arg ) )
return( true );
return( false );
}

Como se puede comprobar, incluso si las etiquetas cambian se puede recibir el evento. Los ejemplos anteriores
corresponden al control de un evento producido por un botón que cambia su etiqueta cada vez que se pulsa. Aunque
esta no es la única forma de manejar eventos; de hecho se puede hacer:

if( [Link] == miBoton )

en donde se comparan objetos en lugar de etiquetas.

Tutorial de Java [Anterior] [Indice] [Siguiente]


MEJORAR EL DISEÑO DE INTERFACES
La interface de usuario es el aspecto más importante de una aplicación, tal como ya hemos repetido. Un diseño pobre
de la interface es un grave problema para que el usuario pueda obtener todo el partido posible de la aplicación. Para
ser efectivos, no debemos limitarnos a colocar una serie de botones, etiquetas y barras de desplazamiento sobre la
pantalla. Desafortunadamente, nadie ha determinado una reglas correctas para del diseño de una buena interface.

Los diseñadores del AWT parece que se pusieron como meta principal que las clases del AWT funcionasen
correctamente, dejando un poco de lado su apariencia. Sin embargo, han proporcionado suficientes mecanismos para
poder alterar la apariencia de los Componentes del AWT, muchas veces no de forma sencilla, pero ahí están para que
los programadores podamos alterar la visualización de los Componentes sobre nuestro interface. Vamos a ver unas
cuantas formas sencillas de alterar y dar un mejor aspecto a nuestros diseños.

● Cambio de Font de Caracteres


● Colores de Fondo y Texto
● Fijar el Tamaño Preferido
● Uso de Insets
● Habilitar y Deshabilitar Componentes

Tutorial de Java [Anterior] [Indice] [Siguiente]


CAMBIO DE FUENTE DE CARACTERES
El font de caracteres con el que se presenta un texto en pantalla influye mucho en el impacto de una interface. Una
interface efectiva no debería utilizar una maraña de fuentes, pero sí que debería utilizar dos o tres diferentes para
aumentar el atractivo y la efectividad de los textos. El applet [Link], tal como se muestra en la figura, ilustra
este extremo.

Utiliza tres tipos de fonts de caracteres (en diferente estilo y diferente tamaño) para llamar la atención del usuario
sobre las tres zonas de la interface. La fuente por defecto para todos los Componentes es la fuente Dialog. Java
proporciona otras fuentes con propósitos más especializados, el número exacto de fuentes depende de la plataforma,
por ello, se puede utilizar el applet [Link] para obtener una lista de las fuentes de caracteres disponibles en
el sistema.

Su navegador no entiende la marca <APPLET>, la siguiente imagen muestra la lista de fuentes


disponible en Windows '95

Cuando un programador necesita presentar un Componente en pantalla, como un objeto TextArea, en una fuente de
caracteres distinta a la de defecto, la nueva fuente debe seleccionarse mediante el método setFont():

public void setFont( Font f )

El método setFont() espera como parámetro una fuente. En el siguiente trozo de código vemos cómo se usa:

TextArea ta = new TextArea();


Font f = new Font( "Helvetica",[Link],12 );
[Link]( f );

Este código con ligeras modificaciones funcionará para cualquier Componente. Si se cambia la fuente de un
Contenedor, todos los Componentes colocados dentro del Contenedor automáticamente adoptarán la nueva fuente de
caracteres. El siguiente código, [Link], muestra esta circunstancia:

import [Link].*;
import [Link];

public class CambioFuentes extends Applet {

public static void main( String args[] ) {


Frame fr = new Frame( "Cambio de Fuentes" );
CambioFuentes cf = new CambioFuentes();

Font f = new Font( "Helvetica",[Link],12 );


[Link]( f );
[Link]( new FlowLayout() );
Button b = new Button( "Hola" );
[Link]( b );
Checkbox cb = new Checkbox( "Púlsame" );
[Link]( cb );
TextArea ta = new TextArea();
[Link]( ta );

[Link]();
[Link]();
}
}

La fuente de caracteres solamente se indica para el objeto Frame, el botón, la caja y el área de texto también
utilizarán esta fuente.

Tutorial de Java [Anterior] [Indice] [Siguiente]


COLORES DE FONDO Y TEXTO
El impacto visual del color nunca debe ser desestimado cuando se ataca el diseño de una interface de usuario. El
color tiende a atraer la visión y puede utilizarse para llamr la atención sobre una parte importante del interface. En el
ejemplo siguiente, el color rojo alrededor del botón hace que la vista se fije inmediatamente en él.

La clase Component proporciona dos métodos para modificar el color de un Componente. A través de los métodos
setBackground() y setForeground(), se pueden indicar los colores del fondo y del texto, respectivamente:

public void setBackground( Color c )


public void setForeground( Color c )

Ambos métodos solamente necesitan un parámetro, un objeto Color. A continuación mostramos un ejemplo de su
uso:

TextArea ta = new TextArea();


[Link]( [Link] );
[Link]( [Link] );

Este código funcionará con ligeras modificaciones para casi todos los Componentes del AWT. Si se cambia el Color
de un Contenedor, todos los Componentes colocados dentro de ese Contenedor, automáticamente adoptan el nuevo
color. El applet, [Link], ilustra este punto. El Color solamente se fija para el color de fondo del objeto
Frame; el botón, la caja y el área de texto usarán ese mismo color de fondo.

import [Link].*;
import [Link];

public class CambioColor extends Applet {

public static void main( String args[] ) {


Frame fr = new Frame( "Cambio de Color" );
CambioColor cc = new CambioColor();

[Link]( [Link] );
[Link]( new FlowLayout() );
Button b = new Button( "Hola" );
[Link]( b );
Checkbox cb = new Checkbox( "Púlsame" );
[Link]( cb );
TextArea ta = new TextArea();
[Link]( ta );

[Link]();
[Link]();
}
}

La calidad de soporte del color varía mucho de una plataforma a otra. Bajo Windows '95, la clase Button ignora
totalmente los comandos de color y se empeña en permanecer bajo un patrón de grises. Por otro lado, el fondo de la
clase Label parece ser transparente. Algunos Componentes no se presentan en pantalla con un mismo color para un
mismo objeto Color. Bajo Windows '95, un fondo de color naranja aparece como naranja en muchos Componentes
(excepto en los botones), pero se presenta como amarillo cuando se trata de objetos TextArea o TextField. El soporte
del color en Solaris parece ser mucho más consistente.

Tutorial de Java [Anterior] [Indice] [Siguiente]


FIJAR EL TAMAÑO PREFERIDO
Otro ingrediente importante de una buena interface es el tamaño con el cual aparecerá un Componente o Contenedor
en la pantalla. En el corazón del control de la composición del interface está el layout manager, que es capaz de fijar
el tamaño y la posición de los Componentes que se vayan incorporando al layout que está manejando. Esto,
indirectamente, también influye en el tamaño del Contenedor.

En este caso, en lugar de llamar a un método para indicar cuál debe ser el tamaño de un Componente, hay que derivar
una nueva clase del Componente y redefinir el método preferredSize() que devolverá el tamaño preferido. El layout
manager llama al método preferredSize() para determinar cuál debe ser el tamaño preferido para cada Componente.

Hay que redefinir el método:

public Dimension preferredSize()

Uno puede estar tentado a utilizar el método resize() o el método reshape() para especificar un tamaño, pero no debe
hacerse. Ambos métodos son usados directamente por el layout manager, y los ajustes de tamaño se reclacularán la
próxima vez que el layout manager tenga que recomponer la posición de los Componentes sobre el Contenedor.

Las siguientes líneas de código demuestran el uso del método preferredSize(), convenientemente redefinido en una
clase derivada. Este método crea un nuevo objeto Dimension con la altura y anchura especificadas y se lo devuelve a
quien lo ha llamado (normalmente el layout manager).

public Dimension preferredSize() {


return new Dimension( 200,100 );
}

Desde luego, no hay nada para evitar que el tamaño preferido de un botón varíe dinámicamente, como ocurre en el
applet [Link], mostrado en la figura:

Este applet contiene dos botones. Pulsando sobre uno de ellos se provoca el cambio de tamaño en el otro. El método
preferredSize() del applet de la figura anterior utiliza la variable dim, que es una variable privada:

public Dimension preferredSize() {


return new Dimension( dim );
}

La variable dim puede ser fijada o cambiada vía una función miembro como la siguiente:

public void newPreferredSize( Dimension dim ) {


[Link] = new Dimension( dim );
resize( dim );
}

El Contenedor debe llamar al método anterior antes de su llamada al método layout() para resituar los Componentes
después de que haya cambiado el tamaño de uno de ellos.

Tutorial de Java [Anterior] [Indice] [Siguiente]


USO DE Insets
Insets, o borde interior, al igual que el tamaño preferido, se puede utilizar para proporcionar a la interface de usuario
una mayor ordenación espacial. El insets de un Contendor, especifica la cantidad de espacio alrededor del borde
interior del Contenedor donde no se situará ningún Componente, estará vacío.

El borde interior se especifica para un Contenedor, redefiniendo su método insets():

public Insets insets()

El método insets() no necesita ningún parámetro y devuelve una instancia del objeto Insets. La clase Insets tiene
cuatro campos, que especifican el número de pixels que constituirán el borde interior desde arriba, izquierda, abajo y
derecha, respectivamente.

A continuación mostramos el uso típico de insets(). El código de este ejemplo indica que los Componentes
contenidos en el layout deberán estar situados a 5 unidades desde cualquiera de los bordes del Contenedor.

public Insets insets() {


return new Insets( 5,5,5,5 );
}

En la figura siguiente se muestra el efecto que provoca en la apariencia del interface el uso de insets().

Tutorial de Java [Anterior] [Indice] [Siguiente]


HABILITAR Y DESHABILITAR COMPONENTES
Los Componentes de una interface de usuario que no están actualmente disponibles pero pueden estarlo, en función
de alguna acción del usuario, se dice que están deshabilitados. Se presentan con su rótulo en gris y no responden a las
acciones del usuario. El deshabilitar Componentes es mucho mejor que ocultarlos, porque el usuario puede ver las
operaciones que puede realizar, aunque en ese momento no las tenga disponibles.

La clase Component proporciona tres métodos para llevar a cabo la habilitación y deshabilitación de Componentes:

public void enable()


public void disable()
public void enable( boolean condicionBooleana )

Los primeros dos métodos habilitan y deshabilitan un Componente. El tercer método también hace eso dependiendo
del valor de un parámetro booleano. Veamos un ejemplo:

Button b = new Button( "Púlsame" );


[Link](); // o,
[Link](); // o,
[Link]( true );

Este código funcionará, con muy pocas modificaciones, sobre cualquier Componente. Para un uso efectivo de estos
métodos, un programa debe monitorizar el estado de la interface de usuario. Como el usuario interactúa con la
interface, su estado interno cambia. Esto hay que reflejarlo en el estado de los Componentes que pasarán de
habilitados a deshabilitados, o viceversa, en función de las circunstancias.

Tomemos como ejemplo ahora el applet que aparece en la figura siguiente, obtenido de la ejecución de
[Link]:

En este applet, los botones Añadir y Borrar están deshabilitados hasta que el usuario haya entrado en el campo de
texto. Este previene una activación inadvertida de los dos botones en el caso de que no haya texto en el campo. Tan
pronto como se teclee el primer carácter en el campo de texto, se habilitan los dos botones, cada cual asumiendo su
propio rol. Si, en cualquier momento, el campo de texto se volviese a quedar vacío, los dos botones volverían a estar
deshabilitados
Además de que los Componentes deshabilitados tienen una apariencia visual diferente, tampoco reciben eventos
desde el sistema Java; los eventos son inmediatamente propagados al Contenedor en que está situado el Componente
deshabilitado.

Tutorial de Java [Anterior] [Indice] [Siguiente]


BOTON GRAFICO
AWT adolece de herramientas ya desarrolladas para implementar interfaces al uso, con alta proliferación de
imágenes y facilidades para que el programador utilice directamente Componentes. Sin embargo, sí proporciona las
herramientas suficientes como para que se puedan implementar cualquier tipo de Componentes, o modificar al gusto
los ya existentes. Para mostrar un ejemplo, vamos a implementar un botón gráfico, [Link]

Partimos de un botón normal al cual aplicaremos tres imágenes diferentes, para cada uno de los tres estados en que
puede encontrarse: pulsado, liberado e inhabilitado.

Su navegador no entiende la marca <APPLET>, la siguiente imagen muestra las tres imágenes que
forman los tres estados posible del botón

En el fichero fuente, podemos comprobar que las tres imágenes se pueden pasar cómo parámetro en la llamada
APPLET, por ejemplo:

<APPLET CODE=[Link] WIDTH=100 HEIGHT=50>


<PARAM NAME=IMAGEN0 VALUE=[Link]>
<PARAM NAME=IMAGEN1 VALUE=[Link]>
<PARAM NAME=IMAGEN2 VALUE=[Link]>
</APPLET>

Observando el código, se puede comprobar que una vez cargadas la imágenes, solamente se deben controlar los
eventos del ratón, para que automáticamente se presenten las imágenes del botón adecuadas y responda
correctamente.

import [Link].*;
import [Link];

public class BotonGrafico extends Applet {


private MediaTracker tracker;
private Image imagen[] = new Image[3];
private boolean BotActivo = false;
private boolean BotPulsado = false;
private boolean tresImg = false;
private int Estado = 0;

public void init() {


String istr;
tracker = new MediaTracker( this );

// Recogemos las tres imágenes de los parámentros de llamada


// al applet
for( int i=0; i < 3; i++ )
{
istr = getParameter( "IMAGEN" + i );
if( istr == null )
tresImg = false;
else
{
// Registramos las imágenes con el Media Tracker
imagen[i] = getImage( getCodeBase(),istr );
[Link]( imagen[i],0 );
try {
[Link]();
}
catch( InterruptedException e ) {
[Link]( "Error cargando imagen " + i );
}
}
}
}

public void start() {


repaint();
}

public void stop(){


}

// Controlamos la pulsación del ratón


public boolean mouseDown( Event evt,int x,int y ) {
BotPulsado = true;
repaint();
return( true );
}

// Controlamos cuando el usuario suelta el botón del ratón


public boolean mouseUp( Event evt,int x,int y ) {
if( BotPulsado && BotActivo )
{
BotPulsado = true;
repaint();
}
else
{
BotPulsado = false;
repaint();
}
return( true );
}
// Controlamos cuando el cursor del ratón entra en el
// campo de acción del applet
// Presentamos un mensaje en la línea de estado
public boolean mouseEnter( Event evt,int x,int y ) {
BotActivo = true;
showStatus( "Tutorial de Java, Boton Grafico" );
repaint();
return( true );
}

// Controlamos cuando el cursor del ratón abandona el


// lugar ocupado por el applet
public boolean mouseExit( Event evt,int x,int y ) {
BotActivo = false;
showStatus( "" );
repaint();
return( true );
}

public void update( Graphics g ) {


// Controlamos el estado en que se queda el botón
// tras la acción que se haya hecho con el ratón
if( !BotActivo )
Estado = 0;
else
if( BotActivo && !BotPulsado )
Estado = 1;
else
Estado = 2;
paint( g );
}

public void paint( Graphics g ) {


[Link]( imagen[Estado],0,0,this );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 11-Ago-1996 15:54:01
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y est sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Los tres graficos que corresponden a los estados del boton se pasan
// en la llamada al applet, y se corresponden con:
// IMAGEN0 - Boton deshabilitado, o cursor fuera del applet
// IMAGEN1 - Boton en estado normal y activo
// IMAGEN2 - Boton pulsado
//
public class BotonGrafico extends Applet {
private MediaTracker tracker;
private Image imagen[] = new Image[3];
private boolean BotActivo = false;
private boolean BotPulsado = false;
private boolean tresImg = false;
private int Estado = 0;

public void init() {


String istr;
tracker = new MediaTracker( this );

// Recogemos las tres imagenes de los paramentros de llamada


// al applet
for( int i=0; i < 3; i++ )
{
istr = getParameter( "IMAGEN" + i );
if( istr == null )
tresImg = false;
else
{
// Registramos las imagenes con el Media Tracker
imagen[i] = getImage( getCodeBase(),istr );
[Link]( imagen[i],0 );
try {
[Link]();
}
catch( InterruptedException e ) {
[Link]( "Error cargando imagen " + i );
}
}
}
}

public void start() {


repaint();
}

public void stop(){


}

// Controlamos la pulsacion del raton


public boolean mouseDown( Event evt,int x,int y ) {
BotPulsado = true;
repaint();

return( true );
}

// Controlamos cuando el usuario suelta el boton del raton


public boolean mouseUp( Event evt,int x,int y ) {
if( BotPulsado && BotActivo )
{
BotPulsado = true;
repaint();
}
else
{
BotPulsado = false;
repaint();
}
return( true );
}

// Controlamos cuando el cursor del raton entra en el


// campo de accion del applet
// Presentamos un mensaje en la linea de estado
public boolean mouseEnter( Event evt,int x,int y ) {
BotActivo = true;
showStatus( "Tutorial de Java, Boton Grafico" );
repaint();

return( true );
}

// Controlamos cuando el cursor del raton abandona el


// lugar ocupado por el applet
public boolean mouseExit( Event evt,int x,int y ) {
BotActivo = false;
showStatus( "" );
repaint();

return( true );
}

public void update( Graphics g ) {


// Controlamos el estado en que se queda el boton
// tras la accion que se haya hecho con el raton
if( !BotActivo )
Estado = 0;
else
if( BotActivo && !BotPulsado )
Estado = 1;
else
Estado = 2;
paint( g );
}

public void paint( Graphics g ) {


[Link]( imagen[Estado],0,0,this );
}
}

//-------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 05:02:43
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración de la apariencia en pantalla de la presentación de textos


// con diferente tipo de fuente para permitir el resaltar zonas de
// inter‰és que compongan la ventana
public class Fuentes extends Applet {
Label lTit = null,lTag = null,lInfo = null;
TextField tfCoords = null;
Panel pActivo = null;

public void init() {


setLayout( new GridLayout( 0,1 ) );
lTit = new Label( "Una Demostración" );
[Link]( new Font( "Helvetica",[Link],16 ) );
add( lTit );
Panel p = new Panel();
[Link]( new GridLayout( 0,2 ) );
lTag = new Label( "Coordenadas" );
[Link]( new Font( "Dialog",[Link],12 ) );
[Link]( lTag );
tfCoords = new TextField();
[Link]( new Font( "Courier",[Link],12 ) );
[Link]( false );
[Link]( tfCoords );
add( p );
lInfo =
new Label("Mueve el ratón en la zona inferior a este texto...");
[Link]( new Font( "Dialog",[Link],10 ) );
add( lInfo );
pActivo = new Panel();
add( pActivo );
}

public Insets insets() {


return new Insets( 10,10,10,10 );
}

public boolean handleEvent( Event evt ) {


if( [Link] == pActivo && [Link] == Event.MOUSE_MOVE )
{
[Link]( evt.x + " " + evt.y );
return true;
}
else if( [Link] == pActivo && [Link] == Event.MOUSE_EXIT )
{
[Link]( "" );
return true;
}
return [Link]( evt );
}

public static void main( String args[] ) {


Frame f = new Frame( "Utilización de Fuentes" );
Fuentes fu = new Fuentes();
[Link]();
[Link]( "Center",fu );
[Link]();
[Link]();
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Ago-1996 05:25:23
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Este applet presenta una lista con todas las fuentes que hay
// disponibles para su uso en el sistema

public class ListaFuentes extends Applet {


private TextArea ta = new TextArea();

public void init() {


setLayout( new BorderLayout() );
add( "Center",ta );

// Obtenemos la lista de fuentes y la vamos escribiendo en el


// area de texto del applet, que haremos no editable para que
// sólo sirva como información
String rgstr[] = [Link]().getFontList();
for( int i=0; i < [Link]; i++ )
[Link]( rgstr[i] + "\n" );
[Link]( false );
}

public static void main( String args[] ) {


Frame f = new Frame( "Fuentes Disponibles" );
ListaFuentes lf = new ListaFuentes();
[Link]();
[Link]( "Center",lf );
[Link]();
[Link]();
}
}

//-------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 05:45:53
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración del uso de diferentes fuentes a la hora de presentar los


/ Componentes sobre la pantalla
public class CambioFuentes extends Applet {
public static void main( String args[] ) {
Frame fr = new Frame( "Cambio de Fuentes" );
CambioFuentes cf = new CambioFuentes();
Font f = new Font( "Helvetica",[Link],12 );
[Link]( f );
[Link]( new FlowLayout() );
Button b = new Button( "Hola" );
[Link]( b );
Checkbox cb = new Checkbox( "Púlsame" );
[Link]( cb );
TextArea ta = new TextArea();
[Link]( ta );

[Link]();
[Link]();
}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 30-Jun-1996 09:10:23
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class ComponentesAWT extends Frame {

public ComponentesAWT() {
Panel bottomPanel = new Panel();
Panel centerPanel = new Panel();
MenuBar mb = new MenuBar();
Menu m = new Menu( "Menú" );
[Link]( new MenuItem( "Menú Selección 1" ) );
[Link]( new CheckboxMenuItem( "Menú Selección 2" ) );
[Link]( new MenuItem( "Menú Selección 3" ) );
[Link]( m );
setMenuBar( mb );

// Incoporamos los elementos pequeños en la zona inferior


[Link]( new TextField( "Campo de Texto" ) );
[Link]( new Button( "Botón" ) );
[Link]( new Checkbox( "Casilla Verificación" ) );

Choice c = new Choice();


[Link]( "Selección Item 1" );
[Link]( "Selección Item 2" );
[Link]( "Selección Item 3" );
[Link]( c );

// En la zona central colocamos los elementos mayores


[Link]( new GridLayout( 1,2 ) );

// En la columna izquierda posicionamos un canvas


[Link]( new MiCanvas() );

// En la zona central colocamos una etiqueta y una zona de texto


Panel p = new Panel();
[Link]( new BorderLayout() );
[Link]( "North",new Label( "Etiqueta",[Link] ) );
[Link]( "Center",new TextArea( "Zona de Texto",5,20 ) );
[Link]( p );

setLayout( new BorderLayout() );


add( "South",bottomPanel );
add( "Center",centerPanel );

// En la columna derecha colocamos una lista de selección


List l = new List( 3,false );
[Link]( "Lista item 1");
[Link]( "Lista item 2");
[Link]( "Lista item 3");
[Link]( "Lista item 4");
[Link]( "Lista item 5");
[Link]( "Lista item 6");
[Link]( "Lista item 7");
[Link]( "Lista item 8");
[Link]( "Lista item 9");
add( "East",l );
}

public static void main( String args[] ) {


ComponentesAWT window = new ComponentesAWT();

[Link]("Los Componentes del AWT");


[Link]();
[Link]();
}
}

class MiCanvas extends Canvas {


public void paint( Graphics g ) {
int w = size().width;
int h = size().height;
[Link]( 0,0,w-1,h-1 );
[Link]( "Canvas",
( [Link]().stringWidth( "Canvas" ) )/2,10 );

[Link]( new Font( "Helvetica",[Link],8 ) );


[Link]( 10,10,100,100 );
[Link]( 9,9,3,3 );
[Link]( "(10,10)",13,10 );
[Link]( 49,49,3,3);
[Link]( "(50,50)",53,50 );
[Link]( 99,99,3,3);
[Link]( "(100,100)",103,100 );
}
}

//------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 20-Ago-1996 20:40:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class Botones extends Applet {


Button b1,b2,b3;

// Creamos tres botones normales, push-button


public void init() {
b1 = new Button( "Botón B1" );
b2 = new Button( "Botón B2" );
b3 = new Button( "Botón B3" );

[Link]( b1 );
[Link]( b2 );
[Link]( b3 );
}

// Comprobamos cuando llega un evento, cual ha sido el boton que


// lo ha generado, e imprimimos un mensaje en la pantalla
public boolean action( Event evt,Object obj ) {
if( [Link]( b1 ) )
[Link]( "Se ha pulsado el boton B1" );
if( [Link]( b2 ) )
[Link]( "Se ha pulsado el boton B2" );
if( [Link]( b3 ) )
[Link]( "Se ha pulsado el boton B3" );

return true;
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 20-Ago-1996 20:56:52
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Presenta una lista de selección para elegir una entre las varias opciones
// que se presentan
public class BotonSeleccion extends Applet {
Choice Selector;

public void init() {


Selector = new Choice();

[Link]( "Rojo" );
[Link]( "Verde" );
[Link]( "Azul" );

add( Selector );
}

// Cuando nos llegue el evento de la lista, presentamos en la


// consola un texto indicando cual ha sido el elemento que se
// ha seleccionado en la lista
public boolean action( Event evt,Object obj ) {
if( [Link] instanceof Choice )
{
String color = (String)obj;

[Link]( "El color elegido es el " + color );


}

return true;
}
}

//------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 20-Ago-1996 21:17:22
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class BotonComprobacion extends Applet {


Checkbox Relleno;

// Creamos el boton de comprobacion


public void init() {
Relleno = new Checkbox( "Relleno" );

add( Relleno );
}

// Imprimimos por consola cuando llega el evento


public boolean action( Event evt,Object obj ) {
if( [Link] instanceof Checkbox )
[Link]( "CheckBox: " + [Link]() );
return true;
}
}

//-------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 20-Ago-1996 21:24:25
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Presenta el Componente que nos permite realizar una selección entre


// varias posibles, pero solamente estaría activa una a la vez
public class BotonRadio extends Applet {
CheckboxGroup Radio;

public void init() {


Radio = new CheckboxGroup();

add( new Checkbox( "Primero",Radio,true ) );


add( new Checkbox( "Segundo",Radio,false ) );
add( new Checkbox( "Tercero",Radio,false ) );
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 16:42:21
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Creamos una clase que presenta el botón en pantalla y maneja los


// eventos que genera ese mismo botón
class BotonAceptar extends Button {

public BotonAceptar() {
setLabel( "Aceptar" );
}

public boolean action( Event evt,Object obj ) {


[Link]( "Boton Aceptar" );
return true;
}
}

// Utilizamos la clase de botón autocontrolado que hemos creado


public class BotonAuto extends Applet {
BotonAceptar boton;

public void init() {


boton = new BotonAceptar();
add( boton );
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 16:42:21
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración de la presencia de textos fijos en la pantalla


public class Etiqueta extends Applet {

public void init() {


Label etiq1 = new Label( "Hola Java!" );
Label etiq2 = new Label( "Otra Etiqueta" );

setLayout( new FlowLayout( [Link],10,10 ) );


add( etiq1 );
add( etiq2 );
}
}

//------------------------------------------ Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 16:54:11
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración del uso de listas, generamos una con los nombres de los
// planetas, teniendo siempre 4 visibles e imprimiendo un mensaje
// por consola cuando se produzca una selección, indicando el elemento
// de la lista que se ha seleccionado
public class Lista extends Applet {

public void init() {


List l = new List( 4,false );

[Link]( "Mercurio" );
[Link]( "Venus" );
[Link]( "Tierra" );
[Link]( "Marte" );
[Link]( "Jupiter" );
[Link]( "Saturno" );
[Link]( "Neptuno" );
[Link]( "Urano" );
[Link]( "Pluton" );
add( l );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof List )
[Link]( "Entrada de la Lista: " + obj );

return( true );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 17:08:36
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración de la selección múltiple en una lista, permite la selección


// de más de un elemento de la lista y cuando se seleccione el boton del
// applet, imprimirá la lista de los elementos seleccionados
public class ListaMult extends Applet {
List lm = new List( 6,true );

public void init() {


Button boton = new Button( "Aceptar" );

[Link]( "Mercurio" );
[Link]( "Venus" );
[Link]( "Tierra" );
[Link]( "Marte" );
[Link]( "Jupiter" );
[Link]( "Saturno" );
[Link]( "Neptuno" );
[Link]( "Urano" );
[Link]( "Pluton" );
add( lm );
add( boton );
}

public boolean action( Event evt,Object obj ) {


if( [Link] instanceof Button )
{
if( "Aceptar".equals( obj ) )
{
String seleccion[];

// Obtiene la lista de los elementos seleccionados y la


// imprime
seleccion = [Link]();
for( int i=0; i < [Link]; i++ )
[Link]( seleccion[i] );
}
}

return( true );
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 20-Ago-1996 21:35:28
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

public class CampoTexto extends Applet {


TextField tf1,tf2,tf3,tf4;

public void init() {


// Campo de texto vacío
tf1 = new TextField();
// Campo de texto vacío con 20 columnas
tf2 = new TextField( 20 );
// Texto predefinido
tf3 = new TextField( "Hola" );
// Texto predefinido en 30 columnas
tf4 = new TextField( "Hola",30 );

// Incorporamos los cuatro campos de texto a la pantalla


add( tf1 );
add( tf2 );
add( tf3 );
add( tf4 );
}

// Cuando se produzcan eventos de aceptación en los campos de texto


// presentamos un mensaje en consola indicando de qué campo ha
// partido el evento y el contenido del campo de texto
public boolean action( Event evt,Object obj ) {
if( [Link] instanceof TextField )
{
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 1: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 2: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 3: " +
[Link]() );
if( [Link]( tf1 ) )
[Link]( "Campo de Texto 4: " +
[Link]() );
}
return true;
}
}
//---------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 17:26:33
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Presentamos dos areas de texto y un boton para imprimir el contenido


public class AreaTexto extends Applet {
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( "Tutorial de Java",5,40 );
// Hacemos que no sea editable
[Link]( false );

add( t1 );
add( t2 );
add( boton );
}

// Solo controlaremos el evento generado por el boton


public boolean action( Event evt,Object obj ) {
// Si pulsamos el boton, imprimimos en la consola el contenido
// del campo de texto que se haya escrito
if( [Link] instanceof Button )
{
if( "Aceptar".equals( obj ) )
{
String texto = [Link]();
[Link]( texto );
}
}

return true;
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 17:42:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase que presenta el canvas propio y un botón. Imprime por


// consola las coordenadas en que se encuentra posicionado el ratón
// cada vez que se pulse y cada vez que se genera un evento
public class Lienzo extends Applet {
Button boton;

public void init() {


setLayout( new BorderLayout( 15,15 ) );
boton = new Button( "Test" );
MiCanvas canv = new MiCanvas( 100,100 );

add( "Center",canv );
add( "South",boton );
}

public boolean action( Event evt,Object obj ) {


[Link]( "Evento: " + obj );
return( true );
}

public boolean mouseDown( Event evt,int x, int y ) {


[Link]( "Raton: ("+x+","+y+")" );
return( true );
}
}

// Creamos una clase derivada de canvas que lo pinte e imprima un


// mensaje por consola cuando el ratón se encuentra en sus dominios
// indicando esa circunstancia y las coordenadas
class MiCanvas extends Canvas {
private int ancho;
private int alto;

public MiCanvas( int anc,int alt ) {


ancho = anc;
alto = alt;

reshape( 0,0,anc,alt );
}

public void paint( Graphics g ) {


[Link]( [Link] );
[Link]( 0,0,ancho,alto );
}

public boolean mouseDown( Event evt,int x, int y ) {


if( x < ancho && y < alto )
{
[Link]( "Raton en Canvas: ("+x+","+y+")" );
return( true );
}
return( false );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 18:14:41
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Presenta tres barras de desplazamiento para, por ejemplo, seleccionar


// un color en base a sus tres componentes RGB
public class Slider extends Applet {
Scrollbar rojo,verde,azul;

public void init() {


rojo = new Scrollbar( [Link],0,1,0,255 );
verde = new Scrollbar( [Link],0,1,0,255 );
azul = new Scrollbar( [Link],0,1,0,255 );

add( rojo );
add( verde );
add( azul );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 18:21:21
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración de la presencia de una barra de desplazamiento en pantalla


public class Ranger extends Applet {
Scrollbar rango;

public void init() {


rango = new Scrollbar( [Link],0,64,0,255 );

add( rango );
}
}

//-------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 18:53:19
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración del uso de una barra de desplazamiento como medidor de


// escalas. Se crea una barra y un texto asociado que va presentando
// la cifra por la que se mueve el indicador de la barra
public class RangoRojo extends Applet {
Scrollbar rango;
TextField valor;
Label etiqueta;

public void init() {


// Al crear la barra se indica cual es el valor de los dos
// extermos para que se pueda actualizar correctamente el
// indicador
rango = new Scrollbar( [Link],0,1,0,255 );
valor = new TextField( "0",5 );
etiqueta = new Label( "Rojo (0-255)" );

setLayout( new GridLayout( 1,3 ) );


[Link]( false );

add( etiqueta );
add( rango );
add( valor );
}

// Cuando se produce un evento en la barra de desplazamiento, se


// actualiza el texto
public boolean handleEvent( Event evt ) {
if( [Link] instanceof Scrollbar )
{
[Link](
[Link]( ((Scrollbar)[Link]).getValue() ) );
return( true );
}

return( [Link]( evt ) );


}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Ago-1996 23:00:56
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// En esta clase creamos un nuevo componente que presentará en pantalla


// una línea de separación con sobra, para dar apariencia de tres
// dimensiones
public class Separador extends Canvas {
public final static int HORIZONTAL = 0;
public final static int VERTICAL = 1;

int orientacion;
Dimension sepTama,sepDim;

// En el constructor debemos indicar la longitud, en ancho y la


// orientación con que vamos a crear el separador
public Separador( int lon,int thick,int orient ) {
orientacion = orient;
if( orient == HORIZONTAL )
sepTama = new Dimension( lon,thick );
else
sepTama = new Dimension( thick,lon );
}

// Este método devuelve la orientación con que se ha creado


// el separador
public int getOrientacion() {
return( orientacion );
}

// Permitimos cambiar la orientación del separador


public void setOrientacion( int orient ) {
// Si en el parámetro no llega una orientación válida generamos
// una excepción de argumento ilegal
if( orient > VERTICAL || orient < HORIZONTAL )
throw new IllegalArgumentException( "Orientación ilegal" );

if( orientacion != orient )


{
orientacion = orient;
sepDim = new Dimension( [Link],[Link] );
invalidate();
}
}

public Dimension preferredSize() {


return( sepDim );
}

public Dimension minimumSize() {


return( sepDim );
}

public void paint( Graphics g ) {


int x1,y1,x2,y2;
Rectangle bbox = bounds();
Color c = getBackground();
Color brillo = [Link]();
Color oscuro = [Link]();

// Hacemos aparecer la caja que formará el separador


if( orientacion == HORIZONTAL )
{
x1 = 0;
x2 = [Link] - 1;
y1 = y2 = [Link]/2 - 1;
}
else
{
x1 = x2 = [Link]/2 - 1;
y1 = 0;
y2 = [Link] - 1;
}

// Pintamos una línea oscura


[Link]( oscuro );
[Link]( x1,y1,x2,y2 );

// Pintamos una línea brillante para completar la sensación de


// tres dimensiones
[Link]( brillo );
if( orientacion == HORIZONTAL )
[Link]( x1,y1+1,x2,y2+1 );
else
[Link]( x1+1,y1,x2+1,y2 );
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Ago-1996 23:00:56
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Ejemplo de uso del componente Separador creado por nosotros, en el


// applet aparecerán dos campos de texto divididos por el Separador
public class EjSeparador extends Applet {
public final static int HORIZONTAL = 0;
public final static int VERTICAL = 1;

public void init() {


setLayout( new BorderLayout() );

TextField texto1 = new TextField( "Hola",20 );


TextField texto2 = new TextField( "que tal",20 );
Separador raya = new Separador( 8,5,HORIZONTAL );

add( "North",texto1 );
add( "Center",raya );
add( "South",texto2 );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 16-Dic-1996 13:21:28
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Extendemos la clase Panel para implementar nuestro nuevo Componente


public class Grupo extends Panel {
String Rotulo;
int altoTexto;
int longTexto;
int offset;
static Font defFuente;
FontMetrics metFuente;

// Al contructor le pasamos el título del Grupo


public Grupo( String titulo ) {
altoTexto = 20;
longTexto = 20;
offset = 10;
Rotulo = titulo;
setLayout( null );
metFuente = getFontMetrics( defFuente );
}

public void paint( Graphics g ) {


Dimension d = size();
Font fuente = getFont();
// Comprobamos que no haya ya una fuente seleccionada por defecto,
// En caso de que no la haya, cogemos la nuestra
if( fuente != null )
metFuente = getFontMetrics( fuente );

longTexto = [Link]( Rotulo );


altoTexto = [Link]();
[Link]( [Link] );
// A la hora de pintar el rectángulo que rodeará al grupo, tenemos
// en cuenta el alto de los caracteres que forman la fuente con
// que estamos trabajando y el ancho de los caracteres, junto con
// la longitud del texto
[Link]( 0, altoTexto/2,[Link]-3,[Link]-altoTexto/2-3 );
[Link]( [Link] );
[Link]( 1,altoTexto/2+1,[Link]-3,[Link]-altoTexto/2-3 );
[Link]( getBackground() );
[Link]( offset,altoTexto/2,offset+longTexto+12,altoTexto/2 );
[Link]( offset,altoTexto/2+1,offset+longTexto+12,altoTexto/2+1 );
[Link]( getForeground() );
[Link]( Rotulo,offset+6,altoTexto-3 );
}
// No manejamos los eventos, porque no tiene sentido, nuestro grupo
// es una mera decoración, así que pasamos los eventos hacia arriba
public boolean handleEvent( Event evt ) {
return( [Link]( evt ) );
}

public Dimension preferredSize() {


return( minimumSize() );
}

public Dimension minimumSize() {


return( new Dimension( 100,100 ) );
}

// Nuestra fuente por defecto


static {
defFuente = new Font( "Dialog",0,12 );
}
}

//--------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 16-Dic-1996 13:26:46
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link]

// Clase creada para demostrar la utilización del Componente Grupo que


// hemos desarrollado para incorporar al set del AWT
public class EjGrupo extends Applet {
Label etiq;
Button izqda;
Button dcha;
Button todo;

public void init() {


setBackground( [Link] );
setLayout( null );

// Creamos un grupo para contener una etiqueta que aparecerá


// centrada sobre la zona que ocupa el Grupo
Grupo g = new Grupo( "Etiqueta" );
add( g );
[Link]( new Font("Dialog",0,14 ) );
[Link]( insets().left + 10,insets().top + 20,290,40 );
[Link]( new FlowLayout( [Link],10,10 ) );
// Creamos e incorporamos la etiqueta al Grupo
etiq = new Label( "Hola Java!" );
[Link]( etiq );

// Creamos otro grupo que contendrá 3 botones. En este caso


// no indicamos el Layout a utilizar dentro del Grupo,
// porque vamos a colocar los botones en posiciones absolutas
Grupo g2 = new Grupo( "Botones" );
add( g2 );
[Link]( insets().left+10,80,290,60 );
// Creamos e incorporamos los 3 botones al Grupo
izqda = new Button( "Botón 1" );
[Link]( izqda );
[Link]( 20,20,70,30 );
dcha = new Button( "Botón 2" );
[Link]( dcha );
[Link]( 110,20,70,30 );
todo = new Button( "Botón 3" );
[Link]( todo );
[Link]( 200,20,70,30 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 08-Jul-1996 06:21:30
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

public class AplicacionAWT extends Frame {


// Fijamos el tamaño de la ventana mediante variables "finales" que
// deben ser constantes
static final int HOR_TAMANO = 350;
static final int VER_TAMANO = 200;
private MenuBar mbarra;

public AplicacionAWT() {
// Ponemos el rotulo a la ventana
super( "Aplicación Java con AWT" );

// Creamos los menus


InicializaMenus();

setFont( new Font( "TimesRoman",[Link],12 ) );


setBackground( [Link] );
setForeground( [Link] );
setLayout( new BorderLayout() );

// Incorporamos dos botones en la parte inferior de la


// ventana
Panel p = new Panel();
[Link]( new Button( "Aceptar" ) );
[Link]( new Button( "Cancelar" ) );
add( "South",p );

// Ajustamos el tama¤o de la ventana a nuestras necesidades


// y la hacemos visible en pantalla
pack();
resize( HOR_TAMANO,VER_TAMANO );
show();
}

// Creamos la barra de men£s y las opciones que se


// abrir n cuando se seleccione cada una de ellas
private void InicializaMenus() {
mbarra = new MenuBar();

// Opcion Archivo del menu y las subopciones


Menu m = new Menu( "Archivo" );
[Link]( new MenuItem( "Nuevo" ) );
[Link]( new MenuItem( "Abrir" ) );
[Link]( new MenuItem( "Guardar" ) );
[Link]( new MenuItem( "Guardar como" ) );
[Link]( new MenuItem( "Imprimir" ) );
[Link]();
[Link]( new MenuItem( "Salir" ) );
[Link]( m );

// Opcion Ayuda del menu y subopciones


m = new Menu( "Ayuda" );
[Link]( new MenuItem( "Ayuda!" ) );
[Link]();
[Link]( new MenuItem( "Acerca de..." ) );
[Link]( m );

setMenuBar( mbarra );
}

public void paint( Graphics g ) {


[Link]( new Font( "TimesRoman",[Link],24 ) );
[Link]( [Link] );
[Link]( getTitle(),30,50 );
}

public boolean handleEvent( Event evt ) {


switch( [Link] ) {
// Aqu¡ controlamos el evento de destruccion de la
// ventana
case Event.WINDOW_DESTROY:
[Link]( 0 );
return true;
// Cuando se selecciona alguna de las opciones del
// Menu, simplemente se imprime en la consola el texto
// indicativo de la opcion seleccionada
case Event.ACTION_EVENT:
if( [Link] instanceof MenuItem )
{
if( "Nuevo".equals( [Link] ) )
AplicacionAWT aAwt = new AplicacionAWT();;
if( "Abrir".equals( [Link] ) )
[Link]( "Opcion -Abrir-" );
if( "Guardar".equals( [Link] ) )
[Link]( "Opcion -Guardar-" );
if( "Guardar como".equals( [Link] ) )
[Link]( "Opcion -Guardar como-" );
if( "Imprimir".equals( [Link] ) )
[Link]( "Opcion -Imprimir-" );
if( "Salir".equals( [Link] ) )
[Link]( 0 );
if( "Ayuda!".equals( [Link] ) )
[Link]( "No hay ayuda disponible" );
if( "Acerca de...".equals( [Link] ) )
{
AboutDialog ad = new AboutDialog( this );
[Link](400,560);
[Link]();
}
}
default:
return false;
}
}

// Main para generar la aplicacion


public static void main( String args[] ) {
new AplicacionAWT();
}
}

// Clase para presentar la ventana Acerca de...


class AboutDialog extends Dialog {
static int HOR_TAMANO = 300;
static int VER_TAMANO = 150;

// Constructor de la clase, que presenta una ventana con informacion


// y un boton pasa ocultarla
public AboutDialog( Frame parent ) {
super( parent,"Acerca de...",true );
[Link]( false );
setBackground( [Link] );
setLayout( new BorderLayout() );

Panel p = new Panel();


[Link]( new Button( "Aceptar" ) );
add( "South",p );
resize( HOR_TAMANO,VER_TAMANO );
}

// Presentamos informaci¢n de la aplicaci¢n cuando se


// selecciona la opcion de Acerca de...
public void paint( Graphics g ) {
[Link]( [Link] );
[Link]( "Aplicación Java con AWT",HOR_TAMANO/4,VER_TAMANO/3 );
[Link]( "Versión 1.00",HOR_TAMANO/3+15,VER_TAMANO/3+20 );
}

public boolean handleEvent( Event evt ) {


switch( [Link] ) {
// Solo manejamos el evento del boton Aceptar,
// y lo que ahcemos es ocultar la ventana
case Event.ACTION_EVENT:
if( "Aceptar".equals( [Link] ) )
{
hide();
return true;
}
default:
return false;
}
}
}

//------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 20:08:32
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Implementación de una clase que nos permite anidar menús de forma que se
// vayan abriendo en función de opciones seleccionadas en el menú anterior
public class Cascada extends Frame {

// Constructor
public Cascada() {
MenuBar menub;
Menu menu;
Menu cMenu1;
Menu cMenu2;

// Fijamos el título de la ventana


setTitle( "Menús en Cascada" );

// Barra de menú principal de la aplicación


menub = new MenuBar();

// Primer elemento desde el menú principal


menu = new Menu( "Archivo" );

// Primer desdendiente de "Archivo", que es otro menú


cMenu1 = new Menu( "Abrir" );
[Link]( new MenuItem( "Nuevo" ) );
[Link]( new MenuItem( "Plantilla" ) );
[Link]( cMenu1 );

// Segundo descendiente que será otro menú en cascada


cMenu1 = new Menu( "Imprimir" );

cMenu2 = new Menu( "Archivo" );


[Link]( new MenuItem( "Guardar" ) );
[Link]( new MenuItem( "Guardar como" ) );
[Link]( new MenuItem( "Borrar" ) );
[Link]( cMenu2 );

cMenu2 = new Menu( "Imprimir" );


[Link]( new MenuItem( "Preparar" ) );
[Link]( new MenuItem( "Imprimir Página" ) );
[Link]( new MenuItem( "Imprimir Todo" ) );
[Link]( cMenu2 );

[Link]( cMenu1 );

// Separador y opción de salida


[Link]();
[Link]( new MenuItem( "Salir" ) );

// Incorporamos el primer elemento a la barra de menú


[Link]( menu );

// Segundo elemento desde el menú principal


menu = new Menu( "Opciones" );

// Una opción cualquiera


[Link]( new MenuItem( "Revisión" ) );

// Incorporamos el segundo elemento a la barra de menú


[Link]( menu );

setMenuBar( menub );
}

public boolean handleEvent( Event evt ) {


// Sólo trataremos el evento de salida, el resto es ejemplo puro
if( Event.WINDOW_DESTROY == [Link] && this == [Link] )
[Link]( 0 );

// Los demás eventos los devolvemos a la clase superior


return( [Link]( evt ) );
}

public boolean action( Event evt,Object obj ) {


// Sólo tratamos el evento se salida de la aplicación, el
// resto los propagamos hacia arriba
if( [Link] instanceof MenuItem && [Link]( "Salir" ) )
[Link]( 0 );

return( false );
}

public static void main( String args[] ) {


Frame frame = new Cascada();

[Link]( 250,250 );
[Link]();
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 21-Ago-1996 18:53:19
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Clase que nos permite introducir un número y nos lo presenta en


// diferentes bases
public class Convertidor extends Frame {
int valorDecimal = 0;
String valorX = new String( "0" );
TextField dTexto,xTexto;

public Convertidor() {
super( "Convertidor Decimal" );

// Creamos la barra de menú, los botones de las bases y los


// paneles que vamos a utilizar para posicionar los
// Componentes
MenuBar menub = new MenuBar();
Button Bin = new Button( "Binario" );
Button Octal = new Button( "Octal" );
Button Hexa = new Button( "Hexadecimal" );
Button Base36 = new Button( "Base36" );
Panel p1 = new Panel();
Panel p2 = new Panel();
Panel p3 = new Panel();

// Creamos el menú desplegable


Menu menu = new Menu( "Aplicación" );
[Link]( new CheckboxMenuItem( "Base36 Activa" ) );
[Link]( new MenuItem( "Salir" ) );
[Link]( menu );
setMenuBar( menub );

// Incorporamos los botones a uno de los paneles


[Link]( new FlowLayout() );
[Link]( Bin );
[Link]( Octal );
[Link]( Hexa );
[Link]( Base36 );

// Creamos los dos campos de texto que vamos a utilizar, uno


// para la introducción del número decimal que queremos
// convertir y el otro para presentar el número convertido
// Y asociamos cada uno de los campos, junto con su etiqueta
// explicativa a uno de los paneles
Label dEtiq = new Label( " Número Decimal:" );
Label xEtiq = new Label( "Valor Convertido:" );
dTexto = new TextField( [Link]( valorDecimal ),7 );
xTexto = new TextField( valorX,32 );
[Link]( new FlowLayout( [Link] ) );
[Link]( new FlowLayout( [Link] ) );
[Link]( dEtiq );
[Link]( dTexto );
[Link]( xEtiq );
[Link]( xTexto );

// Incorporamos los paneles a la ventana


add( "North",p1 );
add( "Center",p2 );
add( "South",p3 );
}

// Fija el tamaño de la ventana y la presenta en pantalla


public void start() {
resize( 400,150 );
show();
}

// Actualiza el texto convertido en el campo de texto que le


// corresponde
public void actualizaTexto() {
[Link]( valorX );
}

// Controlador de eventos, que hace caso solamente al evento de


// destrucción de la ventana y a los de los botones, efectuando la
// operación de coversión que correponda al botón que se haya
// pulsado y llama al método que hace aparecer el nuevo valor en
// el campo de texto del valor convertido
public boolean handleEvent( Event evt ) {
if( [Link] instanceof MenuItem )
{
if( "Salir".equals( ( (MenuItem)[Link]).getLabel() ) )
{
hide();
dispose();
[Link]( 0 );
return false;
}
return( true );
}
else if( [Link] instanceof Button )
{
String boton = ( (Button)[Link]).getLabel();

// Conversión del número decimal a binario


if( [Link]( "Binario" ) )
{
valorDecimal = [Link]( [Link]() );
valorX = [Link]( valorDecimal,2 );
}
// Conversión del número decimal a octal
if( [Link]( "Octal" ) )
{
valorDecimal = [Link]( [Link]() );
valorX = [Link]( valorDecimal,8 );
}
// Conversión del número decimal a hexadecimal
if( [Link]( "Hexadecimal" ) )
{
valorDecimal = [Link]( [Link]() );
valorX = [Link]( valorDecimal,16 );
}
// Conversión del número decimal a un número en base 36
if( [Link]( "Base36" ) )
{
valorDecimal = [Link]( [Link]() );
valorX = [Link]( valorDecimal,36 );
}

actualizaTexto();
return( true );
}
return false;
}

public static void main( String args[] ) {


Convertidor c = new Convertidor();
[Link]();
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 19:55:42
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link].*;
import [Link].*;
import [Link];

// Clase para pintar casi todos los componentes que ofrece el AWT
// de Java y poder visualizar su apariencia en la pantalla
public class AwtGui extends Applet {
TextArea edicion;
miCanvas dibujo;
Label edicionLab,lapizLab;
List colores;
Button imprimir,borrar;
Choice figuras;
Checkbox relleno;
Scrollbar lapizBar;
TextField lapizTex;
Panel panelIzq,panelDch,panelBot,panelDib;

public void init() {


// Creamos los paneles con sus layout managers
panelIzq = new Panel();
[Link]( new BorderLayout() );

panelDch = new Panel();


[Link]( new BorderLayout() );

panelBot = new Panel();


[Link]( new GridLayout( 4,0 ) );

panelDib = new Panel();


[Link]( new BorderLayout() );
[Link]( 1,1,200,20 );

// Construimos el lado izquierdo de la ventana


// Creamos la lista de colores
colores = new List( 6,false );
[Link]( "Rojo" );
[Link]( "Naranja" );
[Link]( "Amarillo" );
[Link]( "Verde" );
[Link]( "Azul" );
[Link]( "Morado" );
[Link]( "Negro" );
[Link]( "Blanco" );
// Añadimos la lista de colores al panel izquierdo
[Link]( "West",colores );

// Creamos un nuevo Canvas


dibujo = new miCanvas();
[Link]( 0,0,100,100 );
// Añadimos el canvas al panel izquierdo
[Link]( "Center",dibujo );

// Creamos los botones


borrar = new Button( "Borrar" );
imprimir = new Button( "Imprimir" );
figuras = new Choice();
[Link]( "Cuadrado" );
[Link]( "Círculo" );
[Link]( "Triángulo" );
relleno = new Checkbox( "Relleno" );
// Añadimos los botones a su propio panel
[Link]( borrar );
[Link]( imprimir );
[Link]( figuras );
[Link]( relleno );
// Añadimos el panel de botones al lado derecho
[Link]( "East",panelBot );

// Creamos el area del lápiz


lapizLab = new Label( "Lápiz" );
lapizBar = new Scrollbar( [Link],1,1,1,10 );
[Link]( 1,1,100,5 );
lapizTex = new TextField( "1",8 );
// Añadimos las partes anteriores a su propio panel
[Link]( "North",lapizLab );
[Link]( "Center",lapizBar );
[Link]( "East",lapizTex );
// Añadimos el panel a la parte inferior
[Link]( "South",panelDib );

// Construimos el lado derecho de la ventana


edicionLab = new Label( "Editor" );
edicion = new TextArea( "Aqui se puede escribir",8,30 );
// Añadimos la etiqueta y el área de texto al lado derecho
[Link]( "North",edicionLab );
[Link]( "South",edicion );

// Incorporamos los dos paneles al applet que utiliza


// FlowLayout por defecto
add( panelIzq );
add( panelDch );
}
}

// Creamos una clase para poder pintar una zona de dibujo y que
// se muestre el canvas. Pintamos un rectangulo alrededor suyo
class miCanvas extends Canvas {
public void paint( Graphics g ) {
int w = size().width;
int h = size().height;
[Link]( 0,0,w-1,h-1 );
[Link]( "Canvas",
( [Link]().stringWidth( "Canvas" ) )/2,10 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 19:01:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostracion de uso del FlowLayout


public class AwtFlow extends Applet {
Button boton1,boton2,boton3;

public void init() {


// Simplemente a¤adimos tres botones al Applet, y como el
// FlowLayout es el que se usa por defecto, ni nos
// molestamos en indicar que ese es el que queremos
boton1 = new Button( "Aceptar" );
boton2 = new Button( "Abrir" );
boton3 = new Button( "Cerrar" );

add( boton1 );
add( boton2 );
add( boton3 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 19:16:32
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase para demostrar la apariencia del BorderLayout


public class AwtBord extends Applet {
Button botonN,botonS,botonE,botonO,botonC;

public void init() {


setLayout( new BorderLayout() );

// Craemos un boton en cada posicion que permite el layout


botonN = new Button( "Norte" );
botonS = new Button( "Sur" );
botonE = new Button( "Este" );
botonO = new Button( "Oeste" );
botonC = new Button( "Centro" );

// Los hacemos aparecer en pantalla


add( "North",botonN );
add( "South",botonS );
add( "East",botonE );
add( "West",botonO );
add( "Center",botonC );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 19:23:08
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostracion de uso del GridLayout


public class AwtGrid extends Applet {
Button boton1,boton2,boton3,boton4,boton5,boton6;

public void init() {


// Creamos un layout de 3 filas por dos columnas
// y colocamos un boton en cada una de las celdas
setLayout( new GridLayout( 3,2 ) );

boton1 = new Button( "1" );


boton2 = new Button( "2" );
boton3 = new Button( "3" );
boton4 = new Button( "4" );
boton5 = new Button( "5" );
boton6 = new Button( "6" );

add( boton1 );
add( boton2 );
add( boton3 );
add( boton4 );
add( boton5 );
add( boton6 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 20:12:24
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostracion del uso del GridBagLayout


// Vamos a crear nueve botones, fijando los Constraints para
// que se pueda ver la flexibilidad que permite el uso de este
// layout
public class AwtGBag extends Applet {

public void init() {


GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();

setLayout( gridbag );

// Para este grupo fijamos la anchura y vamos variando alguna


// de las caracteristicas en los siguientes, de tal forma que
// los botones que aparecen en cada una de las lineas tengan
// apariencia diferente en pantalla
[Link] = [Link];
[Link] = 1.0;
Button boton0 = new Button( "Botón 0" );
[Link]( boton0,gbc );
add( boton0 );
Button boton1 = new Button( "Botón 1" );
[Link]( boton1,gbc );
add( boton1 );
Button boton2 = new Button( "Botón 2" );
[Link]( boton2,gbc );
add( boton2 );

[Link] = [Link];
Button boton3 = new Button( "Botón 3" );
[Link]( boton3,gbc );
add( boton3 );

[Link] = 0.0;
Button boton4 = new Button( "Botón 4" );
[Link]( boton4,gbc );
add( boton4 );

[Link] = [Link];
Button boton5 = new Button( "Botón 5" );
[Link]( boton5,gbc );
add( boton5 );
[Link] = [Link];
Button boton6 = new Button( "Botón 6" );
[Link]( boton6,gbc );
add( boton6 );

[Link] = 1;
[Link] = 2;
[Link] = 1.0;
Button boton7 = new Button( "Botón 7" );
[Link]( boton7,gbc );
add( boton7 );

[Link] = 0.0;
[Link] = [Link];
[Link] = 1;
Button boton8 = new Button( "Botón 8" );
[Link]( boton8,gbc );
add( boton8 );
Button boton9 = new Button( "Botón 9" );
[Link]( boton9,gbc );
add( boton9 );
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 22-Ago-1996 22:42:12
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostracion un poco mas avanzada del uso del GridBagLayout


// para comprobar las facilidades
public class AwtGBagConv extends Applet {
GridBagLayout gridbag = new GridBagLayout();

// Creamos una funcion que permite incorporar automaticamente los


// componentes, sin necesidad de tener que ir fijando los
// constraints para cada uno de ellos
void addComponente( Component comp,int gridx,int gridy,
int gridw,int gridh ) {
GridBagConstraints gbc = new GridBagConstraints();
[Link] = gridx;
[Link] = gridy;
[Link] = gridw;
[Link] = gridh;
[Link]( comp,gbc );
add( comp );
}

public void init() {


setLayout( gridbag );

// Incorporamos unos cuantos componentes de diversos tipos


// utilizando nuestra funcion de a¤adir componente
addComponente( new Label( "Nombre:" ),0,0,1,1 );
addComponente( new TextField( 12 ),1,0,2,1 );
addComponente( new TextArea( 5,20 ),0,1,2,2 );
addComponente( new Checkbox( "Sí?" ),2,1,1,1 );
addComponente( new List(),2,2,1,1 );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 19:39:31
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostracion del uso del CardLayout


public class AwtCard extends Applet {
Panel card;
final static String PanelBoton = "Panel con Botones";
final static String PanelTexto = "Panel con Campo de Texto";

public void init() {


// en la zona de seleccion del CardLayout, creamos un panel
// con una lista de seleccion que nos permita seleccionar
// entre dos paneles diferentes en la zona de visualizacion
setLayout( new BorderLayout() );
Panel ac = new Panel();
Choice c = new Choice();

[Link]( PanelBoton );
[Link]( PanelTexto );
[Link]( c );
add( "North",ac );

card = new Panel();


[Link]( new CardLayout() );

// Uno de los paneles de la zona de visualizacion solo va a


// contener botones
Panel p1 = new Panel();
[Link]( new Button( "Botón 1" ) );
[Link]( new Button( "Botón 2" ) );
[Link]( new Button( "Botón 3" ) );

// El otro panel, contendra un campo de texto de 20 columnas


Panel p2 = new Panel();
[Link]( new TextField( "Texto",20 ) );

// Incorporamos los paneles de visualizacion al Layout


[Link]( PanelBoton,p1 );
[Link]( PanelTexto,p2 );
add( "Center",card );
}

// Solo manejamos el evento de la lista de seleccion, en funcion


// de la opcion elegida presentara uno u otro de los paneles
public boolean action( Event evt,Object arg ) {
if( [Link] instanceof Choice )
{
( (CardLayout)[Link]() ).show( card,(String)arg );
return true;
}
return false;
}
}

//------------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 20:32:40
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Implementación de un controlador de posicionamiento propio, que va


// a permitir colocar los componenetes en cualquier lugar de su dominio
// Tenemos que sobrecargar o definir los métodos que se utilizan en los
// LayoutManager para que todo funcione, aunque no hagan nada, porque
// aunque nosotros no llamemos explícitamente a esos métodos en ninguna
// ocasión, es el propio sistema el que puede hacerlo
public class MiLayout implements LayoutManager {

// Constructor
public MiLayout() {
}

// Método para la incorporación de componentes


public void addLayoutComponent( String name,Component comp ) {
}

// Método para eliminar componentes del controlador


public void removeLayoutComponent( Component comp ) {
}

// Fija la dimensión del controaldor en función de la dimensión


// de los componentes y su posición, para que se vean todos en
// el espacio de pantalla destinado al controlador
public Dimension preferredLayoutSize( Container parent ) {
Insets insets = [Link]();
int numero = [Link]();
int ancho = 0;
int alto = 0;

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();
Point p = [Link]();

if( ( p.x + [Link] ) > ancho )


ancho = p.x + [Link];
if( ( p.y + [Link] ) > alto )
alto = p.y + [Link];
}

return( new Dimension( [Link] + [Link] + ancho,


[Link] + [Link] + alto ) );
}

// Controlamos la dimensión mínima que debe tener el controlador


public Dimension minimumLayoutSize( Container parent ) {
Insets insets = [Link]();
int numero = [Link]();
int ancho = 0;
int alto = 0;

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();
Point p = [Link]();

if( ( p.x + [Link] ) > ancho )


ancho = p.x + [Link];
if( ( p.y + [Link] ) > alto )
alto = p.y + [Link];
}

return( new Dimension( [Link] + [Link] + ancho,


[Link] + [Link] + alto ) );
}

// Reescala los componentes a su tamaño preferido en caso de que


// se pueda hacer
public void layoutContainer( Container parent ) {
int numero = [Link]();

for( int i=0; i < numero; i++ )


{
Component comp = [Link]( i );
Dimension d = [Link]();

[Link]( [Link],[Link] );
}
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 25-Jul-1996 20:43:15
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostraci¢n de la creacion de un layout propio. Utilizamos el


// layout que hemos definido en la clase [Link], que es un
// layout que dispone de un metodo para posicionar los componentes en
// coordenadas espec¡ficas de la pantalla
public class AwtLibre extends Applet {
Button boton1,boton2,boton3;
Label etiqueta;
TextField texto;

public void init() {


// Se utiliza nuestro dise¤o en el Applet
setLayout( new MiLayout() );

// Colocamos tres botones, una etiqueta y un texto asociado


boton1 = new Button( "Aceptar" );
boton2 = new Button( "Abrir" );
boton3 = new Button( "Cerrar" );
etiqueta = new Label( "Texto" );
texto = new TextField( "",20 );

// Incorporamos los componenetes al Layout


add( boton1 );
add( boton2 );
add( boton3 );
add( etiqueta );
add( texto );

// Utilizamos el m‚todo "move" que hemos implementado para


// nuestro layout, que nos permitira colocar los componentes en
// posiciones especificas de la pantalla
[Link]( 0,10 );
[Link]( 70,10 );
[Link]( 30,40 );
[Link]( 75,70 );
[Link]( 120,70 );
}
}

//----------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Jul-1996 20:42:23
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase que presenta en consola los eventos que va recogiendo el sistema


// Por cada evento que se produce, se presenta en la consola un mensaje
// indicando el tipo de evento que se ha generado
public class EventosPrnt extends Applet {

public void init() {


[Link]( "Evento init" );
}

public void start() {


[Link]( "Evento start" );
}

public void destroy() {


[Link]( "Evento destroy" );
}

public void paint( Graphics g ) {


[Link]( "Evento paint" );
}

public void update( Graphics g ) {


[Link]( "Evento update" );
}

public boolean mouseUp( Event evt,int x, int y ) {


[Link]( "Evento mouseUp" );
return false;
}

public boolean mouseDown( Event evt,int x, int y ) {


[Link]( "Evento mouseDown" );
return false;
}

public boolean mouseDrag( Event evt,int x, int y ) {


[Link]( "Evento mouseDrag" );
return false;
}

public boolean mouseMove( Event evt,int x, int y ) {


[Link]( "Evento mouseMove" );
return false;
}
public boolean mouseEnter( Event evt,int x, int y ) {
[Link]( "Evento mouseEnter" );
return false;
}

public boolean mouseExit( Event evt,int x, int y ) {


[Link]( "Evento mouseExit" );
return false;
}

public boolean keyDown( Event evt,int x ) {


[Link]( "Evento keyDown" );
return true;
}

public void getFocus() {


[Link]( "Evento getFocus" );
}

public void gotFocus() {


[Link]( "Evento gotFocus" );
}

public void lostFocus() {


[Link]( "Evento lostFocus" );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 31-Jul-1996 21:17:46
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase que va generando una lista con los eventos que el sistema va
// recogiendo. Se crea una lista y luego, por cada evento que se produce
// de añade un elemento a la lista, indicando el evento que se ha
// producido
public class EventosList extends Applet {
List lista;

public void init() {


lista = new List( 25,false );
add( lista );
[Link]( "Evento init" );
}

public void start() {


[Link]( "Evento start" );
}

public void destroy() {


[Link]( "Evento destroy" );
}

public void paint( Graphics g ) {


[Link]( "Evento paint" );
}

public void update( Graphics g ) {


[Link]( "Evento update" );
}

public boolean mouseUp( Event evt,int x, int y ) {


[Link]( "Evento mouseUp en ("+x+","+y+")" );
return false;
}

public boolean mouseDown( Event evt,int x, int y ) {


[Link]( "Evento mouseDown en ("+x+","+y+")" );
return false;
}

public boolean mouseDrag( Event evt,int x, int y ) {


[Link]( "Evento mouseDrag en ("+x+","+y+")" );
return false;
}
public boolean mouseMove( Event evt,int x, int y ) {
[Link]( "Evento mouseMove en ("+x+","+y+")" );
return false;
}

public boolean mouseEnter( Event evt,int x, int y ) {


[Link]( "Evento mouseEnter en ("+x+","+y+")" );
return false;
}

public boolean mouseExit( Event evt,int x, int y ) {


[Link]( "Evento mouseExit" );
return false;
}

public boolean keyDown( Event evt,int x ) {


[Link]( "Evento keyDown, carácter "+(char)x+" pulsado" );
return true;
}

public void getFocus() {


[Link]( "Evento getFocus" );
}

public void gotFocus() {


[Link]( "Evento gotFocus" );
}

public void lostFocus() {


[Link]( "Evento lostFocus" );
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 18:07:23
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;

// Aplicación que nos abre una ventana donde aparecerán todos los valores
// de los datos que componen cada evento que recibe el sistema
public class VisorEventos extends Frame {
private TextField tfId;
private TextField tfTarget;
private TextField tfKey;
private TextField tfMod;
private TextField tfWhen;
private TextField tfX;
private TextField tfY;
private TextField tfCC;
private TextField tfArg;

boolean EjecucionEnApplet = true;

public VisorEventos() {
super("Visualizador de Eventos");

// Creamos el panel y fijamos el layout y las dimensiones


// para ir colocando los valores de los datos
Panel p;
p = new Panel();
GridBagLayout gbl = new GridBagLayout();
[Link](gbl);

GridBagConstraints gbs1 = new GridBagConstraints();


GridBagConstraints gbs2 = new GridBagConstraints();

[Link] = [Link];
[Link] = 0.5;

[Link] = [Link];
[Link] = [Link];
[Link] = 1.0;
[Link] = 0.5;

// Tipo de evento que se ha producido


Component c;
c = new Label( "Id" );
[Link]( c,gbs1 );
[Link]( c );
tfId = new TextField();
[Link]( false );
[Link]( tfId,gbs2 );
[Link]( tfId );

// Componente sobre el que se ha producido el evento


c = new Label( "Target" );
[Link]( c,gbs1 );
[Link]( c );
tfTarget = new TextField();
[Link]( false );
[Link]( tfTarget,gbs2 );
[Link]( tfTarget );

// Tecla pulsada, en eventos de teclado


c = new Label( "Key" );
[Link]( c,gbs1 );
[Link]( c );
tfKey = new TextField();
[Link]( false );
[Link]( tfKey,gbs2 );
[Link]( tfKey );

// Combinación en que se encuentran las teclas especiales


c = new Label( "Modifiers" );
[Link]( c,gbs1 );
[Link]( c );
tfMod = new TextField();
[Link]( false );
[Link]( tfMod,gbs2 );
[Link]( tfMod );

// Instante en que se ha producido el evento


c = new Label( "When" );
[Link]( c,gbs1 );
[Link]( c );
tfWhen = new TextField();
[Link]( false );
[Link]( tfWhen,gbs2 );
[Link]( tfWhen );

// Coordenada X relativa al componente, donde se ha producido


// el evento
c = new Label("Coordenada X");
[Link](c, gbs1);
[Link](c);
tfX = new TextField();
[Link]( false );
[Link]( tfX,gbs2 );
[Link]( tfX );

// Coordenada Y relativa al componente, donde se ha producido


// el evento
c = new Label("Coordenada Y");
[Link](c, gbs1);
[Link](c);
tfY = new TextField();
[Link]( false );
[Link]( tfY,gbs2 );
[Link]( tfY );

// Número de clicks consecutivos de ratón


c = new Label( "Cont. Clicks" );
[Link]( c,gbs1 );
[Link]( c );
tfCC = new TextField();
[Link]( false );
[Link]( tfCC,gbs2 );
[Link]( tfCC );
// Argumento dependiente el evento que se haya producido
c = new Label( "Argumento" );
[Link]( c,gbs1 );
[Link]( c );
tfArg = new TextField();
[Link]( false );
[Link]( tfArg,gbs2 );
[Link]( tfArg );

add( "Center",p );

// Para generar algunos eventos diferentes del ratón y del


// teclado, incorporamos al panel un bón y una lista de
// selección
p = new Panel();
Button b = new Button( "Púlsame" );
[Link](b);

Choice ch = new Choice();


[Link]( "uno" );
[Link]( "dos" );
[Link]( "tres" );
[Link]( ch );

add( "South",p );
}

// Controlador de eventos. Cuando se produce un evento, se


// actualizan los campos de texto indicando los valores de los
// datos que corresponden a ese evento
public boolean handleEvent( Event evt ) {
[Link]( [Link]() );
[Link]( [Link]( [Link] ) );
[Link]( [Link]( [Link] ) );
[Link]( [Link]( [Link] ) );
[Link]( [Link]( [Link] ) );
[Link]( [Link]( [Link] ) );
[Link]( [Link]( evt.x ) );
[Link]( [Link]( evt.y ) );
[Link]( [Link] == null ? "(null)" : [Link]() );

if( [Link] == Event.WINDOW_DESTROY )


{
if( EjecucionEnApplet )
{
dispose();
return true;
}
else
[Link]( 0 );
}

return( [Link]( evt ) );


}

public static void main( String args[] ) {


VisorEventos ve = new VisorEventos();

[Link] = false;

[Link]();
[Link]();
}
}
//-------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 18:15:46
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Creamos una clase derivada de botón, en donde sobrecargamos su


// constructor para pasarle como parámetro un campo de texto donde
// pueda mostrar mensajes y también sobrecargamos su método controlador
// de eventos, para que cuando reciba el evento ACTION imprima un
// mensaje y lo propague hacia su padre
class BotonPro extends Button {
private TextArea ta;

public BotonPro( String str,TextArea ta ) {


super( str );
[Link] = ta;
}

public boolean handleEvent( Event evt ) {


// Si es el evento ACTION imprime el mensaje
if( [Link] == Event.ACTION_EVENT )
[Link]( "Botón " + getLabel() + " recibe action...\n" );
// Cualquier evento se lo propaga al padre
return( [Link]( evt ) );
}
}

// Clase Panel, en donde tambien hemos sobrecargado el constructor para


// permitirle presentar mensajes y además sobrecargamos el controlador
// de eventos para que nos avise de cuando le llegan eventos propagados
// por sus hijos, imprimiendo un mensaje en ese caso indicando el evento
// que ha recibido
class PanelPro extends Panel {
private String str;
private TextArea ta;

public PanelPro( String str,TextArea ta ) {


super();
[Link] = str;
[Link] = ta;
}

public Insets insets() {


return new Insets( 5,5,5,5 );
}

public void paint( Graphics g ) {


[Link]( 0,0,size().width-1,size().height-1 );
}

public boolean handleEvent( Event evt ) {


if( [Link] == Event.ACTION_EVENT )
[Link]( "Panel " + str + " recibe action...\n" );
else if( [Link] == Event.MOUSE_DOWN )
[Link]( "Panel " + str + " recibe mouse_down...\n" );
// Propagamos el evento hacia el padre
return( [Link]( evt ) );
}
}

// Demostración de la propagación de los eventos


public class EventosPro extends Applet {
TextArea ta = new TextArea();

// Creamos dos paneles, en uno ponemos los botones y en el otro


// el campo de texto y el panel que contiene los botones
public void init() {
setLayout( new BorderLayout() );
add( "Center",ta );
PanelPro p1 = new PanelPro( "1",ta );
PanelPro p2 = new PanelPro( "2",ta );
[Link]( new BotonPro( "Uno",ta ) );
[Link]( new BotonPro( "Dos",ta ) );
[Link]( p2 );
add( "South",p1 );
}

// Fijamos las dimensiones que queremos


public Dimension preferredSize() {
return new Dimension( 400,230 );
}

public Insets insets() {


return new Insets( 5,5,5,5 );
}

// Controlamos los eventos que nos llegan de los hijos


public boolean handleEvent( Event evt ) {
if( [Link] == Event.ACTION_EVENT )
[Link]("Applet recibe action...\n\n" );
else if( [Link] == Event.MOUSE_DOWN )
[Link]("Applet recibe mouse_down...\n\n" );
// Y los propagamos hacia el padre
return( [Link]( evt ) );
}

public static void main(String args[] ) {


Frame f = new Frame( "Propagación de Eventos" );
EventosPro ep = new EventosPro();

[Link]();
[Link]( "Center",ep );
[Link]();
[Link]();
}
}

//---------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 18:48:10
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase que crea una zona de dibujo en la pantalla y va presentando una


// linea entre cada uno de los puntos que se vayan picando con el boton
// del ratón
public class EventosRaton extends Applet{
boolean Pintar;
int lastx,lasty;
int newx,newy;

public void init() {


add( new Canvas() );

Pintar = false;
lastx = size().width / 2;
lasty = size().height / 2;
newx = newy = 0;
}

// Cuando el cursor entre en el dominio del applet, repintamos


// la linea, para que aparesca en pantalla ese línea
public boolean mouseEnter( Event evt,int x,int y ) {
Pintar = true;

repaint();
return true;
}

// También repintamos cuando el cursor abandona el applet para que


// la línea desaparezca de la pantalla
public boolean mouseExit( Event evt,int x,int y ) {
Pintar = false;

repaint();
return true;
}

// Con los movimientos del cursor vamos repintando


public boolean mouseMove( Event evt,int x,int y ) {
newx = x;
newy = y;

repaint();
return true;
}

// Tomamos el puevo punto cuando se pulsa el botón del ratón


// para volver a presentar a partir de ahí la linea
public boolean mouseDown( Event evt,int x,int y ) {
lastx = newx;
lasty = newy;

repaint();
return true;
}

// El método paint pinta la línea desde del último punto que se


// haya pulsado hasta la posición en que actualmente se encuentre
// el cursor
public void paint( Graphics g ) {
if( Pintar )
[Link]( lastx,lasty,newx,newy );
}

public Dimension preferredSize() {


return new Dimension( 400,100 );
}

public static void main( String args[] ) {


Frame f = new Frame( "Eventos del Ratón" );
EventosRaton er = new EventosRaton();

[Link]();

[Link]( "Center",er );
[Link]();
[Link]();
}
}

//-------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 19:25:33
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Demostración del uso del color a la hora de presentar los componentes


// sobre la pantalla
public class CambioColor extends Applet {
public static void main( String args[] ) {
Frame fr = new Frame( "Cambio de Color" );
CambioColor cc = new CambioColor();
[Link]( [Link] );
[Link]( new FlowLayout() );
Button b = new Button( "Hola" );
[Link]( b );
Checkbox cb = new Checkbox( "Púlsame" );
[Link]( cb );
TextArea ta = new TextArea();
[Link]( ta );

[Link]();
[Link]();
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 19:31:13
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Creamos la clase Boton Variable, en donde lo único que sobrecargamos


// es el constructor normal de la clase Button, para que nos permita
// variar el tamaño del botón
class BotonVariable extends Button {
private Dimension dim = null;

public BotonVariable( String str,Dimension dim ) {


super( str );
[Link] = new Dimension( dim );
resize( dim );
}

// Método que hace efectivo el cambio de dimensiones del botón


public void newPreferredSize( Dimension dim ) {
[Link] = new Dimension( dim );
resize( dim );
}

// Método que nos devuelve la dimensión actual del botón


public Dimension preferredSize() {
return( new Dimension( dim ) );
}
}

// Demostración del uso del botón variable que hemos definido antes
public class CambioBoton extends Applet {
private BotonVariable bv1 = null;
private BotonVariable bv2 = null;
public void init() {
setLayout( new FlowLayout() );
setBackground( [Link] );
Dimension dim = new Dimension( 85,30 );

// Creamos dos botones, y lo que haremos será que cuando se


// pulse en uno se haga más grande o más chico que el otro
// y este segundo al contrario
bv1 = new BotonVariable( " Púlsame",dim );
bv2 = new BotonVariable( " No, Púlsame",dim );
add( bv1 );
add( bv2 );
}
// Colocamos los botones con un borde amplio
public Insets insets() {
return( new Insets( 30,10,10,10 ) );
}

public Dimension preferredSize() {


return( new Dimension( 200,100 ) );
}

public boolean action( Event evt,Object obj ) {


Dimension dim1 = [Link]();
Dimension dim2 = [Link]();

// Controlamos que el botón que aumenta de tamaño sea el que se


// ha pulsado, y el otro disminuya
if( [Link] == bv1 )
{
[Link]++;
[Link]++;
[Link]--;
[Link]--;
}
else if( [Link] == bv2 )
{
[Link]++;
[Link]++;
[Link]--;
[Link]--;
}

// Controlamos que las dimensiones no se hagan tan pequeñas


// que no llegue a verse nada
if( [Link] < 1 )
[Link] = 1;
if( [Link] < 1 )
[Link] = 1;
if( [Link] < 1 )
[Link] = 1;
if( [Link] < 1 )
[Link] = 1;

[Link]( dim1 );
[Link]( dim2 );
// Regeneramos el contenido del layout
layout();

// Propagamos el evento a la ventana para que se refresque


return( [Link]( evt,obj ) );
}

public static void main( String args[] ) {


Frame fr = new Frame( "Botones Variables" );
CambioBoton cb = new CambioBoton();
[Link]();
[Link]( "Center",cb );
[Link]();
[Link]();
}
}

//--------------------------------------- Final del fichero [Link]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 19:57:40
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];

// Clase Texto modificada para el control de los botones


class NTextField extends TextField {
Component rgcomp[];

// En el operador le pasamos un array de componentes que será el


// que mantenga controlado
public NTextField( Component rgcomp[] ) {
super();

// De entrada, todos los componentes están deshabilitados


[Link] = rgcomp;
for( int i=0; i < [Link]; i++ )
rgcomp[i].disable();
}

// Cuando se pulsa una tecla y se recibe el evento, se trata


public boolean keyDown( Event evt,int nKey ) {
boolean fin = true;
int n = getText().length();

// Teclas especiales
if( ( nKey > 96 && nKey < 123 ) ||
( nKey > 64 && nKey < 91 ) ||
( nKey > 47 && nKey < 58 ) ||
( nKey == 32 ) )
{
fin = false;
n++;
}
// Tecla de borrado hacia atrás
else if( nKey == 8 )
{
fin = false;
n--;
}

// También controlamos la longitud del texto que se escribe en


// el campo de texto, de forma que si se borran todos los
// caracteres del campo, se deshabilitan los componentes
if( n > 0 )
{
for( int i=0; i < [Link]; i++ )
rgcomp[i].enable();
}
else
{
for( int i=0; i < [Link]; i++ )
rgcomp[i].disable();
}

return( fin );
}
}

// Creamos el applet, en donde creamos dos botones que serán los que se
// controles, en cuando a su habilitación, desde el contenido del campo
// de texto
public class Habilitar extends Applet {

public void init() {


setLayout( new BorderLayout() );

Component rgcomp[] = new Component[2];


rgcomp[0] = new Button( "Añadir" );
rgcomp[1] = new Button( "Borrar" );
Panel p = new Panel();
[Link]( rgcomp[0] );
[Link]( rgcomp[1] );
add( "South",p );
add( "North",new NTextField( rgcomp ) );
}

public Insets insets() {


return new Insets( 5,5,5,5 );
}

public static void main( String args[] ) {


Frame f = new Frame( "Habilitación" );
Habilitar h = new Habilitar();
[Link]();

[Link]( "Center",h );
[Link]();
[Link]();
}
}

//---------------------------------------- Final del fichero [Link]


LA CLASE Math
La clase Math representa la librería matemática de Java. Las funciones que contiene son las de todos los lenguajes,
parece que se han metido en una clase solamente a propósito de agrupación, por eso se encapsulan en Math, y lo
mismo sucede con las demás clases que corresponden a objetos que tienen un tipo equivalente (Character, Float,
etc.). El constructor de la clase es privado, por los que no se pueden crear instancias de la clase. Sin embargo, Math
es public para que se pueda llamar desde cualquier sitio y static para que no haya que inicializarla.

Funciones matemáticas

Si se importa la clase, se tiene acceso al conjunto de funciones matemáticas estándar:

[Link]( x ) para int, long, float y double


[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
Math.atan2( double,double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( double )
[Link]( a,b )
[Link]( x ) para double y float
[Link]() devuelve un double
[Link]( a,b ) para int, long, float y double
[Link]( a,b ) para int, long, float y double
Math.E para la base exponencial
[Link] para PI

He aquí un ejemplo, [Link], de uso de algunas funciones de la clase Math:

class Mates {
public static void main( String args[] ) {
int x;
double rand,y,z;
float max;

rand = [Link]();
x = [Link]( -123 );
y = [Link]( 123.567 );
z = [Link]( 2,4 );
max = [Link]( (float)1e10,(float)3e9 );

[Link]( rand );
[Link]( x );
[Link]( y );
[Link]( z );
[Link]( max );
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Character
Al trabajar con caracteres se necesitan muchas funciones de comprobación y traslación. Estas funciones están
empleadas en la clase Character. De esta clase sí que se pueden crear instancias, al contrario que sucede con la clase
Math.

Declaraciones

La primera sentencia creará una variable carácter y la segunda un objeto Character:

char c;
Character C;

Comprobaciones booleanas

[Link]( c )
[Link]( c )
[Link]( c )
[Link]( c )

En este caso, si tuviésemos un objeto Character C, no se podría hacer [Link], porque no se ha hecho un new
de Character. Estas funciones son estáticas y no conocen al objeto, por eso hay que crealo antes.

Traslaciones de caracteres

char c2 = [Link]( c );
char c2 = [Link]( c );

Traslaciones de carácter/dígito

int i = [Link]( c,base );


char c = [Link]( i,base );

Métodos de la clase Character

C = new Character( 'J' );


char c = [Link]();
String s = [Link]();
Tutorial de Java [Anterior] [Indice] [Siguiente]
LA CLASE Float
Cada tipo numérico tiene su propia clase de objetos. Así el tipo float tiene el objeto Float. De la misma forma que
con la clase Character, se han codificado muchas funciones útiles dentro de los métodos de la clase Float.

Declaraciones

La primera sentencia creará una variable float y la segunda un objeto Float:

float f;
Float F;

Valores de Float

Float.POSITIVE_INFINITY
Float.NEGATIVE_INFINITY
[Link]
Float.MAX_VALUE
Float.MIN_VALUE

Conversiones de Clase/Cadena

String s = [Link]( f );
f = [Link]( "3.14" );

Comprobaciones

boolean b = [Link]( f );
boolean b = [Link]( f );

La función isNaN() comprueba si f es un No-Número. Un ejemplo de no-número es raiz cuadrada de -2.

Conversiones de Objetos

Float F = new Float( [Link] );


String s = [Link]();
int i = [Link]();
long l = [Link]();
float F = [Link]();
double d = [Link]();
Otros Métodos

int i = [Link]();
boolean b = [Link]( Object obj );
int i = [Link]( f );
float f = [Link]( i );

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Double
Cada tipo numérico tiene su propia clase de objetos. Así el tipo double tiene el objeto Double. De la misma forma
que con la clase Character, se han codificado muchas funciones útiles dentro de los métodos de la clase Double.

Declaraciones

La primera sentencia creará una variable double y la segunda un objeto Double:

double d;
Double D;

Valores de Double

Double.POSITIVE_INFINITY
Double.NEGATIVE_INFINITY
[Link]
Double.MAX_VALUE
Double.MIN_VALUE

Métodos de Double

[Link]();
[Link]( d );
[Link]();
[Link]( d );
boolean [Link]();
String [Link]();
int [Link]();
long [Link]();
float [Link]();
double [Link]();
int i = [Link]();
Double [Link]( String s );
long l = [Link]( d );
double d = [Link]( l );

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Integer
Cada tipo numérico tiene su propia clase de objetos. Así el tipo int tiene el objeto Integer. De la misma forma que
con la clase Character, se han codificado muchas funciones útiles dentro de los métodos de la clase Integer.

Declaraciones

La primera sentencia creará una variable int y la segunda un objeto Integer:

int i;
Integer I;

Valores de Integer

Integer.MIN_VALUE;
Integer.MAX_VALUE;

Métodos de Integer

String [Link]( int i,int base );


String [Link]( int i );
int [Link]( String s,int base );
int [Link]( String s );
Integer [Link]( String s,int base );
Integer [Link]( String s );
int [Link]();
long [Link]();
float [Link]();
double [Link]();
String [Link]();
int [Link]();
boolean [Link]( Object obj );

En los métodos toString(), parseInt() y valueOf() que no se especifica la base sobre la que se trabaja, se asume que es
base 10.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Long
Cada tipo numérico tiene su propia clase de objetos. Así el tipo long tiene el objeto Long. De la misma forma que con
la clase Character, se han codificado muchas funciones útiles dentro de los métodos de la clase Long.

Declaraciones

La primera sentencia creará una variable long y la segunda un objeto Long:

long l;
Long L;

Valores de Long

Long.MIN_VALUE;
Long.MAX_VALUE;

Métodos de Long

String [Link]( long l,int base );


String [Link]( long l );
long [Link]( String s,int base );
long [Link]( String s );
Long [Link]( String s,int base );
Long [Link]( String s );
int [Link]();
long [Link]();
float [Link]();
double [Link]();
String [Link]();
int [Link]();
boolean [Link]( Object obj );

En los métodos toString(), parseInt() y valueOf() que no se especifica la base sobre la que se trabaja, se asume que es
base 10.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE Boolean
Los valores boolean también tienen su tipo asociado Boolean, aunque en este caso hay menos métodos
implementados que para el resto de las clases numéricas.

Declaraciones

La primera sentencia creará una variable boolean y la segunda un objeto Boolean:

boolean b;
Boolean B;

Valores de Boolean

[Link];
[Link];

Métodos de Boolean

boolean [Link]();
String [Link]();
boolean [Link]( Object obj );

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE String
Java posee gran capacidad para el manejo de cadenas dentro de sus clases String y StringBuffer. Un objeto String
representa una cadena alfanumérica de un valor constante que no puede ser cambiada después de haber sido creada.
Un objeto StringBuffer representa una cadena cuyo tamaño puede variar.

Los Strings son objetos constantes y por lo tanto muy baratos para el sistema. La mayoría de las funciones
relacionadas con cadenas esperan valores String como argumentos y devuelven valores String.

Hay que tener en cuenta que las funciones estáticas no consumen memoria del objeto, con lo cual es más conveniente
usar Character que char. No obstante, char se usa, por ejemplo, para leer ficheros que están escritos desde otro
lenguaje.

Existen muchos constructores para crear nuevas cadenas:

String();
String( String str );
String( char val[] );
String( char val[],int offset,int count );
String( byte val[],int hibyte );
String( byte val[],int hibyte,int offset,int count );

Tal como uno puede imaginarse, las cadenas pueden ser muy complejas, existiendo muchas funciones muy útiles
para trabajar con ellas y, afortunadamente, la mayoría están codificadas en la clase String.

Funciones Básicas

La primera devuelve la longitud de la cadena y la segunda devuelve el carácter que se encuentra en la posición que se
indica en indice:

int length();
char charAt( int indice );

Funciones de Comparación de Strings

boolean equals( Object obj );


boolean equalsIgnoreCase( Object obj );

Lo mismo que equals() pero no tiene en cuenta mayúsculas o minúsculas.

int compareTo( String str2 );


Devuelve un entero menor que cero si la cadena es léxicamente menor que str2. Devuelve cero si las dos cadenas
son léxicamente iguales y un entero mayor que cero si la cadena es léxicamente mayor que str2.

Funciones de Comparación de Subcadenas

boolean regionMatch( int thisoffset,String s2,int s2offset,int len );


boolean regionMatch( boolean ignoreCase,int thisoffset,String s2,
int s2offset,int 1 );

Comprueba si una región de esta cadena es igual a una región de otra cadena.

boolean startsWith( String prefix );


boolean startsWith( String prefix,int offset );
boolean endsWith( String suffix );

Devuelve si esta cadena comienza o termina con un cierto prefijo o sufijo comenzando en un determinado
desplazamiento.

int indexOf( int ch );


int indexOf( int ch,int fromindex );
int lastIndexOf( int ch );
int lastIndexOf( int ch,int fromindex );
int indexOf( String str );
int indexOf( String str,int fromindex );
int lastIndexOf( String str );
int lastIndexOf( String str,int fromindex );

Devuelve el primer/último índice de un carácter/cadena empezando la búsqueda a partir de un determinado


desplazamiento.

String substring( int beginindex );


String substring( int beginindex,int endindex );
String concat( String str );
String replace( char oldchar,char newchar );
String toLowerCase();
String toUpperCase();
String trim();

Ajusta los espacios en blanco al comienzo y al final de la cadena.

void getChars( int srcBegin,int srcEnd,char dst[],int dstBegin );


void getBytes( int srcBegin,int srcEnd,byte dst[],int dstBegin );
String toString();
char toCharArray();
int hashCode();

Funciones ValueOf

La clase String posee numerosas funciones para transformar valores de otros tipos de datos a su representación como
cadena. Todas estas funciones tienen el nombre de valueOf, estando el método sobrecargado para todos los tipos de
datos básicos.
Veamos un ejemplo de su utilización:

String Uno = new String( "Hola Mundo" );


float f = 3.141592;

String PI = [Link]( f );
String PI = [Link]( f ); // Mucho más correcto

Funciones de Conversión

String valueOf( boolean b );


String valueOf( int i );
String valueOf( long l );
String valueOf( float f );
String valueOf( double d );
String valueOf( Object obj );
String valueOf( char data[] );
String valueOf( char data[],int offset,int count );

Usa arrays de caracteres para la cadena.

String copyValueOf( char data[] );


String copyValueOf( char data[],int offset,int count );

Crea un nuevo array equivalente para la cadena.

Tutorial de Java [Anterior] [Indice] [Siguiente]


LA CLASE StringBuffer
Java posee gran capacidad para el manejo de cadenas dentro de sus clases String y StringBuffer. Un objeto String
representa una cadena alfanumérica de un valor constante que no puede ser cambiada después de haber sido creada.
Un objeto StringBuffer representa una cadena cuyo tamaño puede variar.

La clase StringBuffer dispone de muchos métodos para modificar el contenido de los objetos StringBuffer. Si el
contenido de una cadena va a ser modificado en un programa, habrá que sacrificar el uso de objetos String en
beneficio de StringBuffer, que aunque consumen más recursos del sistema, permiten ese tipo de manipulaciones.

Al estar la mayoría de las características de los StringBuffers basadas en su tamaño variable, se necesita un nuevo
método de creación:

StringBuffer();
StringBuffer( int len );
StringBuffer( String str );

Se puede crear un StringBuffer vacío de cualquier longitud y también se puede utilizar un String como punto de
partida para un StringBuffer.

StringBuffer Dos = new StringBuffer( 20 );


StringBuffer Uno = new StringBuffer( "Hola Mundo" );

Cambio de Tamaño

El cambio de tamaño de un StringBuffer necesita varias funciones específicas para manipular el tamaño de las
cadenas:

int length();
char charAt( int index );
void getChars( int srcBegin,int srcEnd,char dst[],int dstBegin );
String toString();
void setLength( int newlength );
void setCharAt( int index,char ch );
int capacity();
void ensureCapacity( int minimum );
void copyWhenShared();

Obervar que una de las funciones devuelve una cadena constante normal de tipo String. Este objeto se puede usar con
cualquier función String, como por ejemplo, en las funciones de comparación.

Modificación del Contenido


Para cambiar el contenido de un StringBuffer, se pueden utilizar dos métodos: append() e insert().

En el ejemplo [Link], vemos el uso de estos dos métodos:

class CadAppend {
public static void main( String args[] ) {
StringBuffer str = new StringBuffer( "Hola" );
[Link]( " Mundo" );
[Link]( str );
}
}

En este otro ejemplo, [Link], mostramos un método muy simple que le da la vuelta a una cadena:

class CadInversa {
public static String cadenaInversa( String fuente ) {
int longitud = [Link]();

StringBuffer destino = new StringBuffer( longitud );


for( int i=(longitud-1); i >= 0; i-- )
[Link]( [Link]( i ) );

return( [Link]() );
}

public static void main( String args[] ) {


[Link]( cadenaInversa( "Hola Mundo" ) );
}
}

Las funciones que cambian el tamaño son pues:

StringBuffer append( Object obj );


StringBuffer append( String str );
StringBuffer append( char str[] );
StringBuffer append( char str[],int offset,int len );
StringBuffer append( boolean b );
StringBuffer append( int i );
StringBuffer append( long l );
StringBuffer append( float f );
StringBuffer append( double d );
StringBuffer append( char ch );
StringBuffer insert( int offset,Object obj );
StringBuffer insert( int offset,String str );
StringBuffer insert( int offset,char str[] );
StringBuffer insert( int offset,boolean b );
StringBuffer insert( int offset,int i );
StringBuffer insert( int offset,long l );
StringBuffer insert( int offset,float f );
StringBuffer insert( int offset,double d );
StringBuffer insert( int offset,char ch );
Operadores de Concatenación

Hay que recordar que los operadores "+" y "+=" también se pueden aplicar a cadenas. Ambos realizan una
concatenación y están implementados con objetos StringBuffer.

Por ejemplo, la sentencia:

String s = "¿Qué" + " tal ?";

es interpretada por el compilador como:

String s =
new StringBuffer().append( "¿Qué" ).append( " tal ?" ).toString();

y se marcaría el StringBuffer para borrarlo ya que el contenido pasa al objeto String. También, la sentencia:

s += " por ahí!";

sería interpretada por el sistema como:

String s =
new StringBuffer().append( s ).append( " por ahí!" ).toString();

y volvería a marcar para borrar el nuevo StringBuffer.

Tutorial de Java [Anterior] [Indice] [Siguiente]


USO DE CONVERSIONES
Veamos un ejemplo de utilidad de estas funciones. En el applet [Link], que se muestra en el código que
sigue, se usan estas funciones para producir una salida útil en un programa, presentando las coordenadas en las que se
ha hecho click con el botón del ratón.

public class Conversion extends Applet {


int RatonX = 25;
int RatonY = 25;
String Status = "Haz click con el ratón";

public void paint( Graphics g ) {


[Link]( Status,RatonX,RatonY );
}

public boolean mouseDown( Event evt,int x,int y ) {


Integer X = new Integer( x );
Integer Y = new Integer( y );

RatonX = x;
RatonY = y;
Status = [Link]()+","+[Link]();

repaint();
return true;
}
}

Tutorial de Java [Anterior] [Indice] [Siguiente]


//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 27-Ago-1996 10:06:32
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

import [Link].*;
import [Link];
// Este applet muestra la conversión de los enteros correspondientes a la
// posición en que se pulsa el ratón, a cadenas para poder mostrar en
// pantalla esas posiciones
public class Conversion extends Applet {
int RatonX = 25;
int RatonY = 25;
String Status = "Haz click con el ratón";

public void paint( Graphics g ) {


[Link]( Status,RatonX,RatonY );
}

// Cuando se pulsa el ratón se presentarán en pantalla las


// coordenadas de la posición en que se ha pulsado
public boolean mouseDown( Event evt,int x,int y ) {
Integer X = new Integer( x );
Integer Y = new Integer( y );

RatonX = x;
RatonY = y;
Status = [Link]()+","+[Link]();

repaint();
return( true );
}
}
//---------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 21:11:40
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class Mates {

public static void main( String args[] ) {


int x;
double rand,y,z;
float max;

rand = [Link]();
x = [Link]( -123 );
y = [Link]( 123.567 );
z = [Link]( 2,4 );
max = [Link]( (float)1e10,(float)3e9 );

// Se imprimen en consola los números obtenidos de las operaciones


// anteriores para comprobar los resultados de la aplicación de
// los métodos definidos en la clase Math
[Link]( rand );
[Link]( x );
[Link]( y );
[Link]( z );
[Link]( max );
} }
//-------------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 21:20:11
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class CadAppend {

public static void main( String args[] ) {


// Crea un StringBuffer inicializado a un texto por defecto
StringBuffer str = new StringBuffer( "Hola" );

// Le concatena otro texto, String


[Link]( " Mundo" );

// Imprime en consola el resultado de la concatenación


[Link]( str );
} }
//----------------------------------------- Final del fichero [Link]
//
// [Link]
// Copyright (c) 1996, Agustin Froufe
// Todos los derechos reservados.
//
// No se asume ninguna responsabilidad por el uso o alteracion de este
// software. Este software se proporciona COMO ES, sin garantia de ningun
// tipo de su funcionamiento y en ningun caso sera el autor responsable de
// daños o perjuicios que se deriven del mal uso del software, aun cuando
// este haya sido notificado de la posibilidad de dicho daño.
//
// Compilador: javac 1.0
// Autor: Agustin Froufe
// Creacion: 26-Ago-1996 21:23:32
//
//--------------------------------------------------------------------------
// Esta informacion no es necesariamente definitiva y esta sujeta a cambios
// que pueden ser incorporados en cualquier momento, sin avisar.
//--------------------------------------------------------------------------

class CadInversa {

public static String cadenaInversa( String fuente ) {


// Se obtiene la longitud de la cadena que se pasa
int longitud = [Link]();

// Se crea un stringbuffer de la longitud de la cadena


StringBuffer destino = new StringBuffer( longitud );

// Se recorre la cadena de final a principio, añadiendo


// cada uno de los caracteres leidos al stringbuffer
for( int i=(longitud-1); i >= 0; i-- )
[Link]( [Link]( i ) );

// Devolvemos el contenido de la cadena invertida


return( [Link]() );
}

public static void main( String args[] ) {


// Imprime el resultado inverit la cadena que se toma por
// defecto
[Link]( cadenaInversa( "Hola Mundo" ) );
} }
//---------------------------------------- Final del fichero [Link]
ORIGEN DE JAVA
Sun Microsystems, líder en servidores para Internet, uno de cuyos lemas desde hace mucho tiempo es "the network is
the computer" (lo que quiere dar a entender que el verdadero ordenador es la red en su conjunto y no cada máquina
individual), es quien ha desarrollado el lenguaje Java, en un intento de resolver simultáneamente todos los problemas
que se le plantean a los desarrolladores de software por la proliferación de arquitecturas incompatibles, tanto entre las
diferentes máquinas como entre los diversos sistemas operativos y sistemas de ventanas que funcionaban sobre una
misma máquina, añadiendo la dificultad de crear aplicaciones distribuidas en una red como Internet.

He podido leer más de cinco versiones distintas sobre el origen, concepción y desarrollo de Java, desde la que dice
que este fue un proyecto que rebotó durante mucho tiempo por distintos departamentos de Sun sin que nadie le
prestara ninguna atención, hasta que finalmente encontró su nicho de mercado en la aldea global que es Internet;
hasta la más difundida, que justifica a Java como lenguaje de pequeños electrodomésticos.

Hace algunos años, Sun Microsystems decidió intentar introducirse en el mercado de la electrónica de consumo y
desarrollar programas para pequeños dispositivos electrónicos. Tras unos comienzos dudosos, Sun decidió crear una
filial, denominada FirstPerson Inc., para dar margen de maniobra al equipo responsable del proyecto.

El mercado inicialmente previsto para los programas de FirstPerson eran los equipos domésticos: microondas,
tostadoras y, fundamentalmente, televisión interactiva. Este mercado, dada la falta de pericia de los usuarios para el
manejo de estos dispositivos, requería unos interfaces mucho más cómodos e intuitivos que los sistemas de ventanas
que proliferaban en el momento.

Otros requisitos importantes a tener en cuenta eran la fiabilidad del código y la facilidad de desarrollo. James
Gosling, el miembro del equipo con más experiencia en lenguajes de programación, decidió que las ventajas
aportadas por la eficiencia de C++ no compensaban el gran coste de pruebas y depuración. Gosling había estado
trabajando en su tiempo libre en un lenguaje de programación que él había llamado Oak, el cual, aún partiendo de la
sintaxis de C++, intentaba remediar las deficiencias que iba observando.

Los lenguajes al uso, como C o C++, deben ser compilados para un chip, y si se cambia el chip, todo el software debe
compilarse de nuevo. Esto encarece mucho los desarrollos y el problema es especialmente acusado en el campo de la
electrónica de consumo. La aparición de un chip más barato y, generalmente, más eficiente, conduce inmediatamente
a los fabricantes a incluirlo en las nuevas series de sus cadenas de producción, por pequeña que sea la diferencia en
precio ya que, multiplicada por la tirada masiva de los aparatos, supone un ahorro considerable. Por tanto, Gosling
decidió mejorar las características de Oak y utilizarlo.

El primer proyecto en que se aplicó este lenguaje recibió el nombre de proyecto Green y consistía en un sistema de
control completo de los aparatos electrónicos y el entorno de un hogar. Para ello se construyó un ordenador
experimental denominado *7 (Star Seven). El sistema presentaba una interfaz basada en la representación de la casa
de forma animada y el control se llevaba a cabo mediante una pantalla sensible al tacto. En el sistema aparecía Duke,
la actual mascota de Java. Posteriormente se aplicó a otro proyecto denominado VOD (Video On Demand) en el que
se empleaba como interfaz para la televisión interactiva. Ninguno de estos proyectos se convirtió nunca en un sistema
comercial, pero fueron desarrollados enteramente en un Java primitivo y fueron como su bautismo de fuego.
Una vez que en Sun se dieron cuenta de que a corto plazo la televisión interactiva no iba a ser un gran éxito, urgieron
a FirstPerson a desarrollar con rapidez nuevas estrategias que produjeran beneficios. No lo consiguieron y
FirstPerson cerró en la primavera de 1994.

Pese a lo que parecía ya un olvido definitivo, Bill Joy, cofundador de Sun y uno de los desarrolladores principales del
Unix de Berkeley, juzgó que Internet podría llegar a ser el campo de juego adecuado para disputar a Microsoft su
primacía casi absoluta en el terreno del software, y vio en Oak el instrumento idóneo para llevar a cabo estos planes.
Tras un cambio de nombre y modificaciones de diseño, el lenguaje Java fue presentado en sociedad en agosto de
1995.

Lo mejor será hacer caso omiso de las historias que pretenden dar carta de naturaleza a la clarividencia industrial de
sus protagonistas; porque la cuestión es si independientemente de su origen y entorno comercial, Java ofrece
soluciones a nuestras expectativas. Porque tampoco vamos a desechar la penicilina aunque haya sido su origen fruto
de la casualidad.

Tutorial de Java [Anterior] [Indice] [Siguiente]


CARACTERISTICAS DE JAVA
Las características principales que nos ofrece Java respecto a cualquier otro lenguaje de programación, son:

Es SIMPLE:

Java ofrece toda la funcionalidad de un lenguaje potente, pero sin las características menos usadas y más confusas de
éstos. C++ es un lenguaje que adolece de falta de seguridad, pero C y C++ son lenguajes más difundidos, por ello
Java se diseñó para ser parecido a C++ y así facilitar un rápido y fácil aprendizaje.

Java elimina muchas de las características de otros lenguajes como C++, para mantener reducidas las
especificaciones del lenguaje y añadir características muy útiles como el garbage collector (reciclador de memoria
dinámica). No es necesario preocuparse de liberar memoria, el reciclador se encarga de ello y como es un thread de
baja prioridad, cuando entra en acción, permite liberar bloques de memoria muy grandes, lo que reduce la
fragmentación de la memoria.

Java reduce en un 50% los errores más comunes de programación con lenguajes como C y C++ al eliminar muchas
de las características de éstos, entre las que destacan:

● aritmética de punteros
● no existen referencias
● registros (struct)
● definición de tipos (typedef)
● macros (#define)
● necesidad de liberar memoria (free)

Aunque, en realidad, lo que hace es eliminar las palabras reservadas (struct, typedef), ya que las clases son algo
parecido.

Además, el intérprete completo de Java que hay en este momento es muy pequeño, solamente ocupa 215 Kb de
RAM.

Es ORIENTADO A OBJETOS:

Java implementa la tecnología básica de C++ con algunas mejoras y elimina algunas cosas para mantener el objetivo
de la simplicidad del lenguaje. Java trabaja con sus datos como objetos y con interfaces a esos objetos. Soporta las
tres características propias del paradigma de la orientación a objetos: encapsulación, herencia y polimorfismo. Las
plantillas de objetos son llamadas, como en C++, clases y sus copias, instancias. Estas instancias, como en C++,
necesitan ser construidas y destruidas en espacios de memoria.

Java incorpora funcionalidades inexistentes en C++ como por ejemplo, la resolución dinámica de métodos. Esta
característica deriva del lenguaje Objective C, propietario del sistema operativo Next. En C++ se suele trabajar con
librerías dinámicas (DLLs) que obligan a recompilar la aplicación cuando se retocan las funciones que se encuentran
en su interior. Este inconveniente es resuelto por Java mediante una interfaz específica llamada RTTI (RunTime Type
Identification) que define la interacción entre objetos excluyendo variables de instancias o implementación de
métodos. Las clases en Java tienen una representación en el runtime que permite a los programadores interrogar por
el tipo de clase y enlazar dinámicamente la clase con el resultado de la búsqueda.

Es DISTRIBUIDO:

Java se ha construido con extensas capacidades de interconexión TCP/IP. Existen librerías de rutinas para acceder e
interactuar con protocolos como http y ftp. Esto permite a los programadores acceder a la información a través de la
red con tanta facilidad como a los ficheros locales.

La verdad es que Java en sí no es distribuido, sino que proporciona las librerías y herramientas para que los
programas puedan ser distribuidos, es decir, que se corran en varias máquinas, interactuando.

Es ROBUSTO:

Java realiza verificaciones en busca de problemas tanto en tiempo de compilación como en tiempo de ejecución. La
comprobación de tipos en Java ayuda a detectar errores, lo antes posible, en el ciclo de desarrollo. Java obliga a la
declaración explícita de métodos, reduciendo así las posibilidades de error. Maneja la memoria para eliminar las
preocupaciones por parte del programador de la liberación o corrupción de memoria. También implementa los arrays
auténticos, en vez de listas enlazadas de punteros, con comprobación de límites, para evitar la posibilidad de
sobreescribir o corromper memoria resultado de punteros que señalan a zonas equivocadas. Estas características
reducen drásticamente el tiempo de desarrollo de aplicaciones en Java.

Además, para asegurar el funcionamiento de la aplicación, realiza una verificación de los byte-codes, que son el
resultado de la compilación de un programa Java. Es un código de máquina virtual que es interpretado por el
intérprete Java. No es el código máquina directamente entendible por el hardware, pero ya ha pasado todas las fases
del compilador: análisis de instrucciones, orden de operadores, etc., y ya tiene generada la pila de ejecución de
órdenes.

Java proporciona, pues:

● Comprobación de punteros
● Comprobación de límites de arrays
● Excepciones
● Verificación de byte-codes

Es de ARQUITECTURA NEUTRAL:

Para establecer Java como parte integral de la red, el compilador Java compila su código a un fichero objeto de
formato independiente de la arquitectura de la máquina en que se ejecutará. Cualquier máquina que tenga el sistema
de ejecución (run-time) puede ejecutar ese código objeto, sin importar en modo alguno la máquina en que ha sido
generado. Actualmente existen sistemas run-time para Solaris 2.x, SunOs 4.1.x, Windows 95, Windows NT, Linux,
Irix, Aix, Mac, Apple y probablemente haya grupos de desarrollo trabajando en el porting a otras plataformas.
El código fuente Java se "compila" a un código de bytes de alto nivel independiente de la máquina. Este código (byte-
codes) está diseñado para ejecutarse en una máquina hipotética que es implementada por un sistema run-time, que sí
es dependiente de la máquina.

En una representación en que tuviésemos que indicar todos los elementos que forman parte de la arquitectura de Java
sobre una plataforma genérica, obtendríamos una figura como la siguiente:

En ella podemos ver que lo verdaderamente dependiente del sistema es la Máquina Virtual Java (JVM) y las librerías
fundamentales, que también nos permitirían acceder directamente al hardware de la máquina. Además, habrá APIs de
Java que también entren en contacto directo con el hardware y serán dependientes de la máquina, como ejemplo de
este tipo de APIs podemos citar:

● Java 2D: gráficos 2D y manipulación de imágenes


● Java Media Framework : Elementos críticos en el tiempo: audio, video...
● Java Animation: Animación de objetos en 2D
● Java Telephony: Integración con telefonía
● Java Share: Interacción entre aplicaciones multiusuario
● Java 3D: Gráficos 3D y su manipulación

Es SEGURO:

La seguridad en Java tiene dos facetas. En el lenguaje, características como los punteros o el casting implícito que
hacen los compiladores de C y C++ se eliminan para prevenir el acceso ilegal a la memoria. Cuando se usa Java para
crear un navegador, se combinan las características del lenguaje con protecciones de sentido común aplicadas al
propio navegador.

El lenguaje C, por ejemplo, tiene lagunas de seguridad importantes, como son los errores de alineación. Los
programadores de C utilizan punteros en conjunción con operaciones aritméticas. Esto le permite al programador que
un puntero referencie a un lugar conocido de la memoria y pueda sumar (o restar) algún valor, para referirse a otro
lugar de la memoria. Si otros programadores conocen nuestras estructuras de datos pueden extraer información
confidencial de nuestro sistema. Con un lenguaje como C, se pueden tomar números enteros aleatorios y convertirlos
en punteros para luego acceder a la memoria:

printf( "Escribe un valor entero: " );


scanf( "%u",&puntero );
printf( "Cadena de memoria: %s\n",puntero );

Otra laguna de seguridad u otro tipo de ataque, es el Caballo de Troya. Se presenta un programa como una utilidad,
resultando tener una funcionalidad destructiva. Por ejemplo, en UNIX se visualiza el contenido de un directorio con
el comando ls. Si un programador deja un comando destructivo bajo esta referencia, se puede correr el riesgo de
ejecutar código malicioso, aunque el comando siga haciendo la funcionalidad que se le supone, después de lanzar su
carga destructiva. Por ejemplo, después de que el caballo de Troya haya enviado por correo el /etc/shadow a su
creador, ejecuta la funcionalidad de ls persentando el contenido del directorio. Se notará un retardo, pero nada
inusual.

El código Java pasa muchos tests antes de ejecutarse en una máquina. El código se pasa a través de un verificador de
byte-codes que comprueba el formato de los fragmentos de código y aplica un probador de teoremas para detectar
fragmentos de código ilegal -código que falsea punteros, viola derechos de acceso sobre objetos o intenta cambiar el
tipo o clase de un objeto-.

Si los byte-codes pasan la verificación sin generar ningún mensaje de error, entonces sabemos que:

● El código no produce desbordamiento de operandos en la pila


● El tipo de los parámetros de todos los códigos de operación son conocidos y correctos
● No ha ocurrido ninguna conversión ilegal de datos, tal como convertir enteros en punteros
● El acceso a los campos de un objeto se sabe que es legal: public, private, protected
● No hay ningún intento de violar las reglas de acceso y seguridad establecidas

El Cargador de Clases también ayuda a Java a mantener su seguridad, separando el espacio de nombres del sistema
de ficheros local, del de los recursos procedentes de la red. Esto limita cualquier aplicación del tipo Caballo de
Troya, ya que las clases se buscan primero entre las locales y luego entre las procedentes del exterior.
Las clases importadas de la red se almacenan en un espacio de nombres privado, asociado con el origen. Cuando una
clase del espacio de nombres privado accede a otra clase, primero se busca en las clases predefinidas (del sistema
local) y luego en el espacio de nombres de la clase que hace la referencia. Esto imposibilita que una clase suplante a
una predefinida.

En resumen, las aplicaciones de Java resultan extremadamente seguras, ya que no acceden a zonas delicadas de
memoria o de sistema, con lo cual evitan la interacción de ciertos virus. Java no posee una semántica específica para
modificar la pila de programa, la memoria libre o utilizar objetos y métodos de un programa sin los privilegios del
kernel del sistema operativo. Además, para evitar modificaciones por parte de los crackers de la red, implementa un
método ultraseguro de autentificación por clave pública. El Cargador de Clases puede verificar una firma digital
antes de realizar una instancia de un objeto. Por tanto, ningún objeto se crea y almacena en memoria, sin que se
validen los privilegios de acceso. Es decir, la seguridad se integra en el momento de compilación, con el nivel de
detalle y de privilegio que sea necesario.

Dada, pues la concepción del lenguaje y si todos los elementos se mantienen dentro del estándar marcado por Sun, no
hay peligro. Java imposibilita, también, abrir ningún fichero de la máquina local (siempre que se realizan operaciones
con archivos, éstas trabajan sobre el disco duro de la máquina de donde partió el applet), no permite ejecutar ninguna
aplicación nativa de una plataforma e impide que se utilicen otros ordenadores como puente, es decir, nadie puede
utilizar nuestra máquina para hacer peticiones o realizar operaciones con otra. Además, los intérpretes que incorporan
los navegadores de la Web son aún más restrictivos. Bajo estas condiciones (y dentro de la filosofía de que el único
ordenador seguro es el que está apagado, desenchufado, dentro de una cámara acorazada en un bunker y rodeado por
mil soldados de los cuerpos especiales del ejército), se puede considerar que Java es un lenguaje seguro y que los
applets están libres de virus.

Respecto a la seguridad del código fuente, no ya del lenguaje, JDK proporciona un desemsamblador de byte-code,
que permite que cualquier programa pueda ser convertido a código fuente, lo que para el programador significa una
vulnerabilidad total a su código. Utilizando javap no se obtiene el código fuente original, pero sí desmonta el
programa mostrando el algoritmo que se utiliza, que es lo realmente interesante. La protección de los programadores
ante esto es utilizar llamadas a programas nativos, externos (incluso en C o C++) de forma que no sea descompilable
todo el código; aunque así se pierda portabilidad. Esta es otra de las cuestiones que Java tiene pendientes.

Es PORTABLE:

Más allá de la portabilidad básica por ser de arquitectura independiente, Java implementa otros estándares de
portabilidad para facilitar el desarrollo. Los enteros son siempre enteros y además, enteros de 32 bits en
complemento a 2. Además, Java construye sus interfaces de usuario a través de un sistema abstracto de ventanas de
forma que las ventanas puedan ser implantadas en entornos Unix, Pc o Mac.

Es INTERPRETADO:

El intérprete Java (sistema run-time) puede ejecutar directamente el código objeto. Enlazar (linkar) un programa,
normalmente, consume menos recursos que compilarlo, por lo que los desarrolladores con Java pasarán más tiempo
desarrollando y menos esperando por el ordenador. No obstante, el compilador actual del JDK es bastante lento. Por
ahora, que todavía no hay compiladores específicos de Java para las diversas plataformas, Java es más lento que otros
lenguajes de programación, como C++, ya que debe ser interpretado y no ejecutado como sucede en cualquier
programa tradicional.

Se dice que Java es de 10 a 30 veces más lento que C, y que tampoco existen en Java proyectos de gran envergadura
como en otros lenguajes. La verdad es que ya hay comparaciones ventajosas entre Java y el resto de los lenguajes de
programación, y una ingente cantidad de folletos electrónicos que supuran fanatismo en favor y en contra de los
distintos lenguajes contendientes con Java. Lo que se suele dejar de lado en todo esto, es que primero habría que
decidir hasta que punto Java, un lenguaje en pleno desarrollo y todavía sin definición definitiva, está maduro como
lenguaje de programación para ser comparado con otros; como por ejemplo con Smalltalk, que lleva más de 20 años
en cancha.

La verdad es que Java para conseguir ser un lenguaje independiente del sistema operativo y del procesador que
incorpore la máquina utilizada, es tanto interpretado como compilado. Y esto no es ningún contrasentido, me explico,
el código fuente escrito con cualquier editor se compila generando el byte-code. Este código intermedio es de muy
bajo nivel, pero sin alcanzar las instrucciones máquina propias de cada plataforma y no tiene nada que ver con el p-
code de Visual Basic. El byte-code corresponde al 80% de las instrucciones de la aplicación. Ese mismo código es el
que se puede ejecutar sobre cualquier plataforma. Para ello hace falta el run-time, que sí es completamente
dependiente de la máquina y del sistema operativo, que interpreta dinámicamente el byte-code y añade el 20% de
instrucciones que faltaban para su ejecución. Con este sistema es fácil crear aplicaciones multiplataforma, pero para
ejecutarlas es necesario que exista el run-time correspondiente al sistema operativo utilizado.

Es MULTITHREADED:

Al ser multithreaded (multihilvanado, en mala traducción), Java permite muchas actividades simultáneas en un
programa. Los threads (a veces llamados, procesos ligeros), son básicamente pequeños procesos o piezas
independientes de un gran proceso. Al estar los threads contruidos en el lenguaje, son más fáciles de usar y más
robustos que sus homólogos en C o C++.

El beneficio de ser miltithreaded consiste en un mejor rendimiento interactivo y mejor comportamiento en tiempo
real. Aunque el comportamiento en tiempo real está limitado a las capacidades del sistema operativo subyacente
(Unix, Windows, etc.), aún supera a los entornos de flujo único de programa (single-threaded) tanto en facilidad de
desarrollo como en rendimiento.

Cualquiera que haya utilizado la tecnología de navegación concurrente, sabe lo frustrante que puede ser esperar por
una gran imagen que se está trayendo. En Java, las imágenes se pueden ir trayendo en un thread independiente,
permitiendo que el usuario pueda acceder a la información en la página sin tener que esperar por el navegador.

Es DINAMICO:

Java se beneficia todo lo posible de la tecnología orientada a objetos. Java no intenta conectar todos los módulos que
comprenden una aplicación hasta el tiempo de ejecución. Las librería nuevas o actualizadas no paralizarán las
aplicaciones actuales (siempre que mantengan el API anterior).

Java también simplifica el uso de protocolos nuevos o actualizados. Si su sistema ejecuta una aplicación Java sobre la
red y encuentra una pieza de la aplicación que no sabe manejar, tal como se ha explicado en párrafos anteriores, Java
es capaz de traer automáticamente cualquiera de esas piezas que el sistema necesita para funcionar.

Java, para evitar que los módulos de byte-codes o los objetos o nuevas clases, haya que estar trayéndolos de la red
cada vez que se necesiten, implementa las opciones de persistencia, para que no se eliminen cuando de limpie la
caché de la máquina.

Tutorial de Java [Anterior] [Indice] [Siguiente]


HotJava
HotJava, en pocas palabras, es un navegador con soporte Java (Java-enabled), desarrollado en Java. Como cualquier
navegador de Web, HotJava puede decodificar HTML estándar y URLs estándares, aunque no soporta
completamente el estándar HTML 3.0. La ventaja sobre el resto de navegadores, sin soporte Java, es que puede
ejecutar programas Java sobre la red. La diferencia con Netscape, es que tiene implementado completamente los
sistemas de seguridad que propone Java, esto significa que puede escribir y leer en el disco local, aunque esto hace
disminuir la seguridad, ya que se pueden grabar en nuestro disco programas que contengan código malicioso e
introducirnos un virus, por ejemplo. No obstante, el utilizar esta característica de HotJava es decisión del usuario.

Tutorial de Java [Anterior] [Indice] [Siguiente]


JAVA PARA APLICACIONES CORPORATIVAS
Java actualmente está en boca de todos, Java e Intranet son las palabras de moda. Pero, surge la pregunta de si esta es
una buena tecnología para desarrollar aplicaciones corporativas. Y la respuesta es afirmativa y voy a proponer
argumentos para esa afirmación. En donde la red sea algo crítico, Java facilita tremendamente la vida de la
programación corporativa.

Durante años, las grandes empresas se han convencido de que la "red" corporativa es la arteria por donde fluye la
sangre que mantiene vivo su negocio. Desde el gran servidor de sus oficinas centrales, hasta los servidores de las
delegaciones, las estaciones de trabajo de los programadores y la marabunta de PCs, la información va fluyendo de
unos a otros. Para muchas compañías, la Red es la Empresa.

Si esta red no se mantiene sana, los pedidos no llegan, el inventario no se actualiza, el software no se desarrolla
adecuadamente, los clientes no están satisfechos y, fundamentalmente, el dinero no entra. La necesidad de
diagnosticar y reducir la arterioesclerosis de la red, hace que se estén inyectando continuamente nuevas metodologías
que subsanen este grave problema.

¿Es Java la medicina? Está claro que cuando vemos un cepillo animado limpiando los dientes, cubos moviéndose en
3-D, o una banda de gatos locos en applets de Java, nos convencemos de que es el lenguaje idóneo para Internet.
Pero, qué pasa con las aplicaciones corporativas, ¿sería una buena tecnología allí donde la red es el punto crítico?
Vamos a intentar responder comparando las capacidades de Java contra la lista de necesidades de la red corporativa.

Desarrollo rápido de aplicaciones

Hace años, se decía que los programadores pronto desaparecerían. Los generadores automáticos de programas,
eliminarían a los generadores humanos y el mundo sería un lugar mejor para vivir. Desafortunadamente, quienes
decían esto no tuvieron en cuenta una acelerada demanda de software de calidad para muy diferentes aplicaciones.
Sin embargo, la tecnología de objetos pronto vino a intentar facilitar la tarea, adoptando el modelo de "generar parte
de un programa", así, generando la parte básica de un programa (los objetos), se podría conectar con otras partes para
proporcionar diferentes utilidades al usuario.

El lenguaje C++ es una buena herramienta, pero no cumple totalmente la premisa. Visual Basic y NextStep, se
acercan cada vez más al poder de los objetos. Java facilita la creación de entornos de desarrollo-aplicaciones de modo
similar, pero además es flexible, poderoso y efectivo. Los programadores ahora disponen de herramientas de
programación de calidad beta, que apuntan hacia esa meta, como son el Java WorkShop de SunSoft, el entorno Java
de Borland, el Café de Symantec, y pronto, herramientas más sofisticadas como Netcode o FutureTense. Esto
proporciona una gran progresión a los entornos de desarrollo Java.

Aplicaciones efectivas y eficientes

Las aplicaciones que se crean en grandes empresas deben ser más efectivas que eficientes; es decir, conseguir que el
programa funcione y el trabajo salga adelante es más importante que el que lo haga eficientemente. Esto no es una
crítica, es una realidad de la programación corporativa. Al ser un lenguaje más simple que cualquiera de los que
ahora están en el cajón de los programadores, Java permite a éstos concentrarse en la mecánica de la aplicación, en
vez de pasarse horas y horas incorporando APIs para el control de las ventanas, controlando minuciosamente la
memoria, sincronizando los ficheros de cabecera y corrigiendo los agónicos mensajes del linker. Java tiene su propio
toolkit para interfaces, maneja por sí mismo la memoria que utilice la aplicación, no permite ficheros de cabecera
separados (en aplicaciones puramente Java) y solamente usa enlace dinámico.

Muchas de las implementaciones de Java actuales son puros intérpretes. Los byte-codes son interpretados por el
sistema run-time de Java, la Máquina Virtual Java (JVM), sobre el ordenador del usuario. Aunque ya hay ciertos
proveedores que ofrecen compiladores nativos Just-In-Time (JIT). Si la Máquina Virtual Java dispone de un
compilador instalado, las secciones (clases) del byte-code de la aplicación se compilarán hacia la arquitectura nativa
del ordenador del usuario. Los programas Java en ese momento rivalizarán con el rendimiento de programas en C++.
Los compiladores JIT no se utilizan en la forma tradicional de un compilador; los programadores no compilan y
distribuyen binarios Java a los usuarios. La compilación JIT tiene lugar a partir del byte-code Java, en el sistema del
usuario, como una parte (opcional) del entorno run-time local de Java.

Muchas veces, los programadores corporativos, ansiosos por exprimir al máximo la eficiencia de su aplicación,
empiezan a hacerlo demasiado pronto en el ciclo de vida de la aplicación. Java permite algunas técnicas innovadoras
de optimización. Por ejemplo, Java es inherentemente multithreaded, a la vez que ofrece posibilidades de multithread
como la clase Thread y mecanismos muy sencillos de usar de sincronización; Java en sí utiliza threads. Los
desarrolladores de compiladores inteligentes pueden utilizar esta característica de Java para lanzar un thread que
compruebe la forma en que se está utilizando la aplicación. Más específicamente, este thread podría detectar qué
métodos de una clase se están usando con más frecuencia e invocar a sucesivos niveles de optimización en tiempo de
ejecución de la aplicación. Cuanto más tiempo esté corriendo la aplicación o el applet, los métodos estarán cada vez
más optimizados (Guava de Softway es de este tipo).

Si un compilador JIT está embebido en el entorno run-time de Java, el programador no se preocupa de hacer que la
aplicación se ejecute óptimamente. Siempre he pensado que en los Sistemas Operativos tendría que aplicarse esta
filosofía; un optimizador progresivo es un paso más hacia esta idea.

Portabilidad para programador y programa

En una empresa de relativo tamaño hay una pléyade diferente de ordenadores. Probablemente nos encontremos con
estaciones de trabajo Sun para el desarrollo de software, hordas de PCs para cada empleado, algún Mac en el
departamento de documentación, una estación de trabajo HP en administración y una estación SGI en la sala de
demos. Desarrollar aplicaciones corporativas para un grupo tan diferente de plataformas en excesivamente complejo
y caro. Hasta ahora era complicado convencer a los programadores de cada arquitectura que utilizasen un API común
para reducir el coste de las aplicaciones.

Con un entorno run-time de Java portado a cada una de las arquitecturas de las plataformas presentes en la empresa y
una buena librería de clases ("packages" en Java), los programadores pueden entenderse y encontrar muy interesante
trabajar con Java. Esta posibilidad hará tender a los programadores hacia Java, justo donde otros intentos anteriores
con entornos universales (como Galaxy o XVT) han fracasado. Estos APIs eran simplemente inadecuados, no
orientados a redes y, verdaderamente, pesados.

Una vez que los programas estén escritos en Java, otro lado interesante del asunto es que los programadores también
son portables. El grupo de programadores de la empresa puede ahora enfrentarse a un desarrollo para cualquiera de
las plataformas. La parte del cliente y del servidor de una aplicación estarán ahora escritas en el mismo lenguaje. Ya
no será necesario tener un grupo que desarrolle en Solaris en del departamento de I+D, programadores trabajando
sobre Visual Basic en el departamento de documentación y programadores sobre GNU en proyectos especiales; ahora
todos ellos podrán estar juntos y formar el grupo de software de la empresa.
Costes de desarrollo

En contraste con el alto coste de los desarrollos realizados sobre estaciones de trabajo, el coste de creación de una
aplicación Java es similar al de desarrollar sobre un PC.

Desarrollar utilizando un software caro para una estación de trabajo (ahora barata) es un problema en muchas
empresas. La eficiencia del hardware y el poco coste de mantenimiento de una estación de trabajo Sun, por ejemplo,
resulta muy atractivo para las empresas; pero el coste adicional del entorno de desarrollo con C++ es prohibitivo para
la gran mayoría de ellas. La llegada de Java e Intranet reducen considerablemente estos costes. Las herramientas Java
ya no están en el entorno de precios de millones de pesetas, sino a los niveles confortables de precio de las
herramientas de PCs. Y con el crecimiento cada día mayor de la comunidad de desarrolladores de software freeware
y shareware que incluso proporcionan el código fuente, los programadores corporativos tienen un amplio campo
donde moverse y muchas oportunidades de aprender y muchos recursos a su disposición.

El éxito que Internet ha proporcionado a los equipos de software corporativos es un regalo. El precio del software es
ahora el mismo para un poderoso equipo corriendo Unix que para un PC. Incluso Netscape tiene al mismo precio la
versión Unix de su servidor Web SuiteSpot que la versión PC/NT. Esta es la filosofía de precios que parece ser será
la que se siga con las herramientas basadas en Java.

Mantenimiento y soporte

Un problema bien conocido que ocurre con el software corporativo es la demanda de cuidados y realimentación. Java
no es, ciertamente, la cura para la enfermedad del mantenimiento, pero tiene varias características que harán la vida
del enfermero más fácil.

Uno de los componentes del JDK es javadoc. Si se usan ciertas convenciones en el código fuente Java (como
comenzar un comentario con /** y terminarlo con */), javadoc se puede fácilmente generar páginas HTML con el
contenido de esos comentarios, que pueden visualizarse en cualquier navegador. La documentación del API de Java
ha sido creada de este modo. Esto hace que el trabajo de documentar el código de nuevas clases Java sea trivial.

Otro gran problema del desarrollador corporativo es la creación y control de makefiles. Leerse un makefile es como
estar leyendo la historia de empresa. Normalmente se pasan de programador a programador, quitando la información
que no es esencial, siempre que se puede. Esto hace que muchos de los makefiles de las aplicaciones contengan
docenas de librerías, una miríada de ficheros de cabecera y ultra-confusos macros. Es como mirar en el estómago de
la ballena de Jonás.

Java reduce las dependencia de complejos makefiles drásticamente. Primero, no hay ficheros de cabecera. Java
necesita que todo el código fuente de una clase se encuentre en un solo fichero. Java tiene la inteligencia de make en
el propio lenguaje para simplificar la compilación de byte-codes. Por ejemplo:

public class pepe { // Fichero: [Link]


Guitarra flamenca ;
}
public class guitarra { // Fichero: [Link]
}

% javac -verbose [Link]


[parsed [Link] in 720ms]
[loaded C:\JAVA\BIN\..\classes\java\lang\[Link] in 220ms]
[checking class pepe]
[parsed .\\[Link] in 50ms]
[wrote [Link]]
[checking class Guitarra]
[wrote .\\[Link]]
[done in 2300ms]

El compilador Java se da cuenta de que necesita compilar el fichero [Link]. Ahora vamos a forzarlo a que
recompile [Link] sin cambiar [Link], podremos comprobar que el compilador de byte-code Java no
recompila innecesariamente el fichero [Link].

% javac -verbose [Link]


[parsed [Link] in 440ms]
[loaded C:\JAVA\BIN\..\classes\java\lang\[Link] in 160ms]
[checking class pepe]
[loaded .\\[Link] in 0ms]
[wrote [Link]]
[done in 1860ms]

Ahora, si modificamos [Link] (añadiendo, por ejemplo, otro miembro a la clase) y compilamos [Link], el
compilador Java se dará cuenta de que debe recompilar tanto [Link] como [Link]

% javac -verbose [Link]


[parsed [Link] in 710ms]
[loaded C:\JAVA\BIN\..\classes\java\lang\[Link] in 220ms]
[checking class pepe]
[parsed .\\[Link] in 0ms]
[wrote [Link]]
[checking class Guitarra]
[wrote .\\[Link]]
[done in 2640ms]

En el libro Just Java de Peter van der Linden hay un capítulo excelente acerca del compilador de Java, si tienes
oportunidad, no dejes de leerlo.

Aprendizaje

Si la empresa está llena de programadores de C++ con alguna experiencia en el manejo de librería gráficas,
aprenderán rápidamente lo esencial de Java. Si el equipo de ingenieros no conoce C++, pero maneja cualquier otro
lenguaje de programación orientada a objetos, les llevará pocas semanas dominar la base de Java. Lo que sí que no es
cierto es que haya que aprender C++ antes de aprender Java.

Si los ingenieros de la empresa no conocen ningún lenguaje orientado a objetos, sí que tienen que aprender los
fundamentos de esta tecnología antes de nada, y luego aplicarlos a la programación con Java. El análisis y diseño
orientado a objetos debe ser comprendido antes de intentar nada con Java. Los programadores de Java sin un fondo
de conocimientos de OOA/D producirán código pobre. Además, los libros sobre Java crecen como la espuma, ya hay
más de 25 publicados, y si buscas "Progamming in Java" en la Red, encontrarás 312 Web sites, y 30 más dedicados a
"Learning Java". Y si esto, evidentemente, no es el sustituto de un instructor humano, hay ya varias empresas que
ofrecen enseñanza de Java, entre ellas, Sun.

Resumen

En base a los argumentos que acabamos de exponer, ¿podría una empresa utilizar Java para sus aplicaciones críticas?
En este instante, sería suficiente un acercamiento a Java. Porque más importante que la elección de Java o cualquier
otro lenguaje de programación es un buen diseño de la arquitectura de la aplicación. Diseñar la aplicación para que
esté distribuida entre servidores y clientes, y la línea de partida debe ser el diseño modular.

Algunas sugerencias para adoptar Java como tecnología corporativa, serían:

1. Usar Java en el desarrollo de la interface del cliente; Java es suficientemente estable para desarrollar una
interface portable. Utilizar herramientas de programación más estables en los servidores, porque son la parte
crítica.
2. Portar o crear un servidor no-crítico en Java, de forma que tanto cliente como servidor estén escritos en Java.
3. Utilizar Java en proyectos de envergadura tanto en el cliente como en el servidor, para valorar la efectividad
de Java.

Intranet está creciendo actualmente más rápido que Internet. Las organizaciones corporativas están adoptando la
metodología Internet para proporcionar soluciones a sus usuarios y clientes. Java tiene todas las cartas para ser una
herramienta de inestimable valor en el desarrollo de aplicaciones corporativas.

Tutorial de Java [Anterior] [Indice] [Siguiente]

También podría gustarte