将组件放在Glass Pane上

我有一个JLabel的子类,它构成了我GUI的一个组件。 我已经实现了将组件从一个容器拖放到另一个容器的能力,但没有任何视觉效果。 我想让这个JLabel在项目从一个容器拖动到另一个容器时跟随光标。 我想我可以创建一个玻璃窗格并在那里绘制它。 但是,即使我将组件添加到玻璃窗格,将组件设置为可见,并将玻璃窗格设置为可见,并将玻璃窗格设置为不透明,我仍然看不到该组件。 我知道该组件有效,因为我可以将其添加到内容窗格并显示它。

如何将组件添加到玻璃窗格?


最后想出了如何让简单的例子工作。 谢谢,@ kff。 我能够使这个解决方案适应我原来的问题,允许我删除约60行Java2D代码,这些代码手动呈现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); } } 

除了已经提供的LayerPane示例的指针之外,原始代码的问题还在于设置标签的首选大小。 你在JLabel大小之前设置它,所以你的:

 l.setPreferredSize(l.getSize()); 

是无效的。 另一方面,如果您在拨打setBounds后拨打该电话,您将看到所需的结果。 考虑到这一点,请重新排序:

 l.setPreferredSize(l.getSize()); l.setBounds(10, 10, 50, 20); 

看起来像这样:

 l.setBounds(10, 10, 50, 20); l.setPreferredSize(l.getSize()); 

下面的示例代码显示了如何在棋盘上拖动棋子。 它使用JLayeredPane而不是玻璃窗格,但我确信概念是相同的。 那是:

a)将玻璃窗格添加到根窗格
b)使玻璃板可见
c)将组件添加到玻璃窗格,确保边界有效
d)使用setLocation()为组件的拖动设置动画

编辑:添加代码以修复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); 

使用布局管理器时,您永远不会使用setSize()或setBounds()方法。 在您的情况下,您只需将首选大小设置为(0,0),因为这是所有组件的默认大小。

将标签添加到框架时,它会起作用,因为框架内容窗格的默认布局管理器是边框布局,因此将忽略标签的首选大小,并使标签成为框架的大小。

但是,默认情况下,JPanel使用的FlowLayout确实尊重组件的首选大小。 由于首选大小为0,因此无需绘制任何内容。

此外,玻璃板需要可见,以便进行涂漆。

我建议你阅读Swing教程 。 有关布局管理器如何工作以及玻璃窗格如何工作以及每个部分都有工作示例的部分。

编辑:下面添加的示例代码:

 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); } } 

虽然与问题相关,但@camickr引用的JLayeredPane 示例承认了以下适应,它强调了mouseReleased()对现有组件的影响。

 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); } 

自从我在Swing上关注Romain Guy的博客很长一段时间以来。 我有一个你可能感兴趣的链接。他发布了源代码 – 它使用了GlassPane用于DnD效果。

http://jroller.com/gfx/entry/drag_and_drop_effects_the

我自己从来没有对DnD使用过汽水动画/效果,所以不能再评论: – |