2

if you add a jpanel instance to the content pane, the paintComponent method is called, right?

content_pane.add (fDrawingPanel);

so why would you call "repaint" at the first line in the run() method? (it says "to paint the loading message, but it should already be painted, because paintComponent was called before, and once fShow is true, we don't set it back to false, so this code is, i think, supposed to be called once ) :

public class MediaTrackApplet extends JApplet
                       implements Runnable
{
  // Need a reference to the panel for the
  // thread loop.
  DrawingPanel fDrawingPanel;

  // Parameters to track the image
  MediaTracker fTracker;
  Image fImg;
  int fImageNum = 0;
  boolean fShow = false;
  String fMessage ="Loading...";

  /** Use a MediaTracker to load an image.**/
  public void init () {
    Container content_pane = getContentPane ();

    // Create an instance of DrawingPanel
    fDrawingPanel = new DrawingPanel (this);

    // Add the DrawingPanel to the contentPane.
    content_pane.add (fDrawingPanel);

    // Get image and monitor its loading.
    fImg = getImage (getCodeBase (), "m20.gif.jpg" );
    fTracker = new MediaTracker (this);

    // Pass the image reference and an ID number.
    fTracker.addImage (fImg, fImageNum);
  } // init

  /** If the image not yet loaded, run the thread
    * so the run() will monitor the image loading.
   **/
  public void start () {
    if (!fTracker.checkID (fImageNum) ) {
        Thread thread = new Thread (this);
        thread.start ();
    } else
        // Unloading/reloading web page can will leave
        // checkID true but fShow will be false.
        fShow = true;
  } // start

  /** Use a thread to wait for the image to load 
    * before painting it.
   **/
  public void run ()  {
    // Paint the loading message
    repaint ();
    // The wait for the image to finish loading
    try {
      fTracker.waitForID (fImageNum );
    } catch (InterruptedException e) {}

    // Check if there was a loading error
    if (fTracker.isErrorID (fImageNum ))
        fMessage= "Error";
    else
        fShow = true;
    // Repaint with the image now if it loaded OK
    repaint ();
  } // run

}// class MediaTrackApplet


/** This JPanel subclass draws an image on the panel if
  * the image is loaded. Otherwise, it draws a text message.
 **/
class DrawingPanel extends JPanel {
  MediaTrackApplet parent = null;

  DrawingPanel (MediaTrackApplet parent) {
    this.parent = parent;
  }// ctor

  public void paintComponent (Graphics g) {
    super.paintComponent (g);

    // Add your drawing instructions here
    if (parent.fShow)
        g.drawImage (parent.fImg,10,10,this);
    else
        g.drawString (parent.fMessage, 10,10);
  } // paintComponent

} // class DrawingPanel

Thanks

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Paul
  • 6,108
  • 14
  • 72
  • 128
  • Why not try to comment the repaint line and try to run it and see the results instead of asking a question here? – Adel Boutros Feb 02 '12 at 23:50
  • Or, if you're using an IDE you can set a breakpoint in the painting code and run it in debug mode – Tom Feb 03 '12 at 00:07
  • 2
    Most of that code has become redundant since the introduction of the `ImageIO` class. It blocks while loading images, so the `MediaTracker` is not needed. – Andrew Thompson Feb 03 '12 at 00:07
  • See also [Initial Threads](http://download.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). – trashgod Feb 03 '12 at 00:45
  • thanks guys for your answers, @Andrew Thompson Andrew can you tell me more about this? @trashgod are you referring to the `EDT` ? paintComponent already paints the component, so i dont know why we call `repaint` do you have any idea? @MadcoreTom thanks, i've never done that, can you tell more about it? and will it tell me "why" we call repaint there? – Paul Feb 03 '12 at 01:12
  • *"can you tell me more about this?"* Sure, but I'm not about to write a treatise on the subject. Do you have a specific question? – Andrew Thompson Feb 03 '12 at 01:19
  • @Andrew Thompson i did not understand "what" blocks the loading of the images? the mediaTracker? also what method would you use instead of addImage? is `ImageIcon`a better way to do it? – Paul Feb 03 '12 at 02:01
  • 2
    The method [`Applet.getImage(URL)`](http://docs.oracle.com/javase/7/docs/api/java/applet/Applet.html#getImage%28java.net.URL%29) is asynchronous (**not** blocking) so a `MediaTracker` is required to check on the loading of the image. The `ImageIO.read(File/URL/InputStream)` **does** block. By the time the method finishes, it either returns a valid, complete image or throws an `Exception`. Hence an image loaded by `ImageIO` needs no tracker. `ImageIcon` has it's own media tracker I believe, but don't create one if you don't need an `ImageIcon` - just use `ImageIO` instead. – Andrew Thompson Feb 03 '12 at 02:19
  • @Andrew Thompson : okay, so i should (always?) use `ImageIO.read()` in a separate thread? and do you know about the redondant `repaint` method in this code? – Paul Feb 03 '12 at 03:23

1 Answers1

2

Are you referring to the EDT?

Yes. This venerable, but superannuated, example hails from an era that predates our modern understanding that Swing GUI objects should be constructed and manipulated only on the event dispatch thread. The initial invocation of repaint() has the effect of posting a new Runnable on the EventQueue, while allowing the background thread to finish loading images in anticipation of the subsequent repaint(). See also Memory Consistency Properties and this related example.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • But `paintComponent` already paints the graphics in the `EDT`, doesn't it? in the code, we add the loading text by default when we add the panel into the content pane, then : the first repaint is called to load (again) the loading message (this is what i don't understand : this double call to paintComponent before loading the images), and only then: we're loading the images with `waitForID` . – Paul Feb 03 '12 at 01:52
  • The example is incorrectly synchronized, and it should be deprecated. It looks like it was _supposed_ to show the "Loading" message while the image loaded and subsequently paint the image or an error message. – trashgod Feb 03 '12 at 02:03
  • mmh okay, so i thought i did not understand the meaning of the first repaint, but it looks like it's not mandatory : i can only use the second repaint in the `run()` method right? – Paul Feb 03 '12 at 03:25
  • No; at a minimum, there's a data race on `fShow`. The run time behavior of this program may vary from one machine to another. @Andrew Thompson's comments suggest a more reliable approach. If you need to load images in the background, use `SwingWorker`. – trashgod Feb 03 '12 at 11:43