lunes, 2 de julio de 2012

Excepciones en Java


Excepciones en Java

A diferencia de otros lenguajes de programación orientados a objetos como C/C++, Java incorpora en el propio lenguaje la gestión de errores. El mejor momento para detectar los errores es durante la compilación. Sin embargo prácticamente sólo los errores de sintaxis son detectados durante este periodo. El resto de problemas surgen durante la ejecución de los programas.
En el lenguaje Java, una Exception es un cierto tipo de error o una condición anormal que se ha producido durante la ejecución de un programa. Algunas excepciones son fatales y provocan que se deba finalizar la ejecución del programa. En este caso conviene terminar ordenadamente y dar un mensaje explicando el tipo de error que se ha producido. Otras, como por ejemplo no encontrar un fichero en el que hay que leer o escribir algo, pueden ser recuperables. En este caso el programa debe dar al usuario la oportunidad de corregir el error (indicando una nueva localización del fichero no encontrado).
Un buen programa debe gestionar correctamente todas o la mayor parte de los errores que se pueden
producir. Hay dos “estilos” de hacer esto:
  • A la “antigua usanza”: los métodos devuelven un código de error. Este código se chequea en el entorno que ha llamado al método con una serie de if elseif …, gestionando de forma diferente el resultado correcto o cada uno de los posibles errores. Este sistema resulta muy complicado cuando hay varios niveles de llamadas a los métodos.
  • Con soporte en el propio lenguaje: En este caso el propio lenguaje proporciona construcciones especiales para gestionar los errores o Exceptions. Suele ser lo habitual en lenguajes modernos, como C++, Visual Basic y Java.
En los siguientes apartados se examina cómo se trabaja con los bloques y expresiones try, catch, throw, throws y finally, cuándo se deben lanzar excepciones, cuándo se deben capturar y cómo se crean las clases propias de tipo Exception.

Excepciones Estándar en Java

Los errores se representan mediante dos tipos de clases derivadas de la clase Throwable: Error y Exception. La siguiente figura muestra parcialmente la jerarquía de clases relacionada con Throwable:
Jerarquía de clases derivadas de Throwable.
La clase Error está relacionada con errores de compilación, del sistema o de la JVM. De ordinario estos errores son irrecuperables y no dependen del programador ni debe preocuparse de capturarlos y tratarlos.
La clase Exception tiene más interés. Dentro de ella se puede distinguir:
1. RuntimeException: Son excepciones muy frecuentes, de ordinario relacionadas con errores de programación. Se pueden llamar excepciones implícitas.
2. Las demás clases derivadas de Exception son excepciones explícitas. Java obliga a tenerlas en cuenta y chequear si se producen.
El caso de RuntimeException es un poco especial. El propio Java durante la ejecución de un programa chequea y lanza automáticamente las excepciones que derivan de RuntimeException. El programador no necesita establecer los bloques try/catch para controlar este tipo de excepciones.
Representan dos casos de errores de programación:
1. Un error que normalmente no suele ser chequeado por el programador, como por ejemplo recibir una referencia null en un método.
2. Un error que el programador debería haber chequeado al escribir el código, como sobrepasar el tamaño asignado de un array (genera un ArrayIndexOutOfBoundsException automáticamente).
En realidad sería posible comprobar estos tipos de errores, pero el código se complicaría excesivamente si se necesitara chequear continuamente todo tipo de errores (que las referencias son distintas de null, que todos los argumentos de los métodos son correctos, y un largo etcétera).
Las clases derivadas de Exception pueden pertenecer a distintos packages de Java. Algunas perenecen a java.lang (Throwable, Exception, RuntimeException, …); otras a java.io (EOFException, FileNotFoundException, ...) o a otros packages. Por heredar de Throwable todos los tipos de excepciones pueden usar los métodos siguientes:
1. String getMessage()                               Extrae el mensaje asociado con la excepción.
2. String toString()                                       Devuelve un String que describe la excepción.
3. void printStackTrace()                            Indica el método donde se lanzó la excepción.

 Lanzar una Excepción

