Java:如何将控件拖放到新位置而不是其数据? [英] Java: How do I drag and drop a control to a new location instead of its data?

查看:157
本文介绍了Java:如何将控件拖放到新位置而不是其数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java中,当拖动项目是源控件本身时,执行拖放操作的最佳方法是什么?我知道一个控制只不过是数据,但区别确实有UI影响。

In Java, what is the best way to perform drag and drop when the item being dragged is the source control itself? I know a control is nothing but data too, but the difference does have UI impacts.

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

I'm creating a solitaire-style game where I have card objects of class Card derived from JLabel. I want to drag that card to another location by dropping it onto a yet-to-be named Destination control. During the drag, I want the card to visually move with the mouse and when dropped I want it to either move to this destination object or return to its previous location.

I已经完成了各种DnD测试,并没有发现任何根据Java DD的正确规则工作的东西。

I've done various D-n-D tests and haven't found anything that works under the proper rules of Java's D-D.

例如,如果我使用true D-n-D拖动Card对象,则只能创建卡的重影图像,而不是实体图像。另外,光标改变了,我宁愿没有(我想我可以解决这个问题),源代码控件仍然是可见的(虽然拖动时应该很容易让它变得透明)

For example, if I drag the Card object using true D-n-D I can only create a ghosted image of the card and not a solid image. Also, the cursor changes and I'd rather it did not (I think I can fix that), and the source control remains visible (though it should be easy to make it transparent during the drag)

另一方面,我可以通过监听MouseMotionListener.mouseDragged()事件并手动将卡移动到新位置来美丽地拖动卡。这样做很好,但是没有正确的D-n-D,因为这不会通知其他控件的拖动。我想我可以创建自己的系统来通知其他控件,但这不会使用Java的真正的D-n-D。此外,如果我将真正的Java d-n-d的东西与这种在mouseDragged中移动卡的方法进行混合,那么我假设真正的D-n-D东西将永远不会工作,因为鼠标在技术上不会直接超过任何其他控件,而不是被拖动的卡。这个方向似乎是一个粗暴的黑客。

On the other hand, I can drag the Card beautifully by listening for MouseMotionListener.mouseDragged() events and manually moving the Card to the new location. This works great, but it is not following proper D-n-D because this will not inform other controls of the drag. I figured I could either create my own system to notify the other controls, but that would not be using Java's real D-n-D. Also, if I mix the real Java d-n-d stuff with this method of literally moving the Card during mouseDragged then I assume the real D-n-D stuff will never work because the mouse will never technically be directly over any other control than the card being dragged. This direction just seems like a crude hack.

我希望这是有道理的。我在样品中遇到问题,因为它们都看起来很不一样,而且我花了大量的时间学习看起来要在DnD在1.4版本进行大修之前几年。

I hope this makes sense. I've been having problems following samples because they all seem very different, and one that I spent a great deal of time studying looks to be dated a couple years before D-n-D had its major overhaul in version 1.4.

推荐答案

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

One way to drag a component around a single application and not between applications is to use a JLayeredPane. For example please see my code here: dragging a jlabel around the screen

玩扑克牌的一个例子可能是这样(只要扑克牌形象保持有效!):

An example with playing cards could look like this (as long as the playing card image remains valid!):

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://www.jfitz.com/cards/classic-playing-cards.png";
      try {
         final List<ImageIcon> 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<ImageIcon> 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<ImageIcon> createCardIconList(String pathToDeck)
         throws MalformedURLException, IOException {
      BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck));
      int width = fullDeckImg.getWidth();
      int height = fullDeckImg.getHeight();
      List<ImageIcon> iconList = new ArrayList<ImageIcon>();

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

这篇关于Java:如何将控件拖放到新位置而不是其数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