Skip to content

Java Inheritance: Paint Program only shows a black screen but doesn’t have any errors

I know its a lot of code but I could really use some help identifying my problem. Thank you!

I am just now being introduced to inheritance and am challenging myself with this application to a painting program. The program is meant to draw different shapes (lines, oval, rectangles, etc.) and I used trial and error to get what I have so far. I no longer am getting errors but the program only shows a black screen. Changing colors doesn’t seem to do anything so I think it has something to do with my color variable.

This is the main class:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.io.*;

class Main extends JFrame implements ActionListener 
{
    // the draw panel
    JPanel content;
    CustomPanel contentCustom;
    
    String filename = "";
    File file = null;
    
    // Menu Bar 
      JMenuBar bar;

    // file menu
    JMenu     fileMenu;
    JMenuItem openItem;
    JMenuItem saveItem;
    JMenuItem exitItem;
    
    // mode menu
    JMenu     modeMenu;
    JMenuItem lineItem;
    JMenuItem rectItem;
    JMenuItem ellipseItem;
    JMenuItem freeItem;
    
    // color menu
    JMenu     colorMenu;
    JMenuItem colorItem;
    
    public Main()
    {
        super("Paint - Line Mode   Color="+Color.BLUE );
        setSize(800, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // create the menu bar
        bar = new JMenuBar();
        
        // create the menus
        fileMenu = new JMenu("File");
        fileMenu.setMnemonic('F');    // Alt F 
        
        modeMenu = new JMenu("Mode");
        
        colorMenu = new JMenu("Color");

        // **** create the menu items
        // file menu items
        saveItem = new JMenuItem("Save");
        saveItem.setMnemonic('s');
        saveItem.addActionListener(this);

        openItem = new JMenuItem("Open");
        openItem.setMnemonic('o');
        openItem.addActionListener(this);

        exitItem = new JMenuItem("Exit");
        exitItem.setMnemonic('x');
        exitItem.addActionListener(this);
        
        // mode menu items
        lineItem = new JMenuItem("Line");
        lineItem.addActionListener(this);
        
        rectItem = new JMenuItem("Rectangle");
        rectItem.addActionListener(this);
        
        ellipseItem = new JMenuItem("Ellipse");
        ellipseItem.addActionListener(this);

        freeItem = new JMenuItem("Free Draw");
        freeItem.addActionListener(this);

        // color menu items
        colorItem = new JMenuItem("Color");
        colorItem.addActionListener(this);
        

        // **** add menu items to the menus
        // fileMenu
        fileMenu.add(openItem);
        fileMenu.add(saveItem);
        fileMenu.addSeparator();
        fileMenu.add(exitItem);
        
        // modeMenu
        modeMenu.add(lineItem);
        modeMenu.add(rectItem);
        modeMenu.add(ellipseItem);
        modeMenu.add(freeItem);
        
        // colorMenu
        colorMenu.add(colorItem);

        // **** add the menus to the bar
        bar.add(fileMenu);
        bar.add(modeMenu);
        bar.add(colorMenu);
        
        // **** set the bar to be the menu bar
        setJMenuBar(bar);
        
        // Container content = getContentPane(); replace this with our own
        content = new CustomPanel();
        contentCustom = (CustomPanel) content;
        
        FlowLayout lay = new FlowLayout(FlowLayout.LEFT);
        content.setLayout(lay);
 
            setContentPane(content);
        setVisible(true); // always do this last
    }
    
    public void actionPerformed(ActionEvent e)
    {
      Object source = e.getSource();
      
      if (source == exitItem) 
      {
       System.exit(0);
      }
      else if (source == lineItem)
      {
        contentCustom.setMyMode("Line");
        setTitle("Paint - " + ((CustomPanel) content).getMyMode() + " Mode   Color="+
                  ((CustomPanel) content).getColor()
                );
      }
      else if (source == rectItem)
      {
        ((CustomPanel) content).setMyMode("Rectangle");
        setTitle("Paint - " + ((CustomPanel) content).getMyMode() + " Mode   Color="+
                  ((CustomPanel) content).getColor()
                );
      }
      else if (source == ellipseItem)
      {
        ((CustomPanel) content).setMyMode("Ellipse");
        setTitle("Paint - " + ((CustomPanel) content).getMyMode() + " Mode   Color="+
                  ((CustomPanel) content).getColor()
                );
      }
      else if (source == freeItem)
      {
        ((CustomPanel) content).setMyMode("Free");
        setTitle("Paint - " + ((CustomPanel) content).getMyMode() + " Mode   Color="+
                  ((CustomPanel) content).getColor()
                );
      }
      else if (source == colorItem)
      {
        Color  color = Color.black;
        Color newColor = JColorChooser.showDialog(this,"Draw Color",color);
        if (newColor != null)
          ((CustomPanel) content).setColor(newColor);
        setTitle("Paint - " + ((CustomPanel) content).getMyMode() + " Mode   Color="+
                  ((CustomPanel) content).getColor()
                );
      }
      else if (source == saveItem)
      {
        try
        {
          JFileChooser fileChooser = null;
          int result = JFileChooser.APPROVE_OPTION;
          
          if (filename.equals(""))
          {
            fileChooser = new JFileChooser();
            result = fileChooser.showSaveDialog(this);              
          } 
          
          if (result == JFileChooser.APPROVE_OPTION)
          {
            if (filename.equals(""))
              {
              filename = fileChooser.getSelectedFile().getName();
              file = fileChooser.getSelectedFile();
              }
            // use contentCustom to reference the CustomPanel variables
            
            FileWriter fw=null;
            BufferedWriter bw=null;
            try
            {            
              fw = new FileWriter(file);
              bw = new BufferedWriter(fw);
            
              for (int j=0; j < contentCustom.myList.size(); j++)
              {
                AbstractShapeObject myShape =  contentCustom.myList.get(j);
                String outLine = myShape.toString();                               
                
                
                bw.write(outLine);
                bw.newLine();
              }
            }
            catch (Exception e1)
            {
            }
            finally
            { 
              try
              {                    
                bw.close();
              }
              catch (Exception e2)
              {
              }
            }
          }
          else if (result == JFileChooser.CANCEL_OPTION)
          {
          }
        }
        catch (Exception ee)
        {
        }
        
      }
      else if (source == openItem)
      {
        try
        {
          JFileChooser fileChooser = new JFileChooser();
          int result = fileChooser.showOpenDialog(this);
          if (result == JFileChooser.APPROVE_OPTION)
          {
            file = fileChooser.getSelectedFile();

            if (file != null)            
            {
            filename = fileChooser.getSelectedFile().getName();
            contentCustom.myList.clear();


            FileReader fr=null;
            BufferedReader br=null;
            try
            {            
              fr = new FileReader(file);
              br = new BufferedReader(fr);
            
              String s = br.readLine();
              while (s != null)
              {
              
                StringTokenizer st = new StringTokenizer(s,",");
                
                String mode = st.nextToken();
                
                if (mode.equals("Line"))
                {
                    int x1 = Integer.parseInt(st.nextToken());
                    int y1 = Integer.parseInt(st.nextToken());
                    int x2 = Integer.parseInt(st.nextToken());
                    int y2 = Integer.parseInt(st.nextToken());
                    int red = Integer.parseInt(st.nextToken());
                    int green = Integer.parseInt(st.nextToken());
                    int blue = Integer.parseInt(st.nextToken());
                    Color color = new Color(red,green,blue);
                    AbstractShapeObject myShape = new Line(x1,y1,x2,y2,color);
                    myShape.setMode("Line");
                    myShape.setKeep(true);                    
                    contentCustom.myList.add(myShape);                    
                }
                else if (mode.equals("Rectangle"))
                {
                    int x = Integer.parseInt(st.nextToken());
                    int y = Integer.parseInt(st.nextToken());
                    int width = Integer.parseInt(st.nextToken());
                    int height = Integer.parseInt(st.nextToken());
                    int red = Integer.parseInt(st.nextToken());
                    int green = Integer.parseInt(st.nextToken());
                    int blue = Integer.parseInt(st.nextToken());
                    Color color = new Color(red,green,blue);
                    AbstractShapeObject myShape = new Rectangle(x,y,width,height,color);
                    myShape.setMode("Rectangle");
                    myShape.setKeep(true);
                    contentCustom.myList.add(myShape);                    
                }
                else if (mode.equals("Ellipse"))
                {
                    int x = Integer.parseInt(st.nextToken());
                    int y = Integer.parseInt(st.nextToken());
                    int width = Integer.parseInt(st.nextToken());
                    int height = Integer.parseInt(st.nextToken());
                    int red = Integer.parseInt(st.nextToken());
                    int green = Integer.parseInt(st.nextToken());
                    int blue = Integer.parseInt(st.nextToken());
                    Color color = new Color(red,green,blue);
                    AbstractShapeObject myShape = new Ellipse(x,y,width,height,color);
                    myShape.setMode("Rectangle");
                    myShape.setKeep(true);
                    contentCustom.myList.add(myShape);                    
                }
              
                s = br.readLine();
              } // end of while loop
              
            contentCustom.repaint();
            }
            catch (Exception e1)
            {
            }
            finally
            { 
              try
              {                    
                br.close();
              }
              catch (Exception e2)
              {
              }
            }
                
            }
          }
          else if (result == JFileChooser.CANCEL_OPTION)
          {
          }
        }
        catch (Exception ee)
        {
        }
        
      }
      
    }
    
  public static void main(String[] args)
    {
        Main paint = new Main();        
    }
    
    
} // end of class Main

This is the the AbstractShapeObject Class:

public abstract class AbstractShapeObject implements ShapeInterface
{
    private int x;
    private int y;
    private int width;
    private int height;
    private Color color;
    private int thickness;
    private String mode;   // Am I a Rectangle, Line, etc.
    private boolean keep;  // do I keep the shape or erase it later

