Skip to content Skip to navigation Skip to collection information

Connexions

You are here: Home » Content » Object-Oriented Programming (OOP) with Java » Java OOP: A Pixel Color Editor

Navigation

Table of Contents

Recently Viewed

This feature requires Javascript to be enabled.
 

Java OOP: A Pixel Color Editor

Module by: Richard Baldwin. E-mail the author

Summary: Learn how to write an editor program that you can use to modify the colors in an image on a pixel-by-pixel basis.

Preface

This module is one of a series of modules designed to teach you about Object-Oriented Programming (OOP) using Java.

The program described in this module requires the use of the Guzdial-Ericson multimedia class library. You will find download, installation, and usage instructions for the library at Java OOP: The Guzdial-Ericson Multimedia Class Library .

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

  • Figure 1 . Program output at startup.
  • Figure 2 . Program output after zooming the image.
  • Figure 3 . Program output after changing the pixel color to yellow.

Listings

Preview

In this module, you will learn how to write an editor program that you can use to modify the colors in an image on a pixel-by-pixel basis.

Such a program could be useful, for example, for manually correcting "red eye" problems in digital images.

Program output at startup

Figure 1 shows the program output at startup.

The output consists of

  • an Ericson PictureExplorer object displaying an image of a penguin, and
  • a color manipulation GUI similar to those discussed in earlier modules.

Figure 1: Program output at startup.
Program output at startup.
Missing image.

Program output after zooming the image

Figure 2 shows the program output after placing the PictureExplorer cursor on the penguin's nose, and zooming the PictureExplorer image by 500%

If you look carefully, you should be able to see the crosshair cursor on the penguin's nose.

Figure 2: Program output after zooming the image.
Program output after zooming the image.
Missing image.

Program output after changing the pixel color to yellow

Figure 3 shows the result of selecting the color yellow with the GUI, and clicking the button labeled Update Pixel Color

If you look carefully, you should see that the pixel next to the crosshair cursor on the penguin's nose has changed from black to yellow.

Figure 3: Program output after changing the pixel color to yellow.
Program output after changing the pixel color to yellow.
Missing image.

Discussion and sample code

This program requires modifications to Ericson's PictureExplorer class. I will deal with that issue first.

A complete listing of the modified version of the PictureExplorer class is shown in Listing 10 .

Changes to Ericson's PictureExplorer class

The PictureExplorer class was modified to add getter methods to cause the following values to be accessible from outside the object:

  • int xIndex
  • int yIndex
  • double zoomFactor
  • JFrame pictureFrame

Also the call to the setDefaultCloseOperation method was disabled.

Code for methods that were added

Listing 1 shows the code for the methods that were added to the PictureExplorer class.

Listing 1: Code for methods that were added.

  //Method to get the xIndex value.
  public int getXIndex(){
    return xIndex;
  }//end getXIndex

  //Method to get the yIndex value.
  public int getYIndex(){
    return yIndex;
  }//end getYIndex

  //Method to get the zoomFactor value.
  public double getZoomFactor(){
    return zoomFactor;
  }//end getZoomFactor

  //Method to get a reference to the frame
  public JFrame getFrame(){
    return pictureFrame;
  }//end getFrame()

Modified setDefaultCloseOperation method

Listing 2 shows the modified version of the setDefaultCloseOperation method.

Note the parameter that is passed to the method when it is called.

Listing 2: Modified setDefaultCloseOperation method.

explorerFrame.setDefaultCloseOperation(
               WindowConstants.DO_NOTHING_ON_CLOSE);

Similar to previous code

Much of the code in this program is similar to code that I explained in earlier modules, and I won't repeat those explanations.

I will skip down to the event handler registered on the button labeled Update Pixel Color in Figure 1 . That code begins in Listing 3 .

