java - paneles - panel de vidrio liliana
Colocación del componente en el panel de vidrio (4)
Tengo una subclase de JLabel que forma parte de mi GUI. Implementé la capacidad de arrastrar y soltar el componente de un contenedor a otro, pero sin ningún efecto visual. Quiero que este JLabel siga el cursor durante el arrastre del artículo de un contenedor a otro. Pensé que podría simplemente crear un panel de vidrio y dibujarlo allí. Sin embargo, incluso después de agregar el componente al panel de vidrio, establecer el componente visible, establecer el panel de cristal como visible y configurar el panel de cristal como opaco, aún así no veo el componente. Sé que el componente funciona porque puedo agregarlo al panel de contenido y hacer que aparezca.
¿Cómo agrego un componente al panel de vidrio?
Finalmente imaginé cómo hacer funcionar el ejemplo simple. Gracias, @akf. Pude adaptar esta solución a mi problema original, lo que me permitió eliminar ~ 60 líneas de código Java2D que representaban manualmente una JLabel.
package test;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class MainFrame extends JFrame {
/**
* @param args
*/
public static void main(String[] args) {
MainFrame mf = new MainFrame();
mf.setSize(400, 400);
mf.setLocationRelativeTo(null);
mf.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
mf.setGlassPane(new JPanel());
JLabel l = new JLabel();
l.setText("Hello");
l.setBorder(new LineBorder(Color.BLACK, 1));
l.setBounds(10, 10, 50, 20);
l.setBackground(Color.RED);
l.setOpaque(true);
l.setPreferredSize(l.getSize());
//mf.add(l);
((JPanel)mf.getGlassPane()).add(l);
mf.getGlassPane().setVisible(true);
mf.setVisible(true);
}
}
Además de los punteros a los ejemplos de LayerPane ya provistos, el problema con su código original se centra en la configuración del tamaño preferido de su etiqueta. Lo configuraste antes de que se haya dimensionado el JLabel, entonces tu:
l.setPreferredSize(l.getSize());
es ineficaz Si, por otro lado, realiza esa llamada después de realizar su llamada a setBounds
, verá los resultados deseados. Con eso en mente, reordenar esto:
l.setPreferredSize(l.getSize());
l.setBounds(10, 10, 50, 20);
para que se vea así:
l.setBounds(10, 10, 50, 20);
l.setPreferredSize(l.getSize());
Aunque es tangencial a la pregunta, el ejemplo de JLayeredPane
citado por @camickr admite la siguiente adaptación, que destaca el efecto de mouseReleased()
sobre un componente existente.
public ChessBoard() {
...
// Add a few pieces to the board
addPiece(3, 0, "♛");
addPiece(4, 0, "♚");
addPiece(3, 7, "♕");
addPiece(4, 7, "♔");
}
static Font font = new Font("Sans", Font.PLAIN, 72);
private void addPiece(int col, int row, String glyph) {
JLabel piece = new JLabel(glyph, JLabel.CENTER);
piece.setFont(font);
JPanel panel = (JPanel) chessBoard.getComponent(col + row * 8);
panel.add(piece);
}
Desde que he estado siguiendo blogs de Romain Guy en Swing durante mucho tiempo. Tengo un enlace que podría interesarte. Lanzó la fuente, que usaba un GlassPane para efectos DnD.
http://jroller.com/gfx/entry/drag_and_drop_effects_the
Yo mismo nunca utilicé una animación / efecto burbujeante en DnD, por lo que no puedo seguir comentando: - |
El siguiente código de ejemplo muestra cómo arrastrar una pieza de ajedrez alrededor de un tablero de ajedrez. Utiliza JLayeredPane en lugar de un panel de vidrio, pero estoy seguro de que los conceptos serían los mismos. Es decir:
a) agregue el panel de vidrio al panel raíz
b) hacer que el panel de vidrio sea visible
c) agregue el componente al cristal, asegurándose de que los límites sean válidos
d) use setLocation () para animar el arrastre del componente
Editar: código agregado para reparar SSCCE
JLabel l = new JLabel();
l.setText("Hello");
l.setBorder(new LineBorder(Color.BLACK, 1));
// l.setPreferredSize(l.getSize());
// l.setBounds(10, 10, 50, 20);
((JPanel)mf.getGlassPane()).add(l);
mf.setVisible(true);
mf.getGlassPane().setVisible(true);
Cuando se usan administradores de diseño nunca se usan los métodos setSize () o setBounds (). En su caso, simplemente establece el tamaño preferido en (0, 0) ya que este es el tamaño predeterminado de todos los componentes.
Funciona cuando agrega la etiqueta al marco porque el administrador de diseño predeterminado para el panel de contenido del marco es un diseño de borde, por lo tanto, se ignora el tamaño preferido de la etiqueta y la etiqueta se hace del tamaño del marco.
Sin embargo, de forma predeterminada, un JPanel usa un FlowLayout que respeta el tamaño preferido del componente. Como el tamaño preferido es 0, no hay nada que pintar.
Además, el panel de vidrio debe hacerse visible para poder pintarlo.
Te sugiero que leas el tutorial de Swing . Hay una sección sobre cómo funcionan los administradores del diseño y sobre cómo funcionan los paneles de vidrio y cada sección tiene ejemplos de trabajo.
Editar: código de ejemplo agregado a continuación:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener
{
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
public ChessBoard()
{
Dimension boardSize = new Dimension(600, 600);
// Use a Layered Pane for this this application
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize( boardSize );
layeredPane.addMouseListener( this );
layeredPane.addMouseMotionListener( this );
getContentPane().add(layeredPane);
// Add a chess board to the Layered Pane
chessBoard = new JPanel();
chessBoard.setLayout( new GridLayout(8, 8) );
chessBoard.setPreferredSize( boardSize );
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
// Build the Chess Board squares
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
JPanel square = new JPanel( new BorderLayout() );
square.setBackground( (i + j) % 2 == 0 ? Color.red : Color.white );
chessBoard.add( square );
}
}
// Add a few pieces to the board
ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here
JLabel piece = new JLabel( duke );
JPanel panel = (JPanel)chessBoard.getComponent( 0 );
panel.add( piece );
piece = new JLabel( duke );
panel = (JPanel)chessBoard.getComponent( 15 );
panel.add( piece );
}
/*
** Add the selected chess piece to the dragging layer so it can be moved
*/
public void mousePressed(MouseEvent e)
{
chessPiece = null;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JPanel) return;
Point parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
chessPiece = (JLabel)c;
chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
/*
** Move the chess piece around
*/
public void mouseDragged(MouseEvent me)
{
if (chessPiece == null) return;
// The drag location should be within the bounds of the chess board
int x = me.getX() + xAdjustment;
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
x = Math.min(x, xMax);
x = Math.max(x, 0);
int y = me.getY() + yAdjustment;
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
y = Math.min(y, yMax);
y = Math.max(y, 0);
chessPiece.setLocation(x, y);
}
/*
** Drop the chess piece back onto the chess board
*/
public void mouseReleased(MouseEvent e)
{
layeredPane.setCursor(null);
if (chessPiece == null) return;
// Make sure the chess piece is no longer painted on the layered pane
chessPiece.setVisible(false);
layeredPane.remove(chessPiece);
chessPiece.setVisible(true);
// The drop location should be within the bounds of the chess board
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
int x = Math.min(e.getX(), xMax);
x = Math.max(x, 0);
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
int y = Math.min(e.getY(), yMax);
y = Math.max(y, 0);
Component c = chessBoard.findComponentAt(x, y);
if (c instanceof JLabel)
{
Container parent = c.getParent();
parent.remove(0);
parent.add( chessPiece );
parent.validate();
}
else
{
Container parent = (Container)c;
parent.add( chessPiece );
parent.validate();
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public static void main(String[] args)
{
JFrame frame = new ChessBoard();
frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
frame.setResizable( false );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}