0

I have code here that displays a swing window with four jacks on it. I would like to be able to click and move the jacks around the window. I know they need to be redrawn but I'm not sure how to go about that.

How can I make it so a user could click and move the cards?

package p2test;
import javax.swing.*;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.awt.*;

public class main
{
    public static final int PERIMETER_BEVEL = 20;  //space between panel border and perimeter cards
    public static final int LEFT_PERIMETER_BEVEL = 98;
    public static final int INTERIOR_BEVEL = 5;                 //space between cards
    public static final int CARD_HEIGHT = 97;
    public static final int CARD_WIDTH = 73;    

    public static final int PANEL_HEIGHT = (2*PERIMETER_BEVEL) + (4*CARD_HEIGHT) + (3*INTERIOR_BEVEL);
    public static final int PANEL_WIDTH = (2*PERIMETER_BEVEL) + (14*CARD_WIDTH) + (13*INTERIOR_BEVEL);

public static final String   BACKGROUND_COLOR = "#64C866";  //window background color [hex]
public static final String   CARD_FOLDER = "cardImages";    //default folder containing images

public static final String [] RANKS = {  "jack"};
public static final ArrayList<String> ranks = new ArrayList<String>(Arrays.asList(RANKS));

public static void main(String[] args)
{
    JFrame window = new JFrame("deck");
    JPanel panel = new JPanel() {
        public void paintComponent(Graphics g) {                     //find each rank of card in increasing
            super.paintComponent(g);                                 //order as specified in the array. All
            File[] files = new File(CARD_FOLDER).listFiles();        //ranks appear in the same suit order in

          //the filesystem so suits will automatically  
          //be in order when printing in groups of four
          //cards.
            int counter = 0;
            for(String rank : ranks) {                              
                for(File filename : files) {                        
                    if(filename.getName().contains(rank)) {
                        new ImageIcon(filename.getPath()).paintIcon(this, g,
                            LEFT_PERIMETER_BEVEL + (counter/4) * (CARD_WIDTH + INTERIOR_BEVEL),
                            PERIMETER_BEVEL + (3-(counter%4)) * (CARD_HEIGHT + INTERIOR_BEVEL));
                        counter++;
                      //counter/4 keeps track of the correct column
                      //3-(counter%4) keeps track of the correct row
                      //in which to print the card image
                    }                                                
                }                                                    
            }            
        }

    };
    panel.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
    window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    window.setBackground(Color.decode(BACKGROUND_COLOR));
    window.add(panel);
    window.setVisible(true);    
    window.pack();
}
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
SpruceTips
  • 225
  • 1
  • 5
  • 14
  • 3
    Again, don't load resources within the `paintComponent`, this will slow down you program and consume large amount of resources. You need to define a virtual view with which you can determine if a give object is clicked or not and move it by changing it's position within this view and the make that reality on the screen...You may find [How to write a Mouse Listener](http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html) and [Hwot to write a Mouse-Motion Listener](http://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html) useful – MadProgrammer Feb 04 '14 at 06:41
  • In addition to the sages advice of @MadProgrammer, I note the code mentions 'rows and columns'. If the cards never overlap, consider displaying each in a `JButton` inside a `GridLayout`. I use this technique in the [Making a robust, resizable Chess GUI](http://stackoverflow.com/q/21142686/418556) Q&A, and it vastly simplifies detecting clicks and moving things about - as seen in [this variant](http://stackoverflow.com/a/21507745/418556) that animates moving the pawns. – Andrew Thompson Feb 04 '14 at 06:52
  • Putting aside my paintCompenent problem, I do need to have them overlap. I have looked at the Mouse Listener and Mouse-Motion Listener but I was unable to apply those to any card to move. Could you give an example on how to apply these to a single card? – SpruceTips Feb 04 '14 at 19:52
  • Each "Card" needs to be it's own object, which knows how to paint itself and where it should be painted (and it's how big it should be painted). This should separated into some kind of model for easier interactions. Then in you `paintComponent` method, you visualise this... – MadProgrammer Feb 04 '14 at 22:22

1 Answers1

0

I was able to get the cards to move by adding this. A much better way of implementing this would be to follow what MadProgrammer and Andrew Thompson suggested.

public static MouseInputAdapter mouseHandler = new MouseInputAdapter(){
    //internal JLabel displacement on mouse press for smooth dragging
    public int labelDisX;   
    //internal JLabel displacement on mouse press for smooth dragging
    public int labelDisY;                 
    public void mousePressed(MouseEvent e) {
        labelDisX = e.getX();
        labelDisY = e.getY();
        //move the card above all others
        e.getComponent().getParent().setComponentZOrder(e.getComponent(), 0); 
        //repaint so card moves above others
        e.getComponent().getParent().repaint();                               
    }
    public void mouseDragged (MouseEvent e) {
        JPanel panel = (JPanel) e.getComponent().getParent();
        //get preliminary new X coordinate
        int newX = e.getComponent().getX() + e.getX() - labelDisX; 
        //get preliminary new Y coordinate
        int newY = e.getComponent().getY() + e.getY() - labelDisY;  
        //here we check that the card is not
        //being moved off the panel. If the
        //user does try and do this then
        //make the new coordinates such that
        //the card is bounded by the panel's
        //edges [extra credit]
        if(newX > panel.getWidth() - CARD_WIDTH) {
            newX = panel.getWidth() - CARD_WIDTH;                             
        }                                                                     
        if(newY > panel.getHeight() - CARD_HEIGHT) {                          
            newY = panel.getHeight() - CARD_HEIGHT;                           
        }                                                                     
        if(newX < 0) { newX = 0; }                                            
        if(newY < 0) { newY = 0; }
        e.getComponent().setLocation(newX, newY);
    }
};
SpruceTips
  • 225
  • 1
  • 5
  • 14