【问题标题】:How to create an exact JPanel mirror on top of another JPanel如何在另一个 JPanel 之上创建精确的 JPanel 镜像
【发布时间】:2017-01-07 21:04:39
【问题描述】:

我正在尝试使用 Swing 创建一个跳棋游戏,并且我已经设置了棋盘(here)

每个单独的图块都放置在通过 GridBagLayout 管理器组织的 JPanel 中的 GUI 上。为了将各个棋盘格放在棋子上,我想创建另一个 JPanel,它是包含棋盘棋子的 JPanel 的精确副本。 copy-JPanel 将保存棋子并且是透明的,允许棋子位于游戏板的顶部。

我将如何创建第二个 JPanel?如果不可能,在棋盘上创建棋盘的更好选择是什么。

【问题讨论】:

  • I want to create another JPanel that is an exact copy of the JPanel that holds the board tiles. - 不知道你为什么要这样做。查看stackoverflow.com/questions/2561690/… 了解不同的方法。
  • “什么是更好的选择” GridLayoutJBuitton 组件。这是基于棋盘的an example

标签: java swing user-interface jpanel gridbaglayout


【解决方案1】:

您的设计可以得到改进和简化。更简单的是简单地创建一个 JPanel 单元格,保存在 GridLayout 中,然后将 JLabel 片段添加到需要容纳片段的任何单个单元格中。无需镜像或复制任何东西。然后,如果您想让用户能够单击和拖动片段,请在鼠标侦听器代码中将片段提升到玻璃窗格中,或者使用您自己的 JLayeredPane 并移动它。

例如,尝试运行此程序以准确了解我的意思。它只有一块,逻辑很简单——只允许将一块放在一个黑色的方块上,但它确实展示了这些概念:

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;

@SuppressWarnings("serial")
public class ChessEg extends JPanel {
    private static final int IMG_W = 60;
    private static final int CELL_WIDTH = 80;
    private static final Color PIECE_COLOR = Color.RED.darker();
    private ChessBoardPanel chessBoardPanel = new ChessBoardPanel(CELL_WIDTH);
    private JLabel pieceLabel = new JLabel();

    public ChessEg() {
        ChessBrdPanelListener pieceListener = new ChessBrdPanelListener();
        chessBoardPanel.addMouseListener(pieceListener);
        chessBoardPanel.addMouseMotionListener(pieceListener);
        pieceLabel.setIcon(createPieceIcon());
        setLayout(new BorderLayout());
        add(chessBoardPanel, BorderLayout.CENTER);
        chessBoardPanel.getCellAt(1, 0).add(pieceLabel);
    }

