CPSC 225, Spring 2010
Lab 9: Designing a Graphics Program


The lab this week will get you started on a GUI programming project. You will continue to work on it in some future labs. The project will let you do some GUI programming as well as do some work with files and possibly networking. More important, perhaps, it will require you to develop several classes, and it should help you to understand what I mean when I say that your final project should use at least four classes. (Really, I want you to think about how to think about your final project.)

There are no starting files for this class. You are on your own. However, GUI programs that you have worked on in the past can serve as examples. Any program that opens a window on the screen would do. For example, you could use OSCDemo, which was written to help you with Lab 7, as a model. You might want to start with a copy of that program, or at least use some code from it.

The program that you create should allow the user to place things in a drawing area. "Things" should include at least text, pictures, and basic shapes such as rectangles and ovals. Although we won't be able to do everything in the labs, in the long run, it would be nice to have a program that lets the user:

To make things more definite, you might think of a program that lets the user design greeting cards that can be printed out and mailed or "e-cards" that can be sent in email.

For this lab, there are two major goals: Create the basic framework of the GUI program. And start designing a set of classes to represent the items that can be added to the drawing.

This lab is due next Thursday, at the start of next week's lab. The programming part of the lab should be copied into your homework folder in /classes/s10/cs225/homework. The written part of the lab can be handed in on paper, emailed to me, or included in the programming project that you submit.

(This project is designed as an individual project. But if you would like to work with a partner on it, you should discuss that possibility with me.)


The GUI Framework

The project requires a GUI window with a "drawing area". You should define a main class that extends JPanel. The panel will be the drawing area. Add a constructor to the class. Don't forget to set a preferred size for the panel. Add a paintComponent() method. To start, it can simply call super.paintComponent(g).

You will also need a main program, which can be in the JPanel class or in a separate class. The main program should create a window of type JFrame, set the content pane to be a panel created from your class, and show the window on the screen. Make sure that you can run the program and see the window. All this is very standard, and you can look at old programs such as OSCDemo for examples. You should not spend much time getting it working. However, you should make sure that you understand everything that you are doing. If there are parts of the program that you don't understand, ask about them.

Your program will need a menu bar. For a relatively simple program like this one, a reasonable way to handle the menu bar is to provide a method in the main class to create the menu bar. To implement the menu commands, you will need an ActionListener. Again there are many ways to do this; one way is to add a nested class to define the ActionListener. Add the following class and method to your main class:

      private class MenuHandler implements ActionListener {
          public void actionPerformed(ActionEvent evt) {
             String cmd = evt.getActionCommand();
             if (cmd.equals("New")) {
                 System.out.println("New command selected.");
             }
          }
      }

      public JMenuBar createMenuBar() {
          MenuHandler listener = new MenuHandler();
          JMenuBar menuBar = new JMenuBar();
          
          JMenu fileMenu = new JMenu("File");
          menuBar.add(fileMenu);               
          
          JMenuItem newCommand = new JMenuItem("New");
          newCommand.addActionListener(listener);
          fileMenu.add(newCommand);

          return menuBar;
      }

The main() routine has to create the menu bar and add it to the window. If window is the JFrame, and panel is the panel that was made from your main class, then you can do this by adding the following lines to main():

      JMenuBar mb = panel.createMenuBar();
      window.setJMenuBar(mb);

Do this, and make sure that the menu bar appears in your program and is functional (that is, selecting the "New" command prints a message in the Console). Again, if you don't understand anything here, ask about it.


As an exercise in working with menus, let's add a menu command that will allow the user to set the background color of the drawing. The background color of a panel is set by calling setBackground(color). The current background color can be checked by calling getBackground(), which returns a value of type Color. To let the user input a color, you can write a changeBackground() method:

       private void changeBackground() {
          Color oldColor = getBackground();
          Color newColor = JColorChooser.showDialog( this,
                                     "Select New Background", oldColor );
          if (newColor != null)
              setBackground(newColor);
       }

JColorChooser.showDialog opens a color chooser dialog where the user can select a color. The value of oldColor becomes the initial value in the dialog. If the user cancels the dialog, then the return value is null. Otherwise the return value is the color selected by the user.

Add a new menu to the menu bar, named "Control". Add a menu item to the Control menu named "Set Background...". Add some code to the MenuHandler class to cover the case of "if (cmd.equals("Set Background...")).


Designing Classes

Your program will let the user add items of various types to the drawing. To represent the different types of items, it is natural to use different classes. To represent the fact that all the items can be drawn on the screen, all of those classes should be subclasses of a single abstract class. (Alternatively, they could all implement an interface.)

Add a class to represent "drawable items" to your project. The class should be in its own file, not nested. Consider putting it in its own package and using that package to hold all the drawable item classes.

      import java.awt.Graphics;
      
      public abstract class Drawable {
          public abstract void draw(Graphics g);
      }

You need to design a subclass of Drawable to represent each kind of item that can be added to a drawing. Each subclass will have to implement the draw() method, and it will also have variables and methods of its own. You might, as you develop your ideas, find that there should be additional abstract methods in the Drawable class. You might find that there are some properties that are common to all the classes and therefore belong in Drawable. (Hint: Every drawable object will at least have a location.)

Before trying to write all the classes, you should design them. For the written part of this lab, think about the classes that you will need to represent drawable items. Write a paragraph or two explaining exactly what you envision the program as doing and how your classes will make it possible to implement the design. Describe each class, with a brief description of the class and a list the variables and methods that it contains. You do not have to implement the classes at this point


Getting Started

To get started, add a Rectangle class to your project. The Rectangle class should extend Drawable. It will need instance variables to record the position, size, and color of the rectangle, and a draw() method that draws the rectangle based on the information in its instance variables.

Add a instance variable of type ArrayList<Drawable> to your main class. This variable will hold all the items that have been added to the drawing. For testing purposes only, create a couple of Rectangle objects and add them to the list.

Add code to the paintComponent() method to draw all the items in the arraylist. Test your program! Make sure that it draws all the rectangles that you expect.

Also, you can implement the "New" command. It should delete everything from the list of items, and it should reset the background color to the default.

Of course, we want the user to be able to add rectangles to the drawing (as well as other things). Your project will need a "mouse handler" object to handle mouse input from the user. One way to make a mouse handler is with a nested class:

      private class MouseHandler implements MouseListener, MouseMotionListener {
      
         public void mousePressed(MouseEvent evt) {
         }
        
         public void mouseReleased(MouseEvent evt) {
         }
        
         public void mouseDragged(MouseEvent evt) {
         }
        
         public void mouseClicked(MouseEvent evt) { }
         public void mouseEntered(MouseEvent evt) { }
         public void mouseExited(MouseEvent evt) { }
         public void mouseMoved(MouseEvent evt) { }
      }

You will need to create an object of this class and add that object to your main panel as a MouseListener and as a MouseMotionListener.

For now, program the mousePressed() method to add a rectangle at the point where the user pressed the mouse (given by x = evt.getX(), y = evt.getY()). You can just make up a size for the rectangle. Test it!

Finally for this week, give the user control over the color of the rectangle that is added. To implement this, you need a currentColor instance variable. When a rectangle is added to the drawing, its color is set equal to the current color. There will have to be a menu command that allows the user to change the current color. This command will not have any visible affect on the drawing; it changes the color that will be used for new rectangles in the future.

You should think about where we might go with this project. What kind of user interface would you really like to use for adding rectangles? How about text? How will the user input the text? How will the user add pictures? Where will they come from? And what about editing items that are already there, by moving them or changing their properties? How can we store information about the drawing in a file? What menu commands will the program need? What else should the program do?


David Eck, for CPSC 225