As part of my programming assignment, I have to display a rotating fan in an applet.
Here is my code (class to display the fan):
import javax.swing.*;
import java.awt.*;
public class Fan extends JPanel
{
private int angle1 = -15;
private int angle2 = 75;
private int angle3 = 165;
private int angle4 = 255;
public Fan()
{
this.setSize(600, 400);
Runnable spinner = new SpinFan();
Thread thread1 = new Thread(spinner);
thread1.start();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(200, 150, 150, 150);
g.fillArc(210, 160, 130, 130, angle1, 30);
g.fillArc(210, 160, 130, 130, angle2, 30);
g.fillArc(210, 160, 130, 130, angle3, 30);
g.fillArc(210, 160, 130, 130, angle4, 30);
}
}
class SpinFan implements Runnable
{
@Override
public void run()
{
try
{
while(true)
{
angle1 = (angle1 + 1) % 360;
angle2 = (angle2 + 1) % 360;
angle3 = (angle3 + 1) % 360;
angle4 = (angle4 + 1) % 360;
System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);
repaint();
Thread.sleep(10);
}
}
catch(InterruptedException ex)
{
System.out.println("Problem while putting thread to sleep.");
}
}
}
Class for further processing (right now just has instance of Fan):
import java.awt.*;
import javax.swing.*;
public class FanControl extends JPanel
{
public FanControl()
{
add(new Fan());
}
}
And finally, here is the Applet class:
import java.awt.*;
import javax.swing.*;
public class FanApplet extends JApplet
{
public FanApplet()
{
add(new FanControl());
}
}
Now I've been trying all sorts of stuff for a long time so please don't mind the extra commented out code. The Fan.jav
a class works properly (I can see the fan spinning if I run it as an application by putting it in a frame). But I just can't get the fan to rotate in the Applet. However, if I add something like a JButton to the Applet from the Fan.java class, it works.
What am I missing out on? Is there some complications while using threads and applets, or paintComponent()
and applets that I don't seem to know.
When I run the code as an application, it WORKS fine. I can see the rotating fan. Here is the code for that:
import javax.swing.*;
import java.awt.*;
public class Fan extends JPanel
{
private int angle1 = -15;
private int angle2 = 75;
private int angle3 = 165;
private int angle4 = 255;
public Fan()
{
Runnable spinner = new SpinFan();
Thread thread1 = new Thread(spinner);
thread1.start();
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new Fan());
frame.setSize(600, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(200, 150, 150, 150);
g.fillArc(210, 160, 130, 130, angle1, 30);
g.fillArc(210, 160, 130, 130, angle2, 30);
g.fillArc(210, 160, 130, 130, angle3, 30);
g.fillArc(210, 160, 130, 130, angle4, 30);
}
class SpinFan implements Runnable
{
@Override
public void run()
{
try
{
while(true)
{
angle1 = (angle1 - 1) % 360;
angle2 = (angle2 - 1) % 360;
angle3 = (angle3 - 1) % 360;
angle4 = (angle4 - 1) % 360;
System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);
repaint();
Thread.sleep(10);
}
}
catch(InterruptedException ex)
{
System.out.println("Problem while putting thread to sleep.");
}
}
}
}
while(true) .. repaint(); .. Thread.sleep(10);
This is entirely the wrong way to go about animation.
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Instead of calling Thread.sleep(n)
implement a Swing Timer
for repeating tasks or a SwingWorker
for long running tasks. See Concurrency in Swing for more details.
The following source uses the Thread
defined in code but puts the GUI updates back on the EDT.
But the real problem here is that the animation component was being added to the applet at size 0x0. By changing the layout of the parent container to BorderLayout
, we can stretch it to fit the available space.
E.G.
import java.awt.*;
import javax.swing.*;
public class FanApplet extends JApplet
{
private int angle1 = -15;
private int angle2 = 75;
private int angle3 = 165;
private int angle4 = 255;
public FanApplet()
{
add(new FanControl());
}
class FanControl extends JPanel
{
public FanControl()
{
// by setting a BorderLayout and adding a component to the CENTER
// (default if no constraint specified) the child component will
// be stretched to fill the available space.
setLayout(new BorderLayout());
add(new Fan());
}
}
class Fan extends JPanel
{
public Fan()
{
//this.setSize(600, 400);
Runnable spinner = new SpinFan();
Thread thread1 = new Thread(spinner);
thread1.start();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(200, 150, 150, 150);
g.fillArc(210, 160, 130, 130, angle1, 30);
g.fillArc(210, 160, 130, 130, angle2, 30);
g.fillArc(210, 160, 130, 130, angle3, 30);
g.fillArc(210, 160, 130, 130, angle4, 30);
}
}
class SpinFan implements Runnable
{
@Override
public void run()
{
try
{
while(true)
{
angle1 = (angle1 + 1) % 360;
angle2 = (angle2 + 1) % 360;
angle3 = (angle3 + 1) % 360;
angle4 = (angle4 + 1) % 360;
System.out.println(angle1 + " " + angle2 + " " + angle3 + " " + angle4);
// This ensures that repaint() is called on the EDT.
Runnable r = new Runnable() {
public void run() {
repaint();
}
};
SwingUtilities.invokeLater(r);
Thread.sleep(10);
}
}
catch(InterruptedException ex)
{
System.out.println("Problem while putting thread to sleep.");
}
}
}
}