Link to home
Start Free TrialLog in
Avatar of cms6204
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,height);
  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
Avatar of msmolyak
msmolyak

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of heyhey_
heyhey_

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

Avatar of cms6204

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.NullPointerException
     at Ball.draw_ball(Bouncing_Ball2.java:101)
     at Ball.bounce(Bouncing_Ball2.java:109)
     at Bouncing_Ball2.star(Bouncing_Ball2.java:21)              atAppletViewDynamicBeta2.runApp                                         (AppletViewDynamicBeta2.java:332)
     at AppletViewDynamicBeta2.actionPerformed(Compiled 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).newInstance();
      } // 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(getBackground());
  }
  public void start() {
    controls = new Control_Panel(Thread.currentThread());
    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_thread);
    Suspend_Action suspend_action = new Suspend_Action(applet_thread);
    suspend.addActionListener(suspend_action);
    resume.addActionListener(resume_action);
    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(ActionEvent 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(ActionEvent 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().sleep(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);
  }
}





 /*
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.LightweightPeer) {
          // 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(getBackground());
   }

   public void paint(Graphics g) {

     //controls = new Control_Panel(Thread.currentThread());
       ball.draw_ball(g);


       }


   public void start() {
     controls = new Control_Panel(Thread.currentThread());
     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_thread);
     Suspend_Action suspend_action = new Suspend_Action(applet_thread);
     suspend.addActionListener(suspend_action);
     resume.addActionListener(resume_action);
     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(ActionEvent 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(ActionEvent 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().sleep(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() {
     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);
   }
 }
 }

Avatar of cms6204

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_)".  
Avatar of cms6204

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.