Howdy,
It’s not working because you treat the card as a JComponent, but you never actually add the card to a parent component. Hence even though you are drawing it, its not actually ‘there’ for click detection etc.
I’d also suggest that you don’t do all that initialization within the main() method. That can all be moved to the Solitaire constructor.
Perhaps others would disagree with me, but I’m not too keen on your design here; using JComponents, having individual ‘drag handlers’ for each card etc. I’d use a single instance of a MouseInputListener, and handle everything from there.
Here’s something I ripped up quickly, which is roughly how I would do the same thing:
Main Solitaire class:
package solitaire;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.*;
public class Solitaire implements MouseInputListener {
ArrayList<Card> cards = new ArrayList<>();
JFrame frame;
SolitairePanel panel;
int screenWidth = 800;
int screenHeight = 600;
//variables for card selection
boolean cardSelected;
Card selectedCard;
Point lastPosition = new Point();
Solitaire() {
//Setting up the display
frame = new JFrame();
panel = new SolitairePanel(screenWidth, screenHeight, this);
panel.addMouseListener(this);
panel.addMouseMotionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(panel);
frame.pack();
frame.setVisible(true);
//Adding some cards
cards.add(new Card(50,50));
cards.add(new Card(200, 200));
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Solitaire solitaire = new Solitaire();
solitaire.go();
}
public void go(){
//Bad loop just for demonstration.
while(true){
frame.repaint();
try {
Thread.sleep(16);
} catch (Exception ex) {
}
}
}
@Override
public void mousePressed(MouseEvent me) {
for(int x = 0; x < cards.size(); x++) {
if(cards.get(x).bounds.contains(me.getPoint())) {
this.cardSelected = true;
selectedCard = cards.get(x);
lastPosition.setLocation(me.getPoint());
break;
}
}
}
@Override
public void mouseDragged(MouseEvent me) {
if(cardSelected){
selectedCard.move((int)(me.getX() - lastPosition.getX()), (int)(me.getY() - lastPosition.getY()));
}
lastPosition.setLocation(me.getPoint());
}
@Override
public void mouseReleased(MouseEvent me) {
//NOTE: you would probably check if the card move is valid here. If so, update game, stacks, bounds etc. If not, return card to original position.
if(cardSelected) {
selectedCard.updateBounds();
cardSelected = false;
}
}
//Following methods aren't used.
@Override
public void mouseClicked(MouseEvent me) {}
@Override
public void mouseMoved(MouseEvent me) {}
@Override
public void mouseEntered(MouseEvent me) {}
@Override
public void mouseExited(MouseEvent me) {}
}
SolitairePanel - for drawing etc.:
package solitaire;
import java.awt.*;
import javax.swing.*;
public class SolitairePanel extends JPanel {
Solitaire game;
int width;
int height;
SolitairePanel(int width, int height, Solitaire game) {
this.game = game;
this.width = width;
this.height = height;
this.setPreferredSize(new Dimension(width, height));
}
@Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
for(int x = 0; x < game.cards.size(); x++) {
game.cards.get(x).render(g);
}
}
}
Card class:
package solitaire;
import java.awt.*;
public class Card {
int width = 120;
int height = 150;
int xPos;
int yPos;
Rectangle bounds;
Card(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
bounds = new Rectangle(xPos, yPos, width, height);
}
//Move the card by setting the offset from its current position.
public void move(int xOffset, int yOffset) {
xPos += xOffset;
yPos += yOffset;
}
//Update the bounds of the card, so that it can be selected.
public void updateBounds() {
bounds.setBounds(xPos, yPos, width, height);
}
public void render(Graphics g) {
g.setColor(Color.red);
g.fillRect(xPos, yPos, width, height);
g.setColor(Color.blue);
g.drawRect(xPos, yPos, width, height);
}
}
Hope this helps!