Snehasish
Snehasish

Reputation: 1073

frame.repaint() not working properly

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 --");
    }
}

Upvotes: 1

Views: 377

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285450

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.

Upvotes: 4

Related Questions