Creating a new graphic object class

The procedure for creating a new graphic object class comprises stages for defining methods to deal with geometric properties and drawing and stages for making the object persistent.
This example creates the class ShadowEllipse . The complete source code of the ShadowEllipse example is available at <installdir> /jviews-framework810/codefragments/shadow-ellipse/src/ShadowEllipse.java.

Stage 1 - Creating the class

To create the class:
  1. Create a file named ShadowEllipse.java that defines the new class and the necessary overloaded methods. Not every method needs to be overloaded.
  2. Add the following statements at the beginning of your file:
    import ilog.views.*;
    import ilog.views.io.*;
    import ilog.views.graphic.*;
    import java.awt.*;
    import java.io.*;
    
    These statements allow you to use the basic, the input/output, and the graphic packages of the Rogue Wave JViews library.
  3. Define a class that inherits from the IlvGraphic class.
    This class has two colors: one for the ellipse and one for the shadow. It also defines the thickness of the shadow.
  4. Define the bounding rectangle of the object.
    For this, you add a member variable named drawrect of type IlvRect .
    import ilog.views.*;
    import ilog.views.io.*;
    import ilog.views.graphic.*;
    import java.awt.*;
    import java.io.*;
     
    /**
     * A shadow ellipse object. A graphic object defined by two
     * ellipses: The main ellipse and a second ellipse of the same
     * size underneath the first one that represents a shadow.
     */
    public class ShadowEllipse
    extends IlvGraphic
    {
      /**
       * The definition rectangle of the ellipse.
       * This rectangle is the bounding rectangle of the
       * graphic object.
       */
      protected final IlvRect drawrect = new IlvRect();
      /**
       * The color of the ellipse.
       */
      private Color  color = Color.blue;
      /** 
       * The color of the shadow.
       */
      private Color  shadowColor = Color.black;
      /**
       * The thickness of the shadow.
       */
      private int thickness = 5;
    

Stage 2 - Defining the Constructors

  • Define a constructor to create a new shadow ellipse. These constructors simply set the value of the definition rectangle or create a new ShadowEllipse from an existing ShadowEllipse instance:
      /**
       * Creates a new shadow ellipse.
       * @param rect the bounding rectangle of the shadow ellipse.
       */
      public ShadowEllipse(IlvRect rect)
      {
        super();
        // Stores the bounding rectangle of the object.
        drawrect.reshape(rect.x, rect.y, rect.width, rect.height);
      }
    
    /**
       * Creates an ellipse by copying another one.
       * @param source the object to copy.
       */
      public ShadowEllipse(ShadowEllipse source) 
      {
        // First call the superclass constructor 
        // that will copy the information of the superclass.
        super(source);
    
        // Copies the bounding rectangle.
        drawrect.reshape(source.drawrect.x, source.drawrect.y, 
    		     source.drawrect.width, source.drawrect.height);
        // Copies the color and the color of the shadow.
        setColor(source.getColor());
        setShadowColor(source.getShadowColor());
        // Copies the thickness
        setThickness(source.getThickness());
      }
    
    

Stage 3 - Overriding the draw Method

  • Draw the object by calling some of the primitive methods contained in the AWT Graphics class.
    /**
       * Draws the object.
       * Override the draw method to define the way the object will appear.
       * @param dst The AWT object that will perform the
       * drawing operations. 
       * @param t This parameter is the transformer used to draw the object.
       * This parameter may be a translation, a zoom or a rotation.
       * When the graphic object is drawn in a view (IlvManagerView),
       * this transformer is the transformer of the view.
       */
      public void draw(Graphics dst, IlvTransformer t)
      {
        // First copy the rectangle that defines the bounding
        // rectangle of the object so that it is not modified.
         
        IlvRect r = new IlvRect(drawrect);
         
        // To compute the bounding rectangle of the object in 
        // the view coordinate system, apply the transformer ’t’
        // to the definition rectangle.
        // The transformer may define a zoom, a translation or a rotation.
         
        // applyFlooris used so the resulting rectangle
        // is correctly projected for drawing in the view.
        // The object’s coordinate system is defined by ’float’ values
        // Need ’int’ values to be able to draw. applyFloor will
        // apply the transformation to ’r’ and then call Math.floor to
        // translate ’float’ values to ’int’ values.
        if (t != null) 
          t.applyFloor(r);
        else
          r.floor();
         
        // The variable ’r’ now contains the bounding rectangle
        // of the object in the view’s coordinate system ready to
        // draw in this rectangle. In this rectangle, two ellipses
        // are drawn: first the shadow ellipse on the bottom
        // right corner of the definition rectangle, then the main
        // ellipse on the top-left corner. Each ellipse will be of size
        // (r.width-thickness, r.height-thickness).
     
        int thick = thickness;
     
        // Computes a correct value for thickness.
        // Since the size of the ellipses should
        // be (r.width-thickness, r.height-thickness), need to
        // check that the thickness is not too big.
     
        if ((r.width <= thick) || (r.height <= thick))
          thick = (int)Math.min(r.width, r.height);
     
        // Sets the size of the ellipses.
        r.width  -= thick;
        r.height -= thick;
               
        // ’r’ now contains the bounding area of the main ellipse.
     
        // Computes a rectangle to draw the shadow.
        // Copy the variable ’r’, needed for the
        // second ellipse.
        IlvRect shadowRect = new IlvRect(r);
        shadowRect.translate(thick, thick);
     
        // Draws the shadow ellipse
        dst.setColor(getShadowColor());
        dst.fillArc((int)shadowRect.x, 
                    (int)shadowRect.y, 
                    (int)shadowRect.width, 
                    (int)shadowRect.height,
                    0, 360);
     
        // Draws the main ellipse.
        dst.setColor(getColor());
        dst.fillArc((int)r.x, 
                    (int)r.y, 
                    (int)r.width, 
                    (int)r.height,
                    0, 360);
      }
    
The method draw fills the two ellipses. The bounding rectangle, drawrect , actually covers both ellipses.
Note
 The AWT methods, such as fillArc , require all coordinates to be integers. In Rogue Wave JViews, however, the bounding box of a graphic object is defined by float values. To convert coordinates from float to int , use the applyFloor and floor methods of the IlvTransformer class. You must use the same technique to ensure that the other objects comply with the library.

Stage 4 - Overriding the boundingBox method

  • Define the method boundingBox to transform the bounding box. It creates a copy of the rectangle drawrect even if the transformer is null . This is so the returned rectangle can be modified by Rogue Wave JViews.
     /**
       * Computes the bounding rectangle of the graphic 
       * object when drawn with the specified transformer.
       */
      public IlvRect boundingBox(IlvTransformer t)
      {
        // First copy the definition rectangle
        // so that it is not modified.
        IlvRect rect = new IlvRect(drawrect);
        // Apply the transformer on the rectangle to
        // translate to the correct coordinate system.
        if (t != null) t.apply(rect);
        return rect;
      }
    

Stage 5 - Overriding the applyTransform method

  • Override the applyTransform method to apply a transformation to the shape of the ShadowEllipse rectangle.
     public void applyTransform(IlvTransformer t)
      {
        // This method is called by method such as IlvGraphic.move
        // IlvGraphic.rotate or IlvGraphic.scale to modify the
        // shape of the object. For example, when this method
        // is called from IlvGraphic.move, the parameter 't' is the
        // corresponding translation.
        // Simply need to apply the transformer to
        // the definition rectangle of the object.
        t.apply(drawrect);
      }
    

Stage 6 - Overriding the copy method

  • Override the copy method to call the ShadowEllipse copy constructor to make a new instance.
     /**
       * Copies the object.
       */
      public IlvGraphic copy()
      {
        // Simply call the copy constructor that is defined above.
        return new ShadowEllipse(this);
      }
    

Stage 7 - Defining accessors

  • Add public accessors to the graphic object. These accessors deal with thickness and color. They appear in bold type in the following code example.
      /** 
       * Changes the thickness of the shadow ellipse 
       * @param thickness the new thickness
       */ 
      public void setThickness(int thickness) 
      { 
        this.thickness = thickness; 
      } 
     
      /** 
       * Returns the thickness of the shadow ellipse 
       * @return the thickness of the object. 
       */ 
      public int getThickness() 
      { 
        return thickness; 
      } 
     
      /** 
       * Changes the color of the ellipse. 
       * @param color the new color. 
       */ 
      public void setColor(Color color) 
      { 
        this.color = color; 
      } 
     
      /** 
       * Returns the color of the shadow ellipse 
       * @return the color of the object. 
       */ 
      public Color getColor() 
      { 
        return color; 
      } 
     
      /** 
       * Changes the color of the shadow 
       * @param color the new color 
       */ 
      public void setShadowColor(Color color) 
      { 
        this.shadowColor = color; 
      } 
       
      /** 
       * Returns the color of the shadow 
       * @return the color of the shadow 
       */ 
      public Color getShadowColor() 
      { 
        return shadowColor; 
      }