2

hi there i am working on a project(java memory game) and first of all i am trying to understand that how swing timer works. firstly, i my main class implements ActionListener and ItemListener. and i use timer in actionPerformed(ActionEvent e) if two cards which user selected different pictures then i use timer.start() to give him a couple of seconds to see pictures and then they will be closed again. but if user selects two different pictures they suddenly closed, so i can't see the second picture. i read some tutorials about swing timer but i guess i understood wrongly.by the way i created my to SSCCE, and i will be appreciated if you can help me. thanks anwyway...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Menu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Random;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.*;

public class ConcentrationGame4 extends JFrame implements ActionListener, ItemListener{

    private static final long serialVersionUID = 1L;
    private int buttoncounter=0;
    private int counter = 0;
    private JFrame frame;
    private JPanel mainPanel;
    private JPanel buttonPanel;
    private JMenuBar menuBar;
    private JMenu menu;
    private JMenuItem menuItem;
    private int[] arr = new int[16];
    private int i,j;
    private int random;
    private int size = 4;
    private Icon hidden;
    private GameButton buttonFirst;
    private GameButton buttonSecond;
    private Timer timer;

    private Icon img[] = {UIManager.getIcon("OptionPane.errorIcon"),
            UIManager.getIcon("OptionPane.informationIcon"),
            UIManager.getIcon("OptionPane.warningIcon")};

    private Icon iconList[] = new ImageIcon[size];

    public ConcentrationGame4(){
        createArray();
        initComponents();
    }