Cuando en un método se produce una situación anómala es necesario lanzar una excepción. El proceso de lanzamiento de una excepción es el siguiente:
1. Se crea un objeto Exception de la clase adecuada.
2. Se lanza la excepción con la sentencia throw seguida del objeto Exception creado.
// Código que lanza la excepción MyException una vez detectado el error MyException me = new MyException("MyException message"); throw me;
Esta excepción deberá ser capturada (catch) y gestionada en el propio método o en algún otro lugar del programa (en otro método anterior en la pila o stack de llamadas).
Al lanzar una excepción el método termina de inmediato, sin devolver ningún valor. Solamente en el caso de que el método incluya los bloques try/catch/finally se ejecutará el bloque catch que la captura o el bloque finally (si existe).
Todo método en el que se puede producir uno o más tipos de excepciones (y que no utiliza directamente los bloques try/catch/finally para tratarlos) debe declararlas en el encabezamiento de la función por medio de la palabra throws. Si un método puede lanzar varias excepciones, se ponen detrás de throws separadas por comas, como por ejemplo:
public void leerFichero(String fich) throws EOFException, FileNotFoundException {…}
Se puede poner únicamente una superclase de excepciones para indicar que se pueden lanzar excepciones de cualquiera de sus clases derivadas. El caso anterior sería equivalente a:
public void leerFichero(String fich) throws IOException {…}
Las excepciones pueden ser lanzadas directamente por leerFichero() o por alguno de los métodos llamados por leerFichero(), ya que las clases EOFException y FileNotFoundException derivan de IOException.
Se recuerda que no hace falta avisar de que se pueden lanzar objetos de la clases Error o RuntimeException (excepciones implícitas).

Capturar una Excepción

Como ya se ha visto, ciertos métodos de los packages de Java y algunos métodos creados por cualquier programador producen (“lanzan”) excepciones. Si el usuario llama a estos métodos sin tenerlo en cuenta se produce un error de compilación con un mensaje del tipo: “… Exception java.io.IOException must be caugth or it must be declared in the throws clause of this method”. El programa no compilará mientras el usuario no haga una de estas dos cosas:
  • Gestionar la excepción con una construcción del tipo try {…} catch {…}.
  • Re-lanzar la excepción hacia un método anterior en el stack, declarando que su método también lanza dicha excepción, utilizando para ello la construcción throws en el header del método.
El compilador obliga a capturar las llamadas excepciones explícitas, pero no protesta si se captura y luego no se hace nada con ella. En general, es conveniente por lo menos imprimir un mensaje indicando qué tipo de excepción se ha producido.
  • Bloques try y catch
En el caso de las excepciones que no pertenecen a las RuntimeException y que por lo tanto Java obliga a tenerlas en cuenta habrá que utilizar los bloques try, catch y finally. El código dentro del bloque try está “vigilado”: Si se produce una situación anormal y se lanza por lo tanto una excepción el control salta o sale del bloque try y pasa al bloque catch, que se hace cargo de la situación y decide lo que hay que hacer. Se pueden incluir tantos bloques catch como sean necesarios, cada uno de los cuales tratará un tipo de excepción.
Las excepciones se pueden capturar individualmente o en grupo, por medio de una superclase de la que deriven todas ellas.
El bloque finally es opcional. Si se incluye sus sentencias se ejecutan siempre, sea cual sea la excepción que se produzca o si no se produce ninguna. El bloque finally se ejecuta aunque en el bloque try haya un return.

En el siguiente ejemplo se presenta un método que debe "controlar" una IOException relacionada con la lectura ficheros y una MyException propia:
  • Relanzar una Exception
