Creating Object-Oriented Graphics


It is best to read these notes after the object modeling lecture. They might not make sense if you read them beforehand.
These notes provide a nice design example for creating a simple hierarchy of graphical objects. You will flesh out this design in a homework assignment.


Principles

  1. To draw an object on the screen, you create an instance of the object and register it with a canvas object
  2. Objects have settable properties, such as location, size, color, visibility
  3. Objects have draw methods that handle the graphics context and render the object
  4. You can use container objects to organize related groups of objects
  5. You can associate layout managers with container objects
  6. You can associate a display manager with a canvas object

Inheritance Hierarchy

  AbstractShape implements Shape (these are drawable shapes):
     BoxShape
       EllipseShape, ImageShape, RectangleShape, TextShape
     LineShape
       ArrowShape

  ContainerShape: Holds groups of Shape objects
  CanvasShape: The object that provides a surface on which Shapes are drawn

  Shape Interface: 
    draw(Graphics2D): renders the object using the given Graphics2D context
    contains(x,y): indicates whether or not the object contains the given
      (x,y) point
    getBounds: returns the bounding box for this object

    Example draw routine for a TextShape:
      public void draw(Graphics2D g) {
        if (visible) {
          if (filled) { // fill a box behind the TextShape
	    g.setColor(fillColor);
	    // width and height may require a special calculation
            g.fillRect(left, top, getWidth(), getHeight());
          }
          g.setColor(lineColor);
          g.setFont(font);

          FontMetrics fm = g.getFontMetrics();
          g.drawString(text, left, top + fm.getAscent());
      }

Shape Classes

AbstractShape

AbstractShape is the abstract base class for all silhouette shapes
    Subclasses: BoxShape, LineShape
    Defined properties
      visible
      parent
      lineColor
      fillColor
      Filled: whether or not the object is filled or transparent
    There is no location or size attributes because rectangular objects and
      line objects represent this information differently
    Line objects might not have a fill color but arrowlines might, so it
	is okay to have the fillColor property defined for line objects

BoxShape

  BoxShape
    Subclasses: EllipseShape, ImageShape, RectangleShape,
      TextShape
    Defined properties
      left, top
      width, height

LineShape

  LineShape
    Subclasses: ArrowLineShape
    Defined properties
      x1, y1
      x2, y2

ContainerShape

A ContainerShape serves two purposes:

  1. group a loosely related set of objects for layout purposes
  2. group a tightly related set of objects that should be treated as a single entity (e.g., a labeled rectangle)
  ContainerShape: container object--uses a BoxShape for composition. Does not
	want to provide an interface that allows the setting of line or fill
	properties, so it cannot be a subclass of BoxShape
    Defined properties
      shapes: list of shapes for this container
      layoutManager: the layout manager for this container
    New methods
      add: adds an object to the container
      bringToFront/sendToBack: brings an object to the front of the container
	or sends it to the back, so that it is covered by the other objects
	in the container
      getShapes: returns a list of the shapes in this container, ordered from
	back to front (i.e., the first items in the list should be in back and
	the last items should be in front)
      get/setLayoutManager
      revalidate: asks the layout manager to re-layout the objects in
	the container

       public void draw(Graphics2D g) {
         for each shape in getShapes() {
           shape.draw(g);
         }
       }

CanvasShape

   CanvasShape: creates a JPanel that can be added to a Java container
     Superclass: JPanel
     Uses a ContainerShape for composition, since a CanvasShape is essentially
	a container object. It will delegate the add, getShapes, and
	BringToFront/SendToBack methods to the container while ignoring the
	layout methods, since it will be communicating with a display manager
	instead
	
     Methods
         paintComponent(Graphics g) {
	   super.paintComponent(g);
           for each shape in getShapes() {
             shape.draw(g);
	   } 
         }