    private void initComponents(){

        frame = new JFrame("Concentration Game");
        menuBar = new JMenuBar();
        menu = new JMenu("Menu");
        frame.setJMenuBar(menuBar);
        menuBar.add(menu);
        menuItem = new JMenuItem("New Game");
        menu.add(menuItem);
        menuItem = new JMenuItem("Solve");
        menu.add(menuItem);
        menuItem = new JMenuItem("Exit");
        menu.add(menuItem);
        mainPanel = new JPanel(new BorderLayout(5, 5));
        mainPanel.setBorder(new EmptyBorder(4,4,4,4));
        frame.setContentPane(mainPanel);
        buttonPanel = new JPanel(new GridLayout(4,4,5,5));
        buttonPanel.setBackground(Color.green);

        timer = new Timer(2000,this);

        for(i=0; i<4; i++){

            final GameButton button = new GameButton(iconList[i]);
            button.addItemListener(this);
            button.addActionListener(this);
            buttonPanel.add(button);

        }

        mainPanel.add(buttonPanel, BorderLayout.CENTER);
        frame.setSize(300, 300);
        //frame.pack();
        frame.setLocation(300, 300);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public void itemStateChanged(ItemEvent e){

        GameButton button = (GameButton) e.getItem();

        button.setState();
    }

    public void actionPerformed(ActionEvent e){
        GameButton button = (GameButton) e.getSource();

        if(button.isSelected()){
            buttoncounter++;

            if(buttoncounter==1){
                buttonFirst = (GameButton) e.getSource();
            }
            else if(buttoncounter==2){

                buttonSecond = (GameButton) e.getSource();
                buttoncounter=0;

                    if( checkPairs(buttonFirst,buttonSecond) ) {
                        retirePair(buttonFirst,buttonSecond);
                    }

                    else{   
                        timer.start();
                        falsePair(buttonFirst, buttonSecond);

                    }

            }

    }

    }

    class GameButton extends JToggleButton{

        private static final long serialVersionUID = 1L;
        private Icon icon;

        public GameButton(Icon icon){
            this.icon = icon;
        }

         public void setState() {
                if (this.isSelected() || !this.isEnabled()) {
                    this.setIcon(icon);
                }

                else {
                    this.setIcon(hidden);
                }
            }
        }

    private void retirePair(GameButton a, GameButton b){

        a.setSelected(true);
        a.setEnabled(false);
        b.setSelected(true);
        b.setEnabled(false);

    }

    private void falsePair(GameButton buttonFirst, GameButton buttonSecond){

        buttonFirst.setIcon(hidden);
        buttonFirst.setSelected(false);
        buttonSecond.setIcon(hidden);
        buttonSecond.setSelected(false);
    }

    private boolean checkPairs(GameButton first, GameButton second){
        if(first.getIcon().equals(second.getIcon()))
            return true;
        else
            return false;
    }

    private void createArray(){
        Random rnd = new Random();
        while(i<4){

            random = rnd.nextInt(3)+1;
            if(!includes(random)){
                arr[i]=random;
                iconList[i] = img[random-1];
                i++;
            }
        }
    }

    public boolean includes(int rnd){
        counter=0;
        for(j=0; j<arr.length; j++){

            if(arr[j] == rnd){
                counter++;
                if(counter>1)
                    return true;
            }
        }

        return false;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        new ConcentrationGame4();

    }

}
quartaela
  • 2,579
  • 16
  • 63
  • 99
  • Once again, as per people's reactions in http://stackoverflow.com/q/7910639/1005662 this is not sscce. This is a dump of code and a request for help. Please learn what a sscce is : http://sscce.org/ Also, this is almost a duplicate of the aforementioned stackoverflow link... – NickLH Oct 28 '11 at 19:00
  • yes but i deleted some unnecessary part the program. i mean i am not using my own icons,and not create lots of buttons (4 is minimum to understand it), so it is easy copy and compile for others. i mean i cant see more unnecessary codes in it. so what do you expect from me_? in generally i will create 20 buttons and they their own icons blablabla. and yes the subject is very similar to older one. but if you read and look to code carefully i made some changes and just want to know how timer works... – quartaela Oct 28 '11 at 19:09
  • It's not short, but it's at least self-contained and compilable. – JB Nizet Oct 28 '11 at 19:10
  • and i cant understand why people decreasing the rate_? is the reason for asking nearly same question before_? – quartaela Oct 28 '11 at 19:16
  • The Swing Timer is actually working properly -- i.e., it is only doing what you tell it to do. Your code has the bug, but I think that JB Nizet has identified the problem and provided the solution (1+) for this. – Hovercraft Full Of Eels Oct 28 '11 at 19:17

3 Answers3

6

An example of using a Swing Timer to pause action for xxx seconds:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class QuickTimerEg extends JPanel {
   private static final int TIMER_DELAY = 2000;
   private boolean buttonsWorking = true;
   private JButton btn1 = null;
   private JButton btn2 = null;
   private Timer swingTimer;

   public QuickTimerEg() {
      ActionListener btnListener = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            btnActionPerformed(e);
         }
      };
      setLayout(new GridLayout(4, 4));
      for (int i = 0; i < 4; i++) {
         for (int j = 0; j < 4; j++) {
            JButton button = new JButton("   ");
            button.addActionListener(btnListener);
            add(button);
         }
      }
   }

   private void btnActionPerformed(ActionEvent e) {
      if (!buttonsWorking) {
         return;
      }
      JButton button = (JButton)e.getSource();
      button.setBackground(Color.blue);
      button.setEnabled(false);
      if (btn1 == null) {
         btn1 = button;
      } else {
         buttonsWorking = false;
         btn2 = button;
         swingTimer = new Timer(TIMER_DELAY, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               btn1.setBackground(null);
               btn2.setBackground(null);
               btn1.setEnabled(true);
               btn2.setEnabled(true);
               btn1 = null;
               btn2 = null;
               buttonsWorking = true;               
            }
         });
         swingTimer.setRepeats(false);
         swingTimer.start();
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("QuickTimerEg");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new QuickTimerEg());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • i noticed that i must completely try to understand actionevents, cause i didnt know that we can use an actionlistener in an actionPerformed. so the thing is when an event is fired an actionlistener for that will handle with it, so what about the inner actionlistener. is it handles with the same event_? (and thanks a lot for helping cause i was stucked for days about this thing now it look more clear to understand) – quartaela Oct 28 '11 at 21:05
  • so simple like as Swing is +1 – mKorbel Oct 28 '11 at 21:16
5

I don't know what you want to do, but you pass this as argument to the Timer constructor. This means that every 2 seconds, the actionPerformed method of this (instance of ConcentrationGame4) will be called. And the first thing that this method does is

GameButton button = (GameButton) e.getSource();