Existen algunos casos en los cuales el código de un método puede generar una Exception y no se desea incluir en dicho método la gestión del error. Java permite que este método pase o relance (throws) la Exception al método desde el que ha sido llamado, sin incluir en el método los bucles try/catch correspondientes. Esto se consigue mediante la adición de throws más el nombre de la Exception concreta después de la lista de argumentos del método. A su vez el método superior deberá incluir los bloques try/catch o volver a pasar la Exception. De esta forma se puede ir pasando la Exception de un método a otro hasta llegar al último método del programa, el método main().
El ejemplo anterior (metodo1) realizaba la gestión de las excepciones dentro del propio método. Ahora se presenta un nuevo ejemplo (metodo2) que relanza las excepciones al siguiente método:

  • Método finally {...}
El bloque finally {...} debe ir detrás de todos los bloques catch considerados. Si se incluye (ya que es opcional) sus sentencias se ejecutan siempre, sea cual sea el tipo de excepción que se produzca, o incluso si no se produce ninguna. El bloque finally se ejecuta incluso si dentro de los bloques try/catch hay una sentencia continue, break o return. La forma general de una sección donde se controlan las excepciones es por lo tanto:
El bloque finally es necesario en los casos en que se necesite recuperar o devolver a su situación original algunos elementos. No se trata de liberar la memoria reservada con new ya que de ello se ocupará automáticamente el garbage collector.
Como ejemplo se podría pensar en un bloque try dentro del cual se abre un fichero para lectura y escritura de datos y se desea cerrar el fichero abierto. El fichero abierto se debe cerrar tanto si produce una excepción como si no se produce, ya que dejar un fichero abierto puede provocar problemas posteriores. Para conseguir esto se deberá incluir las sentencias correspondientes a cerrar el fichero dentro del bloque finally.

Crear Nuevas Excepciones

El programador puede crear sus propias excepciones sólo con heredar de la clase Exception o de una de sus clases derivadas. Lo lógico es heredar de la clase de la jerarquía de Java que mejor se adapte al tipo de excepción. Las clases Exception suelen tener dos constructores:
1. Un constructor sin argumentos.
2. Un constructor que recibe un String como argumento. En este String se suele definir un mensaje que explica el tipo de excepción generada. Conviene que este constructor llame al constructor de la clase de la que deriva super(String).
Al ser clases como cualquier otra se podrían incluir variables y métodos nuevos. Por ejemplo:

Herencias de Clases y tratamiento de Excepciones

Si un método redefine otro método de una super-clase que utiliza throws, el método de la clase derivada no tiene obligatoriamente que poder lanzar todas las mismas excepciones de la clase base. Es posible en el método de la subclase lanzar las mismas excepciones o menos, pero no se pueden lanzar más excepciones. No puede tampoco lanzar nuevas excepciones ni excepciones de una clase más general.
Se trata de una restricción muy útil ya que como consecuencia de ello el código que funciona con la clase base podrá trabajar automáticamente con referencias de clases derivadas, incluyendo el tratamiento de excepciones, concepto fundamental en la Programación Orientada a Objetos (polimorfismo).

sábado, 30 de junio de 2012

Los Menus de Java

Los Menus de Java
Los Menus de Java no descienden de Component, sino de MenuComponent, pero tienen un comportamiento similar, pues aceptan Events. La Figura  muestra la jerarquía de clases de los Menus de Java 1.1.
Para crear un Menú se debe crear primero una MenuBar; después se crean los Menus y los MenuItem. Los MenuItems se añaden al Menu correspondiente; los Menus se añaden a la MenuBar y la MenuBar se añade a un Frame.
Una MenuBar se añade a un Frame con el método setMenuBar(), de la clase Frame. También puede añadirse un Menu a otro Menu para crear un sub-menú, del modo que es habitual en Windows. La clase Menu es sub-clase de MenuItem. Esto es así precisamente para permitir que un Menu sea añadido a otro Menu.
Jerarquía de clases para los menús.

Clase MenuShortcut

