Download Clase 17 PDF

Document related concepts
no text concepts found
Transcript
1.00 Clase 17
Introducción a la API de
gráficos 2D de Java
Anuncios
• Boletín de problemas 5: compruebe la web
– En los problemas 1 y 2, no es necesario que utilice
clases internas anónimas si prefiere utilizar
getSource() en sus métodos actionPerformed(),
para determinar el origen del evento.
– En el problema 2, hemos decidido facilitarle una de
las dos clases que le pedimos que escribiese
BusDrawing. La puede descargar de la web.
Si lo desea, también puede utilizar su versión.
2
1
Los orígenes de la API de
gráficos 2D de Java
• La herramienta original de la GUI de Java, la AWT, era una
solución rápida y poco fiable. Utilizaba componentes de
pares nativos para dibujar todos los controles.
• Swing dibuja todos los componentes excepto los contenedores de alto nivel, que utilizan los métodos de Java en vez de basarse en controles específicos de la plataforma.
• Para hacer esto, Swing necesitaba mejores gráficos.
• La API 2D de Java surgió como tecnología instrumental para Swing.
• Existe también ahora una API 3D de Java.
• Consulte el tutorial en:
http://java.sun.com/docs/books/tutorial/2d/index.html
3
Arquitectura gráfica de Java
Swing
AWT para Java
API de gráficos 2D de Java
Sistema de ventanas de la plataforma
Arquitectura de gráficos de la plataforma
4
2
NgonApp
Diseño personalizado
Componentes de Swing:
JLabel y JTextField
5
¿En qué momentos se dibuja una GUI?
• En la pantalla de inicio (no necesariamente cuando
el programa se arranca).
•
Cuando la visualización varía. Por ejemplo, cuando la ventana
o parte de ella queda oculta tras otra y luego vuelve a mostrarse.
• Cuando el contenido cambia, y Swing o el programador
piden una actualización
(repaint()).
6
3
¿Cómo se dibuja una GUI?
• Swing programa el diseño. Es posible que
combine múltiples peticiones de rediseño que
se sucedan rápidamente.
• Swing llama a los tres métodos siguientes en
orden:
paintComponent()
paintBorder()
paintChildren()
• El último pinta recursivamente los hijos de un
contenedor.
7
Diseño personalizado
• Los componentes estándar de Swing, tales como JLabel y
JComboBox,
a sí mismos.
utilizan el paintComponent() para dibujarse
• Si desea crear un diseño personalizado, amplíe una clase
contenedora, normalmente JPanel , y anule a
paintComponent () .
• Utilice llamadas de la API 2D en paintComponent()
para dibujar lo que desee en el fondo de JPanel.
• Anule getPreferredSize() o llame a
setPreferredSize ()
a su diseño.
para ajustar el tamaño de JPanel
8
4
La clase Graphics
•
Se llama a paintComponent () con el argumento
Graphics g, que sirve como como herramienta de dibujo
inicializada a los valores por defecto del componente.
•
El argumento es realmente un objeto Graphics2D. Por
tanto, utilícelo. Graphics era, originariamente, la clase de AWT.
• La API 2D arranca normalmente del modo siguiente:
public void paintComponent ( Graphics g ) {
super.paintComponent( g );
Graphics2D g2 = (Graphics2D) g;
// los comandos de dibujo van aquí
}
9
¿De dónde procede el argumento Graphics?
•
El argumento Graphics del método paintComponent()
es una captura de pantalla de los valores gráficos por defecto del
componente, al igual que la fuente y el color del diseño en el momento en que se llama a los métodos de dibujo (paint).
•
Es sólo una copia de estos valores. Cada vez que se llama a los
métodos de dibujo, se obtiene una nueva versión de Graphics.
Ninguno de los cambios realizados a una instancia de Graphics
en una llamada a paintComponent(), se recordará la siguiente
vez que se llame al método; y ningún cambio como, por ejemplo,
el realizado con setFont() se transmitirá al componente en sí.
•
es
10
5
Operaciones básicas de la API 2D
Puede usar el argumento Graphics2D para:
1.
2.
dibujar contornos de figuras utilizando el método
public void draw( Shape s )
dibujar figuras con relleno utilizando el método
public void fill( Shape s )
Puede usar el argumento de Graphics o Graphics2D
para:
3.
4.
dibujar una imagen utilizando uno de los métodos
public void drawImage( . . . )
dibujar una cadena de texto utilizando los métodos
public void drawString( . . . )
11
Contexto de representación de gráficos 2D
Gran parte del poder de la API 2D proviene de la habilidad del usuario
para definir los atributos del objeto Graphics2D, lo que se conoce
como contexto de representación (rendering context):
– public void setStroke(Stroke s)
– public void setPaint(Paint p)
–
–
–
–
public
public
public
public
void
void
void
void
setFont(Font f)
setComposite(Composite c)
setTransform(Transform t)
setRenderingHints(Map m)
12
6
Plantilla de diseño personalizado
import java.awt.*; // para Graphics2D, Paint, Shape, …
import java.awt.geom.*; // para clases Shape concretas
import javax.swing.*; // para JPanel, etc
public class MyPanel extends JPanel {
. . .
public void paintComponent( Graphics g ) {
super.paintComponent( g );
Graphics2D g2 = (Graphics2D) g;
. . .
g2.setPaint/Stroke/Font/etc(...);
Shape s = new Shape2D.Float/Double( ... );
g2.draw/fill( s );
. . .
13
NgonApp, Primera versión
JFrame con
BorderLayout
CENTRO
CON
NgonView
amplía a JPanel
JPanel con
FlowLayout
SUR
14
7
NgonApp, versión 1, 1
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class NgonApp1 extends JFrame {
private NgonView1 view;
private JTextField nField;
public NgonApp1() {
super( "NgonApp" );
setDefaultCloseOperation( EXIT_ON_CLOSE );
view = new NgonView1();
getContentPane().add( view, BorderLayout.CENTER );
15
NgonApp, versión 1, 2
JPanel nPanel = new JPanel();
Font labelFont = new Font( "SansSerif", Font.BOLD, 18
);
JLabel nLabel = new JLabel( "Número de lados = " );
nLabel.setFont( labelFont );
nPanel.add( nLabel );
nField = new JTextField( 5 );
nField.setFont( labelFont );
nField.addActionListener(new ActionListener(){...});
nPanel.add( nField );
getContentPane().add( nPanel, BorderLayout.SOUTH );
pack();
}
16
8
NgonApp, versión 1,3
el ActionListener
nField.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e ) {
int nSides;
String nStr = nField.getText();
try {
nSides = Integer.parseInt( nStr );
view.setSides( nSides );
}
catch ( NumberFormatException n ) {
view.setSides( 0 );
}
nField.selectAll();
} // Fin de actionPerformed
} ); // Fin de addActionListener
17
NgonView , versión 1, 1
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class NgonView1 extends JPanel {
private int nSides = 0;
private Font ngonFont;
static public final Dimension PREF_SIZE =
new Dimension( 600, 700 );
static public final int warnX = 180;
static public final int warnY = 600;
static public final int areaX = 180;
static public final int areaY = 600;
18
9
NgonView , versión 1, 2
public NgonView1() {
ngonFont = new Font("SansSerif", Font.ITALIC, 16);
}
public void setSides ( int n ) {
nSides = n;
repaint();
}
public Dimension getPreferredSize() {
return PREF_SIZE;
}
private double getArea() {
double PIn = Math.PI / nSides;
return nSides * Math.cos( PIn ) * Math.sin( PIn );
}
19
NgonView , versión 1, 3
Texto en el diseño
public void paintComponent( Graphics g ) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent( g );
g2.setFont( ngonFont );
g2.setPaint( Color.red );
if ( nSides < 3 ) {
g2.drawString( "Elija un número de lados >= 3",
warnX, warnY );
} else {
g2.drawString( "Área del polígono = " + getArea(),
areaX, areaY );
}
20
10
NgonView , versión 1
Ubicar el círculo
100
100
400
400
21
NgonView , versión 1, 3
Dibujar el círculo
g2.setStroke( new BasicStroke( 2 ) );
g2.setPaint( Color.blue );
Shape circle =
new Ellipse2D.Float( 100, // superior izquierda x
100, // superior izquierda y
400, // ancho del cuadrado que lo circunscribe
400 ); // altura de dicho cuadrado
g2.draw( circle );
}
22
11
Sistema de coordenadas de Graphics2D
• El objeto Graphics2D utiliza un tipo de coordenadas
reales (en vez de coordenadas de dispositivo) que
Java denomina espacio del usuario.
• Las formas y operaciones de Graphics2D están definidas como coma flotante (float o double) pero la
coordenada Y aumenta hacia abajo.
• Algunas llamadas Graphics2D sólo admiten floats.
• Las coordenadas de coma flotante están diseñadas
para garantizar la independencia de sus gráficos con
respecto al dispositivo de salida.
• La API 2D está diseñada para mostrar la salida en
pantalla a diferentes resoluciones.
L
23
La transformación por defecto de
Graphics2D
• El proyecto de representación 2D aplica una transformación geométrica para mapear el espacio del usuario
con el espacio del dispositivo.
• La transformación por defecto mapea unidades 1.0 de
espacio de usuario con ~1/72 de pulgada, que resulta
ser el tamaño medio por píxel en una pantalla o el tamaño de un punto en una impresora.
• De modo que a menos que haga algo especial, el diseño 2D utilizará por defecto las coordenadas en píxel.
24
12
NgonView , versión 2
Utilizando transformación de coordenadas
(-1.0,-1.0)
Y
1.0
X
(0.0,0.0)
1.0 =
200 pixels
25
NgonView , versión 2,
Transformación de coordenadas, 1
static public final float SCALE = 200.0F;
static public final float tx = 1.5F;
static public final float ty = 1.5F;
private float transX( float x ) {
return ( x + tx ) * SCALE;
}
private float transY( float y ) {
return ( y + ty ) * SCALE;
}
26
13
NgonView , versión 2,
Transformación de coordenadas, 2
public void paintComponent( Graphics g ) {
. . .
g2.setStroke( new BasicStroke( 2 ) );
Shape circle = new Ellipse2D.Float(
transX ( -1.0F ), transY( -1.0F ),
2.0F * SCALE, 2.0F * SCALE );
g2.setPaint( Color.yellow );
g2.fill( circle );
g2.setPaint( Color.blue );
g2.draw( circle );
}
27
NgonView , versión 3
Cómo rellenar el polígono
θ = 2π / 5
θ
( 0.0,0.0 )
(1.0,0.0 )
( cos θ ,sin θ )
28
14
Construcción de formas más complejas
• Puede crear formas más complejas mediante la agrupación de formas y rutas (segmentos de línea,
curvas cuadráticas y curvas cúbicas).
• El Shape combinado es un GeneralPath, que implementa la interfaz Shape para que usted pueda dibujarla
o rellenarla como cualquier otra forma.
• Para saltar a otro punto, dejando un trozo sin dibujar, utilice:
moveTo( float x, float y );
• Para dibujar una línea que siga una ruta, utilice:
lineTo( float x, float y );
29
NgonView , versión 3,
Cómo rellenar el polígono, 2
public void paintComponent( Graphics g ) {
. . .
float dtheta = (float) ( 2 * Math.PI ) / nSides;
g2.setPaint( Color.green );
GeneralPath ngon = new GeneralPath();
ngon.moveTo( transX( 1.0F ), transY( 0.0F ) );
for ( int i = 1; i < nSides; i++ ) {
float x = transX( (float) Math.cos( i*dtheta ));
float y = transY( (float) Math.sin( i*dtheta ));
ngon.lineTo( x, y );
}
ngon.closePath();
g2.fill( ngon );
}
30
15