Obviously, this will throw an exception, since the origin of the event won't be a game button, but the timer.

To understand what a Timer does and how it works, it's very simple. You just have to read its api doc : http://download.oracle.com/javase/6/docs/api/javax/swing/Timer.html. This doc will even lead you to a tutorial explaining how they work, with examples.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • i just thought that if i use `timer.start()` on below the `falsePair()` method it will stop for 2 seconds and after it, it will continue to its work – quartaela Oct 28 '11 at 19:17
  • No, that's not what a Timer does. Read the f** documentation. Thread.sleep does that, but if you do it in the event dispatch thread, the GUI will freeze for 2 seconds. – JB Nizet Oct 28 '11 at 19:19
  • well ok i admitted this is so stupid post so i am going to delete it. sorry for making you angry : ) – quartaela Oct 28 '11 at 19:22
  • You didn't make me angry. Half of the questions I answer here could be answered by just reading the documentation. I just hope you learnt something, and that you'll now take the habit of reading the doc. – JB Nizet Oct 28 '11 at 19:30
  • Don't delete this post or thread as it is not stupid in the least. And here I disagree with JB Nizet in that a Swing Timer *will* work for this, and in fact I've coded just such a thing. Just make it non-repeating. – Hovercraft Full Of Eels Oct 28 '11 at 20:19
  • @Hovercraft: timer.start() will not pause the current thread for two seconds and then continue. timer.start() will start a background thread which will fire an event after some time. Sure, the event listener could call the falsePair() method, but it's not the same thing as pausing the current thread and then continue. – JB Nizet Oct 28 '11 at 20:24
  • @JB Nizet: He doesn't need to or want to pause any thread. He's making a memory game and all he needs to do is show the pictures and make the buttons non-working while showing them. Please see my code "answer" to see what I mean. – Hovercraft Full Of Eels Oct 28 '11 at 20:32
  • I agree with that. The OP thought timer.start() would pause the current thread, like Thread.sleep() would do. I just said it didn't do that. I didn't say it couldn't be used to do what the OP wanted. – JB Nizet Oct 28 '11 at 20:40
  • OK, sorry for my misunderstanding. – Hovercraft Full Of Eels Oct 28 '11 at 21:14
5

As an aside, you might want to look at using List<Icon> and List<GameButton>. Such Collections are easy to shuffle in a reliable way. Also, note the difference between an individual GameButton and a collection of them, external to the GameButton class. It's the collection that you'll need to examine when any one button is clicked.

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.Timer;
import javax.swing.UIManager;

/** @see http://stackoverflow.com/questions/7933424 */
public class ButtonTimer extends JPanel {

    private List<Icon> list = new ArrayList<Icon>();
    private List<GameButton> buttons = new ArrayList<GameButton>();
    private Timer timer = new Timer(1000, new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            createPanel();
        }
    });

    public ButtonTimer() {
        this.setLayout(new GridLayout(1, 0));
        list.add(UIManager.getIcon("OptionPane.errorIcon"));
        list.add(UIManager.getIcon("OptionPane.informationIcon"));
        list.add(UIManager.getIcon("OptionPane.warningIcon"));
        list.add(UIManager.getIcon("OptionPane.questionIcon"));
        createPanel();
        timer.start();
    }

    private void createPanel() {
        Collections.shuffle(list);
        this.removeAll();
        for (Icon icon : list) {
            GameButton gb = new GameButton(icon);
            buttons.add(gb);
            this.add(gb);
        }
        this.revalidate();
    }

    class GameButton extends JToggleButton {

        private Icon icon;

        public GameButton(Icon icon) {
            super(icon);
            this.icon = icon;
        }
    }

    private void display() {
        JFrame f = new JFrame("ButtonTimer");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ButtonTimer().display();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • thanks this is a very good example for me – quartaela Oct 28 '11 at 23:11
  • 2
    Excellent. Don't be too discouraged; it's clear that you are working to adopt the suggestions you have received. When asking questions, let your example focus on a particular aspect of the problem, such as @Hovercraft's use of `Timer` of my use of `shuffle()`. It's a little more work to construct such an example, but the effort will prove valuable to you. – trashgod Oct 29 '11 at 04:05