Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

An inside view of Observer

The Observer pattern facilitates communication between decoupled objects

  • Print
  • Feedback

Page 5 of 6

Figure 5a. Proxy begins loading image

Figure 5b. Proxy finishes loading image and fires a property change event

Figure 5c. Listener reacts to the property change and displays a dialog box

The application, shown in Figures 5a, 5b, and 5c, is listed in Example 5:

Example 5. Observe a proxy object

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.util.ArrayList;
// This class tests a virtual proxy, which is a proxy that
// delays loading an expensive resource (an icon) until that
// resource is needed.
public class VirtualProxyTest extends JFrame {
   private static String IMAGE_NAME = "mandrill.jpg";
   private static int IMAGE_WIDTH = 256, IMAGE_HEIGHT = 256,
                          SPACING = 5,        FRAME_X = 150,
                          FRAME_Y = 200, FRAME_WIDTH = 530, 
                          FRAME_HEIGHT = 286;
   private Icon imageIcon = null, imageIconProxy = null;
   static public void main(String args[]) {
      VirtualProxyTest app = new VirtualProxyTest();
      app.show();
   }
   public VirtualProxyTest() {
      super("Virtual Proxy Test");
      // Create an image icon and an image icon proxy.
      imageIcon = new ImageIcon(IMAGE_NAME);
      imageIconProxy = new ImageIconProxy(IMAGE_NAME,
                                          IMAGE_WIDTH, 
                                          IMAGE_HEIGHT);
            ((ImageIconProxy)imageIconProxy).addPropertyChangeListener(
                  new PropertyChangeListener() {
                  public void propertyChange(PropertyChangeEvent e) {
      JOptionPane.showMessageDialog(VirtualProxyTest.this,"Image Loaded");
                  }
            });
      // Set the bounds of the frame and the frame's default.
      // Close operation.
      setBounds(FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }
   public void paint(Graphics g) {
      super.paint(g);
      Insets insets = getInsets();
      imageIcon.paintIcon(this, g, insets.left, insets.top);
      imageIconProxy.paintIcon(this, g, 
               insets.left + IMAGE_WIDTH + SPACING, // width
               insets.top); // height
   }
}
// ImageIconProxy is a proxy (or surrogate) for an icon.
// The proxy delays loading the image until the first time the
// image is drawn. While the icon is loading its image, the
// proxy draws a border and the message "Loading image...".
//
// This version of the ImageIconProxy class makes the real icon a bound
// property: when the property changes, ImageIconProxy fires a
// PropertyChangeEvent to all interested property change listeners.
class ImageIconProxy implements javax.swing.Icon {
      private ArrayList propertyChangeListeners = new ArrayList();
   private Icon realIcon = null;
   private boolean isIconCreated = false;
   private String  imageName;
   private int     width, height;
   public ImageIconProxy(String imageName, int width, int height){
      this.imageName = imageName;
      this.width = width;
      this.height = height;
   }
   public int getIconHeight() {
      return realIcon == null ? height : realIcon.getIconHeight(); 
   }
   public int getIconWidth() {
      return realIcon == null ? width : realIcon.getIconWidth(); 
   }
   // The proxy's paint method is overloaded to draw a border
   // and a message ("Loading image...") while the image is
   // loaded. After the image is loaded, it is drawn. Notice
   // that the proxy does not load the image until it is
   // actually needed.
   public void paintIcon(final Component c, 
                               Graphics g, int x, int y) {
      if(isIconCreated) {
         realIcon.paintIcon(c, g, x, y);
      }
      else {
         g.drawRect(x, y, width-1, height-1);
         g.drawString("Loading image...", x+20, y+20);
         // The image is loaded via a Runnable passed to
         // SwingUtilties.invokeLater(), which means that
         // it is executed on another thread. 
                  synchronized(this) {
            SwingUtilities.invokeLater(new Runnable() {
                  public void run() {
                  try {
                        // Slow the image-loading process.
                        Thread.currentThread().sleep(2000);
                        // ImageIcon constructor creates the image.
                        realIcon = new ImageIcon(imageName);
                        isIconCreated = true;
                  }
                  catch(InterruptedException ex) {
                        ex.printStackTrace();
                  }
                  c.repaint();
                  notifyPropertyChangeListeners();
                  }
            });
         }
      }
   }
      public void addPropertyChangeListener(
              PropertyChangeListener listener) {
            propertyChangeListeners.add(listener);
      }
      private void notifyPropertyChangeListeners() {
            for(int i=0; i < propertyChangeListeners.size(); ++i) {
                  PropertyChangeListener listener = (PropertyChangeListener)
        propertyChangeListeners.get(i);
                  listener.propertyChange(null);
            }
      }
}


As you can see from Example 5, it's not difficult to make an existing class a property change event source; at a minimum, you have to:

  • Print
  • Feedback

Resources