import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import javax.swing.border.*;
/*
05/15/12
Modified by Baldwin to add getter methods to cause
the following values to be accessible from outside the
PictureExplorer object:
Red color value
Reference to the JFrame containing the PictureExplorer
object.
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/15/12===============//
//Method to get the red color value as text.
public String getRValue(){
return rValue.getText();
}//end getRValue
//Method to get a reference to the JFrame containing
// the PictureExplorer object.
public JFrame getFrame(){
return pictureFrame;
}//end getFrame()
//===End methods added by Baldwin on 05/15/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 5/15/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;
}
}
}
|