    private Icon createPieceIcon() {
        BufferedImage img = new BufferedImage(IMG_W, IMG_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(PIECE_COLOR);
        g2.fillOval(2, 2, IMG_W - 4, IMG_W - 4);
        g2.setStroke(new BasicStroke(2f));
        g2.setColor(Color.DARK_GRAY);
        g2.drawOval(2, 2, IMG_W - 4, IMG_W - 4);
        g2.dispose();
        return new ImageIcon(img);
    }

    public boolean isNewChessCellValid(ChessCell newChessCell) {
        // right now, just checks if placing on a dark square
        // TODO: improve logic
        return ChessBoardPanel.DARK_COLOR.equals(newChessCell.getBackground());
    }

    private class ChessBrdPanelListener extends MouseAdapter {
        private JLabel label;
        private ChessCell originalChessCell;
        private JPanel glassPane;
        private Point gpP;
        private ChessCell newChessCell;

        @Override
        public void mousePressed(MouseEvent e) {
            if (e.getButton() != MouseEvent.BUTTON1) {
                return;
            }
            JPanel src = (JPanel) e.getSource();
            Component comp = src.getComponentAt(e.getPoint());
            if (comp != null && ((JComponent) comp).getComponentCount() == 1) {
                originalChessCell = (ChessCell) comp;
                label = (JLabel) originalChessCell.getComponent(0);
            } else {
                return;
            }
            originalChessCell.remove(label);
            originalChessCell.revalidate();
            originalChessCell.repaint();
            glassPane = (JPanel) SwingUtilities.getRootPane(originalChessCell).getGlassPane();
            glassPane.setVisible(true);
            gpP = glassPane.getLocationOnScreen();
            glassPane.setLayout(null);
            int x = e.getXOnScreen() - gpP.x - label.getWidth() / 2;
            int y = e.getYOnScreen() - gpP.y - label.getHeight() / 2;
            label.setLocation(x, y);
            label.setSize(label.getPreferredSize());
            glassPane.add(label);
            glassPane.repaint();
            e.consume();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (label == null) {
                return;
            }
            int x = e.getXOnScreen() - gpP.x - label.getWidth() / 2;
            int y = e.getYOnScreen() - gpP.y - label.getHeight() / 2;
            label.setLocation(x, y);
            repaint();
            JPanel src = (JPanel) e.getSource();
            Component comp = src.getComponentAt(e.getPoint());
            if (comp != null) {
                newChessCell = (ChessCell) comp;
                if (isNewChessCellValid(newChessCell)) {
                    newChessCell.add(label);
                } else {
                    originalChessCell.add(label);
                }
            } else {
                originalChessCell.add(label);
            }


            label = null;
            glassPane.setVisible(false);
            revalidate();
            repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (label == null) {
                return;
            }
            int x = e.getXOnScreen() - gpP.x - label.getWidth() / 2;
            int y = e.getYOnScreen() - gpP.y - label.getHeight() / 2;
            label.setLocation(x, y);
            repaint();
        }
    }

    private static void createAndShowGui() {
        ChessEg mainPanel = new ChessEg();
        JFrame frame = new JFrame("Chess Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class ChessBoardPanel extends JPanel {
    public static final Color DARK_COLOR = new Color(180, 85, 0);
    public static final Color LIGHT_COLOR = new Color(220, 190, 160);
    private int cellWidth;
    private ChessCell[][] panelGrid = new ChessCell[8][8];

    public ChessBoardPanel(int cellWidth) {
        this.cellWidth = cellWidth;
        setLayout(new GridLayout(8, 8));
        for (int i = 0; i < panelGrid.length; i++) {
            for (int j = 0; j < panelGrid[i].length; j++) {
                char rank = (char) ('8' - i);
                char file = (char) ('a' + j);
                panelGrid[i][j] = new ChessCell(rank, file);
                panelGrid[i][j].setPreferredSize(new Dimension(cellWidth, cellWidth));
                Color bg = i % 2 == j % 2 ? LIGHT_COLOR : DARK_COLOR;
                panelGrid[i][j].setBackground(bg);
                add(panelGrid[i][j]);
            }
        }
    }

    public JPanel getCellAt(int i, int j) {
        return panelGrid[i][j];
    }

    public int getCellWidth() {
        return cellWidth;
    }
}

@SuppressWarnings("serial")
class ChessCell extends JPanel {
    private char rank;
    private char file;

    public ChessCell(char rank, char file) {
        super(new GridBagLayout());
        this.rank = rank;
        this.file = file;
    }

    public char getRank() {
        return rank;
    }

    public char getFile() {
        return file;
    }

    @Override
    public String toString() {
        return "ChessCell [rank=" + rank + ", file=" + file + "]";
    }
}

【讨论】:

  • 单个游戏图块是通过 JLabel ImageIcon 创建的。我如何将游戏块 JLabel 重叠到图块 JLabel 上?
  • @GandalfDaGrey:将 tile 设为 JPanel,而不是 JLabel,并在其 paintComponent 方法中显示其图像。或者给你的 JLabel 一个像样的布局管理器,比如 GridBagLayout。使用此布局,添加到 JLabel 的任何单个组件都会自动居中。否则,您正在谈论将 JLayeredPane 与笨拙的数学结合使用。
  • @GandalfDaGrey:我的意思见上面的例子。
  • 谢谢!将 JLabels 设置为使用 GridBagLayout 管理器,然后简单地将棋盘格标签添加到平铺标签上效果很好。
猜你喜欢
  • 2017-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多