    public AbstractShapeObject() 
    {
        this(0,0,0,0,defaultThickness,defaultColor);
    }
 
    public AbstractShapeObject(int x, int y) 
    {
        this(x,y,defaultWidth,defaultHeight,defaultThickness,defaultColor);
    }

    public AbstractShapeObject(int x, int y, Color color) 
    {
        this(x,y,defaultWidth,defaultHeight,defaultThickness,color);
    }

    public AbstractShapeObject(int x, int y, int thickness) 
    {
        this(x,y,defaultWidth,defaultHeight,thickness,defaultColor);
    }

    public AbstractShapeObject(int x, int y, int thickness, Color color) 
    {
        this(x,y,defaultWidth,defaultHeight,thickness,color);
    }

    public AbstractShapeObject(int x, int y, int width, int height) 
    {
        this(x,y,width,height,defaultThickness,defaultColor);
    }
    
    public AbstractShapeObject(int x, int y, int width, int height, Color color) 
    {
        this(x,y,width,height,defaultThickness,color);// call this(?????)  (the constructor with all the parameters below)
    }

    public AbstractShapeObject(int x, int y, int width, int height, int thickness) 
    {
        this(x,y,width,height,thickness,defaultColor);// call this(?????)  (the constructor with all the parameters below)
    }

