Java: Example - Card Demo

This program reads in a bunch of images (cards) and allows them to be dragged around the screen. The images are stored in an array that represents the z coordinate (what's on top of what). This order is never changed even if a card is dragged, which give the peculiar effect of dragging under.

It is divided into several source files. The card images are in a zipped file.

  • CardDemo.java functions as either an application (it defines main()) or an applet (it subclasses JApplet).
  • CardDemoGUI.java is a subclass of JPanel that creates the GUI interface. A JPanel can be used by either an application or applet.
  • Card.java represents a single card. This is really only the skeleton of what a real class representing a card would be.
  • cards20.zip is a zipped file of the card images (.gif), including a back and joker. These images are GPLed, not the MIT License.

CardDemo.java - the main program / applet

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
// "appletviewer CardDemo.java" works because of the following line.
// <applet code="CardDemo.class" height="200" width="200"></applet>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
///////////////////////////////////////////////////////////// class CardDemo
/** CardDemo.java - Dragging card images example dual application/applet.
    <ul>
    <li>TODO: The card that is being dragged should be moved to the 
        end of the _deck array so that it displays on top.</li>
    <li>TODO: The applet version doesn't work correctly yet because
        it needs to use getCodeBase() in loading the images.</li>
    </ul>
    
    @author Fred Swartz
    @version 2004-04-22
*/
public class CardDemo extends JApplet {
    //========================================================== method main
    /** Create JFrame, add the CardDemoPanel, display. */
    public static void main(String[] args) {
        JFrame window = new JFrame();
        window.setTitle("Card Demo");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setContentPane(new CardDemoGUI());
        window.pack();
        window.show();
    }//end main
    
    //=================================================== applet constructor
    /** Constructor for applet */
    public CardDemo() {
        this.setContentPane(new CardDemoGUI());
    }
}//endclass CardDemo

CardDemoGUI.java provides the GUI to this demo program

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/////////////////////////////////////////////////////////// class CardDemoGUI
/** CardDemoGUI.java - Panel that allows dragging playing card images.
    @author Fred Swartz
    @version 2004-04-23
*/
class CardDemoGUI extends JPanel implements MouseListener, 
                                              MouseMotionListener {

    private static final int IMAGE_WIDTH = 73;
    private static final int IMAGE_HEIGHT = 97;
    //--- instance variables
    /** Initial image coords. */
    private int _initX     = 0;   // x coord - set from drag
    private int _initY     = 0;   // y coord - set from drag
    
    /** Position in image of mouse press to make dragging look better. */
    private int _dragFromX = 0;  // Displacement inside image of mouse press.
    private int _dragFromY = 0;
    
    private Card[] _deck = new Card[52];
    private Card _currentCard = null;  // Current draggable card.
    
    //============================================================= constructor
    /** Constructor sets size, colors, and adds mouse listeners.*/
    public CardDemoGUI() {
        //-- Read in the cards
        String suits = "shdc";
        String faces = "a23456789tjqk";
        int cardPosition = 0;
        for (int suit=0; suit<suits.length(); suit++) {
            for (int face=0; face<faces.length(); face++) {
                ImageIcon img = new ImageIcon("cards/"+ faces.charAt(face)
                                             + suits.charAt(suit) + ".gif");
                _deck[cardPosition++] = new Card(img, _initX++, _initY++);
            }
        }

        //-- Initialize graphics
        setPreferredSize(new Dimension(300, 300));
        setBackground(Color.blue);
        //--- Add mouse listeners.
        this.addMouseListener(this); 
        this.addMouseMotionListener(this);
    }//endconstructor
    
    //=================================================== method paintComponent
    /** Ball is drawn at the last recorded mouse listener coordinates. */
    public void paintComponent(Graphics g) {
        super.paintComponent(g);   // Required
        //-- Display the cards, starting with the first array element.
        //   The array order defines the z-axis depth.
        for (int crd=0; crd<_deck.length; crd++) {
            Card c = _deck[crd];
            c.image.paintIcon(this, g, c.x, c.y);
        }
    }//end paintComponent
    
    //===================================================== method mousePressed
    /** When the mousePressed listener is called,
    check if it's in the area of a card..  If it is, 
    <ol>
    <li>_currentCard is set so mouseDragged knows what to drag.</li>
    <li>Record where in the image (relative to the upper left coordinates) 
        the mouse was clicked, because it looks best if we drag from there.</li>
    </ol>
    TODO: Move the card to the last position so that it displays on top.
    */
    public void mousePressed(MouseEvent e) {
        int x = e.getX();   // Save the x coord of the click
        int y = e.getY();   // Save the y coord of the click
        
        //-- Find card image this is in.  Check from top down.
        _currentCard = null;  // Assume not in any image.
        for (int crd=_deck.length-1; crd>=0; crd--) {
            Card testCard = _deck[crd];
            if (x >= testCard.x && x <= (testCard.x + IMAGE_WIDTH)
                    && y >= testCard.y && y <= (testCard.y + IMAGE_HEIGHT)) {
                _dragFromX = x - testCard.x;  // how far from left
                _dragFromY = y - testCard.y;  // how far from top
                _currentCard = testCard;  // Remember what we're dragging.
                break;   // Stop when we find the first match.
            }
        }
    }//end mousePressed
    
    //============================================================ mouseDragged
    /** Set x,y to mouse position and repaint. */
    public void mouseDragged(MouseEvent e) {
        if (_currentCard != null) {   // Non-null if pressed inside card image.
            _currentCard.x = e.getX() - _dragFromX;
            _currentCard.y = e.getY() - _dragFromY;
            
            //--- Don't move the image off the screen sides
            _currentCard.x = Math.max(_currentCard.x, 0);
            _currentCard.x = Math.min(_currentCard.x, getWidth()-IMAGE_WIDTH);
            
            //--- Don't move the image off top or bottom
            _currentCard.y = Math.max(_currentCard.y, 0);
            _currentCard.y = Math.min(_currentCard.y, getHeight()-IMAGE_HEIGHT);
            
            this.repaint(); // Repaint because position changed.
        }
    }//end mouseDragged

    //====================================================== method mouseExited
    /** Turn off dragging if mouse exits panel. */
    public void mouseExited(MouseEvent e) {
        _currentCard = null;
    }//end mouseExited

    //=============================================== Ignore other mouse events.
    public void mouseMoved   (MouseEvent e) {}  // ignore these events
    public void mouseEntered (MouseEvent e) {}  // ignore these events
    public void mouseClicked (MouseEvent e) {}  // ignore these events
    public void mouseReleased(MouseEvent e) {}  // ignore these events
}//endclass CardDemoGUI

Card.java - Class representing one card

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
/////////////////////////////////////////////////////////////////// Card
/** Card.java - Utility class for grouping the image and its position.  
    A real card game would expand this into a better class. 
    @author Fred Swartz
    @version 2004-04-23
*/
class Card {
    javax.swing.ImageIcon image;
    int x;
    int y;
    
    public Card(javax.swing.ImageIcon image, int x, int y) {
        this.image = image;
        this.x = x;
        this.y = y;
    }
}