英文:
Using Drag and Drop in Solitaire Game for Java
问题
我正在使用Java创建一个纸牌游戏。我已经编写了纸牌、牌组和大多数GUI的代码。但是,当我尝试将拖放功能添加到GUI中时,我可以将纸牌拖动到不同的表格堆栈,但是当我放下它时,它只是粘贴在先前存在的纸牌上,而不是将其堆叠在上面。而且,该纸牌没有从其旧位置移除。你将如何解决这个问题?
我已经尝试使用`exportAsDrag(jc,e,TransferHandler.MOVE);`并添加了代码来使其运行,但似乎也不起作用。
以下是三个类(Solitaire类是GUI类):
```java
//导入语句
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Solitaire extends JFrame {
//实例变量
private static final int CARD_WIDTH = 73;
private static final int CARD_HEIGHT = (int)(CARD_WIDTH*1.49137931+.5);
private static final int TOP_STACKS_X_DIFF = 435;
private static final int TOP_STACKS_Y_DIFF = 30;
private static final int WASTE_STACK_X_DIFF = 139;
private static final int WASTE_STACK_Y_DIFF = 30;
private static final int MAIN_STACKS_X_DIFF = 30;
private static final int MAIN_STACKS_Y_DIFF = 40;
private final JLabel newStack;
private final JLabel wasteStack;
private final JLabel[] topStacks;
private final JLayeredPane[] mainStacks;
private Card wasteCard;
private Deck deckOfCards;
//方法
/**
* 创建一个新的游戏屏幕GUI
*/
public Solitaire() {
//设置JFrame
setTitle("Solitaire");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setBackground(new Color(0,153,0));
//创建topStacks
topStacks = new JLabel[4]; //初始化topStacks
for (int index = 0; index < topStacks.length; index++) { //循环创建每个花色的堆栈
topStacks[index] = new JLabel(); //创建新堆栈
topStacks[index].setBounds((index*CARD_WIDTH) + (index*10) + TOP_STACKS_X_DIFF, TOP_STACKS_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //为每个顶部堆栈创建边界
topStacks[index].setBorder(BorderFactory.createLineBorder(Color.BLACK)); //为每个顶部堆栈设置边框
add(topStacks[index]); //添加到GUI
} //结束for循环
//创建wasteStack
wasteStack = new JLabel(); //初始化wasteStack
wasteStack.setBounds(WASTE_STACK_X_DIFF, WASTE_STACK_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //为waste堆栈创建边界
wasteStack.setBorder(BorderFactory.createLineBorder(Color.BLACK)); //设置waste堆栈边界的边框
add(wasteStack); //添加到GUI
//创建newStack
newStack = new JLabel(); //初始化newStack
newStack.setBounds(WASTE_STACK_X_DIFF - CARD_WIDTH - 36, WASTE_STACK_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //为新堆栈创建边界
newStack.setBorder(BorderFactory.createLineBorder(Color.BLACK)); //设置新堆栈边界的边框
newStack.addMouseListener(new newStackOnClick()); //添加事件
add(newStack); //添加到GUI
//创建mainStacks
mainStacks = new JLayeredPane[7]; //初始化mainStacks
for (int index = 0; index < mainStacks.length; index++) { //循环创建7个堆栈
mainStacks[index] = new JLayeredPane(); //创建新堆栈
mainStacks[index].setBounds((index*CARD_WIDTH) + (index*36) + MAIN_STACKS_X_DIFF, MAIN_STACKS_Y_DIFF + (CARD_HEIGHT + 10), CARD_WIDTH, CARD_HEIGHT); //为每个主堆栈创建边界
mainStacks[index].setBorder(BorderFactory.createLineBorder(Color.BLACK)); //为每个主堆栈设置边框
add(mainStacks[index]); //添加到GUI
} //结束for循环
setLayout(null); //将布局更改为null
setSize(800, 600); //定义窗口大小
setVisible(true); //显示窗口
startGame(); //开始游戏
} //结束构造方法
/**
* 创建游戏。
*/
private void startGame() {
//创建并洗牌一副新牌
deckOfCards = new Deck();
deckOfCards.shuffleDeck();
MouseListener ml = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
JComponent jc = (JComponent)e.getSource();
TransferHandler th = jc.getTransferHandler();
th.exportAsDrag(jc, e, TransferHandler.COPY);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
};
for (int stack = 0; stack < mainStacks.length; stack++) { //循环遍历mainStacks中的堆栈
int stackHeight = 0; //存储堆栈高度
for (int cardInStack = 0; cardInStack <= stack; cardInStack++) { //循环添加每个堆栈中的纸牌
Card placementCard = deckOfCards.drawCard(); //抽取纸牌
placementCard.setIsFaceUp(false);
//检查卡片是否是堆栈中的最后一张卡片
if (stack == cardInStack) {
placementCard.setIsFaceUp(true); //卡片正面朝上
//调整图像大小并将其设置为placementCard
ImageIcon placementCardFace = new ImageIcon(placementCard.getImagePath());
Image placementCardScaled = placementCardFace.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
JLabel cardLabel = new JLabel(new ImageIcon(placementCardScaled));
cardLabel.setBounds(0,card
<details>
<summary>英文:</summary>
so I'm creating a Solitaire game in Java. I have the card, deck, and most of the GUI coded out. However, when I go to implement drag and drop into the GUI, I am able to drag the cards to a different tableau stack, but when I drop it, it just pastes the card on the card that was previously there instead of stacking it on it. Plus, the card is not removed from its old location. How would you resolve this?
I have tried using exportAsDrag(jc,e,TransferHandler.MOVE); and added code to make it run, but that didn't seem to work either.
here are the three classes (Solitaire class is the GUI one):
//imports
import javax.swing.;
import java.awt.;
import java.awt.event.*;
public class Solitaire extends JFrame {
//instance variables
private static final int CARD_WIDTH = 73;
private static final int CARD_HEIGHT = (int)(CARD_WIDTH*1.49137931+.5);
private static final int TOP_STACKS_X_DIFF = 435;
private static final int TOP_STACKS_Y_DIFF = 30;
private static final int WASTE_STACK_X_DIFF = 139;
private static final int WASTE_STACK_Y_DIFF = 30;
private static final int MAIN_STACKS_X_DIFF = 30;
private static final int MAIN_STACKS_Y_DIFF = 40;
private final JLabel newStack;
private final JLabel wasteStack;
private final JLabel[] topStacks;
private final JLayeredPane[] mainStacks;
private Card wasteCard;
private Deck deckOfCards;
//methods
/**
* Creates new form gameScreenGUI
*/
public Solitaire() {
//setting up JFrame
setTitle("Solitaire");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setBackground(new Color(0,153,0));
//Create the topStacks
topStacks = new JLabel[4]; //initializing topStacks
for (int index = 0; index < topStacks.length; index++) { //loop through to create stack for each suit
topStacks[index] = new JLabel(); //creating new stack
topStacks[index].setBounds((index*CARD_WIDTH) + (index*10) + TOP_STACKS_X_DIFF, TOP_STACKS_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //creating the boundary for each top stack
topStacks[index].setBorder(BorderFactory.createLineBorder(Color.BLACK)); //setting the border for each top stack
add(topStacks[index]); //adding to GUI
} //end of for loop
//Create the wasteStack
wasteStack = new JLabel(); //initializing wasteStack
wasteStack.setBounds(WASTE_STACK_X_DIFF, WASTE_STACK_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //creating the boundary for the waste stack
wasteStack.setBorder(BorderFactory.createLineBorder(Color.BLACK)); //setting the border for the boundary of the waste stack
add(wasteStack); //adding to GUI
//Create the newStack
newStack = new JLabel(); //initializing newStack
newStack.setBounds(WASTE_STACK_X_DIFF - CARD_WIDTH - 36, WASTE_STACK_Y_DIFF, CARD_WIDTH, CARD_HEIGHT); //creating the boundary for the new stack
newStack.setBorder(BorderFactory.createLineBorder(Color.BLACK)); //setting the border for the boundary of the new stack
newStack.addMouseListener(new newStackOnClick()); //adding event
add(newStack); //adding to GUI
//Create the mainStacks
mainStacks = new JLayeredPane[7]; //initializing mainStacks
for (int index = 0; index < mainStacks.length; index++) { //loop through to create 7 stacks
mainStacks[index] = new JLayeredPane(); //creating new stack
mainStacks[index].setBounds((index*CARD_WIDTH) + (index*36) + MAIN_STACKS_X_DIFF, MAIN_STACKS_Y_DIFF + (CARD_HEIGHT + 10), CARD_WIDTH, CARD_HEIGHT); //creating the boundary for each main stack
mainStacks[index].setBorder(BorderFactory.createLineBorder(Color.BLACK)); //setting the border for each main stack
add(mainStacks[index]); //add to GUI
} //end of for loop
setLayout(null); //changing to null layout
setSize(800, 600); //defining size of window
setVisible(true); //displaying window
startGame(); //starts the game
} //end of constructor method
/**
* This method creates the game.
*/
private void startGame() {
//creates and shuffles a new deck
deckOfCards = new Deck();
deckOfCards.shuffleDeck();
MouseListener ml = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
JComponent jc = (JComponent)e.getSource();
TransferHandler th = jc.getTransferHandler();
th.exportAsDrag(jc, e, TransferHandler.COPY);
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
};
for (int stack = 0; stack < mainStacks.length; stack++) { //loop through the stacks in the mainStacks
int stackHeight = 0; //stores the height of the stack
for (int cardInStack = 0; cardInStack <= stack; cardInStack++) { //loop through to add the cards in each Stack
Card placementCard = deckOfCards.drawCard(); //draws card
placementCard.setIsFaceUp(false);
//checking if the card is the last card in the stack
if (stack == cardInStack) {
placementCard.setIsFaceUp(true); //card is facing up
//sizes the image and sets it to placementCard
ImageIcon placementCardFace = new ImageIcon(placementCard.getImagePath());
Image placementCardScaled = placementCardFace.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
JLabel cardLabel = new JLabel(new ImageIcon(placementCardScaled));
cardLabel.setBounds(0,cardInStack*22, CARD_WIDTH, CARD_HEIGHT);
cardLabel.addMouseListener(ml);
cardLabel.setTransferHandler(new TransferHandler("icon"));
mainStacks[stack].add(cardLabel, Integer.valueOf(cardInStack));
} //end of if statement
//if statement to check whether the card should be revealed or not
if (!placementCard.getIsFaceUp()) { //hide cardFront
//sizes the image and sets it to placementCard
ImageIcon placementCardBack = new ImageIcon(Card.getBackImagePath());
Image placementCardScaled = placementCardBack.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
JLabel cardLabel = new JLabel(new ImageIcon(placementCardScaled));
cardLabel.setBounds(0,cardInStack*22, CARD_WIDTH, CARD_HEIGHT);
mainStacks[stack].add(cardLabel, Integer.valueOf(cardInStack));
} //end of if statement
stackHeight = CARD_HEIGHT + (22*stack); //increments the stack height with each new card
} //end of for loop
mainStacks[stack].setSize(CARD_WIDTH, stackHeight); //sets the size of the stack so that all cards show
} //end of for loop
//sizes the image and sets it to newCard
ImageIcon cardBack = new ImageIcon(Card.getBackImagePath());
Image cardBackScaled = cardBack.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
newStack.setIcon(new ImageIcon(cardBackScaled));
wasteCard = deckOfCards.drawCard(); //new card from pile to possibly add to mainStacks
wasteCard.setIsFaceUp(true); //sets card facing up
//sizes the image and sets it to wasteCard
ImageIcon wasteCardFace = new ImageIcon(wasteCard.getImagePath());
Image wasteCardFaceScaled = wasteCardFace.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
wasteStack.addMouseListener(ml);
wasteStack.setTransferHandler(new TransferHandler("icon"));
wasteStack.setIcon(new ImageIcon(wasteCardFaceScaled));
} //end of startGame method
private void newStackClick() {
if(!deckOfCards.isEmpty()) {
wasteCard = deckOfCards.drawCard();
System.out.println(wasteCard);
wasteCard.setIsFaceUp(true);
ImageIcon wasteCardFace = new ImageIcon(wasteCard.getImagePath());
Image wasteCardScaled = wasteCardFace.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
wasteStack.setIcon(new ImageIcon(wasteCardScaled));
} else {
resetNewStack();
} //end of if statement
} //end of newStackClick method
private void resetNewStack() {
deckOfCards.resetDrawCardIndex();
deckOfCards.shuffleDeck();
wasteCard = deckOfCards.drawCard();
wasteCard.setIsFaceUp(true);
ImageIcon wasteCardFace = new ImageIcon(wasteCard.getImagePath());
Image wasteCardScaled = wasteCardFace.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
wasteStack.setIcon(new ImageIcon(wasteCardScaled));
ImageIcon cardBack = new ImageIcon(Card.getBackImagePath());
Image cardBackScaled = cardBack.getImage().getScaledInstance(CARD_WIDTH, CARD_HEIGHT, Image.SCALE_SMOOTH);
newStack.setIcon(new ImageIcon(cardBackScaled));
} //end of resetNewStack method
private class newStackOnClick extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
newStackClick();
} //end of mouseClicked method
} //end of newStackOnClick class
public static void main(String[] args) {
new Solitaire();
} //end of main method
} //end of SolitaireJLP class
public class Card {
//instance variables
private final Suit SUIT;
private final Rank RANK;
private boolean isFaceUp;
//methods
/**
* This is the constructor method for the Card class.
* @param suit - the suit to be assigned to the card.
* @param rank - the rank to be assigned to the card.
*/
public Card(Suit suit, Rank rank) {
this.SUIT = suit;
this.RANK = rank;
this.isFaceUp = false;
} //end of constructor
/**
* This method gives the user the suit of the Card.
* @return Suit - the suit of the Card.
*/
public Suit getSuit() {
return this.SUIT;
} //end of getSuit method
/**
* This method gives the user the rank of the Card.
* @return Rank - the rank of the Card.
*/
public Rank getRank() {
return this.RANK;
} //end of getRank method
/**
* This method gives whether the Card is faced up or not.
* @return Boolean - true or false based on if the Card is facing up.
*/
public boolean getIsFaceUp() {
return this.isFaceUp;
} //end of getIsFaceUp method
/**
* This method sets the isFaceUp variable to true if the card is facing up in the game.
*/
public void setIsFaceUp(boolean b) {
this.isFaceUp = b;
} //end of setIsFaceUp method
/**
* This method determines if the Card is from a red suit.
* @return Boolean - true or false if card is red
*/
public boolean isRed() {
return this.SUIT == Suit.HEARTS || this.SUIT == Suit.DIAMONDS;
} //end of isRed method
/**
* This method determines if the Card is from a black suit.
* @return a Boolean true or false if card is black
*/
public boolean isBlack() {
return this.SUIT == Suit.CLUBS || this.SUIT == Suit.SPADES;
} //end of isBlack method
/**
* This method determines if the card can be stacked on the card behind it.
* @return a Boolean true or false if it can be stacked
*/
public boolean stackable(Card card) {
return this.isRed() != card.isRed();
} //end of stackable method
/**
* This method gives the name of each card.
* @return a string that has two letters- the first letter of the rank and the first letter of the suit.
*/
public String getName() {
String number = ""; //variable declaration
switch(RANK) { //switch to assign rank name
case ACE -> number = "A"; //case
case TWO -> number = "2"; //case
case THREE -> number = "3"; //case
case FOUR -> number = "4"; //case
case FIVE -> number = "5"; //case
case SIX -> number = "6"; //case
case SEVEN -> number = "7"; //case
case EIGHT -> number = "8"; //case
case NINE -> number = "9"; //case
case TEN -> number = "10"; //case
case JACK -> number = "J"; //case
case QUEEN -> number = "Q"; //case
case KING -> number = "K"; //case
} //end of switch
String suitName = ""; //variable declaration
switch(SUIT) { //switch to assign suit name
case HEARTS -> suitName = "H"; //case
case DIAMONDS -> suitName = "D"; //case
case SPADES -> suitName = "S"; //case
case CLUBS -> suitName = "C"; //case
} //end of switch
return number + suitName; //return statement
} //end of getName method
/**
* This method gives the path to a corresponding image.
* @return String - returns the path of the image corresponding with the card.
*/
public String getImagePath() {
return "C:\\ICS3U_SUMMATIVE_SOLITAIRE\\src\\cards\\" + getName().substring(1,getName().length()) + "\\" + getName() + ".jpg"; //return statement
} //end of getImage method
/**
* This method gives the file path to the back of the card image.
* @return String the file path to the card back image
*/
public static String getBackImagePath() {
return "C:\\ICS3U_SUMMATIVE_SOLITAIRE\\src\\CardBack.jpg";
} //end of getImageBackPath method
@Override
/**
* This method returns the description about the instance variables.
* @return String - rank and suit of card along with image path.
*/
public String toString() {
return this.RANK + " of " + this.SUIT + " ---- " + getImagePath();
}
} //end of Card class
//imports
import java.util.ArrayList;
import java.util.Collections;
public class Deck {
//instance variables
private final ArrayList<Card> cards;
private int drawCardIndex;
//methods
/**
* This constructor for the Deck class creates all 52 cards and adds them to cards List.
*/
public Deck() {
cards = new ArrayList<>(); //creating new deck
for (Suit suit: Suit.values()) { //loops through suits
for (Rank rank: Rank.values()) { //loops through ranks
cards.add(new Card(suit, rank)); //adds a unique Card to cards
}
}
drawCardIndex = 0; //initializes index
} //end of constructor
/**
* This method returns the size of the deck.
* @return int - size of deck
*/
public int getSize() {
return cards.size();
} //end of getSize method
/**
* This method returns a drawn card in the deck of cards.
* @return Card - a new drawn card in the deck of cards.
*/
public Card drawCard() {
if (drawCardIndex<cards.size()) { //checks if all of the cards have been drawn
Card card = cards.get(drawCardIndex); //draws a card
drawCardIndex++; //increments
return card; //return statement
}
return null; //returns null if all of the cards have already been drawn
} //end of drawCard method
/**
* This method shuffles the deck of cards.
*/
public void shuffleDeck() {
Collections.shuffle(cards); //mixes ArrayList
resetDrawCardIndex(); //resets the drawCardIndex variable
} //end of shuffleDeck method
/**
* This method resets the drawCardIndex.
*/
public void resetDrawCardIndex() {
drawCardIndex = 0;
} //end of resetDrawCardIndex method
/**
* This method checks if all of the cards have been drawn.
* @return Boolean true or false based on if all the cards have been drawn or not.
*/
public boolean isEmpty() {
return cards.size() <= drawCardIndex;
} //end of isEmpty method
} //end of Deck class
</details>
# 答案1
**得分**: 1
以下是您提供的代码的翻译部分:
```java
使用我上面评论中提到的概念,我想出了一个简单的示例:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
import javax.swing.border.*;
import java.io.*;
public class DragCards extends JPanel
{
private static DataFlavor COMPONENT_FLAVOR;
private PanelHandler panelHandler = new PanelHandler();
private ComponentHandler componentHandler = new ComponentHandler();
private MouseListener dragListener;
private Dimension cardSize = new Dimension(100, 175);
public DragCards()
{
try
{
COMPONENT_FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";;class=\"" + Component[].class.getName() + "\"");
}
catch(Exception e) { System.out.println(e); }
dragListener = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.MOVE);
}
};
setLayout( new BorderLayout() );
add(createDeckPanel(), BorderLayout.PAGE_START);
add(createStacksPanel(), BorderLayout.CENTER);
}
private JPanel createDeckPanel()
{
JPanel deckPanel = new JPanel( new OverlapLayout( new Point(0, 0) ) );
for (int i = 0; i < 10; i++)
{
JLabel label = new JLabel( "Card: " + i );
label.setVerticalAlignment(JLabel.TOP);
label.setBorder( new LineBorder(Color.BLACK) );
label.setOpaque( true );
label.setBackground( Color.WHITE );
label.setPreferredSize( cardSize );
label.addMouseListener( dragListener );
label.setTransferHandler( componentHandler );
deckPanel.add( label );
}
JPanel wrapper = new JPanel();
wrapper.add( deckPanel );
return wrapper;
}
private JPanel createStacksPanel()
{
JPanel stackPanels = new JPanel( new GridLayout(0, 4, 10, 10) );
Dimension stackDimension = new Dimension(cardSize.width, cardSize.height + 200);
for (int i = 0; i < 4; i++)
{
JPanel stackPanel = new JPanel( new OverlapLayout( new Point(0, 20) ) );
stackPanel.setBackground( Color.YELLOW );
stackPanel.setBorder( new EmptyBorder(10, 0, 0, 0) );
stackPanel.setPreferredSize( stackDimension );
stackPanel.setTransferHandler( panelHandler );
stackPanels.add( stackPanel );
}
JPanel wrapper = new JPanel();
wrapper.add( stackPanels );
return (wrapper );
}
class ComponentHandler extends TransferHandler
{
@Override
public int getSourceActions(JComponent c)
{
// setDragImage( ScreenImage.createImage(c) );
return MOVE;
}
@Override
public Transferable createTransferable(final JComponent c)
{
return new Transferable()
{
@Override
public Object getTransferData(DataFlavor flavor)
{
Component[] components = new Component[1];
components[0] = c;
return components;
}
@Override
public DataFlavor[] getTransferDataFlavors()
{
DataFlavor[] flavors = new DataFlavor[1];
flavors[0] = DragCards.COMPONENT_FLAVOR;
return flavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return flavor.equals(DragCards.COMPONENT_FLAVOR);
}
};
}
@Override
public void exportDone(JComponent c, Transferable t, int action)
{
}
}
class PanelHandler extends TransferHandler
{
@Override
public boolean canImport(TransferSupport support)
{
if (!support.isDrop())
{
return false;
}
boolean canImport = support.isDataFlavorSupported(DragCards.COMPONENT_FLAVOR);
return canImport;
}
@Override
public boolean importData(TransferSupport support)
{
if (!canImport(support))
{
return false;
}
Component[] components;
try
{
components = (Component[])support.getTransferable().getTransferData(DragCards.COMPONENT_FLAVOR);
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
Component component = components[0];
Container parent = component.getParent();
Container container = (Container)support.getComponent();
container.add(component);
container.getParent().revalidate();
container.getParent().repaint();
parent.revalidate();
parent.repaint();
return true;
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("DragCards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new DragCards());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
希望这对您有所帮助!如果您需要任何进一步的协助,请随时告诉我。
英文:
Using concepts from my comments above I came up with a simple example:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import javax.swing.text.*;
import javax.swing.border.*;
import java.io.*;
public class DragCards extends JPanel
{
private static DataFlavor COMPONENT_FLAVOR;
private PanelHandler panelHandler = new PanelHandler();
private ComponentHandler componentHandler = new ComponentHandler();
private MouseListener dragListener;
private Dimension cardSize = new Dimension(100, 175);
public DragCards()
{
try
{
COMPONENT_FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + Component[].class.getName() + "\"");
}
catch(Exception e) { System.out.println(e); }
dragListener = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.MOVE);
}
};
setLayout( new BorderLayout() );
add(createDeckPanel(), BorderLayout.PAGE_START);
add(createStacksPanel(), BorderLayout.CENTER);
}
private JPanel createDeckPanel()
{
JPanel deckPanel = new JPanel( new OverlapLayout( new Point(0, 0) ) );
for (int i = 0; i < 10; i++)
{
JLabel label = new JLabel( "Card: " + i );
label.setVerticalAlignment(JLabel.TOP);
label.setBorder( new LineBorder(Color.BLACK) );
label.setOpaque( true );
label.setBackground( Color.WHITE );
label.setPreferredSize( cardSize );
label.addMouseListener( dragListener );
label.setTransferHandler( componentHandler );
deckPanel.add( label );
}
JPanel wrapper = new JPanel();
wrapper.add( deckPanel );
return wrapper;
}
private JPanel createStacksPanel()
{
JPanel stackPanels = new JPanel( new GridLayout(0, 4, 10, 10) );
Dimension stackDimension = new Dimension(cardSize.width, cardSize.height + 200);
for (int i = 0; i < 4; i++)
{
JPanel stackPanel = new JPanel( new OverlapLayout( new Point(0, 20) ) );
stackPanel.setBackground( Color.YELLOW );
stackPanel.setBorder( new EmptyBorder(10, 0, 0, 0) );
stackPanel.setPreferredSize( stackDimension );
stackPanel.setTransferHandler( panelHandler );
stackPanels.add( stackPanel );
}
JPanel wrapper = new JPanel();
wrapper.add( stackPanels );
return (wrapper );
}
class ComponentHandler extends TransferHandler
{
@Override
public int getSourceActions(JComponent c)
{
// setDragImage( ScreenImage.createImage(c) );
return MOVE;
}
@Override
public Transferable createTransferable(final JComponent c)
{
return new Transferable()
{
@Override
public Object getTransferData(DataFlavor flavor)
{
Component[] components = new Component[1];
components[0] = c;
return components;
}
@Override
public DataFlavor[] getTransferDataFlavors()
{
DataFlavor[] flavors = new DataFlavor[1];
flavors[0] = DragCards.COMPONENT_FLAVOR;
return flavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor)
{
return flavor.equals(DragCards.COMPONENT_FLAVOR);
}
};
}
@Override
public void exportDone(JComponent c, Transferable t, int action)
{
}
}
class PanelHandler extends TransferHandler
{
@Override
public boolean canImport(TransferSupport support)
{
if (!support.isDrop())
{
return false;
}
boolean canImport = support.isDataFlavorSupported(DragCards.COMPONENT_FLAVOR);
return canImport;
}
@Override
public boolean importData(TransferSupport support)
{
if (!canImport(support))
{
return false;
}
Component[] components;
try
{
components = (Component[])support.getTransferable().getTransferData(DragCards.COMPONENT_FLAVOR);
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
Component component = components[0];
Container parent = component.getParent();
Container container = (Container)support.getComponent();
container.add(component);
container.getParent().revalidate();
container.getParent().repaint();
parent.revalidate();
parent.repaint();
return true;
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("DragCards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new DragCards());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Notes:
-
If you want to set the
setDragImage(...)
method you will need to get the Screen Image code. -
When dragging to on of the 4 stack panels, the mouse must be on the panel, not the label. If you want the logic to work when the mouse is over a label, then (I think - but have not tried) you would need to add the import logic into the ComponentHandler class. This logic should be similar to the import logic in the panel class.
Or the second approach using custom dragging code might look something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class DragCards2 extends JPanel implements MouseListener, MouseMotionListener
{
private Dimension cardSize = new Dimension(100, 175);
private JPanel deckPanel;
private JPanel stacksPanel;
private Component card;
int xAdjustment;
int yAdjustment;
private MouseListener dragListener;
public DragCards2()
{
setLayout( new BorderLayout() );
add(createDeckPanel(), BorderLayout.PAGE_START);
add(createStacksPanel(), BorderLayout.CENTER);
}
private JPanel createDeckPanel()
{
deckPanel = new JPanel( new OverlapLayout( new Point(0, 0) ) );
for (int i = 0; i < 10; i++)
{
JLabel label = new JLabel( "Card: " + i );
label.setVerticalAlignment(JLabel.TOP);
label.setBorder( new LineBorder(Color.BLACK) );
label.setOpaque( true );
label.setBackground( Color.WHITE );
label.setPreferredSize( cardSize );
deckPanel.add( label );
}
deckPanel.addMouseListener( this );
deckPanel.addMouseMotionListener( this );
JPanel wrapper = new JPanel();
wrapper.add( deckPanel );
return wrapper;
}
private JPanel createStacksPanel()
{
stacksPanel = new JPanel( new GridLayout(0, 4, 10, 10) );
Dimension stackDimension = new Dimension(cardSize.width, cardSize.height + 200);
for (int i = 0; i < 4; i++)
{
JPanel stackPanel = new JPanel( new OverlapLayout( new Point(0, 20) ) );
stackPanel.setBackground( Color.YELLOW );
stackPanel.setBorder( new EmptyBorder(10, 0, 0, 0) );
stackPanel.setPreferredSize( stackDimension );
stacksPanel.add( stackPanel );
}
JPanel wrapper = new JPanel();
wrapper.add( stacksPanel );
return (wrapper );
}
/*
** Add the card to the dragging layer so it can be moved
*/
public void mousePressed(MouseEvent e)
{
JPanel deckPanel = (JPanel)e.getComponent();
card = deckPanel.getComponent( 0 );
if (card instanceof JPanel) return;
Point parentLocation = card.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
card.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
JLayeredPane lp = getRootPane().getLayeredPane();
lp.add(card, JLayeredPane.DRAG_LAYER);
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
/*
** Move the chess piece around
*/
public void mouseDragged(MouseEvent me)
{
if (card == null) return;
int x = me.getX() + xAdjustment;
int y = me.getY() + yAdjustment;
card.setLocation(x, y);
}
/*
** Drop the card back onto the game board
*/
public void mouseReleased(MouseEvent e)
{
setCursor(null);
if (card == null) return;
// Make sure the card is no longer painted on the layered pane
card.setVisible(false);
// check to see if card was dragged to a stack
JPanel stackPanel = null;
Point localPoint = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), stacksPanel);
for (int i = 0; i < stacksPanel.getComponentCount(); i++)
{
JPanel panel = (JPanel)stacksPanel.getComponent(i);
if (panel.getBounds().contains(localPoint))
{
stackPanel = panel;
break;
}
}
if (stackPanel == null)
deckPanel.add( card );
else
stackPanel.add( card );
card.setVisible(true);
}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
private static void createAndShowUI()
{
JFrame frame = new JFrame("DragCards2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new DragCards2());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Both examples use the Overlap Layout to allow for easy stacking of the cards.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论