cms6204
asked on
Assigning appletContext to an applet
I have been working on making an applet that runs other applets. Everything works with most applets, but an applet which uses the getGraphics() method returns a null pointer exception. I believe, as someone suggested, I just need to assign the parent appletContext to the instance of the applet, but for some reason I have not been able to get that to work. This is essentially the part of the code I use to instantiate and run an applet:
the_frame = new Frame();
the_app.init();
the_frame.add(the_app);
the_frame.setSize(width,he ight);
the_frame.show();
the_app.start();
Exactly how can I can assign appletContext to this, and do I need to do any extra implements, import, or extends commands for my class? Will this allow me to use getGraphics() with the applets it runs?
Thanks a lot.
the_frame = new Frame();
the_app.init();
the_frame.add(the_app);
the_frame.setSize(width,he
the_frame.show();
the_app.start();
Exactly how can I can assign appletContext to this, and do I need to do any extra implements, import, or extends commands for my class? Will this allow me to use getGraphics() with the applets it runs?
Thanks a lot.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
"getGraphics returns null" is probably because applet peer is not created / initialized at the moment (so your applet don't have associated Graphics object). you probably must create Applet, add it to Frame, show it (peers are created) and then call its init method ... (just a quick suggestion)
and when exactly getGraphics() returns null. Give us the stacktrace (+ the source code of the "bad applet")
ASKER
Here is the method which runs the applets. In the real version, the applets are in a linked list so that we can intercept each one's windowClosing message and destroy them when the user clicks on the close box (multiple applets can be run at once), but I have made it simpler here. As it is coded below, it correctly runs any applet (that we have tested) that does not call getGraphics(), but when an applet does call getGraphics(), it gives the following errors (Bouncing_Ball2 code is at end of this comment):
java.lang.NullPointerExcep tion
at Ball.draw_ball(Bouncing_Ba ll2.java:1 01)
at Ball.bounce(Bouncing_Ball2 .java:109)
at Bouncing_Ball2.star(Bounci ng_Ball2.j ava:21) atAppletViewDynamicBeta2.r unApp (AppletViewDynamicBeta2.ja va:332)
at AppletViewDynamicBeta2.act ionPerform ed(Compile d Code)
as well as errors in java.awt
public void runApp(){
boolean appletFound=true;
Applet app = new Applet();
try {
Class c = Class.forName(app_to_run);
app = (Applet) Class.forName(app_to_run). newInstanc e();
} // end of try
// if no applet class can be instantiated, assign an error
// message and return to user-input paint method
catch (Exception e) {
error = "No applet with this name found.";
appletFound=false;
repaint();
} // end of catch
if (appletFound) {
Frame fr=new Frame();
app.init();
fr.add(app);
fr.setSize(width,height);
fr.show();
app.start();
} // end of if
// be processed
} // end of runApp()
If I move the app.init() line to between fr.show() and app.start(), it gives no errors with either program, but components, such as buttons and textfields, will either not appear or not work. Thanks a lot for your help. If you can help, I may accept msmolyak's answer, but I can post a "dummie" question for you so you can get some points for your efforts. Here is Bouncing_Ball2 (it is threaded):
import java.applet.Applet;
import java.awt.*;
public class Bouncing_Ball2 extends Applet {
private final int SIZE = 300;
private Ball ball = new Ball(150, 10, 250, 200);
private Graphics page;
private Control_Panel controls;
public void init() {
setVisible(true);
setSize(SIZE,SIZE);
page = getGraphics();
page.setXORMode(getBackgro und());
}
public void start() {
controls = new Control_Panel(Thread.curre ntThread() );
controls.start();
ball.pause();
while(ball.moving()) {
ball.bounce(page);
}
}
}
class Control_Panel extends Thread {
private Button suspend = new Button("suspend");
private Button resume = new Button("resume");
private Frame frame = new Frame("Bouncing Ball Control Panel");
private Thread applet_thread;
Control_Panel(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void run() {
Resume_Action resume_action = new Resume_Action(applet_threa d);
Suspend_Action suspend_action = new Suspend_Action(applet_thre ad);
suspend.addActionListener( suspend_ac tion);
resume.addActionListener(r esume_acti on);
frame.setLayout(new FlowLayout());
frame.add(suspend);
frame.add(resume);
frame.pack();
frame.setLocation(250, 200);
frame.setVisible(true);
}
}
class Suspend_Action implements ActionListener {
Thread applet_thread;
Suspend_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven t action) {
applet_thread.suspend();
}
}
class Resume_Action implements ActionListener {
Thread applet_thread;
Resume_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven t action) {
applet_thread.resume();
}
}
class Ball {
private final int MOVE = 2;
private final float DISTANCE = 0.97f;
private final int SIZE = 20;
private final int PAUSE = 5;
private int x;
private int start_y;
private int end_y;
private int length;
private boolean moving_up = true;
Ball(int new_x, int new_start_y, int new_end_y, int new_length) {
x = new_x;
start_y = new_start_y;
end_y = new_end_y;
length = new_length;
}
public void pause() {
try {
Thread.currentThread().sle ep(PAUSE);
}
catch (InterruptedException exception) {
System.out.println("have an exception");
}
}
void move() {
if (moving_up) {
end_y = end_y - MOVE;
}
else {
end_y = end_y + MOVE;
}
}
void draw_ball (Graphics page) {
page.drawOval (x-(SIZE/2), end_y, SIZE, SIZE);
page.drawLine (x, start_y, x, end_y);
}
public boolean moving() {
return length != 0;
}
public void bounce(Graphics page) {
for (int count = 1; count < length; count+=MOVE) {
draw_ball(page);
pause();
draw_ball(page);
move();
}
moving_up = !moving_up;
length = (int) (DISTANCE * length);
}
}
java.lang.NullPointerExcep
at Ball.draw_ball(Bouncing_Ba
at Ball.bounce(Bouncing_Ball2
at Bouncing_Ball2.star(Bounci
at AppletViewDynamicBeta2.act
as well as errors in java.awt
public void runApp(){
boolean appletFound=true;
Applet app = new Applet();
try {
Class c = Class.forName(app_to_run);
app = (Applet) Class.forName(app_to_run).
} // end of try
// if no applet class can be instantiated, assign an error
// message and return to user-input paint method
catch (Exception e) {
error = "No applet with this name found.";
appletFound=false;
repaint();
} // end of catch
if (appletFound) {
Frame fr=new Frame();
app.init();
fr.add(app);
fr.setSize(width,height);
fr.show();
app.start();
} // end of if
// be processed
} // end of runApp()
If I move the app.init() line to between fr.show() and app.start(), it gives no errors with either program, but components, such as buttons and textfields, will either not appear or not work. Thanks a lot for your help. If you can help, I may accept msmolyak's answer, but I can post a "dummie" question for you so you can get some points for your efforts. Here is Bouncing_Ball2 (it is threaded):
import java.applet.Applet;
import java.awt.*;
public class Bouncing_Ball2 extends Applet {
private final int SIZE = 300;
private Ball ball = new Ball(150, 10, 250, 200);
private Graphics page;
private Control_Panel controls;
public void init() {
setVisible(true);
setSize(SIZE,SIZE);
page = getGraphics();
page.setXORMode(getBackgro
}
public void start() {
controls = new Control_Panel(Thread.curre
controls.start();
ball.pause();
while(ball.moving()) {
ball.bounce(page);
}
}
}
class Control_Panel extends Thread {
private Button suspend = new Button("suspend");
private Button resume = new Button("resume");
private Frame frame = new Frame("Bouncing Ball Control Panel");
private Thread applet_thread;
Control_Panel(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void run() {
Resume_Action resume_action = new Resume_Action(applet_threa
Suspend_Action suspend_action = new Suspend_Action(applet_thre
suspend.addActionListener(
resume.addActionListener(r
frame.setLayout(new FlowLayout());
frame.add(suspend);
frame.add(resume);
frame.pack();
frame.setLocation(250, 200);
frame.setVisible(true);
}
}
class Suspend_Action implements ActionListener {
Thread applet_thread;
Suspend_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven
applet_thread.suspend();
}
}
class Resume_Action implements ActionListener {
Thread applet_thread;
Resume_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven
applet_thread.resume();
}
}
class Ball {
private final int MOVE = 2;
private final float DISTANCE = 0.97f;
private final int SIZE = 20;
private final int PAUSE = 5;
private int x;
private int start_y;
private int end_y;
private int length;
private boolean moving_up = true;
Ball(int new_x, int new_start_y, int new_end_y, int new_length) {
x = new_x;
start_y = new_start_y;
end_y = new_end_y;
length = new_length;
}
public void pause() {
try {
Thread.currentThread().sle
}
catch (InterruptedException exception) {
System.out.println("have an exception");
}
}
void move() {
if (moving_up) {
end_y = end_y - MOVE;
}
else {
end_y = end_y + MOVE;
}
}
void draw_ball (Graphics page) {
page.drawOval (x-(SIZE/2), end_y, SIZE, SIZE);
page.drawLine (x, start_y, x, end_y);
}
public boolean moving() {
return length != 0;
}
public void bounce(Graphics page) {
for (int count = 1; count < length; count+=MOVE) {
draw_ball(page);
pause();
draw_ball(page);
move();
}
moving_up = !moving_up;
length = (int) (DISTANCE * length);
}
}
/*
the real answer is - you don't have problems with the "visualizator" applet,
but with applets that use getGraphics, because THEY DON'T BEHAVE properly !!!
so this is not an AppletContext problem, but a Graphics one.
*/
/*
getGraphics is a pretty tricky method and applets (and all other java components) are not supposed to use it at all
(you can search through java.* sources and see that NOBODY, NOWHERE uses this method directly !!!)
applets are supposed to draw themselves only in their update / paint methods (and there they receive the appropriate Graphics object as method invocation parameter)
i think that
- (for your own applets) you should always NOT use getGraphics. you should make the appropriate change, call repaint and
JVM will call your paint method with the appropriate Graphics object.
- (for your own applets) you should always use SAFE coding - for example
public void paint(Graphics g)
{
if (g == null) return; // paranoia :)
if (img == null) return; // safe !!
g.drawImage(img);
}
- using getGraphics() will probably bring many refresh problems. for example suspend your ball, and bring some other Frame in front of the applet window. when you move this window, Ball will not repaint itself !!!
- from the docs
public void paint(Graphics g)
Paints this component. This method is called when the contents of the component should be
painted in response to the component first being shown or damage needing repair. The clip
rectangle in the Graphics parameter will be set to the area which needs to be painted.
public Graphics getGraphics()
Creates a graphics context for this component. This method will return null if this component
is currently not on the screen.
so you will receive graphics object only after you've already showed your component
(that is - when the native peer is already created)
look at the source of getGraphics method
public Graphics getGraphics() {
if (peer instanceof java.awt.peer.LightweightP
// This is for a lightweight component, need to
// translate coordinate spaces and clip relative
// to the parent.
Graphics g = parent.getGraphics();
g.translate(x,y);
g.setClip(0, 0, width, height);
g.setFont(getFont());
return g;
} else {
ComponentPeer peer = this.peer;
return (peer != null) ? peer.getGraphics() : null;
}
}
Summary:
1.) never use .getGraphics method and never KEEP the returned Graphics object !!! (this is a really bad practice)
2.) if you really need this to work with this "VERY BAD behaved applet", you certainty need to call the fr.show()
method before app.init() method (so that all the peer objects are created and you have the peer Graphics)
3.) i'm posting modified version of the applet code that paints itself only in its paint method. it works in appletviewer and it should work in your frame too
hope this helps
heyhey
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class Bouncing_Ball2 extends Applet {
private final int SIZE = 300;
private Ball ball = new Ball(150, 10, 250, 200);
// private Graphics page;
private Control_Panel controls;
public void init() {
setVisible(true);
setSize(SIZE,SIZE);
// page = getGraphics();
// page.setXORMode(getBackgro
}
public void paint(Graphics g) {
//controls = new Control_Panel(Thread.curre
ball.draw_ball(g);
}
public void start() {
controls = new Control_Panel(Thread.curre
controls.start();
ball.pause();
while(ball.moving()) {
ball.bounce();
}
}
class Control_Panel extends Thread {
private Button suspend = new Button("suspend");
private Button resume = new Button("resume");
private Frame frame = new Frame("Bouncing Ball Control Panel");
private Thread applet_thread;
Control_Panel(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void run() {
Resume_Action resume_action = new Resume_Action(applet_threa
Suspend_Action suspend_action = new Suspend_Action(applet_thre
suspend.addActionListener(
resume.addActionListener(r
frame.setLayout(new FlowLayout());
frame.add(suspend);
frame.add(resume);
frame.pack();
frame.setLocation(250, 200);
frame.setVisible(true);
}
}
class Suspend_Action implements ActionListener {
Thread applet_thread;
Suspend_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven
applet_thread.suspend();
}
}
class Resume_Action implements ActionListener {
Thread applet_thread;
Resume_Action(Thread applet_thread) {
this.applet_thread = applet_thread;
}
public void actionPerformed(ActionEven
applet_thread.resume();
}
}
class Ball {
private final int MOVE = 2;
private final float DISTANCE = 0.97f;
private final int SIZE = 20;
private final int PAUSE = 5;
private int x;
private int start_y;
private int end_y;
private int length;
private boolean moving_up = true;
Ball(int new_x, int new_start_y, int new_end_y, int new_length) {
x = new_x;
start_y = new_start_y;
end_y = new_end_y;
length = new_length;
}
public void pause() {
try {
Thread.currentThread().sle
}
catch (InterruptedException exception) {
System.out.println("have an exception");
}
}
void move() {
if (moving_up) {
end_y = end_y - MOVE;
}
else {
end_y = end_y + MOVE;
}
}
void draw_ball (Graphics page) {
page.drawOval (x-(SIZE/2), end_y, SIZE, SIZE);
page.drawLine (x, start_y, x, end_y);
}
public boolean moving() {
return length != 0;
}
public void bounce() {
for (int count = 1; count < length; count+=MOVE) {
//draw_ball(page);
repaint();
pause();
//draw_ball(page);
repaint();
move();
}
moving_up = !moving_up;
length = (int) (DISTANCE * length);
}
}
}
ASKER
Thanks for your help heyhey_; I think I have everything working the way it needs to now. I'm posting another "dummie" question for you to answer so I can give you some of the points you deserve for helping me with your comments on this one. It's titled "AppletViewer (for heyhey_)".
ASKER
msmolyak, sorry it took me so long to respond; I wanted to keep my question active for a while because I also got a lot of valuable help from someone else's comments. I think I have everything working as it needs to now. Thanks.