Академический Документы
Профессиональный Документы
Культура Документы
Captulo 6
APPLETS
2002 por Angel Franco Garca de la Escuela Universitaria de Ingeniera Tcnica Industrial de Eiba 1. Adaptado por Diego L Aristizbal Ramrez, para el curso Introduccin a la Fsica Computacional y a la Simulacin que se ofrece a los estudiantes de Ingeniera Fsica de la Escuela de Fsica de la Universidad Nacional de Colombia Sede Medelln
En este captulo se estudiar la elaboracin de applets con herramientas grficas de java 1 y java 2.
119
Final mente, cuando salimos del navegador se llama al mtodo destroy. Recomendamos al lector ir al captulo 1 seccin 1.4.2 donde se dan los pasos para elaborar el primer applet. Otra forma ligeramente diferente a la expuesta en el captulo 1, de incluir un applet en una pgina web es comprimiendo los archivos .class en archivos .jar La ventaja de este mtodo es que la bajada de ellos en la red Internet es mucho ms rpida. En la siguiente seccin expondremos como se deber proceder para lograr esto.
Si adems tiene por ejemplo archivos de imagen .gif tambin se podrn empaquetar en el mismo archivo .jar: C\mis_proyectos\ejemplo_1> jar cf NombreApplet. jar *.class *.gif De la misma forma se procedera para otros archivos de imgenes y de sonido.
120
Para ms detalles sobre los archivos .jar se deber consultar un manual de java o visitar la pgina de SUN . 6.1.2 .2 Cmo incluir los archivos .jar en una pgina web? Supongamos que colocamos el archivo applet1.jar en el mismo subdirectorio que documento HTML que contiene el applet, la etiqueta <APPLET>... </APPLET > se escribe de la forma que sigue. Fija rse que aparece un nuevo parmetro ARCHIVE que indica el nombre y la ubicacin del archivo comprimido .jar.
<APPLET CODE = "applet1.Applet1.class" ARCHIVE = "applet1.jar" WIDTH = 400 HEIGHT = 300 HSPACE = 0 VSPACE = 0 ALIGN = middle > </APPLET>
Si el archivo applet1.jar est en un subdirectorio denominado jars por debajo del documento HTML escribimo s
<APPLET CODE = "applet1.Applet1.class" ARCHIVE = "jars/applet1.jar" WIDTH = 400 HEIGHT = 300 HSPACE = 0 VSPACE = 0 ALIGN = middle > </APPLET>
Si el archivo applet1.jar est en un subdirectorio denominado jars al mismo nivel que el subdirectorio que contiene el documento HTML escribimos
121
>
</APPLET>
</APPLET>
122
} En el appletviewer el tamao de la ventana y tamao del applet son distintos. La ventana del appletviewer es mayor que el applet. Sin embargo, en Internet Expl orer 5.0 la ventana que aparece en el navegador y el applet tienen las mismas dimensiones, las dadas por los parmetros WIDTH y HEIGHT dejando sin efecto la sentencia setSize. Para evitar posibles inconvenientes, el applet puede leer los datos asociados a los parmetros WIDTH y HEIGHT de la etiqueta APPLET mediante la funcin getParameter miembro de la clase base Applet, y despus pasarle dichos datos a la funcin setSize para establecer el tamao del applet. En la funcin miembro init, getParameter miembro de la clase Applet lee el dato asociado al parmetro (WIDTH o HEIGHT), y devuelve un string, que ha de convertirse en un dato numrico de tipo int . Los valores numricos se guardan en las variables locales ancho y alto, y luego, se pasan a la funcin setSize para establecer el tamao del applet. De este modo el tamao y disposicin del applet est controlado por la pgina web en la que est insertado. public void init(){ int ancho = Integer.parseInt(this.getParameter("WIDTH")); int alto = Integer.parseInt(this.getParameter("HEIGHT")); this.setSize(ancho,alto); } Como vimos al estudiar el captulo de las excepciones (seccin 5.1) , la conversin de un string en un nmero es mejor llevarla a cabo, por razones de seguridad, en un bloque try...catch. En el caso de que el proceso de conversin falle, se crea y se lanza un objeto ex de la clase NumberFormatException que es capturado por el bloque catch para notificar este problema al usuario. public void init(){ int ancho=400; //valores por defecto int alto=300; try{ ancho = Integer.parseInt(this.getParameter("WIDTH")); alto = Integer.parseInt(this.getParameter("HEIGHT")); }catch(NumberFormatException ex){ System.out.println("Error en los parmetros WIDTH y HEIGHT") ; } this.setSize(ancho,alto); } 6.1.3.2 Otros parmetros Los parmetros que vamos a definir son tres, la posicin (ABSCISA y ORDENADA) del mensaje que se va a imprimir en el applet, y el MENSAJE mismo. En la figura y en el cuadro adjunto se mue stra la definicin de cada uno de los parmetros Nombre ABSCISA MENSAJE Tipo Variable int x y String texto Valor por defecto 10 20 El primer applet
ORDENADA int
123
Para pasar los parmetros al applet se deber escribir unas lneas adicionales en el archi vo .html: <APPLET CODEBASE = "." CODE = "applet2.Applet2.class" NAME = "TestApplet" WIDTH = 400 HEIGHT = 300 HSPACE = 0 VSPACE = 0 ALIGN = middle > <PARAM NAME = "ABSCISA" VALUE = "10"> <PARAM NAME = "ORDENADA" VALUE = " 20"> <PARAM NAME = "MENSAJE" VALUE = "El primer applet"> </APPLET> Asimismo, genera una funcin la redefinicin de getParameterInfo de la clase base Applet que devuelve la informacin relativa a los parmetros pero que no tiene de momento inters El cdigo fuente del applet se da a continuacin: package applet2; public class Applet2 extends Applet { int x; int y; String texto; public void init() { int ancho=250; //valores por defecto int alto=100; x=10; y=20; try{ ancho=Integer.parseInt(this.getParameter("WIDTH")); alto=Integer.parseInt(this.getParameter("HEIGHT")); x=Integer.parseInt(this.getParameter("ABSCISA")); y=Integer.parseInt(this.getParameter("ORDENADA")); }catch(NumberFormatExcept ion ex){ System.out.println("Error en los parmetros"); } texto=this.getParameter("MENSAJE"); this.setSize(ancho,alto); } public void paint(Graphics g){ g.drawString(texto, x, y); } }
124
Ahora bien, los valores devueltos por getParameter y despus convertidos se deben de guardar en variables de instancia para que luego puedan ser utilizadas por otras funciones miembro. As, el valor del parmetro ABSCISA se guarda en el miembro dato x, el valor del parmetro ORDENADA en y, y el valor del parmetro MENSAJE en texto. En la redefinicin de paint , se muestra en el contexto grfico g, el contenido del mensaje guardado en texto en la posicin x e y mediante la llamda a la funcin drawString . Se invita al lector a que corra el applet anterior (Applet2). Para ello deber ubicarlo acuerdo a como lo exige la instruccin package . Complelo y luego comprmalo. Para ejecutarlo utilice el archivo .html con la configuracin requerida.
125
Un contexto grfico es como la hoja en blanco situada en un trazador (plotter). Para dibujar en dicha hoja se toma una pluma, se dibuja, se toma otra pluma de distinto color o grosor, se dibuja otra porcin del grfico, y as sucesivamente. Cuando no se selecciona explcitamente, se dibuja con una pluma que se establece por defecto. Las libreras grficas como la de Windows, disponen de plumas de distinto grosor para dibujar lneas con distintos estilos, brochas para rellenar el interior de una figura cerrada con un color slido, con una determinada trama o figura, y fuentes de texto, para dibujar texto con distintas fuentes y estilos. La librera grfica que viene con la versin 1.1 de Java es muy limitada. No hay objetos pinceles, ni brochas. Las lneas tienen un nico grosor y estilo, solamente se pueden cambiar de color, las figuras cerradas solamente se pueden rellenar con un color slido, y las fuentes de texto disponibles son muy pocas. La clase Graphics describe el contexto grfico y proporciona un conjunto de funciones para dibujar las siguientes figuras Lneas Crculos y elipses Rectngulos y polgones Imgenes Texto El sistema de coordenadas que se usa en Java es similar a Windows. El rea de trabajo del applet est compuesta por una matriz bidimensional de puntos o pixels. Decimos que un punto tiene de coordendas (x, y) cuando est en la columna x medida desde la izquierda, y est en la fila y, medida desde arriba.
La esquina superior izquierda es el origen (0, 0). La esquina inferior derecha viene determinada por las dimensiones del componente. La funcin getSize nos devuelve un objeto de la clase Dimension cuyos miembros width y height nos suministran la anchura y altura del componenete. int ancho=getSize().width; int alto=getSize().heigth; 6.2.2 Funciones grficas No vamos a examinar completamente la clase Graphics , pero si vamos a mostrar mediante un applet el uso de algunas funciones de esta clase. En el captulo dedicado al estudio de los ejemplos completos se representarn diagramas en forma de barras o tarta, y funciones matemticas (Captulo 11). La funcin paint nos va a proporcionar el objeto g de la clase Graphics que denominamos contexto grfico del componente (a pplet). Desde dicho objeto llamaremos a las funciones miembro de la clase Graphics.
126
6.2.2.1 Establecer un color El color negro es el color por defecto del contexto grfico. Para establecer otro color , como veremos en la seccin siguiente, se utiliza la funcin setColor , y se le pasa un color predefinido o definido por el usuario. g.setColor(Color.cyan); 6.2.2.2 Dibujar una lnea Para dibujar una lnea recta se llama a la funcin drawLine, le pasamos el punto inicial y el punto final. Para dibujar una lnea diagonal desde el origen (0, 0) o esquina superior izquierda, hasta la esquina inferior derecha, obtenemos las dimensiones del applet mediante la funcin getSize, que devuelve un objeto de la clase Dimension . El miembro width nos sproporciona la anchura y el miembro height la altura. g.drawLine(0, 0, getSize().width-1, getSize().height-1); 6.2.2.3 Dibujar un rectngulo Un rectngulo viene definido por un origen (esquina superior izquierda), su anchura y altura. La siguiente sentencia dibuja un rectngulo cuyo origen es el punto 50, 150, que tiene una anchura de 50, y una altura de 60. La funcin drawRect dibuja el contorno del color seleccionado, y fillRect dibuja el rectngulo pintando su interior del color seleccionado, en este caso de color rojo. g.setColor(Color.red); g.fillRect(50, 150, 50, 60); 6.2.2.4 Dibujar un arco Los elipses (oval), arcos (arc), se dibujan en el interior del rectngulo circundante. Una elipse de dibuja mediante drawOval o fillOval , con los mismos parmetros que el rectngulo. Un arco requiere dos parmetros ms el ngulo inical y el ngulo final. Las sentencias que vienen a continuacin, dibujan un arco en el interior del rectngulo cuyo origen es el punto 10, 10, cuya anchura es 150, y cuya altura es 100. El ngulo inicial es 0 y el ngulo final es 270, expresado en grados. g.setColor(Color.cyan); g.fillArc(10, 10, 150, 100, 0, 270); g.setColor(Color.black); g.drawArc(10, 10, 150, 100, 0, 270); 6.2.2.5 Dibujar un polgono Para dibujar un polgono, se requieren un array de puntos. Un polgono y una polilnea son parecidos, el primero es una figura cerrada mientas que una polilnea es un conjunto de segmentos. Para formar un polgono a partir de una pililnea se une el punto inicial y el punto final. El polgono precisa de un array de abscisas x, un array de ordenadas y, y la dimensin del array. int[] x={100, 150, 170, 190, 200}; int[] y={120, 280, 200, 250, 60}; g.setColor(Color.blue); g.drawPolygon(x, y, x.length);
127
Alternativamente, se puede usar un objeto de la clase Polygon , al cual se le aaden puntos mediante la funcin miembro addPoint. Polygon poligono=new Polygon(); poligono.addPoint(100, 120); poligono.addPoint(150, 280); poligono.addPoint(170, 200); poligono.addPoint(190, 250); poligono.addPoint(200, 60); Para dibujar el polgono con su interior pintado del color seleccionado se llama a la funcin fillPolygon y se le pasa el objeto poligono de la clase Polygon . g.setColor(Color.yellow); g.fillPolygon(poligono); Veremos en el applet un polgono cuyo contorno est dibujado en azul y su interior en amarillo. 6.2.2.6 Dibujar una imagen Para dibujar una imagen se requieren dos pasos: Cargar la imagen y crear un objeto de la clase Image Dibujar dicho objeto en el contexto grfico
Para crear una imagen u objeto disco de la clase Image a partir del archivo disco.gif se usa la funcin getImage. Le hemos de indicar la ubicacin de dicho archivo relativa a la pgina web que contiene el applet o al cdigo compilado. En nuestro caso, hemos situado la imagen en el mismo subdirectorio que la pgina web que contiene al applet. El lugar ms adecuado para cargar la imagen es en la funcin init, ya que como se ha mencionado se llama una sola vez. public void init(){ disco=getImage(getDocumentBase(), "disco.gif"); } Para dibujar la imagen en el contexto grfico g, se llama a la funcin drawImage. Hay varias versiones de esta funcin, la ms simple es aquella a la que se le proporciona el objeto disco de la clase Image, las coordenadas de su esquina superior izquierda (250, 50), y el observador, el propio applet o this. g.drawImage(disco, 250, 50, this); Si deseamos obtener las dimensiones del objeto disco de la clase Image, llamamos a dos funciones de esta clase getWidth y getHeight int ancho=disco.getWidth(this); int alto=disco.getHeight(this);
128
import java.applet.*; public class FuncionesApplet extends Applet { Image disco; public void init() { this.setSize(400,300); disco=getImage(getDocumentBase(), "disco.gif" ); } public void paint(Graphics g){ g.drawLine(0, 0, getSize().width-1, getSize().height-1); g.setColor(Color.red); g.fillRect(50, 150, 50, 60); g.setColor(Color.cyan); g.fillArc(10, 10, 150, 100, 0, 270); g.setColor(Color.black); g.drawArc(10, 10, 150, 100, 0, 270); Polygon poligono=new Polygon(); poligono.addPoint(100, 120); poligono.addPoint(150, 280); poligono.addPoint(170, 200); poligono.addPoint(190, 250); poligono.addPoint(200, 60); g.setColor(Color.yellow); g.fillPolygon(poligono); int[] x={100, 150, 170, 190, 200}; int[] y={120, 280, 200, 250, 60}; g.setColor(Color.blue); g.drawPolygon(x, y, x.length); g.drawImage(disco, 250, 50, this); } } Se invita al lecto r a que corra el applet anterior (FuncionesApplet). Para ello deber ubicarlo acuerdo a como lo exige la instruccin package. Complelo y luego comprmalo. Para ejecutarlo utilice el archivo .html con la configuracin requerida. 6.2.3 Las clases Color, Font y FontMetrics 6.2.3.1 La clase Color Los colores primarios son el rojo, el verde y el azul. Java utiliza un modelo de color denominado RGB, que significa que cualquier color se puede describir dando las cantidades de rojo (Red), verde (Green), y azul (Blue). Estas cantidades son nmeros enteros comprendidos entre 0 y 255, o bien, nmeros reales comprendidos entre 0.0 y 1.0. La siguiente tabla nos proporciona los colores ms comunes y sus valores RGB. Nombre white lightGray gray Red (rojo) 255 192 128 Green (verde) 255 192 128 Blue (azul) 255 192 128
129
drakGray black red pink orange yellow green magenta cyan blue
Para crear un objeto de la clase Color , se pasan tres nmeros a su constructor que indican la cantidad de rojo, verde y azul. Color colorRosa=new Color(255, 175, 175); Mediante la funcin setColor, cambiamos color con el que dibujamos una lnea, un texto o rellenamos una figura cerrada en el contexto grfico g . g.setColor(colorRosa); No es necesario tener a mano la tabla de las componentes RGB de cada color. La clase Color nos proporciona un conjunto de colores predefinidos en forma de miembros estticos de dicha clase. Podemos escribir alternativamente g.setColor(Color.pink); Los colores predefinidos son los siguientes Color.white Color.black Color.lightGray Color.red Color.gray Color.pink Color.blue El color d e fondo del componente se establece con setBackground y se obtiene con getBackground. En el siguiente applet observamos cmo se utiliza esta segunda funcin para crear una diana. En la funcin init establecemos el color de fondo en blanco mediante setBackground. En la funcin miembro paint obtenemos el color de fondo mediante getBackground. Los crculos se pintan de mayor a menor radio. Se pinta un crculo de color rojo y se borra parte de su interior con el color de fondo, de este modo se crea un anillo, luego otro y as scuesivamente, hasta completar cuatro anillos de color rojo con la apariencia de una diana. En el programa, tambin podemos apreciar que la funcin paint suministra el contexto grfico g del componente (applet) en el cual podemos dibujar. El objeto g llama a setColor para establecer el color, y a fillOval para dibujar un crculo pintado de dicho color. Las funcin getSize nos devuelve el tamao del componente (applet), de modo que los dimetros de la elipse mayor son respectivamete la anchura y altura del applet. Color.yellow Color.green Color.magenta
130
package paint1; import java.awt.*; import java.awt.event.*; import java.applet.*; public class PaintApplet extends Applet { public void init(){ setBackground(Color.white); } public void paint(Graphics g) { int x, y, ancho, alto; int appletAlto = getSize().height; int appletAncho = getSize().width; for (int i=8; i>=0; i--) { if ((i % 2)==0) g.setColor(Color.red); else g.setColor(getBackground()); alto = appletAlto*i/8; ancho = applet Ancho*i/8; x=appletAncho/2-i*appletAncho/16; y=appletAlto/2-i*appletAlto/16; g.fillOval(x, y, ancho, alto); } } } Se invita al lector a que corra el applet anterior (PaintApplet). Para ello deber ubicarlo acuerdo a como lo exige la instruccin package. Complelo y luego comprmalo. Para ejecutarlo utilice el archivo .html con la configuracin requerida. 6.2.3 .2 La clase Font Para crear una fuente de texto u objeto de la clase Font llamamos a su constructor, y le pasamos el nombre de la fuente de texto, el estilo y el tamao. Por ejemplo, Font fuente=new Font("TimesRoman", Font.BOLD, 12); Esta sentencia, crea una fuente de texto Times Roman, en letra negrita, de 12 puntos. Los estilos vienen datos por constantes ( miembros estticos de la clase Font), Font.BOLD establece el estilo negrita, Font.ITALIC, el estilo cursiva, y Font.PLAIN, el estilo normal. Se pueden combinar las constantes Font.BOLD+Font.ITALIC para establecer el estilo negrita y cursiva a la vez. La funcin setFont de la clase Graphics establece la fuente de texto en el contexto grfico g. g.setFont(fuente); La funcin getFont obtiene la fuente de texto actual de dicho contexto grfico. La funcin drawString dibuja el string guardado en el objeto texto de la clase String, y lo sita en la posicin cuyas coordenadas vienen dadas por los dos nmeros enteros que le siguen.
131
En la siguiente porcin de cdigo, establecemos una fuente de texto, dibujamos el texto, y reestablecemos la fuente de texto por defecto, una operacin habitual que se realiza al programar un applet. Font oldFont=getFont(); Font fuente=new Font("Monospaced", Font.BOLD, 36); g.setFont(fuente); g.drawString(texto, 100, 50); g.setFont(oldFont); g.drawString(otroTexto, 100, 70); Para obtener el nombre de las fuentes de texto disponibles se escribe el siguiente cdigo String[] nombreFuentes=getToolkit().getFontList(); for(int i=0; i<nombreFuentes.length; i++){ System.out.println(nombreFuentes[i]); }
6.2.3 .3 La clase FontMetrics La clase FontMetrics nos permite conocer las caractersticas de una fuente de texto. Desde el contexto grfico g, llamamos a la funcin getFontMetrics para obtener un objeto f m de la clase FontMetrics que nos describe las caractersticas de una fuente determinada o de la fuente actualmente seleccionada. En el primer caso escribimos Font fuente=new Font("Dialog", Font.BOLD, 36); FontMetrics fm=g.getFontMetrics(fuente); En el segundo caso, escribimos Font fuente=new Font("Courier", Font.BOLD, 36); g.setFont(fuente); FontMetrics fm=g.getFontMetrics(); En el applet mostramos las caractersticas de una fuente de texto: Ascent es la distancia entre lnea horizontal de color azul (baseline) y la lnea horizontal de color rojo. Descent es la distancia entre la lnea h orizontal de color azul (baseline) y la lnea horizontal de color verde. Leading sera la distancia entre las lnea de color verde (descent) y la lnea roja (ascent) de la siguiente lnea de texto.. Para obtener la altura de una fuente de texto, llamamos a la funcin getHeight miembro de FontMetrics. La altura de una fuente de texto, es la distancia entre dos lneas base (baseline) consecutivas, y es la suma de el ascent, descent y leading. Tres funciones que comienzan por get devuelven los valores de
132
estos tres atributos de una fuente de texto: getAscent, getDescent, y getLeading . Para escribir dos lneas de texto, una debajo de otra escribimos FontMetrics fm=g.getFontMetrics(); String texto="La cigea vendr"; g.drawString(texto, 10, 50); int hFont=fm.getHeight(); texto=new String("ser en primavera"); g.drawString(texto, 10, 50+hFont); La primera lnea de texto, se sita en el punto (10, 50), la ordenada 50, seala la posicin vertical de la lnea base de la fuente de texto, vase la figura. La segunda lnea de texto tiene una lnea base cuya posicin vertical se obtiene sumando a 50 la altura hFont de la fuente de texto. Otro valor interesante, es la anchura de un texto, que se obtiene mediante la funcin miembro stringWidth, y se le pasa el texto. Por ejemplo, para centrar horizontalmente un texto en el applet escribimos. String texto="La cigea vendr"; int ancho=fm.stringWidth(texto); g.drawString(texto, (anchoApplet -ancho)/2, 50); La funcin getSize().width obtiene la anchura del componente (applet), y la variable ancho , guarda la anchura del string texto. Un poco ms difcil es centrar un texto verticalmente, en una determinada posicin. Teniendo en cuanta, que las coordendas que se le pasan a la funcin drawString se refieren a la lnea base del primer carcter, tal como se ve en la figura. La frmula de centrado vertical en un punto de ordenada y sera: la ordenda y de la lnea base menos descent ms la mitad de la altura de los caracteres hFont. Se ha de tener en cuenta que la ordenada y aumenta de arriba hacia abajo. g.drawLine(0, y, anchoApplet, y); g.setColor(Color.red); texto="Centrado: a, p, , , "; g.drawString(texto, 10, y+hFont/2-descent);
Como los caracteres pueden estar o no acentuados, escritos en maysculas o minsculas, etc, la frmula para mostrar un texto centrado verticamente no es nica, se sugiere probar estas dos dadas por otros autores g.drawString(texto, 10, y+ascent/4);
g.drawString(texto, 10, y-hFont/2+ascent); El cdigo completo de este ejemplo es, el siguiente package fonts2; import java.awt.*;
133
import java.applet.*; public class FontApplet2 extends Applet { public void init() { setBackground(Color.white); } public void paint(Graphics g){ int anchoApplet=getSize().width; Font oldFont=getFont(); Font fuente=new Font("Monospaced", Font.BOLD, 36); g.setFont(fuente); FontMetrics fm=g.getFontMetrics(); String texto="La cigea vendr"; int ancho=fm.stringWidth(texto); int y=50; g.drawString(texto, (anchoApplet-ancho)/2, y); texto=new String("ser en primavera"); ancho=fm.stringWidth(texto); //caractersticas de las fuentes de texto int hFont=fm.getHeight(); int ascent=fm.getAscent(); int descent=fm.getDescent(); int leading=fm.getLeading(); g.drawString(texto, (anchoApplet-ancho)/2, y+hFont); //dibuja lnea base g.setColor(Color.blue); g.drawLine(0, y, getSize().width, y); g.drawLine(0, y+hFont, anchoApplet, y+hFont); //dibuja ascent g.setColor(Color.red); g.drawLine(0, y- ascent, anchoApplet, y-ascent); g.drawLine(getSize().width/2, y+hFont-ascent, anchoApplet, y+hFontascent); //dibuja descent g.setColor(Color.green); g.drawLine(0, y+descent, anchoApplet/2, y+descent); g.drawLine(0, y+hFont+descent, anchoApplet, y+hFont+descent); //texto centrado verticalmente en la posicin y y+=2*hFont; g.setColor(Color.black); g.drawLine(0, y, anchoApplet, y); g.setColor(Color.red); texto="Centrado: a, p, , 5, "; g.drawString(texto, 10, y+hFont/2-descent); //Escribe tres lneas de texto en la fuente de texto por defecto. g.setFont(oldFont); fm=g.getFontMetrics(); hFont=fm.getHeight(); y+=3*hFont; g.setColor(Color.black); texto="leading ="+leading; g.dra wString(texto, 10, y); texto="ascent ="+ascent; y+=hFont;
134
g.drawString(texto, 10, y); texto="descent ="+descent; y+=hFont; g.drawString(texto, 10, y); texto="altura=ascent+descent+leading= "+(ascent+descent+leading); y+=hFont; g.drawString(texto, 10, y); } } Se invita al lector a que corra el applet anterior (FonttApplet2). Para ello deber ubicarlo acuerdo a como lo exige la instruccin package. Complelo y luego comprmalo. Para ejecutarlo utilice el archivo .html con la configuracin requerida.
public
class
Resorte
private int X1, Y1, X2, Y2, a, largo, N, n; private double alfa ; private double[] exes ;
135
// Constructor /**(X1,Y1) coordenadas de un extremo del resorte *(X2,Y2) coordenadas del otro extremo del resorte *ancho es el radio de las espiras *Espiras es el nmero de espiras */ public Resorte(int X1,int Y1,int X2,int Y2,int a,int N){ //ancho Espiras this.X1=X1; this.Y1=Y1; this.X2=X2; this.Y2=Y2; this.a=a; this.N=N; calculo(); } /** Recibe el color con el cual se debe dibujar el resorte*/ public void setColorResorte(Color c){ this.c=c; } /**Mtodo que realiza los clculos para dibujar el resorte con //base en los parmetros dados */ private void calculo(){ //Decide que valor le da al ngulo respecto a la horizontal
if ((X1-X2) = 0 ) //valor diferente a 90 {alfa = Math.atan(-(1.0*(Y2-Y1))/(1.0*(X1-X2)));} else //valor igual a 90 {alfa=((Math.PI)/2.0);} //Calcula la longitud del resorte double l=0.5D*(Math.sqrt((Y1-Y2)*(Y1 -Y2)+(X1 -X2)*(X1 -X2))); //calcula el nmero de vtices que tiene la figura que va a //generar el resorte n = 2*N + 1; double h = Math.sqrt((a*a) + ((0.5*l)/N)*((0.5*l)/N));
136
//clculos adicionales para lograr saber la ubicacin de los //vtices que generan el resorte //que sern los arreglos exes y eyes double beta = Math.asin(a/h); double gama1 =(Math.PI/2)- ((alfa)+beta ); double gama2 =(Math.PI/2) ((alfa) -beta ); exes =new double[n+2]; eyes =new double[n+2]; exesint =new int[n+2]; eyesint =new int[n+2]; exes[0]=(X1) ; exes[1]=( X1 + 10*Math.cos(alfa)) ; exes[2]=( exes[1] + h*Math.sin(gama1)) ; eyes[0]=(Y1) ; eyes[1]=( Y1 + 10*Math.sin(alfa)); eyes[2]=( eyes[1] + h*Math.cos(gama1));
}//fin for
if ((n) % 2 == 0){ exes[n-1]=( exes[n-2]+h*Math.sin(gama2)) ; eyes[n-1]=( eyes[n-2]+h*Math.cos(gama2)) ; } else{ exes[n-1]=( exes[n-2]+h*Math.sin(gama1)) ; eyes[n-1]=( eyes[n-2]+h*Math.cos(gama1)) ; } exes[n]=X2; eyes[n]=Y2; //convierte los arreglos de doubles a arreglos de int for (int i=0;i<n+1;i++){ double d1= exes[i]; double d2= eyes[i]; exesint[i]=(int)(d1);
137
eyesint[i]=(int)(d2); } }//fin calculo //Metodo que recoge el contexto grfico del contenedor donde se //dibuja (por ejemplo un applet) public void dibujar (Graphics g){ //Obtiene el color actual de los objetos que se estn //dibujando en el contenedor de dibujo (por ejemplo applet Color c1=g.getColor(); //Asigna el color con que se va a dibujar el resorte g.setColor; //Dibuja el resorte g.drawPolyline(exesint,eyesint, n+1); //Devuelve el color con que se estaban dibujando lo s objetos //en el contenedor antes de que Resorte se apoderara del //contexto grfico g.setColor(c1); }//Fin Dibujese }//fin de la clase Resorte La clase Flecha:
/* * Copyright (c) 200 2 Diego Aristizbal R */ package org.opensourcephysics.unal; import java.awt.*; public class Flecha extends Canvas{ private int x1,y1,x2,y2; private Color c= Color.black;; private Graphics g; //constructor /** (x1,y1)coordenadas de un extremo de la flecha * (x2,y2) coordenadas del otro extremo de la flecha */
public Flecha( int x1,int y1,int x2,int y2){ this.x1=x1; this.y1=y1; this.x2=x2;
138
this.y2=y2; } /**recibe el color con el cual se dibujar la flecha*/ public void setColorFlecha(Color c){ this.c=c; }
private void dibuja_flecha( int x1, int y1, int x2, int y2) { //asegura que las vraiables loclales x1,y1,x2,y2 //sean las mismas que las variables de instancia //x1,y1,x2,y2 this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; //dibuja la lnea de la flecha Linea( x1, y1, x2, y2); //realiza clculos necesarios para lograr obtener //los vrtices de las lneas que dibujarn //la cabeza de la flecha double d = 0.20000000000000001D; double d1 = 10D; double d2 = x2 - x1; double d3 = y1 - y2;
//dibuja la cabezaCabeza if(d2 * d2 + d3 * d3 <= 16D) { return; } else { //clculos adicionales para obtener vrtices de los //segmentos de la cabeza double d4 = Math.atan2(d3, d2); x1 = (int)(((double)x2 - d1 * Math.cos(d4 + d)) + 0.5D); y1 = (int)((double)y2 + d1 * Math.sin(d4 + d) + 0.5D); //dibuja un segemento de la cabeza Linea( x1, y1, x2, y2); x1 = (int)(((double)x2 - d1 * Math.cos(d4 - d)) + 0.5D); y1 = (int)((double)y2 + d1 * Math.sin(d4 - d) + 0.5D); //dibuja el otro segmento de la cabeza Linea( x1, y1, x2, y2); return; }
139
private void Linea( int x1, int y1, int x2, int y2) { g.drawLine(x1, y1, x2, y2);
public void dibujar(Graphics g){ //asegura que el contexto grafico g sea el mismo //en toda esta clase this.g=g; //Obtiene el color actual de los objetos que se estan estn //dibujando en el contenedor (por ejemplo el applet) Color c1 = g.getColor(); //Asigna el color con que se dibujar la flecha g.setColor(c); dibuja_flecha( x1, y1, x2,y2); //regresa el color con que se estaban dibujando los //objetos en el contenedor (por ejemplo el applet) g.setColor(c1);
}//Fin dibujar }//Fin flecha 6.2.4.2 Cmo usar nuestros objetos dibujables? La recomendacin es hacer un paquete con ellos. Por ejemplo, la clase Resorte y la clase Flecha las hemos colocado en el paquete, org.opensourcephysics.unal;
Si nuestro directorio de desarrollo est en c \>mis_proyectos, entonces las clases se debern ubicar en el siguiente subdirectori o, tal y como lo indica el nombre del paquete: C\>mis_proyectos\>org\>opensourcephysics\>unal\>
Para usar las clases deber importar el paquete: import org.opensourcephysics.unal; Se sugiere al lector corra el siguiente applet siguiendo estos consejos : import java.awt.event.*; import java.applet.*; import org.opensourcephysics.unal.* ;
140
public class ObjetosDibujablesPropios Applet extends Applet { public void init() { setBackground(Color.white); } public void paint(Graphics g){ //crea un objeto resorte Resorte r=new Resorte (20,50,200,100,10,8); //le asigna el color al resorte r.setColorResorte(Color.red); //dibuja el resorte pasando el contexto grfico //desde este applet al objeto resorte r.dibujar(g); //crea un objeto flecha Flecha f= new Flecha(100,100,200,200); //le asigna el color a la flecha f.setColorFlecha(new Color(180,250,90)); //dibuja el resorte pasando el contexto grfico //desde este applet al objeto flecha f.dibujar(g); }
Por ejemplo, podramos usar el API 2D de Java para mostrar grficos y charts complejos que usan varios estilos de lnea y de relleno para distinguir conjuntos de datos, como se muestra en la siguiente figura:
El API 2D de Java tambin nos permite a lmacenar datos de imgenes. Por ejemplo, podemos realizar fcilmente filtros de imgenes, como blur o recortado, como se muestra en la siguiente figura:
141
Recome ndamos al lector que profundice su conocimiento en esta EXCELENTE API en alguna de las siguientes direcci ones: http://java.sun.com/products/jdk/1.2/docs/guide/2d/spec/j2d-title.fm.html http://www.programacion.com/tutorial.2d.html En esta seccin nos limit aremos a indicar los usos bsicos.
El estilo de lpiz que se aplica al exterior de una forma. Este atributo stroke nos permite dibujar lneas con cualquier tamao de punto y patrn de sombreado y aplicar finalizadores y decoraciones a la lnea.
142
El estilo de relleno que se aplica al interior de la forma. Este atributo paint nos permite rellenar formas con colores slidos, gradientes o patrones.
El estilo de composicin se utiliza cuando los objetos dibujados se solapan con objetos existentes.
La transformacin que se aplica durante el dibujado para convertir el objeto dibujado desde el espacio de usuario a las coordenadas de espacio del dispositivo. Tambin se pueden aplicar otras transformaciones opcionales como la translacin, rotacin escalado, recortado, a travs de este atributo.
El Clip que restringe el dibujado al rea dentro de los bordes de la Shape se utiliza para definir el re a de recorte. Se puede usar cualquier Shape para definir un clip.
Punto de Renderizado que especifican las preferencias en cuanto a velocidad y calidad. Por ejemplo, podemos especificar si se debera usar antialiasing, si est disponible.
Para configurar un atributo en el contexto de renderizado de Graphics2D, se usan los mtodos setAttribute. setStroke setPaint setComposite setTransform setClip setFont setRenderingHints
Cuando configuramos un atributo, se le pasa al objeto el atributo apropiado. Por ejemplo, para cambiar el atributo paint a un relleno de gradiente azul-gris, deberamos construir el objeto GradientPaint y luego llamar a set Paint. gp = new GradientPaint(0f,0f,blue,0f,30f,green);
143
g2.setPaint(gp); Graphics2D contiene referencias a sus objetos atributos: no son clonados. Si modificamos un objeto atributo que forma parte del contexto Graphics2D, necesitamos llamar al mtodo set para notificarlo al contexto. La modificacin de un atributo de un objeto durante el renderizado puede causar comportamientos impredecibles. 6.3.1.3 Mtodos de renderizado de Graphics2D Graphics2D proporciona los siguientes mtodos generales de dibujado que pueden usarse para dibujar cualquier primitivo geomtrico, texto o imagen. Draw.: dibuja el exterior de una forma geomtrica primitiva usando los atributos stroke y paint. Fill: dibuja cualquier forma geomtrica primitiva rellenado su interior con el color o patrn especificado por el atributo paint. drawString: dibuja cualquier cadena de texto. El atributo font se usa para convertir la fuente a glyphs que luego se rellenan con el color o patrn especificados por el atributo paint. drawImage: dibuja la imagen especificada.
Adems, Graphics2D soporta los mtodos de renderizado de Graphics para formas particulares, como drawOval y fillRect.
6.3.1.4 Espacios de coordenadas Uno de los conceptos introducidos con Java2D es la diferencia entre un espacio de coordenadas de un dispositivo de salida y el espacio de coordenadas al que uno se refiere cuando dibujamos un objeto. Para todas las operaciones de dibujo que hemos realizado hasta aqu y todas las operaciones previas a Java 2, el nico espacio de coordenadas que se us fue el del espacio de coordenadas de dispositivo. Especificamos las coordenadas (x,y) de una superficie de salida como una ventana de un applet y las coordenadas que se usaron para dibujar lneas, textos y otros elementos. Java2D presenta otro espacio de coordenadas al que uno se refiere cuando se cree un objeto y realmente se dibuje. Este se le denomina espacio de coordenadas de usuario . Antes de que cualquier dibujo de 2D haya ocurrido en un programa, el espacio de dispositvo y el espacio de usuario tienen la coordenada (0,0) en el mismo lugar: la esquina superior izquierda del rea de dibujo. La coordenada (0,0) del espacio del usuario se puede mover como resultado de las operaciones de dibujo de 2D que se llevan a cabo. Incluso los ej es x,y se pueden rotar. Resumiendo: e l sistema 2D de Java mantiene dos espacios de coordenadas: El espacio de usuario es el espacio en que se especifican los grficos primitivos. El espacio de dispositivo es el sistema de coordenadas para un diopositivo de salida, como una pantalla, una ventana o una impresora.
144
El espacio de usuario es un sistema de coordenadas lgicas independiente del dispositivo: el espacio de coordenas que usan nuestros programas. Todos los objetos geomtricos pasados a las rutinas Java 2D de renderizado se especifican en coordenadas de espacio de usuario. Cuando se utiliza la transformacin por defecto desde el espacio de usuario al espacio de dispositivo, el origen del espacio de usuario es la esquina superior izquierda del rea de dibujo del componente. La coordenada x se incrementa hacia la derecha, y la coordenada y hacia abajo. El espacio de dispositivo es un sistema de coordenadas dependiente del dispositivo que vara de acuerdo a la fuente del dispositivo. Aunque el siste ma de coordenadas para una ventana o una pantalla podra ser muy distinto que para una impresora, estas diferencias son invisibles para los programas Java. Las conversiones necesarias entre el espacio de usuario y el espacio de dispositivo se realizan automticamente durante el dibujado.
6.3.1.5 Formas 2D
Las clases del paquete java.awt.geom definen grficos primitivos comunes, como puntos, lneas, curvas, arcos, rectngulos y elipses. Clases en el paquete java.awt.geom Arc2D Area Ellipse2D QuadCurve2D RectangularShape RoundRectangle2D
GeneralPath Rectangle2D
Excepto para Point2D y Dimension2D , cada una de las otras clases geomtricas implementa el interface Shape , que proporciona un conjunto de mtodos comunes para describir e inspeccionar objetos geomtricos bi-dimensionales. Con estas clases podemos crear de forma virtual cualquier forma geomtrica y dibujarla a travs de Graphics2D llamando al mtodo draw o al mtodo fill. Por ejemplo, las formas geomtricas del siguiente applet (ShapesDemo2D) estn definidas usando los objetos geomtricos bsicos de Java 2D.
145
/* * 1.2 version. */ import import import import java.awt.*; java.awt.event.*; java.awt.geom.*; javax.swing.*;
public class ShapesDemo2D extends JApplet { public void init() { //Initialize drawing colors setBackground(Color.white); setForeground(Color.black); } public void paint(Graphics g) { //Contexto grfico Graphics2D g2 = (Graphics2D) g; //Mejora la calidad del dibujo g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //Rectngulos 3D g2.setPaint(Color.red); g2.draw3DRect(10, 10, 40,30, true); g2.setPaint(Color.blue); g2.draw3DRect(60,10, 40,30, false); //Cadenas con tipo de letra por defecto g2.setPaint(Color.black); g2.drawString("Rectngulos 3D",10 ,60); //Line2D.Double g2.setPaint(Color.black); g2.draw(new Line2D.Double(120,10, 180 , 30)); //Cadenas con tipo de letra definido Font letra_1= new Font("NewTimes",Font.PLAIN,10); g2.setFont(letra_1); g2.drawString("Lnea2D",120 ,60); //Bug //Rectangle2D.Double g2.setPaint(new Color(200,150,250)); g2.draw(new Rectangle2D.Double(220, 10, 40, 30)); //Rectangle2D.Double cambiando el ancho de la lnea BasicStroke stroke = new BasicStroke(2.0f);
146
g2.setStroke(stroke); g2.draw(new Rectangle2D.Double(280, 10, 40, 30)); //Rectangle2D.Double con otro trazo BasicStroke dashed = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); g2.setStroke(dashed); g2.draw(new Rectangle2D.Double(340, 10, 40, 30)); //Dibujar Arco g2.setPaint(Color.red); BasicStroke wideStroke = new BasicStroke(6.0f); g2.setStroke(wideStroke); g2.draw(new Arc2D.Double(10,80,40,40, 90, 135, Arc2D.OPEN)); //Dibujar elipse g2.setStroke(stroke); g2.draw(new Ellipse2D.Double(60,80,60,40)); //Dibujar polgono GeneralPath (polygon) int x1Points[] = {120,180, 120, 180}; int y1Points[] = {80, 140, 140, 80}; GeneralPath polygon = new GeneralPath ( GeneralPath.WIND_EVEN_ODD, x1Points.length); polygon.moveTo(x1Points[0], y1Points[0]); for ( int index = 1; index < x1Points.length; index++ ) { polygon.lineTo(x1Points[index], y1Points[index]); }; polygon.closePath(); g2.draw(polygon); // Dibujar lnea poligonal GeneralPath (polyline) int x2Points[] = {220, 280, 220, 280}; int y2Points[] = {80, 140, 140, 80}; GeneralPath polyline = new GeneralPath( GeneralPath.WIND_EVEN_ODD, x2Points.length); polyline.moveTo (x2Points[0], y2Points[0]); for ( int index = 1; index < x2Points.length; index++ ) { polyline.lineTo(x2Points[index], y2Points[index]); }; g2.draw(polyline); // Rectngulo relleno: fill Rectangle2D.Double (red) g2.fill(new Rectangle2D.Double(340, 80, 60, 40)); // Arco relleno: fill Arc2D g2.fill(new Arc2D.Double(10, 140, 60, 60, 90, 135, Arc2D.OPEN)); // Elipse rellena con color gradiente
147
GradientPaint redtowhite = new GradientPaint(120,160, Color.blue,180, 160,Color.white); g2.setPaint(r edtowhite); g2.fill (new Ellipse2D.Double(120, 160, 60,40)); } } Se recomienda al lector correr el applet y construir ms figuras consultando la API de Java 2. Las dimensiones del applet son width=500 heigth=200
x y = 1
y la traslacin en una cantidad
cos sen 0
sen cos 0
0 0 1
x y 1 b
en la direccin y:
en la direccin x y
x y = 1
1 0 a x 0 1 b y 0 0 1 1
La transformacin afn ms general es una combinacin de un escalado, una traslacin, y una rotacin. Esta puede ser escrita as:
x y = 1
m00 m 10 0
x y 1
Esta transformacin es creada en Java2D usando el constructor AffineTransform: AffineTransform t = new AffineTransform(double m00,double m10,double m01, double m11, double m02, double m12) ; Hay mtodos que implementan las rotaciones y traslaciones puras.
148
6.3.2.1 Formas de implementar las transformaciones afnes: Podemos modificar el atributo transform en el contexto Graphics2D para mover, rotar, escalar y modificar grficos primitivos mientras son dibujados. El atributo transform est definido por una instancia de AffineTransform. Graphics2D proporciona varios mtodos para cambiar el atributo transform . Podemos construir un nuevo AffineTransform y cambiar el atributo transform de Graphics2D llamando al mtodo setTransform. AffineTransform define los siguientes mtodos para hacer ms sencilla la construccin de nuevas transformaciones: getRotateInstance getScaleInstance getShearInstance getTranslateInstance
De forma alternativa podemos usar uno de los mtodos de transformaci n de Graphics2D para modificar la transformacin actual. Cuando se llama a uno de esos mtodos de conveniencia, la transformacin resultante se concatena con la transformacin actual y es aplicada durante el dibujado. r otate: para especificar un ngulo de rotacin en radianes. scale: para especificar un factor de escala en direcciones x e y. shear : para especificar un factor de comparticin en direcciones x e y translate: para especificar un desplazamiento de movimiento en direcciones x e y
Tambin po demos construir directamente un AffineTransform y concatenarlo con la transformacin actual llamando al mtodo transform . El mtodo drawImage tambin est sobrecargado para permitirnos especificar un AffineTransform que es aplicado a la imagen a dibujar. Especificar un transform cuando se llama a drawImage no afecta al atributo transform de Graphics2D. 6.3.2.2 Ejemplos Los dos programas que se listan a continuacin ilustran diferentes formas de implementar las transformaciones afines . El lector deber co rrerlos y hacerles variaciones para practicar. Ambos applets tiene como dimensiones width=500 height=400: import import import import java.awt.*; java.awt.event.*; java.awt.geom.*; javax.swing.*;
149
setForeground(Color.black); }
public void paint(Graphics g) { //Contexto grfico Graphics2D g2 = (Graphics2D) g; //Mejora la calidad del dibujo g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Mtodo 1: Creando una transformacin afn //Traslacin del origen al punto (100,0) y rotacin de 45 alrededor de el AffineTransform t_1=new AffineTransform(); Shape rectangulo_1=new Rectangle2D.Double(0, 0, 150, 100); g2.setPaint(Color.red); t_1.translate(100.0,0.0); t_1.rotate(Math.PI/4); g2.setTransform(t_1); g2.draw(rectangulo_1);
//Traslacin del origen al punto (100,100) y rotacin de 45 alrededor de el AffineTransform t_2=new AffineTransform(); Shape rectangulo_2= (new Rectangle2D.Double(0, 0, 150, 100)); g2.setPaint(new Color(0,128,0)); t_2.translate(100.0,200.0); t_2.rotate(Math.PI/4); g2.setTransform(t_2); g2.draw(rectangulo_2); g2.fill(rectangulo_2); //Rotacin alrededor de 60 del punto (100,100) AffineTransform t_3=new AffineTransform(); Shape rectangulo_3= (new Rectangle2D.Double(0, 0, 150, 100)); g2.setPaint(Color.green); t_3.rotate(Math.PI/3,100.0,200.0); g2.setTransform(t_3); g2.draw(rectangulo_3);
//Traslacin del origen al punto (250,200)y rotacin alrededor de el de -60 double teta=-Math.PI/3; AffineTransform t_4= new AffineTransform(Math.cos(teta),Math.sin(teta), Math.sin(teta),Math.cos(teta),250.0,200.0); Shape rectangulo_4= (new Rectangle2D.Double(0, 0, 150, 100)); g2.setPaint(Color.black); g2.setTransform(t_4);
150
g2.draw(rectangulo_4); //Transformacin sobre una cadena AffineTransform t_5=new AffineTransform(); t_5.rotate(Math.PI/3,100.0,100.0); g2.setPaint(Color.magenta); g2.setTransform(t_5); g2.setFont(new Font("SanSerif",Font.BOLD,40)); g2.drawString("Fsica",350,0);
} }
public void paint(Graphics g) { //Contexto grfico Graphics2D g2 = (Graphics2D) g; //Mejora la calidad del dibujo g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Metodo 2 : Actuando directamente sobre el objeto Graphics2D. //Hace las operaciones respecto al estado actual de Graphics2D Shape rectangulo_1=new Rectangle2D.Double(0, 0, 150, 100); g2.translate(250,200); g2.setPaint(new Color(0,128,0)); g2.draw(rectangulo_1); //rotacin de 45 Shape rectangulo_2=new Rectangle2D.Double(0, 0, 150, 100); g2.rotate(Math.PI/4); g2.setPaint(Color.green); g2.draw(rectangulo_2);
151
//escalar Shape rectangulo_3=new Rectangle2D.Double(0, 0, 150, 100); g2.scale(0.5,0.5); g2.setPaint(Color.blue); g2.draw(rectangulo_3); //Estiramiento g2.shear(2.5,1.5); g2.setPaint(Color.red); g2.draw(rectangulo_1); //Transformacn sobre cadenas g2.shear(2.5,3.5); g2.setFont(new Font("SanSerif",Font.BOLD,20)); g2.drawString("Fsica",-40,20);
} }
152
153
Software Educativo:
Publicidad:
154
Visualizaci n de datos:
Diseo:
155
public void paint(Graphics g) { //Contexto grfico Graphics2D g2 = (Graphics2D) g; //Mejora la calidad del dibujo g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} //Este mtodo esttico hace que el applet se pueda ejecutar como una aplicacin public static void main(String[] args) { JApplet applet = new AppletAplicacion(); JFrame f = new JFrame("Aplicacin y Applet"); //evento de cerrar ventana: se ver ms adelante f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); f.getContentPane().add(applet, BorderLayout.CENTER); f.setSize(new Dimension(350, 200)); f.setVisible(true); }
156