Java:如何将控件拖放到新位置而不是其数据?

在Java中,当拖动项目是源控件本身时执行拖放的最佳方法是什么? 我知道控件只不过是数据,但差异确实会产生UI影响。

我正在创建一个单人纸牌游戏,其中我有来自JLabel的类卡牌卡片对象。 我想将该卡拖放到尚未命名的目标控件上,将其拖到另一个位置。 在拖动期间,我希望卡可以用鼠标在视觉上移动,当我想要它移动到这个目标对象或返回到它以前的位置时。

我已经完成了各种DnD测试,但没有发现任何可以在Java DD的正确规则下工作的东西。

例如,如果我使用真DnD拖动Card对象,我只能创建卡的幻影图像而不是实心图像。 此外,光标更改,我宁愿它没有(我想我可以修复它),并且源控件仍然可见(尽管在拖动过程中应该很容易使其透明)

另一方面,我可以通过监听MouseMotionListener.mouseDragged()事件并手动将卡移动到新位置来漂亮地拖动卡。 这很好用,但它没有遵循正确的DnD,因为这不会通知其他控件的拖动。 我想我可以创建自己的系统来通知其他控件,但这不会使用Java真正的DnD。 此外,如果我将真正的Java dnd内容与在mouseDragged期间逐字移动卡片的方法混合,那么我认为真正的DnD内容永远不会起作用,因为鼠标在技术上永远不会直接超过任何其他控件而不是被拖动的卡片。 这个方向看起来像粗暴的黑客。

我希望这是有道理的。 我一直在跟踪样品时出现问题,因为它们看起来非常不同,而且我花费了大量时间研究的样子看起来是在DnD在1.4版本进行重大改革之前的几年。

在单个应用程序而不是应用程序之间拖动组件的一种方法是使用JLayeredPane。 例如,请在此处查看我的代码: 在屏幕上拖动jlabel

扑克牌的一个例子可能是这样的(只要扑克牌图像仍然有效!):

import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.imageio.ImageIO; import javax.swing.*; public class PlayingCardTest { public static void main(String[] args) { String pathToDeck = "http://sofzh.miximages.com/java/classic-playing-cards.png"; try { final List cardImgList = CreateCards.createCardIconList(pathToDeck); SwingUtilities.invokeLater(new Runnable() { public void run() { JFrame frame = new JFrame("Moving Cards"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new CardGameTable(cardImgList, frame)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } catch (MalformedURLException e) { e.printStackTrace(); System.exit(-1); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } } } @SuppressWarnings("serial") class CardGameTable extends JLayeredPane { private static final int PREF_W = 600; private static final int PREF_H = 400; private static final Color BASE_COLOR = new Color(0, 80, 0); private static final int CARD_COUNT = 20; private static final int WIDTH_SHOWING = 20; private JPanel basePane = new JPanel(null); public CardGameTable(List cardImgList, final JFrame frame) { basePane.setSize(getPreferredSize()); basePane.setBackground(BASE_COLOR); add(basePane, JLayeredPane.DEFAULT_LAYER); final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane); addMouseListener(myMouseAdapter); addMouseMotionListener(myMouseAdapter); for (int i = 0; i < CARD_COUNT; i++) { JLabel card = new JLabel(cardImgList.remove(0)); card.setSize(card.getPreferredSize()); int x = (PREF_W / 2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i) / 2 - card.getPreferredSize().width / 2; int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2; card.setLocation(x, y); basePane.add(card); } } @Override public Dimension getPreferredSize() { return new Dimension(PREF_W, PREF_H); } } class MyMouseAdapter extends MouseAdapter { private JLabel selectedCard = null; private JLayeredPane cardGameTable = null; private JPanel basePane = null; private int deltaX = 0; private int deltaY = 0; public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) { this.cardGameTable = gameTable; this.basePane = basePane; } @Override public void mousePressed(MouseEvent mEvt) { Component comp = basePane.getComponentAt(mEvt.getPoint()); if (comp != null && comp instanceof JLabel) { selectedCard = (JLabel) comp; basePane.remove(selectedCard); basePane.revalidate(); basePane.repaint(); cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER); cardGameTable.revalidate(); cardGameTable.repaint(); deltaX = mEvt.getX() - selectedCard.getX(); deltaY = mEvt.getY() - selectedCard.getY(); } } @Override public void mouseReleased(MouseEvent mEvt) { if (selectedCard != null) { cardGameTable.remove(selectedCard); cardGameTable.revalidate(); cardGameTable.repaint(); basePane.add(selectedCard, 0); basePane.revalidate(); basePane.repaint(); selectedCard = null; } } @Override public void mouseDragged(MouseEvent mEvt) { if (selectedCard != null) { int x = mEvt.getX() - deltaX; int y = mEvt.getY() - deltaY; selectedCard.setLocation(x, y); cardGameTable.revalidate(); cardGameTable.repaint(); } } } class CreateCards { private static final int SUIT_COUNT = 4; private static final int RANK_COUNT = 13; public static List createCardIconList(String pathToDeck) throws MalformedURLException, IOException { BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck)); int width = fullDeckImg.getWidth(); int height = fullDeckImg.getHeight(); List iconList = new ArrayList(); for (int suit = 0; suit < SUIT_COUNT; suit++) { for (int rank = 0; rank < RANK_COUNT; rank++) { int x = (rank * width) / RANK_COUNT; int y = (suit * height) / SUIT_COUNT; int w = width / RANK_COUNT; int h = height / SUIT_COUNT; BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h); iconList.add(new ImageIcon(cardImg)); } } Collections.shuffle(iconList); return iconList; } }