La clase java.awt.MenuShortcut (derivada de Object) representa las teclas aceleradoras que pueden utilizarse para activar los menús desde teclado, sin ayuda del ratón. Se establece un Shortcut creando un objeto de esta clase con el constructor MenuShortcut(int vk_key), y pasándoselo al constructor adecuado de MenuItem. Para más información, consúltese la adocumentación on-line de Java. La Tabla muestra algunos métodos de esta clase. Los MenuShortcut de Java están restringidos al uso la tecla control (CTRL). Al definir el MenuShortcut no hace falta incluir dicha tecla.
Métodos de la clase MenuShortcut.

Clase MenuBar

La Tabla  muestra algunos métodos de la clase MenuBar. A una MenuBar sólo se pueden añadir objetos Menu.
Métodos de la clase MenuBar.

Clase Menu

El objeto Menu define las opciones que aparecen al seleccionar uno de los menús de la barra de menús. En un Menu se pueden introducir objetos MenuItem, otros objetos Menu (para crear submenús), objetos CheckboxMenuItem, y separadores. La Tabla muestra algunos métodos de la clase Menu. Obsérvese que como Menu desciende de MenuItem, el método add(MenuItem) permite añadir objetos Menu a otro Menu.
Métodos de la clase Menu.

Clase MenuItem

Los objetos de la clase MenuItem representan las distintas opciones de un menú. Al seleccionar, en la ejecución del programa, un objeto MenuItem se generan eventos del tipo ActionEvents. Para cada item de un Menu se puede definir un ActionListener, que define el método actionPerformed(). La Tabla muestra algunos métodos de la clase MenuItem.
Métodos de la clase MenuItem.
El método getActionCommand(), asociado al getSource() del evento correspondiente, no permite identificar correctamente al item cuando éste se ha activado mediante el MenuShortcut (en ese caso devuelve null).

Clase CheckboxMenuItem

Son items de un Menu que pueden estar activados o no activados. La clase CheckboxMenuItem no genera un ActionEvent, sino un ItemEvent, de modo similar a la clase Checkbox. En este caso hará registrar un ItemListener. La Tabla muestra algunos métodos de esta clase.
Métodos de la clase CheckboxMenuItem.

Menús pop-up

Los menús pop-up son menús que aparecen en cualquier parte de la pantalla al clicar con el botón derecho del ratón (pop-up trigger) sobre un componente determinado (parent Component). El menú pop-up se muestra en unas coordenadas relativas al parent Component, que debe estar visible.
Métodos de la clase PopupMenu.
Además, se pueden utilizar los métodos de la clase Menu, de la que deriva PopupMenu. Para hacer que aparezca el PopupMenu habrá que registrar el MouseListener y definir el método mouseClicked().

Gráficos, Texto e Imágenes en Java


En esta parte final del AWT se van a describir, también muy sucintamente, algunas clases y métodos para realizar dibujos y añadir texto e imágenes a la interface gráfica de usuario.

Capacidades gráficas del AWT: Métodos paint(), repaint() y update()

La clase Component tiene tres métodos muy importantes relacionados con gráficos: paint(), repaint() y update(). Cuando el usuario llama al método repaint() de un componente, el AWT llama al método update() de ese componente, que por defecto llama al método paint().

Método paint(Graphics g)

El método paint() está definido en la clase Component, pero ese método no hace nada y hay que redefinirlo en una de sus clases derivadas. El programador no tiene que preocuparse de llamar a este método: el sistema operativo lo llama al dibujar por primera vez una ventana, y luego lo vuelve a llamar cada vez que entiende que la ventana o una parte de la ventana debe ser re-dibujada (por ejemplo, por haber estado tapada por otra ventana y quedar de nuevo a la vista).

Método update(Graphics g)

