1

I am trying to make a Java application which on Clicking a button, displays random colors in the Panel for a particular time duration.

But my problem is that after clicking the button the color of the frame changes only once and also the the title of the Button doesn't changes to "U Clicked me".

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

class MyDrawPanel extends JPanel {

    @Override
    public void paintComponent(Graphics g) {
        // g.fillRect(0, 0, this.getWidth(), this.getHeight())
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        Color randomizecolor = new Color(red, green, blue);
        g.setColor(randomizecolor);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
    }
}

public class CustomWidget implements ActionListener {

    JButton button;
    JFrame frame;

    public void Gui() {
        frame = new JFrame();
        MyDrawPanel pan = new MyDrawPanel();
        button = new JButton("-- Click Me to Change Me --");
        frame.add(BorderLayout.SOUTH, button);
        frame.add(BorderLayout.CENTER, pan);
        button.addActionListener(this);
        frame.setSize(500, 500);
        frame.setTitle("Random Color GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public void asd() {
        button.setText("U clicked Me");
        for (int i = 0; i < 150; i++) {
            frame.repaint();
            try {
                Thread.sleep(10);
            } catch (Exception x) {
            }
        }
        button.setText("Again Click me");
    }

    public static void main(String[] args) {
        CustomWidget obj = new CustomWidget();
        obj.Gui();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        this.asd();
        // this.button.setText("-- Click Me to Change Me --");
    }
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
Snehasish
  • 1,051
  • 5
  • 20
  • 37
  • possible duplicate of [using sleep() for a single thread](http://stackoverflow.com/questions/14074329/using-sleep-for-a-single-thread) – David Kroukamp Feb 03 '13 at 18:48

1 Answers1

4

Don't call Thread.sleep(...) on the Swing event thread as all this does is put the entire GUI to sleep including its ability to paint. Instead use a Swing Timer. Check the link for the tutorial. Incidentally, 10 ms is awfully short and may be too short for time slices or for folks to notice. Also, I'd randomize and create the new Color in the Swing Timer's ActionListener and not in the paintComponent(...) method itself.

Edit:
Note that Swing uses a single thread, the Event Dispatch Thread or EDT, to update all graphics and to do all user interactions. If you put this thread to sleep by calling Thread.sleep(...) or by calling a long-running bit of code on this thread, then the entire Swing application will go to sleep, and no user interactions or Swing drawing will occur until the sleep ends. The key to a solution is to do all long-running tasks on a background thread. The Swing Timer will do this for you, and the tutorial will show you how.

Edit 2:
in semi-pseudocode:

  button.setText(BTN_CLICKED_TEXT);
  // TIMER_DELAY is some constant int
  Timer myTimer = new Timer(TIMER_DELAY, new ActionListener() {
     private int count = 0;

     @Override
     public void actionPerformed(ActionEvent timerActionEvt) {
        if the count variable is >= some maximum count
          // stop the timer by calling stop on it
          // I'll show you this one since it is a bit complex
          ((Timer)timerActionEvt.getSource()).stop();
          // set the button text to its original state
          // return from this method

        else 
          // randomize pan's color and repaint it
          count++; // increment the counter variable
     }
  });

  myTimer.start();

Note that the pan variable must be declared in the Gui class, not in its constructor for the Timer to be able to get to it.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • 1
    very good advice. However, the OP's code runs on the main thread apparently. Which brings us to: Run Swing code on EDT (!!) – Radu Murzea Feb 03 '13 at 18:49
  • I tried increasing the sleep time but no change at all.. I am fairly new to Java... So I am unable to understand what's the fault.. – Snehasish Feb 03 '13 at 18:54
  • Swing Timer won't cause the execution of the code to run on a different thread, just the waiting to be done on a different thread. If he wants the execution to be done on a different thread he should use Swing Worker. That said the explanation above is probably all that is needed, just wanted to clarify. – sage88 Feb 03 '13 at 19:10
  • @sage88: The Swing Timer will cause the timer portion of the code, the equivalent to the `Thread.sleep(...)` to be run on a different thread. But you're right, the code in the ActionListener will be called on the Swing event thread. – Hovercraft Full Of Eels Feb 04 '13 at 03:27