Frosted Cupcake
Frosted Cupcake

Reputation: 1970

How does repaint() method behave inside an infinite for loop?

I have this code,

import java.awt.*;
import java.applet.*;
public class FirstApplet extends Applet 
{
    int len;
    char ch;
    String msg="Hello World ";
    public void init()
    {
        setBackground(Color.CYAN);
        setForeground(Color.WHITE);
    }
    public void start()
    {
        System.out.println("Inside Start");
        repaint();
    }
    public void paint(Graphics g)
    {
        System.out.println("Inside paint");
        g.drawString(msg,200,200);
    }
}

It outputs a CYAN coloured background with Hello World on it.And on the console(cmd),it outputs-

Inside Start

Inside paint

Now if I modify the code to this-

import java.awt.*;
import java.applet.*;
public class FirstApplet extends Applet 
{
    String msg="Hello World ";
    int len;
    char ch;
    public void init()
    {
        setBackground(Color.CYAN);
        setForeground(Color.WHITE);
    }
    public void start()
    {
        System.out.println("Inside Start");
        for(;;)
        {
            repaint();
        }
    }
    public void paint(Graphics g)
    {
        System.out.println("Inside paint");
        g.drawString(msg,200,200);
    }
}

It outputs a white coloured screen with no text on it,and on the console it just outputs-

Inside Start

I am unable to understand the output of second program,Although I am calling the repaint() inside the for loop every time yet why the colour of the applet window is not changing to CYAN colour and why its not printing "Inside paint" on the console?Can somebody please help me out.

Upvotes: 0

Views: 666

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

You're tying up the GUI's event thread with your infinite loop, so that although repaint() is being called, the GUI's event thread is unable to act on it. Consider using a Swing Timer or a background thread instead.

For example, and continuing with your 1890's Applet example:

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.*;

public class PaintEg extends Applet {
   String msg = "Hello World ";
   int len;
   char ch;

   public void init() {
      setBackground(Color.CYAN);
      setForeground(Color.WHITE);
   }

   public void start() {
      System.out.println("Inside Start");
      new Thread(new Runnable() {
         public void run() {
            for (;;) {
               repaint();
               try {
                  Thread.sleep(10);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         }
      }).start();
   }

   public void paint(Graphics g) {
      System.out.println("Inside paint");
      g.drawString(msg, 10, 20);
   }
}

Better maybe is a Swing example that uses a Swing Timer and performs basic animation:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class PaintEg2 extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 30;
   private String msg = "Hello World ";
   private int msgX = 0;
   private int msgY = 0;

   public PaintEg2() {
      setBackground(Color.CYAN);
      setForeground(Color.WHITE);
      setFont(new Font(Font.SANS_SERIF, Font.BOLD, 20));

      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawString(msg, msgX, msgY);
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         msgX++;
         msgY++;
         repaint();
      }
   }

   private static void createAndShowGui() {
      PaintEg2 mainPanel = new PaintEg2();

      JFrame frame = new JFrame("PaintEg2");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Note that in your code repaint() is being called and is being executed, but the paint manager is unable to act on this because it does so on the GUI's event thread. If the GUI's event thread is tied up, no painting can be done.

For more on how painting is done in Swing and AWT, please read Painting in AWT and Swing

Upvotes: 2

Related Questions