El método update() hace dos cosas: primero re-dibuja la ventana con el color de fondo y luego llama al método paint(). Este método también es llamado por el AWT, y también puede ser llamado por el programador, quizás porque ha realizado algún cambio en la ventana y necesita que se dibuje de nuevo.
La propia estructura de este método -el comenzar pintando de nuevo con el color de fondo hace que se produzca parpadeo (flicker) en las animaciones. Una de las formas de evitar este efecto es redefinir este método de una forma diferente, cambiando de una imagen a otra sólo lo que haya que cambiar, en vez de re-dibujar todo otra vez desde el principio. Este método no siempre proporciona los resultados buscados y hay que recurrrir al método del doble buffer.

Método repaint()

Este es el método que con más frecuencia es llamado por el programador. El método repaint() llama “lo antes posible” al método update() del componente. Se puede también especificar un número de milisegundos para que el método update() se llame transcurrido ese tiempo. El método repaint() tiene las cuatro formas siguientes:
repaint( )
repaint(long time)
repaint(int x, int y, int w, int h)
repaint(long time, int x, int y, int w, int h)
Las formas tercera y cuarta permiten definir una zona rectangular de la ventana a la que aplicar el método.

Clase Graphics

El único argumento de los métodos update() y paint() es un objeto de esta clase. La clase Graphics dispone de métodos para soportar dos tipos de gráficos:
  1. Dibujo de primitivas gráficas (texto, líneas, círculos, rectángulos, polígonos, …).
  2.  Presentación de imágenes en formatos *.gif y *.jpeg.
Además, la clase Graphics mantiene un contexto gráfico: un área de dibujo actual, un color de dibujo del background y otro del foreground, un font con todas sus propiedades, etc. La Figura muestra el sistema de coordenadas utilizado en Java. Como es habitual en Informática, los ejes están situados en la esquina superior izquierda, con la orientación indicada en la Figura (eje de ordenadas descendente). Las coordenadas se miden siempre en pixels.
Coordenadas de los gráficos de Java.

Primitivas gráficas

Java dispone de métodos para realizar dibujos sencillos, llamados a veces “primitivas” gráficas. Como se ha dicho, las coordenadas se miden en pixels, empezando a contar desde cero. La clase Graphics dispone de los métodos para primitivas gráficas reseñados en la Tabla. Excepto los polígonos y las líneas, todas las formas geométricas se determinan por el rectángulo que las comprende, cuyas dimensiones son w y h. Los polígonos admiten un argumento de la clase java.awt.Polygon.
Métodos de la clase Graphics para dibujo de primitivas gráficas.
Los métodos draw3DRect()fill3DRect()drawOval()fillOval()drawArc() y fillArc() dibujan objetos cuyo tamaño total es (w+1, h+1) pixels.

Clases Graphics y Font

La clase Graphics permite “dibujar” texto, como alternativa al texto mostrado en los componentes Label, TextField y TextArea. Los métodos de esta clase para dibujar texto son los siguientes:
drawBytes(byte data[ ], int offset, int length, int x, int y);
drawChars(char data[ ], int offset, int length, int x, int y);
drawString(String str, int x, int y);
En estos métodos, los argumentos x e y representan las coordenadas de la línea base. El argumento offset indica el elemento del array que se empieza a imprimir.
Cada tipo de letra está representado por un objeto de la clase Font. Las clases Component y Graphics disponen de métodos setFont() y getFont(). El constructor de Font tiene la forma:
Font(String name, int style, int size)
donde el style se puede definir con las constantes Font.PLAINFont.BOLD y Font.ITALIC. Estas constantes se pueden combinar en la forma: Font.BOLD | Font.ITALIC.
La clase Font tiene tres variables protected, llamadas name, style y size. Además tiene tres constantes enteras: PLAINBOLD e ITALIC. Esta clase dispone de los métodos String getName()int getStyle()int getSize()boolean isPlain()boolean isBold() y boolean isItalic(), cuyo significado es inmediato.
Para mayor portabilidad se recomienda utilizar nombres lógicos de fonts, tales como Serif (Times New Roman), SansSerif (Arial) y Monospaced (Courier).
Líneas importantes en un tipo de letra.

Clase FontMetrics