    public AbstractShapeObject(int x, int y, int width, int height, int thickness, Color color) 
    {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
        this.thickness = thickness;
        mode = "None";
        keep = true;
    }
        
    // write all of your getter and setter methods here !!!
    // do NOT write your draw methods here
    // you will write your draw methods in the specific classes
    // since you don't really know what to draw here
    
    
    public int getX()
    {
        return x; //change me
    }
    
    public void setX(int x)
    {this.x = x;
    }

    public int getY()
    {
        return y; //change me
    }
    
    public void setY(int y)
    {this.y = y;
    }

    public int getWidth()
    {
        return width; //change me
    }
    
    public void setWidth(int width)
    {this.width = width;
    }

    public int getHeight()
    {
        return height; //change me
    }
    
    public void setHeight(int height)
    {this.height = height;
    }

    public int getThickness()
    {
        return thickness; //change me
    }
    
    public void setThickness(int thickness)
    {this.thickness = thickness;
    }

    public Color getColor()
    {
        // ************* change this to ????? **************
        // What are you getting?
        return color; //change me!!!!!!!!!!
    }
    
    public void setColor(Color color)
    {this.color = color;
    }

    public String getMode()
    {
        return mode; // change me   
    }
    
    public void setMode(String mode)
    {this.mode = mode;
    }
    
    public boolean getKeep()
    {
        return keep; // change me
    }
    
    public void setKeep(boolean keep)
    {this.keep = keep;
    }



    // do NOT change this method
    public void calcXYWidthHeight(int x1, int y1, int x2, int y2)
    {
        int width = Math.abs(x2-x1);
        int height = Math.abs(y2-y1);
        
        // now I need to find my upper left corner point
        
        // find the x1 value
        if (x2 <= x1)
        { 
            x1 = x2;                    
        }           

        // find the y1 value
        if (y2 <= y1)  // they have dragged the mouse up
        {
            y1 = y2;
        }
        
        // now set the instance variables of the class
        setX(x1);
        setY(y1);
        setWidth(width);
        setHeight(height);
    }

} // end of class AbstractShapeObject

This is one of the shape classes I coded. All of them have the same format but this one is for drawing an ellipse:

import java.awt.*;
import java.awt.geom.*;

public class Ellipse extends AbstractShapeObject {

    public Ellipse(int x, int y, int width, int height) {
        super(x,y,width,height);
    }
    
    public Ellipse(int x, int y, int width, int height, Color color) {
        super(x,y,width,height,color);// call the appropriate super constructor
        
    }