Listing 3: Beginning of ActionListener registered on update button.

    updateButton.addActionListener(
      new ActionListener(){
        public void actionPerformed(ActionEvent e){

          //Get properties of PictureExplorer object.
          xIndex = explorer.getXIndex();
          yIndex = explorer.getYIndex();
          zoomFactor = explorer.getZoomFactor();

Important to preserve properties

The only thing that changes when you click the update button is the color of the pixel at the crosshair cursor.

Therefore, the program must preserve the state of the explorer object including such items as the zoom factor and the location of crosshair cursor.

Listing 3 gets and saves the property values that determine the state of the explorer object.

Convert zoom factor to String

The getZoomFactor method returns the zoom factor as type double . However, we need the zoom factor as type String . The code in Listing 4 converts the zoom factor to type String .

Listing 4: Convert zoom factor to type String.

          //Save zoom factor as a string.
          String zoomString = "100%";
          if(zoomFactor == 0.25){
            zoomString = "25%";
          }else if(zoomFactor == 0.50){
            zoomString = "50%";
          }else if(zoomFactor == 0.75){
            zoomString = "75%";
          }else if(zoomFactor == 1.0){
            zoomString = "100%";
          }else if(zoomFactor == 1.5){
            zoomString = "150%";
          }else if(zoomFactor == 2.0){
            zoomString = "200%";
          }else if(zoomFactor == 5.0){
            zoomString = "500%";
          }else{
            zoomString = "100%";//in case no match
          }//end else

Set pixel color in original image

The code in Listing 5

  • creates a new Color object based on the values in the text fields of Figure 3 , and
  • changes the color of the corresponding pixel in the original image to the new color.

At this point, the color of the pixel in the original image has been modified.

Listing 5: Set pixel color in original image.

          Color newColor = new Color(
                                 redInt,greenInt,blueInt);
          pix.getPixel(xIndex,yIndex).setColor(newColor);

Create and populate a new PictureExplorer object

Listing 6 begins by disposing of the original PictureExplorer object. Then Listing 6 creates a new PictureExplorer object containing the modified image.

Finally Listing 6 calls the setDefaultCloseOperation on the JFrame that houses the PictureExplorer object disabling the X-button in the upper-right corner.

Listing 6: Create and populate a new PictureExplorer object.

          //Dispose of the existing explorer and create a
          // new one.
          explorerFrame.dispose();

          explorer = new PictureExplorer(pix);
          
          //Get reference to the new frame
          explorerFrame = explorer.getFrame();
          explorerFrame.setDefaultCloseOperation(
                     WindowConstants.DO_NOTHING_ON_CLOSE);

Set the state of the PictureExplorer object

You will probably need to study the event handling code in the PictureExplorer class to fully understand the remaining code in this discussion.

When you click the image in the PictureExplorer object, a MouseListener object registered on the PictureExplorer object calls the mousePressed method belonging to that object

Simulate a physical click

We can simulate a physical click on that image by calling the same method from outside the PictureExplorer object.

Call the mousePressed method

Listing 7 calls the mousePressed method on the PictureExplorer object passing the crosshair coordinates as parameters. Other parameters are also passed to satisfy the requirements of the mousePressed method.

(I will leave it as an exercise for the student to investigate those other parameters.)

Listing 7: Call the mousePressed method.

          //Now set the state of the new explorer.
          
          //Simulate a mouse pressed event in the picture
          // to set the cursor and the text in the
          // coordinate fields.
          explorer.mousePressed(new MouseEvent(
                           new JButton("dummy component"),
                           MouseEvent.MOUSE_PRESSED,
                           (long)0,
                           0,
                           xIndex,
                           yIndex,
                           0,
                           false));

PictureExplorer object handles crosshair cursor

The code in Ericson's mousePressed method takes care of all the requirements that result from setting the location of the crosshair cursor, such as setting the coordinate values in the PictureExplorer object's text fields shown in Figure 3 .

Set the zoom state

Manually selecting a zoom level from the Zoom menu in the PictureExplorer object causes the actionPerformed method belonging to an ActionListener object registered on the PictureExplorer object to be executed.

As before, we can simulate the manual selection of a Zoom menu value by calling that actionPerformed method from outside the object.

Set the zoom state

Listing 8 calls Ericson's actionPerformed method, passing the String representation of the zoom factor as a parameter.

(I will leave it as an exercise for the student to investigate the other parameters.)

Listing 8: Set the zoom state.

          //Simulate an action event on the zoom menu to
          // set the zoom.
          explorer.actionPerformed(new ActionEvent(
                             explorer,
                             ActionEvent.ACTION_PERFORMED,
                             zoomString));


        }//end actionPerformed
      }//end newActionListener
    );//end addActionListener

Conclusion of discussion

That concludes the discussion of the ActionListener object registered on the button labeled Update Pixel Color in Figure 1 .

It also concludes the discussion of the program.

Run the program

I encourage you to copy the code from Listing 9 and Listing 10 and download the image file named Prob15.jpg . Compile the code and execute it. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.

Summary

In this module, you learned how to write an editor program that you can use to modify the colors in an image on a pixel-by-pixel basis.

Miscellaneous

This section contains a variety of miscellaneous information.

Note:

Housekeeping material
  • Module name: Java OOP: A Pixel Color Editor
  • File: Java3130.htm
  • Published: 09/11/12

Note:

Disclaimers:

Financial : Although the Connexions site makes it possible for you to download a PDF file for this module at no charge, and also makes it possible for you to purchase a pre-printed version of the PDF file, you should be aware that some of the HTML elements in this module may not translate well into PDF.

I also want you to know that, I receive no financial compensation from the Connexions website even if you purchase the PDF version of the module.

In the past, unknown individuals have copied my modules from cnx.org, converted them to Kindle books, and placed them for sale on Amazon.com showing me as the author. I neither receive compensation for those sales nor do I know who does receive compensation. If you purchase such a book, please be aware that it is a copy of a module that is freely available on cnx.org and that it was made and published without my prior knowledge.

Affiliation : I am a professor of Computer Information Technology at Austin Community College in Austin, TX.

Complete program listing

Complete listings of the source code discussed in this module are shown in Listing 9 and Listing 10 below.

Listing 9: Complete listing of Prob15.

/*File Prob15 Copyright 2012 R.G.Baldwin

The purpose of this program is demonstrate one way to
change the color of a pixel in a Picture object that is
encapsulated in a PictureExplorer object.

The pixel to be modified is selected by placing the
cursor in the PictureExplorer object.
*********************************************************/
import java.awt.event.MouseEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.border.LineBorder;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Dimension;
import javax.swing.JColorChooser;

public class Prob15{
  public static void main(String[] args){
    new Prob15Runner();
  }//end main method
}//end class Prob15
//======================================================//