La clase FontMetrics permite obtener información sobre una font y sobre el espacio que ocupa un char o un String utilizando esa font. Esto es muy útil cuando se pretende rotular algo de modo que quede siempre centrado y bien dimensionado.
La clase FontMetrics es una clase abstract. Esto quiere decir que no se pueden crear directamente objetos de esta clase ni llamar a su constuctor. La forma habitual de soslayar esta dificultad es creando una subclase. En la práctica Java resuelve esta dificultad para el usuario, ya que la clase FontMetrics tiene como variable miembro un objeto de la clase Font. Por ello, un objeto de la clase FontMetrics contiene información sobre la font que se le ha pasado como argumento al constructor. De todas formas, el camino más habitual para obtener esa información es a partir de un objeto de la clase Graphics que ya tiene un font definido. A partir de un objeto g de la clase Graphics se puede obtener una referencia FontMetrics en la forma:
FontMetrics miFontMet = g.getFontMetrics();
donde está claro que se está utilizando una referencia de la clase abstract FontMetrics para refererirse a un objeto de una clase derivada creada dentro del API de Java. Con una referencia de tipo FontMetrics se pueden utilizar todos los métodos propios de dicha clase.
Métodos de la clase FontMetrics.

Clase Color

La clase java.awt.Color encapsula colores utilizando el formato RGB (Red, Green, Blue). Las componentes de cada color primario en el color resultante se expresan con números enteros entre 0 y 255, siendo 0 la intensidad mínima de ese color, y 255 la máxima.
En la clase Color existen constantes para colores predeterminados de uso frecuente: black, white, green, blue, red, yellow, magenta, cyan, orange, pink, gray, darkGray, lightGray. La Tabla muestra algunos métodos de la clase Color.
Métodos de la clase Color.

Imágenes

Java permite incorporar imágenes de tipo GIF y JPEG definidas en ficheros. Se dispone para ello de la clase java.awt.Image. Para cargar una imagen hay que indicar la localización del fichero (URL) y cargarlo mediante los métodos Image getImage(String) o Image getImage(URL, String). Estos métodos existen en las clases java.awt.Toolkit y java.applet.Applet. El argumento de tipo String representa una variable conteniendo el nombre del fichero.
Cuando estas imágenes se cargan en applets, para obtener el URL pueden ser útiles las funciones getDocumentBase() y getCodeBase(), que devuelven el URL del fichero HTML que llama al applet, y el directorio que contiene el applet (en forma de String).
Para cargar una imagen hay que comenzar creando un objeto Image, y llamar al método getImage(), pasándole como argumento el URL. Por ejemplo:
Image miImagen = getImage(getCodeBase(), "imagen.gif")
Una vez cargada la imagen, hay que representarla, para lo cual se redefine el método paint() para llamar al método drawImage() de la clase Graphics. Dicho método admite varias formas, aunque casi siempre hay que incluir el nombre del objeto imagen creado, las dimensiones de dicha imagen y un objeto ImageObserver.
ImageObserver es una interface que declara métodos para observar el estado de la carga y visualización de la imagen. Si se está programando un applet, basta con poner como ImageObserver la referencia this, ya que en la mayoría de los casos, la implementación de esta interface en la clase Applet proporciona el comportamiento deseado. Para más información sobre dicho método dirigirse a la referencia de la API.
La clase Image define ciertas constantes para controlar los algoritmos de cambio de escala:
SCALE_DEFAULT, SCALE_FAST, SCALE_SMOOTH,
SCALE_REPLICATE, SCALE_AVERAGE.
Métodos de la clase Image.


Animaciones en Java