    public Ellipse(int x, int y, int width, int height, int thickness) {
        super(x,y,width,height,thickness);// call the appropriate super constructor
        
    }

    public Ellipse(int x, int y, int width, int height, int thickness, Color color) {
        super(x,y,width,height,thickness,color);// call the appropriate super constructor
        
    }

    public void draw(Graphics window)
    {
        // first, set your draw color
        Color drawColor = window.getColor();
        window.setColor(drawColor);// window.????(????);
        
        // second, draw the shape (i.e. draw the ellipse or Oval)
    
        window.drawOval(getX(),getY(),getWidth(),getHeight());// window.????(????);
    }
    
    // write the toString() method
    // use the same format that is used for the Rectangle and Line classes
    public String toString()
    {
        return getMode() + "," + getX() + "," + getY() + "," + getWidth() + "," + getHeight() + "," 
                    + getColor().getRed() + "," + getColor().getGreen() + "," + getColor().getBlue();                 
    }
} // end of class Ellipse

This is the CustomPanel Class (this was provided to us so I don’t think its an error here):

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.image.BufferedImage;

    // this JPanel listens for the mouse events
 public class CustomPanel extends JPanel implements MouseListener, MouseMotionListener
    {
      // for buffering
      private BufferedImage back;
      
      ArrayList <AbstractShapeObject> myList  = new ArrayList<AbstractShapeObject>();
      String myMode     = "Line";  // None, Line, Rectangle, etc.
      Color  color = Color.blue;   // current draw color
      int    x1 = 0;
      int    y1 = 0;
      int    x2 = 0;
      int    y2 = 0;
      boolean drawing = false; // are we drawing with the mouse?
      
      public CustomPanel()
      {
        addMouseListener(this);
        addMouseMotionListener(this);
        setBackground(Color.red);        
      }
      
      public void setMyMode(String mode)
      {
        myMode = mode;
      }
      
      public String getMyMode()
      {
        return myMode;
      }

      public void setColor(Color color)
      {
        this.color = color;
      }      

      public Color getColor()
      {
        return color;
      }      

      public void removeTempShapes()
      {
            // get rid of temp objects
            for (int j=0; j < myList.size(); j++)
            {
                AbstractShapeObject myShape = myList.get(j);
                if (!myShape.getKeep())
                {
                    myList.remove(j);
                }
            }
      }
      
      public void update(Graphics window)
      {
          paintComponent(window);
      }
      
      public void paintComponent(Graphics window)
      {  
        super.paintComponent((Graphics2D)window);
        Graphics2D g2 = (Graphics2D) window;

        //take a snap shop of the current screen and same it as an image
        //that is the exact same width and height as the current screen
        back = (BufferedImage)(createImage(getWidth(),getHeight()));

        //create a graphics reference to the back ground image
        //we will draw all changes on the background image
        Graphics gMemory = back.createGraphics();

        // clear the screen
        gMemory.setColor(Color.BLACK);
        gMemory.fillRect(0,0,getWidth(),getHeight());
      
        // draw all the objects
        for (int j=0; j < myList.size(); j++)
        {
            AbstractShapeObject myShape = myList.get(j);
            myShape.draw(gMemory);
        }
      
        // *** show the screen by copying the image to the graphics display ********
        g2.drawImage(back, null, 0, 0); 
      }
    
    /* mouse motion events... */
    
    public void mouseMoved(MouseEvent event)
    { 
        // DO NOT DO ANYTHING HERE  
    }
    
    public void mouseDragged(MouseEvent event)
    {
      if (drawing)
      {
        if (myMode.equals("Line"))
        {
            x2 = event.getX();
            y2 = event.getY();
            // get rid of temp objects
            removeTempShapes();
            
            AbstractShapeObject myShape = new Line(x1,y1,x2,y2,color);
            myShape.setMode("Line");
            myShape.setKeep(false);
            myList.add(myShape);
            repaint();
        } // end of if (myMode.equals("Line"))
        else if (myMode.equals("Free"))
        {
            // update the from coordinates
            x1 = x2;
            y1 = y2;
            // get the draw to coordinates
            x2 = event.getX();
            y2 = event.getY();
            
            AbstractShapeObject myShape = new Line(x1,y1,x2,y2,color);
            myShape.setMode("Free");
            myShape.setKeep(true);
            myList.add(myShape);
            repaint();
        } // end of if (myMode.equals("Line"))
        
        else if (myMode.equals("Rectangle"))
        {
            // get the draw to coordinates (lower right)
            x2 = event.getX();
            y2 = event.getY();

            // get rid of temp objects
            removeTempShapes();
                        
            AbstractShapeObject myShape = new Rectangle(x1,y1,x2,y2,color);
            myShape.calcXYWidthHeight(x1,y1,x2,y2);
            myShape.setMode("Rectangle");
            myShape.setKeep(false);
            myList.add(myShape);
            repaint();
        } // end of if (myMode.equals("Line"))
        else if (myMode.equals("Ellipse"))
        {
            // get the draw to coordinates (lower right)
            x2 = event.getX();
            y2 = event.getY();

            // get rid of temp objects
            removeTempShapes();
                        
            AbstractShapeObject myShape = new Ellipse(x1,y1,x2,y2,color);
            myShape.calcXYWidthHeight(x1,y1,x2,y2);
            myShape.setMode("Ellipse");
            myShape.setKeep(false);
            myList.add(myShape);
            repaint();
        } // end of if (myMode.equals("Ellipse"))
        
      }  // end of if (drawing)
        
    }

