Java: ¿Cómo dibujar una superposición sin desplazamiento sobre la ventana de ScrollPane?

Me gustaría usar un ScrollPane para mostrar una imagen en su Viewport, y también tener una superposición de cuadrícula (o recuadro, o cualquier otro tipo de marcador de registro / ubicación) en la imagen. Necesito que la superposición permanezca fija cuando se desplaza (lo que significa que la imagen parece moverse “debajo” de la superposición). Desplazaré la vista en la ventana gráfica a una velocidad fija para proporcionar un movimiento suave, y la superposición proporcionará una referencia a una determinada ubicación dentro de la ventana gráfica. Conceptualmente, piense en un mapa grande que se desplaza en una ventana gráfica, y la ventana gráfica que tiene un rectángulo que no se mueve (en relación con la ventana gráfica) que marca una región que puede ampliarse en función de alguna acción del usuario.

Supongo (pero aún no lo he confirmado) que la implementación de ScrollPane maneja la representación de la Vista de manera eficiente (desde el almacén de respaldo, sin tener que repintar toda la Vista (o incluso ViewPort) para cada nueva exposición parcial) y, por lo tanto, preferiría no tener que Anular el método de pintura ().

Miré a LayerPane, y aunque no lo había dominado, parece que se trata de un enfoque de fuerza bruta. El ScrollPane es un Componente de un SplitPane y se moverá / redimensionará. Espero que tenga que mantener manualmente la relación correcta entre ViewPort y LayerPane usando el posicionamiento absoluto. Estoy lejos de ser un experto en el diseño e implementación de GUI y estoy seguro de que me faltan posibilidades que van desde obvias a oscuras y elegantes que una persona con experiencia sabría.

Estoy abierto a cualquier sugerencia, no solo a la ruta que comencé. ¿Debo (puedo) agregar un JPanel como un componente en mi SplitPane, luego agregar un LayerPane al que contiene mi ScrollPane y la superposición (otro JPanel) en diferentes capas en el LayerPane? ¿Hay funcionalidad en ScrollPane para soportar esto directamente? He consultado los Java Swing Tutorials y la documentación API, pero aún no he visto nada.

Gracias.

ACTUALIZAR:

Gracias por el enlace, trashgod. Esto fue mucho más fácil de lo que esperaba. No hay necesidad de LayerPane, GlassPane, composición basada en xor … No sé por qué no se me ocurrió intentar reemplazar JViewport.paint () para dibujar mi superposición, pero con el siguiente código validé el concepto dame lo que estoy buscando. Simplemente use la subclase de JViewport y haga lo que yo quiera (en este caso, superponiendo un rectángulo en el centro de la ventana gráfica mientras la imagen se desplaza por debajo). No soy un experto en GUI, y la API de Java es increíblemente amplia; No tengo ni idea de cómo guardan todo esto en la cabeza, ¡pero gracias!

class MyViewport extends JViewport { @Override public void paint(Graphics g) { super.paint(g); Graphics2D g2 = (Graphics2D)g; g2.setPaint(Color.BLACK); g2.drawRect(getWidth()/4,getHeight()/4,getWidth()/2,getHeight()/2); } } 

Por lo general, “los progtwigs Swing deben anular paintComponent() lugar de anular paint() ,” como se menciona en Pintura en AWT y Swing: The Paint Methods . Basado en ScrollPanePaint , que dibuja debajo del contenido de desplazamiento, el siguiente ejemplo anula paint() para dibujar sobre el contenido de desplazamiento.

ScrollPanePaint

 import java.awt.*; import javax.swing.*; /** * @see https://stackoverflow.com/a/10097538/230513 * @see https://stackoverflow.com/a/2846497/230513 * @see https://stackoverflow.com/a/3518047/230513 */ public class ScrollPanePaint extends JFrame { private static final int TILE = 64; public ScrollPanePaint() { JViewport viewport = new MyViewport(); viewport.setView(new MyPanel()); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewport(viewport); this.add(scrollPane); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.pack(); this.setLocationRelativeTo(null); this.setVisible(true); } private static class MyViewport extends JViewport { public MyViewport() { this.setOpaque(false); this.setPreferredSize(new Dimension(6 * TILE, 6 * TILE)); } @Override public void paint(Graphics g) { super.paint(g); g.setColor(Color.blue); g.fillRect(TILE, TILE, 3 * TILE, 3 * TILE); } } private static class MyPanel extends JPanel { public MyPanel() { this.setOpaque(false); this.setPreferredSize(new Dimension(9 * TILE, 9 * TILE)); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.lightGray); int w = this.getWidth() / TILE + 1; int h = this.getHeight() / TILE + 1; for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { if ((row + col) % 2 == 0) { g.fillRect(col * TILE, row * TILE, TILE, TILE); } } } } } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ScrollPanePaint(); } }); } } 

Nota: Establecer un componente opaco (por ejemplo JTable ) como una vista para el panel de desplazamiento dará errores visuales extraños, por ejemplo, mover el cuadro azul fijo al desplazarse. Use setOpaque (falso) en el componente de vista para arreglar eso.