Las animaciones tienen un gran interés desde diversos puntos de vista. Una imagen vale más quemil palabras y una imagen en movimiento es todavía mucho más útil. Para presentar o describir ciertos conceptos el movimiento animado es fundamental. Además, las animaciones o mejor dicho, la forma de hacer animaciones en Java ilustran mucho la forma en que dicho lenguaje realiza los gráficos. En estos apartados se va a seguir el esquema del Tutorial de Sun sobre el AWT.
Se pueden hacer animaciones de una forma muy sencilla: se define el método paint() de forma que cada vez que sea llamado dibuje algo diferente de lo que ha dibujado la vez anterior. De todas formas, recuérdese que el programador no llama directamente a este método. El programador llama al método repaint(), quizás dentro de un bucle while que incluya una llamada al método sleep() de la clase Thread , para esperar un cierto número de milisegundos entre dibujo y dibujo (entre frame y frame, utilizando la terminología de las animaciones). Recuérdese que repaint() llama a update() lo antes posible, y que update() borra todo redibujando con el color de fondo y llama a paint().
La forma de proceder descrita da buenos resultados para animaciones muy sencillas, pero produce parpadeo o flicker cuando los gráficos son un poco más complicados. La razón está en el propio proceso descrito anteriormente, combinado con la velocidad de refresco del monitor. La velocidad de refresco vertical de un monitor suele estar entre 60 y 75 herzios. Eso quiere decir que la imagen se actualiza unas 60 ó 75 veces por segundo. Cuando el refresco se realiza después de haber borrado la imagen anterior pintando con el color de fondo y antes de que se termine de dibujar de nuevo toda la imagen, se obtiene una imagen incompleta, que sólo aparecerá terminada en uno de los siguientes pasos de refresco del monitor. Ésta es la causa del flicker. A continuación se verán dos formas de reducirlo o eliminarlo.

Eliminación del parpadeo o flicker redefiniendo el método update()

El problema del flicker se localiza en la llamada al método update(), que borra todo pintando con el color de fondo y después llama a paint(). Una forma de resolver esta dificultad es re-definir el método update(), de forma que se adapte mejor al problema que se trata de resolver.
Una posibilidad es no re-pintar todo con el color de fondo, no llamar a paint() e introducir en update() el código encargado de realizar los dibujos, cambiando sólo aquello que haya que cambiar.
A pesar de esto, es necesario re-definir paint() pues es el método que se llama de forma automática cuando la ventana de Java es tapada por otra que luego se retira. Una posible solución es hacer que paint() llame a update(), terminando por establecer un orden de llamadas opuesto al de defecto. Hay que tener en cuenta que, al no borrar todo pintando con el color de fondo, el programador tiene que preocuparse de borrar de forma selectiva entre frame y frame lo que sea necesario. Los métodos setClip() y clipRect() de la clase Graphics permiten hacer que las operaciones gráficas no surtan efecto fuera de un área rectangular previamente determinada. Al ser dependiente del tipo de gráficos concretos de que se trate, este método no siempre proporciona soluciones adecuadas.

Técnica del doble buffer

La técnica del doble buffer proporciona la mejor solución para el problema de las animaciones, aunque requiere una programación algo más complicada. La idea básica del doble buffer es realizar los dibujos en una imagen invisible, distinta de la que se está viendo en la pantalla, y hacerla visible cuando se ha terminado de dibujar, de forma que aparezca instantáneamente.
Para crear el segundo buffer o imagen invisible hay que crear un objeto de la clase Image del mismo tamaño que la imagen que se está viendo y crear un contexto gráfico u objeto de la clase Graphics que permita dibujar sobre la imagen invisible. Esto se hace con las sentencias,
Image imgInv;
Graphics graphInv;
Dimension dimInv;
Dimension d = size();    // se obtiene la dimensión del panel
en la clase que controle el dibujo (por ejemplo en una clase que derive de Panel). En el método update() se modifica el código de modo que primero se dibuje en la imagen invisible y luego ésta se haga visible:
Los gráficos y las animaciones son particularmente útiles en las applets. El Tutorial de Sun tiene un ejemplo (un applet) completamente explicado y desarrollado sobre las animaciones y los distintos métodos de eliminar el flicker o parpadeo.