Friday 14 September 2012

Very Basic Java Graphics: 3 Examples

We're going to build up a graphics app from something so basic it doesn't really work, like the example from Java Graphics--Start with a JFrame and building to something more sophisticated. In the JFrame article and in A Most Basic Graphics App I've avoided the use of comments in the code to keep it shorter. In these examples I'm going to include comments in the code to describe what's happening. So don't be scared of the length of these examples, most of what's there is just comments, which Java ignores. They're there just for humans.

/* BasicFrame.java

  This is a really simple graphics program.
  It opens a frame on the screen with a single
  line drawn across it.

  It's not very polished, but it demonstrates
  a graphical program as simply as possible.mag-27Apr2008
*/

// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;

public class BasicFrame extends JFrame{

  // Create a constructor method
  public BasicFrame(){
    // All we do is call JFrame's constructor.
    // We don't need anything special for this
    // program.
    super();
  }

  // The following methods are instance methods.
  /* Create a paint() method to override the one in JFrame.
     This is where the drawing happens. 
     We don't have to call it in our program, it gets called
     automatically whenever the frame needs to be redrawn,
     like when it it made visible or moved or whatever.*/
  public void paint(Graphics g){
    g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
  }

  public static void main(String arg[]){
    // create an identifier named 'window' and
    // apply it to a new BasicFrame object
    // created using our constructor, above.
    BasicFrame frame = new BasicFrame();

    // Use the setSize method that our BasicFrame
    // object inherited to make the frame
    // 200 pixels wide and high.
    frame.setSize(200,200);

    // Make the window show on the screen.
    frame.setVisible(true);
  }
}

This example draws a line on the JFrame. The window decorations take up some of our drawing space, so the title bar may cover some of our line. With some JVMs the background area of the JFrame won't be cleared before you draw. Also, when you close the window using the close button, the application doesn't shut down. For many applications on Mac OS X this is normal behavior, but on other OSes, and even many applications under OS X it's normal to expect an application to close down completely if you click the close button on the last open window (for applications that have multiple windows) or the close button on the main window for other applications.

So here's our next example, where we take care of that last problem:

/* CloseFrame.java
  This is a really simple graphics program.
  It opens a frame on the screen with a single
  line drawn across it.

  We're starting to add a little bit of polish
  here--we make the program close nicely when
  the close box is clicked, rather than just
  sort of hanging around half-dead.
  mag-28Apr2008
*/

// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;

public class CloseFrame extends JFrame{

  // Create a constructor method
  public CloseFrame(){
    // All we do is call JFrame's constructor.
    // We don't need anything special for this.
    super();
  }

  // The following methods are instance methods.

  /* Create a paint() method to override the one in JFrame.
     This is where the drawing happens.
     We don't have to call it in our program, 
     it gets called automatically whenever the 
     frame needs to be redrawn, like when it is 
     made visible or moved or whatever.
  */
  public void paint(Graphics g){
    g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
  }

  public static void main(String arg[]){
    BasicFrame frame = new BasicFrame();
    // This uses a constant EXIT_ON_CLOSE that's a member of JFrame.
    // The constant is passed to the setDefaultCloseOperation method
    // of our frame object, which is a CloseFrame object,
    // which inherits the method from its parent JFrame.
    // It makes the program exit (close completely) when we click
    // the close button.
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200,200);frame.setVisible(true);
  }
}

The magic line that makes the application exit when we click the close button is the one that reads: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. We can tell that EXIT_ON_CLOSE is a type of variable called a "constant" because the name follows the convention of being written in all capital letters. So we're not YELLING when we say "EXIT_ON_CLOSE" we're using the value stored in EXIT_ON_CLOSE as part of the JFrame class.
A JFrame has this constant available because it implements the interface WindowConstants. By implementing this interface, in essence, the JFrame class of objects promise to do the right thing if one of these constants is passed to a method that handles it, in this case setDefaultCloseOperation.

Our final example for this entry goes one big step further:

/* BasicJPanel.java
  This is a somewhat more sophisticated drawing program.
  It uses a new child of JPanel as the drawing surface
  for a JFrame, to avoid the problems with drawing
  directly on a JFrame.

  A custom JPanel child class called BasicJPanel is created
  with its own paintComponent method, which contains our
  drawing code.
 
  A generic JFrame is then created to hold the BasicJPanel
  object, the BasicJPanel is created, made into the JPanel's
  content pane, and our paintComponent method is called
  automatically. *Whew!*
  mag-28Apr2008
*/

// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;

public class BasicJPanel extends JPanel{

  // Create a constructor method
  public BasicJPanel(){
    super();
  }

  // The following methods are instance methods.

  /* Create a paintComponent() method to override the one in
    JPanel.This is where the drawing happens. We don't have 
    to call it in our program, it gets called automatically 
    whenever the panel needs to be redrawn, like when it is 
    made visible or moved or whatever.
  */
  public void paintComponent(Graphics g){
    g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
  }

  public static void main(String arg[]){
    JFrame frame = new JFrame("BasicJPanel");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200,200);

    // Create a new identifier for a BasicJPanel called "panel",
    // then create a new BasicJPanel object for it to refer to.
    BasicJPanel panel = new BasicJPanel();

    // Make the panel object the content pane of the JFrame.
    // This puts it into the drawable area of frame, and now
    // we do all our drawing to panel, using paintComponent(), above.
    frame.setContentPane(panel);
    frame.setVisible(true);
  }
}

Here, we've added a JPanel inside the drawable area of our JFrame. This means that if we start drawing at 0,0 we'll actually be drawing somewhere we can see it, it won't be hidden by the window decorations.

The other big change is the change of our drawing method's name from paint() to paintComponent(). This is because we changed from a JFrame to a JPanel. If you take a look at JPanel in the API Specification you'll see that it extends JComponent. This family of objects uses paintComponent() to manage drawing.

This last example is a good starting point for any graphical operation. In future examples, I'll be extending it further to add additional features.

0 comments:

Post a Comment