如何使用ImageIcon制作可拖动的组件

我正在尝试为国际象棋游戏构建用户界面。 我使用了填充JLabelGridBagLayout ,棋子是JLabel的 ImageIcons

现在我想通过在板上拖动它来移动它们。 有没有办法用ImageIcons做到这一点? 或者有更好的方法来解决问题吗?

编辑:这是一个示例代码。 你可以注意到你可以移动iconImage,但它不会用鼠标“拖动”。

import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.HashMap; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class MainDebug extends JFrame implements MouseListener { private JPanel BoardPanel; private String buffercase_mousepressed; private String buffercase_mouseentered; private JLabel A8 = new JLabel("A8"); private JLabel B8 = new JLabel("B8"); private HashMap componentMap; private ImageIcon RookIcon = createImageIcon("50px-Rook.png", "Rook"); public MainDebug(String name) { super(name); setResizable(true); } private ImageIcon createImageIcon(String path, String description) { java.net.URL imgURL = getClass().getResource(path); if (imgURL != null) { return new ImageIcon(imgURL, description); } else { System.err.println("Couldn't find file: " + path); return null; } } public void addComponentsToPane(final Container pane) { BoardPanel = new JPanel(); BoardPanel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); Dimension dim50 = new Dimension(50,50); A8.setOpaque(true); A8.setBackground(Color.white); A8.setPreferredSize(dim50); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; BoardPanel.add(A8,c); A8.setName("A8"); A8.addMouseListener(this); B8.setOpaque(true); B8.setBackground(Color.lightGray); B8.setPreferredSize(dim50); B8.setName("B8"); c.gridx=1; BoardPanel.add(B8,c); B8.addMouseListener(this); A8.setIcon(RookIcon); pane.add(BoardPanel, BorderLayout.CENTER); createComponentMap(); } private void createComponentMap() { componentMap = new HashMap(); int max_components = BoardPanel.getComponentCount(); //Component[] components = BoardPanel.getComponentCount(); //Component[] components = BoardPanel.getContentPane().getComponents(); for (int i=0; i < max_components; i++) { componentMap.put(BoardPanel.getComponent(i).getName(), BoardPanel.getComponent(i)); } } public Component getComponentByName(String name) { if (componentMap.containsKey(name)) { return (Component) componentMap.get(name); } else return null; } public void mousePressed(MouseEvent e) { buffercase_mousepressed = e.getComponent().getName(); } public void mouseReleased(MouseEvent e) { moveIcon(buffercase_mousepressed,buffercase_mouseentered); } public void mouseEntered(MouseEvent e) { buffercase_mouseentered = e.getComponent().getName(); } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void moveIcon(String A, String B){ if ((A != null) && (B != null)){ JLabel Ja = (JLabel)getComponentByName(A); JLabel Jb = (JLabel)getComponentByName(B); Icon iconeA = Ja.getIcon(); Icon iconeB = Jb.getIcon(); if (iconeA != null && iconeB == null){ Ja.setIcon(null); Jb.setIcon(iconeA); } } buffercase_mousepressed = null; buffercase_mouseentered = null; } private static void createAndShowGUI() { //Create and set up the window. MainDebug frame = new MainDebug("Test interface"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Set up the content pane. frame.addComponentsToPane(frame.getContentPane()); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } 

好的,这是我对你的小问题……

在此处输入图像描述

现在,而不是使用GridBagLayout ,我设计了自己的布局管理器,这将允许我指定一块应该放置的“网格”位置,并允许电路板和布局管理器计算该块将出现的物理位置。 就个人而言,我认为你会发现它比使用GridBagLayout更容易。

代码有两种模式。 它有一个“对齐”模式,这将导致该片段在它开始拖动时想要“捕捉”到网格和一个“自由”模式,这将允许片段在你拖动时“滑动”到整个板上…

如果您选择继续使用GridBagLayout ,则基本拖动过程不会更改。 您可以使用GridBagLayout#setConstraint来修改给定组件的约束

 public class Chess { public static void main(String[] args) { new Chess(); } public Chess() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new Board()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public static final int GRID_SIZE = 50; public static final boolean SNAP_TO_GRID = false; public class Board extends JPanel { private BufferedImage board; private Point highlightCell; public Board() { setLayout(new BoardLayoutManager()); int width = GRID_SIZE * 8; int height = GRID_SIZE * 8; board = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = board.createGraphics(); g2d.setColor(Color.WHITE); g2d.fill(new Rectangle(0, 0, width, height)); g2d.setColor(Color.BLACK); for (int row = 0; row < 8; row++) { int xPos = (row % 2 == 0) ? GRID_SIZE : 0; for (int col = 0; col < 8; col += 2) { g2d.fill(new Rectangle(xPos, row * GRID_SIZE, GRID_SIZE, GRID_SIZE)); xPos += (GRID_SIZE * 2); } } JLabel piece = new JLabel(); try { piece.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("/Luke.png")))); } catch (IOException ex) { piece.setBackground(new Color(255, 0, 0, 64)); piece.setOpaque(true); } add(piece, new Point(0, 0)); MouseHandler mouseHandler = new MouseHandler(this); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler); } protected Rectangle getBoardBounds() { return new Rectangle(getBoardOffset(), new Dimension(GRID_SIZE * 8, GRID_SIZE * 8)); } public Point gridToPoint(Point grid) { Point p = new Point(); if (grid != null) { Point offset = getBoardOffset(); px = grid.x * GRID_SIZE + offset.x; py = grid.y * GRID_SIZE + offset.y; } return p; } public Point pointToGrid(Point p) { Point grid = null; Rectangle board = getBoardBounds(); if (board.contains(p)) { px = px - board.x; py = py - board.y; grid = new Point(); grid.x = px / GRID_SIZE; grid.y = py / GRID_SIZE; } return grid; } public void setPieceGrid(Component comp, Point grid) { ((BoardLayoutManager) getLayout()).setPieceGrid(comp, grid); invalidate(); revalidate(); repaint(); } @Override public Dimension getPreferredSize() { return new Dimension(GRID_SIZE * 8, GRID_SIZE * 8); } protected Point getBoardOffset() { int width = getWidth(); int height = getHeight(); Point p = new Point(); px = (width - board.getWidth()) / 2; py = (height - board.getHeight()) / 2; return p; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Point p = getBoardOffset(); g2d.drawImage(board, px, py, this); if (highlightCell != null) { Point cell = gridToPoint(highlightCell); Rectangle bounds = new Rectangle(cell.x, cell.y, GRID_SIZE, GRID_SIZE); g2d.setColor(Color.RED); g2d.draw(bounds); } g2d.dispose(); } public void setHightlightCell(Point p) { if (highlightCell != p) { highlightCell = p; repaint(); } } } public class MouseHandler extends MouseAdapter { private Component dragComponent; private Board board; private Point dragOffset; public MouseHandler(Board board) { this.board = board; } public Board getBoard() { return board; } @Override public void mousePressed(MouseEvent e) { Component comp = getBoard().getComponentAt(e.getPoint()); if (comp != null) { dragComponent = comp; dragOffset = new Point(); dragOffset.x = e.getPoint().x - comp.getX(); dragOffset.y = e.getPoint().y - comp.getY(); } } @Override public void mouseReleased(MouseEvent e) { if (dragComponent != null) { Board board = getBoard(); Point p = board.pointToGrid(e.getPoint()); System.out.println(p); board.setPieceGrid(dragComponent, p); dragComponent = null; board.setHightlightCell(null); } } @Override public void mouseDragged(MouseEvent e) { if (dragComponent != null) { Board board = getBoard(); Point grid = board.pointToGrid(e.getPoint()); if (SNAP_TO_GRID) { Point p = board.gridToPoint(grid); dragComponent.setLocation(p); } else { Point dragPoint = new Point(); dragPoint.x = e.getPoint().x - dragOffset.x; dragPoint.y = e.getPoint().y - dragOffset.y; dragComponent.setLocation(dragPoint); } board.setHightlightCell(grid); } } } public class BoardLayoutManager implements LayoutManager2 { private Map mapGrid; public BoardLayoutManager() { mapGrid = new HashMap<>(25); } public void setPieceGrid(Component comp, Point grid) { mapGrid.put(comp, grid); } @Override public void addLayoutComponent(Component comp, Object constraints) { if (constraints instanceof Point) { mapGrid.put(comp, (Point) constraints); } else { throw new IllegalArgumentException("Unexpected constraints, expected java.awt.Point, got " + constraints); } } @Override public Dimension maximumLayoutSize(Container target) { return new Dimension(GRID_SIZE * 8, GRID_SIZE * 8); } @Override public float getLayoutAlignmentX(Container target) { return 0.5f; } @Override public float getLayoutAlignmentY(Container target) { return 0.5f; } @Override public void invalidateLayout(Container target) { } @Override public void addLayoutComponent(String name, Component comp) { } @Override public void removeLayoutComponent(Component comp) { mapGrid.remove(comp); } @Override public Dimension preferredLayoutSize(Container parent) { return new Dimension(GRID_SIZE * 8, GRID_SIZE * 8); } @Override public Dimension minimumLayoutSize(Container parent) { return new Dimension(GRID_SIZE * 8, GRID_SIZE * 8); } @Override public void layoutContainer(Container parent) { Point offset = ((Board) parent).getBoardOffset(); for (Component comp : parent.getComponents()) { Point p = mapGrid.get(comp); if (p == null) { comp.setBounds(0, 0, 0, 0); // Remove from sight :P } else { int x = px * GRID_SIZE + offset.x; int y = py * GRID_SIZE + offset.y; comp.setBounds(x, y, GRID_SIZE, GRID_SIZE); } } } } } 

几年前我写了一个框架来自定义Swing控件。

也许您可以将它作为一个开始,并根据您的用例进行调整。

教程: http : //softsmithy.sourceforge.net/lib/current/docs/tutorial/swing/customizer/index.html

的Javadoc:

http://softsmithy.sourceforge.net/lib/current/docs/api/softsmithy-lib-swing-customizer/index.html

Maven的:

  org.softsmithy.lib softsmithy-lib-swing-customizer 0.3  

您可能希望实现另一个CustomizerLayout以使用Chessboard布局替换InfiniteTableLayout ,可能还会扩展AbstractCustomizerLayout 。

您可以使用JXIconCustomizer来支持图像/图标。 您还可能希望从JXIconCustomizer的可自定义的一组中删除“width”和“height”,以防止用户更改图像的大小: http ://softsmithy.sourceforge.net/lib/current/docs /api/softsmithy-lib-swing-customizer/org/softsmithy/lib/swing/customizer/AbstractCustomizer.html#getCustomizableProperties%28%29

您可以在此处找到有关最新版本的更多信息: http : //puces-blog.blogspot.ch/2012/11/news-from-software-smithy-version-03.html

如果您认为这种方法由于某种原因不适合您,您可以查看源代码(该库是开源)以获得一些起点:

http://softsmithy.hg.sourceforge.net/hgweb/softsmithy/lib/main-golden/file/6171c01d6fd0/softsmithy-lib-swing-customizer

我想知道最简单的方法

这将是使用标准的Swing DnD支持属性(虽然远不如@ Mad的解决方案:-),基本上:

  • 将电路板构建为JLabel网格
  • 根据需要将碎片设置为标签
  • 实现一个自定义TransferHandler,它导出/导入icon属性并控制移动
  • 注册一个开始拖动的mouseListener

就像是:

 // the shared mouseListener MouseListener listener = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } }; // the shared TransferHandler // super supports copy only, so it needs to do the move itself // taking the lazy way of null the icon on the source TransferHandler handler = new TransferHandler("icon") { private JComponent source; @Override public void exportAsDrag(JComponent comp, InputEvent e, int action) { super.exportAsDrag(comp, e, action); } @Override public boolean canImport(TransferSupport support) { // empty fields only return (((JLabel) support.getComponent()).getIcon() == null) && super.canImport(support); } @Override protected void exportDone(JComponent source, Transferable data, int action) { ((JLabel) source).setIcon(null); } }; // lazy me: a one row board JComponent board = new JPanel(new GridLayout(0, 8)); Color[] colors = new Color[] {Color.WHITE, Color.BLACK}; for (int column = 0; column < 8; column++) { // filled with labels as fields board.add(createField(colors[column % 2], listener, handler)); } Icon figure = XTestUtils.loadDefaultIcon(); ((JLabel) board.getComponent(0)).setIcon(figure); // create and configure a JLabel as field private JLabel createField(Color color, MouseListener listener, TransferHandler handler) { JLabel label = new JLabel(); label.setOpaque(true); label.setBackground(color); label.addMouseListener(listener); label.setTransferHandler(handler); return label; } 
    Interesting Posts