    /* mouse events... */
    
    public void mouseClicked(MouseEvent event)
    {
        // DO NOT DO ANYTHING HERE
    }
    
    public void mousePressed(MouseEvent event)
    {
       drawing = true;
       // save the original coordinates
       x1 = event.getX();
       y1 = event.getY();
       // save where to draw to
       x2 = event.getX();
       y2 = event.getY(); 
    }
    
    public void mouseReleased(MouseEvent event)
    {
      if (drawing) 
      {
        if (myMode.equals("Line"))
        {
            // get rid of temp objects
            removeTempShapes();
            
            x2 = event.getX();
            y2 = event.getY();
            AbstractShapeObject myShape = new Line(x1,y1,x2,y2,color);
            myShape.setMode("Line");
            myShape.setKeep(true);
            myList.add(myShape);
        }            
        else if (myMode.equals("Free"))
        {
            // nothing to do since it has already been drawn
        }            
        else if (myMode.equals("Rectangle"))
        {
            // get rid of temp objects
            removeTempShapes();

            x2 = event.getX();
            y2 = event.getY();
            AbstractShapeObject myShape = new Rectangle(x1,y1,x2,y2,color);
            myShape.calcXYWidthHeight(x1,y1,x2,y2);
            myShape.setMode("Rectangle");
            myShape.setKeep(true);
            myList.add(myShape);
        }            
        else if (myMode.equals("Ellipse"))
        {
            // get rid of temp objects
            removeTempShapes();

            x2 = event.getX();
            y2 = event.getY();
            AbstractShapeObject myShape = new Ellipse(x1,y1,x2,y2,color);
            myShape.calcXYWidthHeight(x1,y1,x2,y2);
            myShape.setMode("Ellipse");
            myShape.setKeep(true);
            myList.add(myShape);
        }            
      drawing = false;
      repaint();
      } // end of if (drawing)
    } // end of mouseReleased
    
    public void mouseEntered(MouseEvent event)
    {
       // DO NOT DO ANYTHING HERE
    }
    
    public void mouseExited(MouseEvent event)
    {
       // DO NOT DO ANYTHING HERE        
    }
    
  } // end of class CustomPanel

This is the ShapeInterface class (This was also provided):

// DO NOT TOUCH THIS FILE
// THE INTERFACE HAS BEEN WRITTEN FOR YOU


import java.awt.Color;
import java.awt.*;

public interface ShapeInterface
{
    // all variables (constants) are public static final by default

    public int defaultWidth = 1;
    public int defaultHeight = 1;
    public int defaultThickness = 1;
    public Color defaultColor = Color.RED;
    
    // these methods are all public abstract by default
    public int getX();
    public void setX(int x);

    public int getY();
    public void setY(int y);

    public int getWidth();
    public void setWidth(int width);

    public int getHeight();
    public void setHeight(int height);

    public int getThickness();
    public void setThickness(int thickness);

    public Color getColor();
    public void setColor(Color color);

    public String getMode();
    public void setMode(String mode);
    
    public boolean getKeep();
    public void setKeep(boolean keep);

    public abstract void draw(Graphics window); 
} //end of interface ShapeInterface

Answer

I didn’t check all the code, but there is an error in Ellipse class, check my remarks

 public void draw(Graphics window)
    {
        //This is a nonsense, get the Color from the graphics and setting back the same color will do nothing
        Color drawColor = window.getColor();

        //Here you should set your own color, since when your code is called the Graphic's color is black
        //You have a color member variable in AbstractShape class, use it here
        window.setColor(drawColor);// window.????(????);
        
        // second, draw the shape (i.e. draw the ellipse or Oval)
    
        window.drawOval(getX(),getY(),getWidth(),getHeight());// window.????(????);
    }