Java 将组件放置在窗格玻璃上

Java 将组件放置在窗格玻璃上,java,swing,glasspane,Java,Swing,Glasspane,我有一个子类JLabel,它构成了GUI的一个组件。我已经实现了将组件从一个容器拖放到另一个容器的功能,但是没有任何视觉效果。我希望在将项目从一个容器拖动到另一个容器的过程中,此JLabel跟随光标。我想我可以创建一个玻璃窗格并在上面绘制它。但是,即使我将组件添加到玻璃窗格中,将组件设置为可见,将玻璃窗格设置为可见,并将玻璃窗格设置为不透明,我仍然无法看到该组件。我知道该组件可以工作,因为我可以将其添加到内容窗格并显示出来 如何将组件添加到玻璃窗格中 最后,我想出了如何让这个简单的例子发挥作用

我有一个子类JLabel,它构成了GUI的一个组件。我已经实现了将组件从一个容器拖放到另一个容器的功能,但是没有任何视觉效果。我希望在将项目从一个容器拖动到另一个容器的过程中,此JLabel跟随光标。我想我可以创建一个玻璃窗格并在上面绘制它。但是,即使我将组件添加到玻璃窗格中,将组件设置为可见,将玻璃窗格设置为可见,并将玻璃窗格设置为不透明,我仍然无法看到该组件。我知道该组件可以工作,因为我可以将其添加到内容窗格并显示出来

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


最后,我想出了如何让这个简单的例子发挥作用。谢谢,@akf。我能够使这个解决方案适应我最初的问题,允许我删除约60行手工呈现JLabel表示的Java2D代码

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

下面的示例代码显示了如何在棋盘上拖动棋子。它使用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,因此无需绘制任何内容

此外,玻璃窗格需要使其可见,以便进行喷漆

我建议你读这本书。有一节介绍布局管理器如何工作以及窗格玻璃如何工作,每个节都有工作示例

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

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);
     }
}
import java.awt.*;
导入java.awt.event.*;
导入java.util.*;
导入javax.swing.*;
公共类棋盘扩展JFrame实现MouseListener、MouseMotionListener
{
JLayeredPane layeredPane;
JPanel棋盘;
JLabel棋子;
内部调整;
内部调整;
公共棋盘()
{
尺寸板尺寸=新尺寸(600600);
//为此应用程序使用分层窗格
layeredPane=新的JLayeredPane();
layeredPane.setPreferredSize(boardSize);
layeredPane.addMouseListener(此);
layeredPane.addMouseMotionListener(此);
getContentPane().add(layeredPane);
//将棋盘添加到分层窗格
棋盘=新JPanel();
棋盘布局(新网格布局(8,8));
棋盘。设置首选大小(棋盘大小);
棋盘.立根(0,0,boardSize.width,boardSize.height);
layeredPane.add(棋盘,JLayeredPane.DEFAULT_层);
//建造棋盘格
对于(int i=0;i<8;i++)
{
对于(int j=0;j<8;j++)
{
JPanel square=newjpanel(newborderlayout());
方形立根背景((i+j)%2==0?颜色。红色:颜色。白色);
棋盘。加(正方形);
}
}
//在黑板上加几块
ImageIcon duke=newImageIcon(“dukewaveed.gif”);//在此处添加图像
JLabel工件=新JLabel(杜克);
JPanel面板=(JPanel)chessBoard.getComponent(0);
面板。添加(件);
工件=新JLabel(杜克);
panel=(JPanel)chessBoard.getComponent(15);
面板。添加(件);
}
/*
**将所选棋子添加到拖动层,以便可以移动它
*/
公共无效鼠标按下(MouseEvent e)
{
棋子=空;
组件c=chessBoard.findComponentAt(e.getX(),e.getY());
如果(JPanel的c实例)返回;
Point parentLocation=c.getParent().getLocation();
xAdjustment=parentLocation.x-e.getX();
yAdjustment=parentLocation.y-e.getY();
棋子=(JLabel)c;
chessPiece.setLocation(e.getX()+xaadjustment,e.getY()+yaadjustment);
layeredPane.add(棋子,JLayeredPane.DRAG_层);
layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_Cursor));
}
/*
**把棋子四处移动
*/
公共无效鼠标标记(MouseEvent me)
{
if(chessPiece==null)返回;
//拖动位置应在棋盘的范围内
intx=me.getX()+xaadjustment;
int xMax=layeredPane.getWidth()-chessPiece.getWidth();
x=数学最小值(x,xMax);
x=数学最大值(x,0);
int y=me.getY()+yaadjustment;
int yMax=layeredPane.getHeight()-chessPiece.getHeight();
y=数学最小值(y,yMax);
y=数学最大值(y,0);
棋子。设定位置(x,y);
}
/*
**把棋子放回棋盘上
*/
公共无效MouseEvent(MouseEvent e)
{
layeredPane.setCursor(空);
if(chessPiece==null)返回;
//确保棋子不再绘制在分层窗格上
棋子。设置可见(假);
分层窗格。移除(棋子);
棋子。设置可见(真);
//下棋位置应在棋盘的范围内
int xMax=layeredPane.getWidth()-chessPiece.getWidth();
intx=Math.min(e.getX(),xMax);
x=数学最大值(x,0);
int yMax=layeredPane.getHeight()-chessPiece.getHeight();
在里面
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);
}
l.setPreferredSize(l.getSize());
l.setPreferredSize(l.getSize());
l.setBounds(10, 10, 50, 20);
l.setBounds(10, 10, 50, 20);
l.setPreferredSize(l.getSize());