Soportar Interacción con el Usuario
Para permitir que el usuario interactúe con los graficos que hemos dibujado, necesitamos
poder determinar cuando el usuario pulsa sobre uno de ellos. El método
hit de Graphics2D proporciona una forma para determinar
fácilmente si ha ocurrido una pulsación de ratón sobre una Shape
particular. De forma alternativa podemos obtener la posición del click de ratón y llamar
a contains sobre la Shape para determinar si el
click ocurrió dentro de los límites de la Shape.
Si estamos usando texto primitvo, podemos realizar una simple comprobación obteniendo la
línea exterior de la Shape que corresponde al texto y luego llamando
a hit o contains con esa
Shape. El soporte de edición de texto requiere una comprobación mucho más
sofisticada. Si queremos permitir que el usuario edite el texto, generalmente deberíamos
usar uno de los componentes de texto editable de Swing. Si estamos trabajando con texto
primitivo y estamos usando TextLayout para manejar la forma y
posición del texto, también podemos usar TextLayout para realizar la
comprobación para la edición de texto. Para más información puedes ver
Java 2D Programmer's Guide.
Ejemplo: ShapeMover
Este applet permite al usuario arrastrar la Shape por la ventana del
applet. La Shape se redibuja en cada nueva posición del ratón para
proporcionar información al usuario mientras la arrastra.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa
sobre ella. El applet aparecerá en una nueva ventana del navegador.
ShapeMover.java
contiene el código completo de este applet.
Se llama al método contains para determinar si el cursor está
dentro de los límites del rectángulo cuando se pulsa el botón. Si es así, se actualiza la
posición del rectángulo.
public void mousePressed(MouseEvent e){
last_x = rect.x - e.getX();
last_y = rect.y - e.getY();
if(rect.contains(e.getX(), e.getY())) updateLocation(e);
...
public void updateLocation(MouseEvent e){
rect.setLocation(last_x + e.getX(), last_y + e.getY());
...
repaint();
Podrías haber sobservado que redibujar la Shape en cada posición del
ratón es muy lento, porque el rectángulo relleno es renderizado cada vez que se mueve,
Usando el doble buffer podemos eliminar este problema. Si estamos usando Swing, el dibujo
usará doble buffer automáticamente; si no es así tendremos que cambiar todo el código de
renderizado. El código para una versión swing de este programa es SwingShapeMover.java
. Para ejecutar la versión Swing, visita SwingShapeMover.
Si no estamos usando Swing, el Ejemplo:
BufferedShapeMover en la siguiente lección nos muestra cómo podemos
implementar el doble buffer usando un BufferedImage. Podemos dibujar
en un BufferedImage y luego copiar la imagen en la pantalla.
Ejemplo: HitTestSample
Esta aplicación ilustra la comprobación de pulsaciones dibujando el cursor por defecto
siempre que el usuario pulse sobre el TextLayout, como se muestra en
la siguiente figura.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa
sobre ella. El applet aparecerá en una nueva ventana del navegador.
HitTestSample.java contiene el código completo de este applet.
El método mouseClicked usa
TextLayout.hitTestChar para devolver un objeto
java.awt.font.TextHitInfo que contiene la posición del click (el índice de
inserción) en el objeto TextLayout.
La información devuelta por los métodos de TextLayout,
getAscent, getDescent y getAdvance
se utiliza para calcular la posición del origen del objeto
TextLayout para que esté centrado tanto horizontal como verticalmente.
...
private Point2D computeLayoutOrigin() {
Dimension size = getPreferredSize();
Point2D.Float origin = new Point2D.Float();
origin.x = (float) (size.width - textLayout.getAdvance()) / 2;
origin.y =
(float) (size.height - textLayout.getDescent()
+ textLayout.getAscent())/2;
return origin;
}
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.white);
Graphics2D graphics2D = (Graphics2D) g;
Point2D origin = computeLayoutOrigin();
graphics2D.translate(origin.getX(), origin.getY());
// Draw textLayout.
textLayout.draw(graphics2D, 0, 0);
// Retrieve caret Shapes for insertionIndex.
Shape[] carets = textLayout.getCaretShapes(insertionIndex);
// Draw the carets. carets[0] is the strong caret and
// carets[1] is the weak caret.
graphics2D.setColor(STRONG_CARET_COLOR);
graphics2D.draw(carets[0]);
if (carets[1] != null) {
graphics2D.setColor(WEAK_CARET_COLOR);
graphics2D.draw(carets[1]);
}
}
...
private class HitTestMouseListener extends MouseAdapter {
/**
* Compute the character position of the mouse click.
*/
public void mouseClicked(MouseEvent e) {
Point2D origin = computeLayoutOrigin();
// Compute the mouse click location relative to
// textLayout's origin.
float clickX = (float) (e.getX() - origin.getX());
float clickY = (float) (e.getY() - origin.getY());
// Get the character position of the mouse click.
TextHitInfo currentHit = textLayout.hitTestChar(clickX, clickY);
insertionIndex = currentHit.getInsertionIndex();
// Repaint the Component so the new caret(s) will be displayed.
hitPane.repaint();
}