class Prob15Runner extends JFrame{
  private Prob15Runner jFrameObj = null;
  private PictureExplorer explorer = null;
  private Picture pix;
  private JFrame explorerFrame;
  
  private JPanel controlPanel = new JPanel();
  private JPanel colorPanel = new JPanel();
  private JPanel buttonPanel = new JPanel();
  private JPanel colorIndicatorPanel = new JPanel();

  private JTextField redField = new JTextField("000000");
  private JTextField greenField = 
                                 new JTextField("000000");
  private JTextField blueField = new JTextField("000000");
  
  private int redInt = 0;
  private int greenInt = 0;
  private int blueInt = 0;
  
  //Copies of properties of the PictureExplorer object
  private int xIndex = 0;
  private int yIndex = 0;
  private double zoomFactor = 0;

  private JButton chooseButton = 
                              new JButton("Choose Color");
  private JButton updateButton = 
                        new JButton("Update Pixel Color");
  //----------------------------------------------------//

  public Prob15Runner(){//constructor

    pix = new Picture("Prob15.jpg");
    pix.addMessage("Dick Baldwin",10,20);
    explorer = new PictureExplorer(pix);
    explorerFrame = explorer.getFrame();
    explorerFrame.setDefaultCloseOperation(
               WindowConstants.DO_NOTHING_ON_CLOSE);

    //Set the location for the control GUI
    // immediately below the PictureExplorer object,
    // and set its default close operation.
    setLocation(0,pix.getHeight() + 128);

    setDefaultCloseOperation(
                           WindowConstants.EXIT_ON_CLOSE);

    controlPanel.setLayout(new GridLayout(2,1));
    controlPanel.add(colorPanel);
    controlPanel.add(buttonPanel);

    colorPanel.setBackground(Color.GREEN);
    colorPanel.add(new JLabel("Red = "));
    colorPanel.add(redField);
    colorPanel.add(new JLabel(" Green = "));
    colorPanel.add(greenField);
    colorPanel.add(new JLabel(" Blue = "));
    colorPanel.add(blueField);
    colorPanel.add(colorIndicatorPanel);
    
    redField.setEditable(false);
    greenField.setEditable(false);
    blueField.setEditable(false);

    colorIndicatorPanel.setBorder(
                           new LineBorder(Color.black,1));
    colorIndicatorPanel.setPreferredSize(
                                    new Dimension(20,20));

    buttonPanel.setBackground(Color.BLUE);
    buttonPanel.add(chooseButton);
    buttonPanel.add(updateButton);
//    buttonPanel.add(darkerButton);
    
    //Color the swatch for the first time.
    paintColorSwatch();

    //Add the controlPanel to the content pane, adjust to
    // the correct size, and set the tiele.
    getContentPane().add(controlPanel);
    pack();
    setTitle("Dick Baldwin");

    //Make the GUI visible
    setVisible(true);

    //--------------------------------------------------//
    //Register listeners on the user input components.
    //--------------------------------------------------//
    chooseButton.addActionListener(
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
          Color selColor = JColorChooser.showDialog(
                    chooseButton,"Choose color",new Color(
                       redInt,greenInt,blueInt));
          if(selColor != null){
            //Don't change the color if the user cancels
            // out.
            redField.setText("" + selColor.getRed());
            greenField.setText(
                                "" + selColor.getGreen());
            blueField.setText("" + selColor.getBlue());
          }//end if

        }//end action performed
      }//end new ActionListener
    );//end addActionListener
    //--------------------------------------------------//

    updateButton.addActionListener(
      new ActionListener(){
        public void actionPerformed(ActionEvent e){

          //Get properties of PictureExplorer object.
          xIndex = explorer.getXIndex();
          yIndex = explorer.getYIndex();
          zoomFactor = explorer.getZoomFactor();
          
          //Save zoom factor as a string.
          String zoomString = "100%";
          if(zoomFactor == 0.25){
            zoomString = "25%";
          }else if(zoomFactor == 0.50){
            zoomString = "50%";
          }else if(zoomFactor == 0.75){
            zoomString = "75%";
          }else if(zoomFactor == 1.0){
            zoomString = "100%";
          }else if(zoomFactor == 1.5){
            zoomString = "150%";
          }else if(zoomFactor == 2.0){
            zoomString = "200%";
          }else if(zoomFactor == 5.0){
            zoomString = "500%";
          }else{
            zoomString = "100%";//in case no match
          }//end else

          Color newColor = new Color(
                                 redInt,greenInt,blueInt);
          pix.getPixel(xIndex,yIndex).setColor(newColor);

          //Dispose of the existing explorer and create a
          // new one.
          explorerFrame.dispose();

          explorer = new PictureExplorer(pix);
          //Get reference to the new frame
          explorerFrame = explorer.getFrame();
          explorerFrame.setDefaultCloseOperation(
                     WindowConstants.DO_NOTHING_ON_CLOSE);

          //Now set the state of the new explorer.
          //Simulate a mouse pressed event in the picture
          // to set the cursor and the text in the
          // coordinate fields.
          explorer.mousePressed(new MouseEvent(
                           new JButton("dummy component"),
                           MouseEvent.MOUSE_PRESSED,
                           (long)0,
                           0,
                           xIndex,
                           yIndex,
                           0,
                           false));

          //Simulate an action event on the zoom menu to
          // set the zoom.
          explorer.actionPerformed(new ActionEvent(
                             explorer,
                             ActionEvent.ACTION_PERFORMED,
                             zoomString));


        }//end actionPerformed
      }//end newActionListener
    );//end addActionListener
    //--------------------------------------------------//

    //Register a document listener on the red text field.
    // This listener will respond when the contents of
    // the text field are modified either by the program
    // or by the user.
    redField.getDocument().addDocumentListener(
      new DocumentListener(){
        public void changedUpdate(DocumentEvent e){
          //Empty method - not needed
        }//end changedUpdate

        public void removeUpdate(DocumentEvent e){
          try{
            redInt = Integer.parseInt(
                                   redField.getText());
            if((redInt >= 0) && (redInt <= 255)){
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end removeUpdate

        public void insertUpdate(DocumentEvent e){
          try{
            redInt = Integer.parseInt(
                                   redField.getText());
            if((redInt >= 0) && (redInt <= 255)){
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end insertUpdate

      }//end new DocumentListener
    );//end addDocumentListener
    //--------------------------------------------------//

    //Register a document listener on the green text
    // field. Essentially the same as the above.
    greenField.getDocument().addDocumentListener(
      new DocumentListener(){
        public void changedUpdate(DocumentEvent e){}

        public void removeUpdate(DocumentEvent e){
          try{
            greenInt = Integer.parseInt(
                                 greenField.getText());
            if((greenInt >= 0) && (greenInt <= 255))
            {
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end removeUpdate

        public void insertUpdate(DocumentEvent e){
          try{
            greenInt = Integer.parseInt(
                                 greenField.getText());
            if((greenInt >= 0) && (greenInt <= 255))
            {
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end insertUpdate

      }//end new DocumentListener
    );//end addDocumentListener
    //--------------------------------------------------//
    
    //Register a document listener on the blue text
    // field. Essentially the same as the above.
    blueField.getDocument().addDocumentListener(
      new DocumentListener(){
        public void changedUpdate(DocumentEvent e){}

        public void removeUpdate(DocumentEvent e){
          try{
            blueInt = Integer.parseInt(
                                  blueField.getText());
            if((blueInt >= 0) && (blueInt <= 255)){
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end removeUpdate

        public void insertUpdate(DocumentEvent e){
          try{
            blueInt = Integer.parseInt(
                                  blueField.getText());
            if((blueInt >= 0) && (blueInt <= 255)){
              paintColorSwatch();
            }//end if
          }catch(Exception ex){
            //do nothing on exception
          }//end catch
        }//end insertUpdate

      }//end new DocumentListener
    );//end addDocumentListener
    //--------------------------------------------------//
  }//end constructor
  //----------------------------------------------------//

  //The purpose of this method is to color a swatch 
  // located next to the RGB color values.
  private void paintColorSwatch(){
    colorIndicatorPanel.setBackground(
                      new Color(redInt,greenInt,blueInt));
  }//end paintColorSwatch

  //----------------------------------------------------//

  //The purpose of this method is to absorb any exceptions
  // that may be thrown by the parseInt method in order
  // to avoid having the program abort. In the event that
  // an exception is thrown, this method simply returns an
  // int value of 0;
  private int goParseInt(String string){
    int result = 0;
    try{
      result = Integer.parseInt(string);
    }catch(Exception e){
      result = 0;
    }//end catch
    return result;
  }//end goParseInt

  //----------------------------------------------------//


}//end class Prob15Runner

Listing 10: Complete listing of modified PictureExplorer class.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import javax.swing.border.*;

/*
05/16/12 Modified by Baldwin to add getter methods to
 cause the following values to be accessible from 
 outside the object:
 
int xIndex
int yIndex
double zoomFactor
JFrame pictureFrame

Also disabled the call to setDefaultCloseOperation

*/

/**
 * Displays a picture and lets you explore the picture by displaying the x, y, red,
 * green, and blue values of the pixel at the cursor when you click a mouse button or
 * press and hold a mouse button while moving the cursor.  It also lets you zoom in or
 * out.  You can also type in a x and y value to see the color at that location.
 *
 * Originally created for the Jython Environment for Students (JES).
 * Modified to work with DrJava by Barbara Ericson
 *
 * Copyright Georgia Institute of Technology 2004
 * @author Keith McDermottt, gte047w@cc.gatech.edu
 * @author Barb Ericson ericson@cc.gatech.edu
 */
public class PictureExplorer implements MouseMotionListener, ActionListener, MouseListener
{

 // current x and y index
 private int xIndex = 0;
 private int yIndex = 0;

 //Main gui variables
 private JFrame pictureFrame;
 private JScrollPane scrollPane;

 //information bar variables
 private JLabel xLabel;
 private JButton xPrevButton;
 private JButton yPrevButton;
 private JButton xNextButton;
 private JButton yNextButton;
 private JLabel yLabel;
 private JTextField xValue;
 private JTextField yValue;
 private JLabel rValue;
 private JLabel gValue;
 private JLabel bValue;
 private JLabel colorLabel;
 private JPanel colorPanel;

 // menu components
 private JMenuBar menuBar;
 private JMenu zoomMenu;
 private JMenuItem twentyFive;
 private JMenuItem fifty;
 private JMenuItem seventyFive;
 private JMenuItem hundred;
 private JMenuItem hundredFifty;
 private JMenuItem twoHundred;
 private JMenuItem fiveHundred;

 /** The picture being explored */
 private DigitalPicture picture;

 /** The image icon used to display the picture */
 private ImageIcon scrollImageIcon;

 /** The image display */
 private ImageDisplay imageDisplay;

 /** the zoom factor (amount to zoom) */
 private double zoomFactor;

 /** the number system to use, 0 means starting at 0, 1 means starting at 1 */
 private int numberBase=0;

 /**
  * Public constructor
  * @param picture the picture to explore
  */
 public PictureExplorer(DigitalPicture picture)
 {
   // set the fields
   this.picture=picture;
   zoomFactor=1;

   // create the window and set things up
   createWindow();
 }

//===Methods added by Baldwin on 05/16/12===============//

  //Method to get the xIndex value.
  public int getXIndex(){
    return xIndex;
  }//end getXIndex

  //Method to get the yIndex value.
  public int getYIndex(){
    return yIndex;
  }//end getYIndex

  //Method to get the zoomFactor value.
  public double getZoomFactor(){
    return zoomFactor;
  }//end getZoomFactor

  //Method to get a reference to the frame
  public JFrame getFrame(){
    return pictureFrame;
  }//end getFrame()

//===End methods added by Baldwin on 05/16/12===========//






 /**
  * Changes the number system to start at one
  */
 public void changeToBaseOne()
 {
   numberBase=1;
 }

 /**
  * Set the title of the frame
  *@param title the title to use in the JFrame
  */
 public void setTitle(String title)
 {
   pictureFrame.setTitle(title);
 }

 /**
  * Method to create and initialize the picture frame
  */
 private void createAndInitPictureFrame()
 {
   pictureFrame = new JFrame(); // create the JFrame
   pictureFrame.setResizable(true);  // allow the user to resize it
   pictureFrame.getContentPane().setLayout(new BorderLayout()); // use border layout
   
   //Disabled by Baldwin on 05/16/12
   //pictureFrame.setDefaultCloseOperation(
   // JFrame.DISPOSE_ON_CLOSE);
   
   pictureFrame.setTitle(picture.getTitle());
   PictureExplorerFocusTraversalPolicy newPolicy = new PictureExplorerFocusTraversalPolicy();
   pictureFrame.setFocusTraversalPolicy(newPolicy);

 }

 /**
  * Method to create the menu bar, menus, and menu items
  */
 private void setUpMenuBar()
 {
   //create menu
   menuBar = new JMenuBar();
   zoomMenu = new JMenu("Zoom");
   twentyFive = new JMenuItem("25%");
   fifty = new JMenuItem("50%");
   seventyFive = new JMenuItem("75%");
   hundred = new JMenuItem("100%");
   hundred.setEnabled(false);
   hundredFifty = new JMenuItem("150%");
   twoHundred = new JMenuItem("200%");
   fiveHundred = new JMenuItem("500%");

   // add the action listeners
   twentyFive.addActionListener(this);
   fifty.addActionListener(this);
   seventyFive.addActionListener(this);
   hundred.addActionListener(this);
   hundredFifty.addActionListener(this);
   twoHundred.addActionListener(this);
   fiveHundred.addActionListener(this);

   // add the menu items to the menus
   zoomMenu.add(twentyFive);
   zoomMenu.add(fifty);
   zoomMenu.add(seventyFive);
   zoomMenu.add(hundred);
   zoomMenu.add(hundredFifty);
   zoomMenu.add(twoHundred);
   zoomMenu.add(fiveHundred);
   menuBar.add(zoomMenu);

   // set the menu bar to this menu
   pictureFrame.setJMenuBar(menuBar);
 }

 /**
  * Create and initialize the scrolling image
  */
 private void createAndInitScrollingImage()
 {
   scrollPane = new JScrollPane();

   BufferedImage bimg = picture.getBufferedImage();
   imageDisplay = new ImageDisplay(bimg);
   imageDisplay.addMouseMotionListener(this);
   imageDisplay.addMouseListener(this);
   imageDisplay.setToolTipText("Click a mouse button on a pixel to see the pixel information");
   scrollPane.setViewportView(imageDisplay);
   pictureFrame.getContentPane().add(scrollPane, BorderLayout.CENTER);
 }

 /**
  * Creates the JFrame and sets everything up
  */
 private void createWindow()
 {
   // create the picture frame and initialize it
   createAndInitPictureFrame();

   // set up the menu bar
   setUpMenuBar();

   //create the information panel
   createInfoPanel();

   //creates the scrollpane for the picture
   createAndInitScrollingImage();

   // show the picture in the frame at the size it needs to be
   pictureFrame.pack();
   pictureFrame.setVisible(true);
 }

 /**
  * Method to set up the next and previous buttons for the
  * pixel location information
  */
 private void setUpNextAndPreviousButtons()
 {
   // create the image icons for the buttons
   Icon prevIcon = new ImageIcon(SoundExplorer.class.getResource("leftArrow.gif"),
                                 "previous index");
   Icon nextIcon = new ImageIcon(SoundExplorer.class.getResource("rightArrow.gif"),
                                 "next index");
   // create the arrow buttons
   xPrevButton = new JButton(prevIcon);
   xNextButton = new JButton(nextIcon);
   yPrevButton = new JButton(prevIcon);
   yNextButton = new JButton(nextIcon);

   // set the tool tip text
   xNextButton.setToolTipText("Click to go to the next x value");
   xPrevButton.setToolTipText("Click to go to the previous x value");
   yNextButton.setToolTipText("Click to go to the next y value");
   yPrevButton.setToolTipText("Click to go to the previous y value");

   // set the sizes of the buttons
   int prevWidth = prevIcon.getIconWidth() + 2;
   int nextWidth = nextIcon.getIconWidth() + 2;
   int prevHeight = prevIcon.getIconHeight() + 2;
   int nextHeight = nextIcon.getIconHeight() + 2;
   Dimension prevDimension = new Dimension(prevWidth,prevHeight);
   Dimension nextDimension = new Dimension(nextWidth, nextHeight);
   xPrevButton.setPreferredSize(prevDimension);
   yPrevButton.setPreferredSize(prevDimension);
   xNextButton.setPreferredSize(nextDimension);
   yNextButton.setPreferredSize(nextDimension);

   // handle previous x button press
   xPrevButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent evt) {
       xIndex--;
       if (xIndex < 0)
         xIndex = 0;
       displayPixelInformation(xIndex,yIndex);
     }
   });

   // handle previous y button press
   yPrevButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent evt) {
       yIndex--;
       if (yIndex < 0)
         yIndex = 0;
       displayPixelInformation(xIndex,yIndex);
     }
   });

   // handle next x button press
   xNextButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent evt) {
       xIndex++;
       if (xIndex >= picture.getWidth())
         xIndex = picture.getWidth() - 1;
       displayPixelInformation(xIndex,yIndex);
     }
   });

   // handle next y button press
   yNextButton.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent evt) {
       yIndex++;
       if (yIndex >= picture.getHeight())
         yIndex = picture.getHeight() - 1;
       displayPixelInformation(xIndex,yIndex);
     }
   });
 }

 /**
  * Create the pixel location panel
  * @param labelFont the font for the labels
  * @return the location panel
  */
 public JPanel createLocationPanel(Font labelFont) {

   // create a location panel
   JPanel locationPanel = new JPanel();
   locationPanel.setLayout(new FlowLayout());
   Box hBox = Box.createHorizontalBox();

   // create the labels
   xLabel = new JLabel("X:");
   yLabel = new JLabel("Y:");

   // create the text fields
   xValue = new JTextField(Integer.toString(xIndex + numberBase),6);
   xValue.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       displayPixelInformation(xValue.getText(),yValue.getText());
     }
   });
   yValue = new JTextField(Integer.toString(yIndex + numberBase),6);
   yValue.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
      displayPixelInformation(xValue.getText(),yValue.getText());
     }
   });

   // set up the next and previous buttons
   setUpNextAndPreviousButtons();

   // set up the font for the labels
   xLabel.setFont(labelFont);
   yLabel.setFont(labelFont);
   xValue.setFont(labelFont);
   yValue.setFont(labelFont);

   // add the items to the vertical box and the box to the panel
   hBox.add(Box.createHorizontalGlue());
   hBox.add(xLabel);
   hBox.add(xPrevButton);
   hBox.add(xValue);
   hBox.add(xNextButton);
   hBox.add(Box.createHorizontalStrut(10));
   hBox.add(yLabel);
   hBox.add(yPrevButton);
   hBox.add(yValue);
   hBox.add(yNextButton);
   locationPanel.add(hBox);
   hBox.add(Box.createHorizontalGlue());

   return locationPanel;
 }

 /**
  * Create the color information panel
  * @param labelFont the font to use for labels
  * @return the color information panel
  */
 private JPanel createColorInfoPanel(Font labelFont)
 {
   // create a color info panel
   JPanel colorInfoPanel = new JPanel();
   colorInfoPanel.setLayout(new FlowLayout());

   // get the pixel at the x and y
   Pixel pixel = new Pixel(picture,xIndex,yIndex);

   // create the labels
   rValue = new JLabel("R: " + pixel.getRed());
   gValue = new JLabel("G: " + pixel.getGreen());
   bValue = new JLabel("B: " + pixel.getBlue());

   // create the sample color panel and label
   colorLabel = new JLabel("Color at location: ");
   colorPanel = new JPanel();
   colorPanel.setBorder(new LineBorder(Color.black,1));

   // set the color sample to the pixel color
   colorPanel.setBackground(pixel.getColor());

   // set the font
   rValue.setFont(labelFont);
   gValue.setFont(labelFont);
   bValue.setFont(labelFont);
   colorLabel.setFont(labelFont);
   colorPanel.setPreferredSize(new Dimension(25,25));

   // add items to the color information panel
   colorInfoPanel.add(rValue);
   colorInfoPanel.add(gValue);
   colorInfoPanel.add(bValue);
   colorInfoPanel.add(colorLabel);
   colorInfoPanel.add(colorPanel);

   return colorInfoPanel;
 }

 /**
  * Creates the North JPanel with all the pixel location
  * and color information
  */
 private void createInfoPanel()
 {
   // create the info panel and set the layout
   JPanel infoPanel = new JPanel();
   infoPanel.setLayout(new BorderLayout());

   // create the font
   Font largerFont = new Font(infoPanel.getFont().getName(),
                              infoPanel.getFont().getStyle(),14);

   // create the pixel location panel
   JPanel locationPanel = createLocationPanel(largerFont);

   // create the color informaiton panel
   JPanel colorInfoPanel = createColorInfoPanel(largerFont);

   // add the panels to the info panel
   infoPanel.add(BorderLayout.NORTH,locationPanel);
   infoPanel.add(BorderLayout.SOUTH,colorInfoPanel);

   // add the info panel
   pictureFrame.getContentPane().add(BorderLayout.NORTH,infoPanel);
 }

 /**
  * Method to check that the current position is in the viewing area and if
  * not scroll to center the current position if possible
  */
 public void checkScroll()
 {
   // get the x and y position in pixels
   int xPos = (int) (xIndex * zoomFactor);
   int yPos = (int) (yIndex * zoomFactor);

   // only do this if the image is larger than normal
   if (zoomFactor > 1) {

     // get the rectangle that defines the current view
     JViewport viewport = scrollPane.getViewport();
     Rectangle rect = viewport.getViewRect();
     int rectMinX = (int) rect.getX();
     int rectWidth = (int) rect.getWidth();
     int rectMaxX = rectMinX + rectWidth - 1;
     int rectMinY = (int) rect.getY();
     int rectHeight = (int) rect.getHeight();
     int rectMaxY = rectMinY + rectHeight - 1;

     // get the maximum possible x and y index
     int maxIndexX = (int) (picture.getWidth() * zoomFactor) - rectWidth - 1;
     int maxIndexY = (int) (picture.getHeight() * zoomFactor) - rectHeight - 1;

     // calculate how to position the current position in the middle of the viewing
     // area
     int viewX = xPos - (int) (rectWidth / 2);
     int viewY = yPos - (int) (rectHeight / 2);

     // reposition the viewX and viewY if outside allowed values
     if (viewX < 0)
       viewX = 0;
     else if (viewX > maxIndexX)
       viewX = maxIndexX;
     if (viewY < 0)
       viewY = 0;
     else if (viewY > maxIndexY)
       viewY = maxIndexY;

     // move the viewport upper left point
     viewport.scrollRectToVisible(new Rectangle(viewX,viewY,rectWidth,rectHeight));
   }
 }

 /**
  * Zooms in the on picture by scaling the image.
  * It is extremely memory intensive.
  * @param factor the amount to zoom by
  */
 public void zoom(double factor)
 {
   // save the current zoom factor
   zoomFactor = factor;

   // calculate the new width and height and get an image that size
   int width = (int) (picture.getWidth()*zoomFactor);
   int height = (int) (picture.getHeight()*zoomFactor);
   BufferedImage bimg = picture.getBufferedImage();

   // set the scroll image icon to the new image
   imageDisplay.setImage(bimg.getScaledInstance(width, height, Image.SCALE_DEFAULT));
   imageDisplay.setCurrentX((int) (xIndex * zoomFactor));
   imageDisplay.setCurrentY((int) (yIndex * zoomFactor));
   imageDisplay.revalidate();
   checkScroll();  // check if need to reposition scroll
 }

 /**
  * Repaints the image on the scrollpane.
  */
 public void repaint()
 {
   pictureFrame.repaint();
 }

 //****************************************//
 //               Event Listeners          //
 //****************************************//

 /**
  * Called when the mouse is dragged (button held down and moved)
  * @param e the mouse event
  */
 public void mouseDragged(MouseEvent e)
 {
   displayPixelInformation(e);
 }

 /**
  * Method to check if the given x and y are in the picture
  * @param x the horiztonal value
  * @param y the vertical value
  * @return true if the x and y are in the picture and false otherwise
  */
 private boolean isLocationInPicture(int x, int y)
 {
   boolean result = false; // the default is false
   if (x >= 0 && x < picture.getWidth() &&
       y >= 0 && y < picture.getHeight())
     result = true;

   return result;
 }

 /**
  * Method to display the pixel information from the passed x and y but
  * also converts x and y from strings
  * @param xString the x value as a string from the user
  * @param yString the y value as a string from the user
  */
 public void displayPixelInformation(String xString, String yString)
 {
   int x = -1;
   int y = -1;
   try {
     x = Integer.parseInt(xString);
     x = x - numberBase;
     y = Integer.parseInt(yString);
     y = y - numberBase;
   } catch (Exception ex) {
   }

   if (x >= 0 && y >= 0) {
     displayPixelInformation(x,y);
   }
 }

 /**
  * Method to display pixel information for the passed x and y
  * @param pictureX the x value in the picture
  * @param pictureY the y value in the picture
  */
 private void displayPixelInformation(int pictureX, int pictureY)
 {
   // check that this x and y is in range
   if (isLocationInPicture(pictureX, pictureY))
   {
     // save the current x and y index
     xIndex = pictureX;
     yIndex = pictureY;

     // get the pixel at the x and y
     Pixel pixel = new Pixel(picture,xIndex,yIndex);

     // set the values based on the pixel
     xValue.setText(Integer.toString(xIndex  + numberBase));
     yValue.setText(Integer.toString(yIndex + numberBase));
     rValue.setText("R: " + pixel.getRed());
     gValue.setText("G: " + pixel.getGreen());
     bValue.setText("B: " + pixel.getBlue());
     colorPanel.setBackground(new Color(pixel.getRed(), pixel.getGreen(), pixel.getBlue()));

   }
   else
   {
     clearInformation();
   }

   // notify the image display of the current x and y
   imageDisplay.setCurrentX((int) (xIndex * zoomFactor));
   imageDisplay.setCurrentY((int) (yIndex * zoomFactor));
 }

 /**
  * Method to display pixel information based on a mouse event
  * @param e a mouse event
  */
 private void displayPixelInformation(MouseEvent e)
 {

   // get the cursor x and y
   int cursorX = e.getX();
   int cursorY = e.getY();

   // get the x and y in the original (not scaled image)
   int pictureX = (int) (cursorX / zoomFactor + numberBase);
   int pictureY = (int) (cursorY / zoomFactor + numberBase);

   // display the information for this x and y
   displayPixelInformation(pictureX,pictureY);

 }

 /**
  * Method to clear the labels and current color and reset the
  * current index to -1
  */
 private void clearInformation()
 {
   xValue.setText("N/A");
   yValue.setText("N/A");
   rValue.setText("R: N/A");
   gValue.setText("G: N/A");
   bValue.setText("B: N/A");
   colorPanel.setBackground(Color.black);
   xIndex = -1;
   yIndex = -1;
 }

 /**
  * Method called when the mouse is moved with no buttons down
  * @param e the mouse event
  */
 public void mouseMoved(MouseEvent e)
 {}

 /**
  * Method called when the mouse is clicked
  * @param e the mouse event
  */
 public void mouseClicked(MouseEvent e)
 {
   displayPixelInformation(e);
 }

 /**
  * Method called when the mouse button is pushed down
  * @param e the mouse event
  */
 public void mousePressed(MouseEvent e)
 {
   displayPixelInformation(e);
 }

 /**
  * Method called when the mouse button is released
  * @param e the mouse event
  */
 public void mouseReleased(MouseEvent e)
 {
 }

 /**
  * Method called when the component is entered (mouse moves over it)
  * @param e the mouse event
  */
 public void mouseEntered(MouseEvent e)
 {
 }

 /**
  * Method called when the mouse moves over the component
  * @param e the mouse event
  */
 public void mouseExited(MouseEvent e)
 {
 }

 /**
  * Method to enable all menu commands
  */
 private void enableZoomItems()
 {
   twentyFive.setEnabled(true);
   fifty.setEnabled(true);
   seventyFive.setEnabled(true);
   hundred.setEnabled(true);
   hundredFifty.setEnabled(true);
   twoHundred.setEnabled(true);
   fiveHundred.setEnabled(true);
 }

 /**
  * Controls the zoom menu bar
  *
  * @param a the ActionEvent
  */
 public void actionPerformed(ActionEvent a)
 {

   if(a.getActionCommand().equals("Update"))
   {
     this.repaint();
   }

   if(a.getActionCommand().equals("25%"))
   {
     this.zoom(.25);
     enableZoomItems();
     twentyFive.setEnabled(false);
   }

   if(a.getActionCommand().equals("50%"))
   {
     this.zoom(.50);
     enableZoomItems();
     fifty.setEnabled(false);
   }

   if(a.getActionCommand().equals("75%"))
   {
     this.zoom(.75);
     enableZoomItems();
     seventyFive.setEnabled(false);
   }

   if(a.getActionCommand().equals("100%"))
   {
     this.zoom(1.0);
     enableZoomItems();
     hundred.setEnabled(false);
   }

   if(a.getActionCommand().equals("150%"))
   {
     this.zoom(1.5);
     enableZoomItems();
     hundredFifty.setEnabled(false);
   }

   if(a.getActionCommand().equals("200%"))
   {
     this.zoom(2.0);
     enableZoomItems();
     twoHundred.setEnabled(false);
   }

   if(a.getActionCommand().equals("500%"))
   {
     this.zoom(5.0);
     enableZoomItems();
     fiveHundred.setEnabled(false);
   }
 }

 /**
  * Test Main.  It will ask you to pick a file and then show it
  */
 public static void main( String args[])
 {
   Picture p = new Picture(FileChooser.pickAFile());
   PictureExplorer test = new PictureExplorer(p);

 }

 /**
  * Class for establishing the focus for the textfields
  */
 private class PictureExplorerFocusTraversalPolicy
                 extends FocusTraversalPolicy {

        /**
         * Method to get the next component for focus
         */
        public Component getComponentAfter(Container focusCycleRoot,
                                           Component aComponent) {
            if (aComponent.equals(xValue))
              return yValue;
            else
              return xValue;
        }

        /**
         * Method to get the previous component for focus
         */
         public Component getComponentBefore(Container focusCycleRoot,
                                       Component aComponent) {
            if (aComponent.equals(xValue))
              return yValue;
            else
              return xValue;
         }

         public Component getDefaultComponent(Container focusCycleRoot) {
            return xValue;
        }

        public Component getLastComponent(Container focusCycleRoot) {
            return yValue;
        }

        public Component getFirstComponent(Container focusCycleRoot) {
            return xValue;
        }
    }

}

-end-

Collection Navigation

Content actions

Download:

Collection as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Module as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Add:

Collection to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks

Module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks