Closed Thread
Results 1 to 10 of 10

Thread: Simple Swing Problem

  1. #1
    cod3b3ast's Avatar
    cod3b3ast is offline Learning Programmer
    Join Date
    Dec 2009
    Posts
    74
    Rep Power
    0

    Simple Swing Problem

    Hello, everybody!

    I have been struggling with this problem for many hours, and I have determined that I need outside help. I have a simple swing application that displays a deck of cards. The program is supposd to allow the user to drag the cards around the screen and disallow the gray (empty) slots to be dragged. I was able to handle this without much problem. I am trying to figure out how to get the card being dragged to appear on top of the other cards on the screen. I cannot figure that part out for the life of me! I will post my entire program.

    Main:
    Code:
    package cards;
    
    import java.awt.*;
    import javax.swing.*;
    
    public class Main extends JFrame 
    {
        private Deck deck;
        private GameScreen game;
    
        /**
         * Constructor
         */
        public Main()
        {
            deck = new Deck();
            deck.shuffle();
            game = new GameScreen(deck);
        }
    
        public static void main(String[] args)
        {
            new Main();
        }
    }
    Deck:
    Code:
    package cards;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class Deck
    {
        private Card[] deck;
    
        /**
         * Constructor
         */
        public Deck()
        {
            deck = new Card[52];
            fillDeck();
        }
    
        /**
         * @return the Card at the given position in teh deck (JPanels)
         */
        public Card getCard(int pos)
        {
            return deck[pos];
        }
    
        /**
         * Randomizes the order of the cards in the deck
         */
        public void shuffle()
        {
            // perform 100 swaps of random cards
            // TODO: prove performance of this function
            for (int i=0; i<100; ++i) {
                int a = (int) (Math.random() * 52);
                int b = (int) (Math.random() * 52);
                swap(a, b);
            }
        }
    
        /**
         * Fills the deck with 52 cards that are not shuffled
         */
        private void fillDeck()
        {
            int tempFace = 0;   // Keeps track of which cards are being created
            int tempSuit = 0;
            // Fill deck with images from the the filepaths created
            for (int suit=0; suit<4; ++suit) {
                for (int face=1; face<14; ++face) {
                    // "cardImages/cards"
                    String filepath = new String("cardImages/cards/");
                    // append face of card
                    switch (face) {
                    case 1:
                        // "cardsImages/cards/ace"
                        filepath = filepath.concat("ace");
                                            tempFace = 1;
                        break;
                    case 11:
                        filepath = filepath.concat("jack");
                                            tempFace = 11;
                        break;
                    case 12:
                        filepath = filepath.concat("queen");
                                            tempFace = 12;
                        break;
                    case 13:
                        filepath = filepath.concat("king");
                                            tempFace = 13;
                        break;
                    default:
                        filepath = filepath.concat(Integer.toString(face));
                                            tempFace = face;
                    }
                    // append suit of card
                    switch (suit) {
                    case 3:
                        // "cardsImages/cards/aceClubs"
                        filepath = filepath.concat("Clubs");
                                            tempSuit = 1;
                        break;
                    case 2:
                        filepath = filepath.concat("Diamonds");
                                            tempSuit = 2;
                        break;
                    case 1:
                        filepath = filepath.concat("Hearts");
                                            tempSuit = 3;
                        break;
                    default:
                        filepath = filepath.concat("Spades");
                                            tempSuit = 4;
                    }
                    // "cardsImages/cards/aceClubs.gif"
                    filepath = filepath.concat(".gif");
    
                    deck[suit*13+face-1] = new Card(filepath,
                                                    	 tempSuit,
                                                    	 tempFace);
                }
            }
        }
    
        /**
         * Swaps the the two cards at the given
         * positions in the deck.
         */
        private void swap(int pos1, int pos2)
        {
            Card temp = deck[pos1];
            deck[pos1] = deck[pos2];
            deck[pos2] = temp;
        }
    }
    GameScreen:
    Code:
    package cards;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class GameScreen extends JFrame
    {
        /**
         * Constructor
         */
        public GameScreen(Deck deck)
        {
            // this GridLayout aligns its components in 4 rows
            // and 14 columns
            GridLayout layout = new GridLayout(4, 14);
            setLayout(layout);
    
            placeCards(deck);
    
            setTitle("Project1 - Cards Mysterious");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setMinimumSize(new Dimension(1200, 500));
            // set background color to pale green
            this.getContentPane().setBackground(new Color(51, 255, 102));
            pack();
            setVisible(true);
        }
    
        /**
         * Arranges a deck of cards on the JPanel
         * Places the cards in four rows, and adds a
         * gray card in front of each row.
         *
         * @param deck
         */
        private void placeCards(Deck deck)
        {
            String grayCardPath = new String("cardImages/gray.gif");
            for (int i=0; i<52; i++) {
                Card grayCard = new Card(grayCardPath, 0, 0);
                JPanel panel = new JPanel();
                // add one gray card to the front of each row
                if (i &#37; 13 == 0) {
                    add(grayCard);
                } else {
                	add(deck.getCard(i));
                }
            }
        }
    }
    Card:
    Code:
    package cards;
    
    import java.awt.*;
    import java.awt.event.*;
    
    import javax.swing.*;
    
    public class Card extends JPanel
    {
        private final ImageIcon card;     // the card image to be displayed
        private final int       suit;
        private final int       face;
        private int deltax = 0;
        private int deltay = 0;
    
        /**
         * Constructor
         *
         * @param filepath	the file path where the card image
         * 					can be found
         */
        public Card(String filepath, int suit, int face)
        {
            card = new ImageIcon(filepath);
            this.suit = suit;
            this.face = face;
            // if a real suit is given 1 - 4, the card is
            // enabled for user input - otherwise not
            if (suit < 1)
                setEnabled(false);
            else
                setEnabled(true);
            // do not show the JPanel's background
            setOpaque(false);
            // listen for mouse dragging and mouse pressing
            addMouseMotionListener(mouseDrag);
            addMouseListener(mousePress);
        }
        
        public void paintComponent(Graphics g)
        {
        	super.paintComponent(g);
        	card.paintIcon(this, g, 10, 10);
        }
        
        /**
         * @return
         */
        public ImageIcon getIcon() {
        	return card;
        }
    
        /**
         * @return the suit
         */
        public int getSuit() {
            return suit;
        }
    
        /**
         * @return the face
         */
        public int getFace() {
            return face;
        }
        
        // Listens for when the mouse is dragged
        MouseMotionListener mouseDrag = new MouseMotionAdapter()
        {
            @Override
            public void mouseDragged (MouseEvent e)
            {
                // if enabled for user input, move image with pointer
                if (isEnabled()) {
                    Point p = MouseInfo.getPointerInfo().getLocation();
                    p.x -= deltax;
                    p.y -= deltay;
                    setLocation(p);
                }
            }
        };
    
        // Listens for when the mouse is pressed
        MouseListener mousePress = new MouseAdapter()
        {
            @Override
            public void mousePressed (MouseEvent e)
            {
            	// Records the offset of the mouse and origin of the card.
            	// This prevents the card from immediately jumping to the
            	// position of the mouse. By factoring this in, it 
                if (isEnabled()) {
                	Point p = MouseInfo.getPointerInfo().getLocation();
                    deltax = p.x - getX();
                    deltay = p.y - getY();
                }
            }
        };
    }
    Any help is much appreciated. Thanks!

  2. CODECALL Circuit advertisement
    Join Date
    Always
    Posts
    Many

     
  3. #2
    Join Date
    May 2009
    Location
    Belgium
    Posts
    1,879
    Rep Power
    24

    Re: Simple Swing Problem

    Hi, hard to solve problem you have there :/

    After a while i came up with this. Gonna stop thinking now, clear my mind

    Here is what i got so far:

    GameScreen:
    Code:
    import javax.swing.*;
    import java.awt.*;
    import java.util.Observable;
    import java.util.Observer;
    
    public class GameScreen extends JFrame implements Observer
    {
        private int i=0;
        JLayeredPane pane;
        Card lastcard;
        /**
         * Constructor
         */
        public GameScreen(Deck deck)
        {
            pane = new JLayeredPane();
            pane.setLayout(new FlowLayout());
    
    
            placeCards(deck);
    
            setTitle("Project1 - Cards Mysterious");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setMinimumSize(new Dimension(1200, 500));
            // set background color to pale green
            this.getContentPane().setBackground(new Color(51, 255, 102));
            getContentPane().add(pane);
            pack();
            setVisible(true);
        }
    
        /**
         * Arranges a deck of cards on the JPanel
         * Places the cards in four rows, and adds a
         * gray card in front of each row.
         *
         * @param deck
         */
        private void placeCards(Deck deck)
        {
            String grayCardPath = new String("cardImages/gray.gif");
            for (int i=0; i<52; i++) {
                Card grayCard = new Card(grayCardPath, 0, 0);
    
                if (i &#37; 13 == 0) {
                    pane.add(grayCard.getLabel());
                    grayCard.addObserver(this);
                } else {
                	pane.add(deck.getCard(i).getLabel());
    
                    deck.getCard(i).addObserver(this);
                }
            }
        }
    
        public void update(Observable o, Object arg) {
            JLabel label = (JLabel) arg;
            pane.setComponentZOrder(label,0);
        }
    }
    Card:
    Code:
    import javax.swing.*;
    import java.util.Observable;
    import java.awt.event.*;
    import java.awt.*;
    
    public class Card extends Observable
    {
        private JLabel label;
        private final ImageIcon card;     // the card image to be displayed
        private final int       suit;
        private final int       face;
        private int deltax = 0;
        private int deltay = 0;
    
        /**
         * Constructor
         *
         * @param filepath	the file path where the card image
         * 					can be found
         */
        public Card(String filepath, int suit, int face)
        {
            card = new ImageIcon(filepath);
            label = new JLabel();
            label.setIcon(card);
    
            this.suit = suit;
            this.face = face;
            // if a real suit is given 1 - 4, the card is
            // enabled for user input - otherwise not
            if (suit < 1)
                label.setEnabled(false);
            else
                label.setEnabled(true);
            // do not show the JPanel's backgroun
    
            label.setSize(card.getIconWidth(),card.getIconHeight());
            label.addMouseListener(mousePress);
            label.addMouseMotionListener(mouseDrag);
        }
        /**
         * @return
         */
        public ImageIcon getIcon() {
        	return card;
        }
    
        /**
         * @return the suit
         */
        public int getSuit() {
            return suit;
        }
    
        /**
         * @return the face
         */
        public int getFace() {
            return face;
        }
    
        public JLabel getLabel() {
            return label;
        }
    
        MouseMotionListener mouseDrag = new MouseMotionAdapter()
        {
            @Override
            public void mouseDragged (MouseEvent e)
            {
                // if enabled for user input, move image with pointer
                if (label.isEnabled()) {
                    Point p = MouseInfo.getPointerInfo().getLocation();
                    p.x -= deltax;
                    p.y -= deltay;
                    label.setLocation(p);
                }
            }
        };
    
        // Listens for when the mouse is pressed
        MouseListener mousePress = new MouseAdapter()
        {
            @Override
            public void mousePressed (MouseEvent e)
            {
            	// Records the offset of the mouse and origin of the card.
            	// This prevents the card from immediately jumping to the
            	// position of the mouse. By factoring this in, it
                if (label.isEnabled()) {
                	Point p = MouseInfo.getPointerInfo().getLocation();
                    deltax = p.x - label.getX();
                    deltay = p.y - label.getY();
                    setChanged();
                    notifyObservers(label);
                }
            }
        };
    }

    As you see I removed the "extends JPanel" from the class Card. I did this because i wanted it to "extends Observerable" and i could easily put the images on a JLabel.

    Main things that changed in the Card class is:
    Code:
    card = new ImageIcon(filepath);
            label = new JLabel();
            label.setIcon(card);
    in the constructor. I don't think i changed much more in that class. Apart from a getLabel method.
    +the observable ofcourse. More of that later.

    In GameScreen, instead of just putting the cards on the contentpane, i'm now putting them on a JLayeredPane and the layeredpane on the contentpane. I also made Gamescreen "implements Observer"...

    For every card i add in "placeCards(..)" i do
    Code:
    deck.getCard(i).addObserver(this);
    So card = observable, gamescreen = observer.

    I did this because i wanted the card to send a message to the gamescreen saying: 'hey i'm being dragged, put me on top.'
    So in the mousepressed of Card i do
    Code:
    setChanged();
                    notifyObservers(label);
    And in the gameScreen, i catch this with the "update" method
    Code:
    public void update(Observable o, Object arg) {
            JLabel label = (JLabel) arg;
            pane.setComponentZOrder(label,0);
        }
    So here i put the card that has been clicked on as high as possible on the screen.

    You may have noticed that i changed the GridLayout in a FlowLayout. I know this looks like **** but i've been using the gridlayout and discovered it resizes the stuff that i add inside it. So the label, that normally has the size of the image put onto it. becomes bigger on top, to the right and at the bottom :S So if 'xx' represents the image, the lines around represent the label. It's too big.
    Code:
    --------------
    |            |
    xxxxxxxxxxx  |
    xxxxxxxxxxx  |
    xxxxxxxxxxx  |
    |            |
    --------------
    You can simply change the current flowlayout in my code to the previous gridlayout and you'll notice that you can click about 10-15 pixel above the image and it will still be dragged around, same with the right side and bottom.


    I'm not sure if i changed anything else. If you got questions, just ask em.
    Neither do i know if this is the best /easiest solution for your problem

  4. #3
    kmhosny's Avatar
    kmhosny is offline Programmer
    Join Date
    Feb 2008
    Location
    Egypt
    Posts
    133
    Rep Power
    0

    Re: Simple Swing Problem

    you can try to set the draw points of paint() method -which are 10,10- to be variable so that you can change for every card.
    so card 1 might have 10,10 and card 2 might have 10,15 so a part of card 1 -5 pixels- will be displayed and then card 2 will be displayed.
    "Recursion is just a line of code"
    -Karim Hosny-
    My flickr

  5. #4
    Join Date
    May 2009
    Location
    Belgium
    Posts
    1,879
    Rep Power
    24

    Re: Simple Swing Problem

    Okay, instead of using all the observer/observable stuff. It may be better to just drop that and give Card an extra parameter, the GameScreen.
    Code:
    public Card(String filepath, int suit, int face, GameScreen gs){
      this.gs = gs;
      ...
    }
    and then use gs to give the message 'hey i'm clicked put me on top. This is way more simple and i can't believe i didn't think of that a bit earliers ><

  6. #5
    cod3b3ast's Avatar
    cod3b3ast is offline Learning Programmer
    Join Date
    Dec 2009
    Posts
    74
    Rep Power
    0

    Re: Simple Swing Problem

    Wow, thank you both for your help! It turns out there is an even SIMPLER solution. I don't know if you will be happy or sad to see how easy it is, but it can actually be done in a single line placed in the event listener in the Card class.
    Code:
    e.getComponent().getParent().setComponentZOrder(e.getComponent(), 0)
    Sorry to have made you think so hard!

  7. #6
    kmhosny's Avatar
    kmhosny is offline Programmer
    Join Date
    Feb 2008
    Location
    Egypt
    Posts
    133
    Rep Power
    0

    Re: Simple Swing Problem

    think out of the "Card" , so nice to see that it has a simple solution
    "Recursion is just a line of code"
    -Karim Hosny-
    My flickr

  8. #7
    Join Date
    May 2009
    Location
    Belgium
    Posts
    1,879
    Rep Power
    24

    Re: Simple Swing Problem

    The funny thing is that when i used the setComponentZOrder on the contentpane (which is the parent of e.getcomponent when you use it. I had really bad fps issues : /

  9. #8
    cod3b3ast's Avatar
    cod3b3ast is offline Learning Programmer
    Join Date
    Dec 2009
    Posts
    74
    Rep Power
    0

    Re: Simple Swing Problem

    I apologize for my ignorance, but what is "fps?"

    There is a slight problem with the code. I am not too worried about fixing it at this point, but it is a curiosity. When the window is resized, all cards are moved back to their original positions. Also, the order of the cards is messed up when I set the ZOrder property, so I had to remember it's original ZOrder and restore it after the card was dropped.

  10. #9
    Join Date
    May 2009
    Location
    Belgium
    Posts
    1,879
    Rep Power
    24

    Re: Simple Swing Problem

    fps = frames per second. It's not really that which was my issue. But when i used the setComponentZOrder on the contentpane and not on the layeredPane, the card that i'm dragging around would be ... blinking really fast. Very annoying. Even worse when i dropped the card on another one and i then click the card below it. the dropped card would become invisible for 75&#37; or so :S

    so I had to remember it's original ZOrder and restore it after the card was dropped
    "I had" that means this problem is allready solved right?

  11. #10
    cod3b3ast's Avatar
    cod3b3ast is offline Learning Programmer
    Join Date
    Dec 2009
    Posts
    74
    Rep Power
    0

    Re: Simple Swing Problem

    Ya, the problem is solved. I attached a .zip file of the source files and pictures, so you can take a look at it.
    Attached Files Attached Files

Closed Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. I need help with a very simple problem
    By Walizzay in forum Java Help
    Replies: 4
    Last Post: 07-23-2011, 10:24 AM
  2. Facing problem in Java Swing
    By hbeon in forum Java Help
    Replies: 1
    Last Post: 12-02-2010, 08:48 AM
  3. Java Swing Problem
    By Funk in forum Java Help
    Replies: 2
    Last Post: 01-20-2010, 12:41 PM
  4. Simple text presentation with swing.
    By Turk4n in forum Classes and Code Snippets
    Replies: 0
    Last Post: 01-06-2010, 10:12 AM
  5. Tricky Problem (iPod touch & JAVA Swing)
    By Schafer5 in forum Technology Ramble
    Replies: 0
    Last Post: 03-11-2009, 01:00 PM

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts