Sunday, February 20, 2011

Java : Chasing Rodents - "Allegedly"

As promised, today we're going to modify our "glorified .GIF" program to make it interactive. We're going to change the image depending on the position of the mouse.

Even to us, it doesn't make sense to have Hitler and Bambi emit hearts based on the mouse position, so we're going to change the images. Who better to illustrate mouse following than famed celebrity rodent fan and Scott Brown lookalike, Richard Gere?

We must admit, we almost changed our minds about using Mr Gere after doing a google image search. He's old, really old: his rodent catching days are long behind him. The only furry action he could get nowadays would be with a sloth.

Richard Gere with his sloth companion, Mr Frisky.

Also, let's face it, the whole felching thing (don't look it up) has been done to death. There is absolutely no truth to the rumors, and after two (three?) decades it's time the internet gave him a break.

On the other hand, Gere's iconic movies, "Officer & a Gentleman" and "Pretty Woman" defined the chick-flick genre. Thanks to Gere, we've had to sit through numerous sad re-hashes of these crappy wish-fulfillment fantasies over the years: all the time feeling as though a furry animal was burrowing in our bowels.

So we owe him: sorry, Dick. We'll use this thumbnail of a Robert Mapplethorpe portrait of Gere and its mirror image. (Don't look up Mapplethorpe either.)




Save to your "Images" directory as "richard_gere_0.jpg" and "richard_gere_1.jpg"

Now to modify our program. First, let's add some new constant definitions "LEFT" & "RIGHT". the idea is that the left-facing image will be stored in the "0th" element of our images array, and the right-facing will be the "1th" element. (As in many languages, the 1st element of an array is numbered 0. Safer to say "0th" & "1th" than "1st" and "2nd".)
private static final int LEFT  =  0; // images[0] faces L
private static final int RIGHT =  1; // images[1] faces R
Don't forget to load images of Gere rather than Hitler.
images [0] = loadImage("Images/richard_gere_0.jpg");
images [1] = loadImage("Images/richard_gere_1.jpg");
Now we change our Timer response method "actionPerformed()" to test which side of the window the mouse is at before painting the corresponding image.
public void actionPerformed(ActionEvent e)
{
 imageIndex = getMouseDirection(); // is mouse to L or R?
 repaint();
}
Here's the code of the "getMouseDirection()" function. Note that "MouseInfo.getPointerInfo().getLocation()" returns the position of the mouse in screen co-ordinates. I.e the point (0,0) is at the top-left corner of the screen. We need to call "SwingUtilities.convertPointFromScreen" to convert to component co-ordinates. I.e. the point (0,0) is at the top-left corner of the panel. If the mouse's x-co-ordinate in component co-ordinates is less than half the window width, return "LEFT", otherwise return "RIGHT".
public int getMouseDirection(){
 
 // mouse location in *screen* co-ordinates
 Point mouseCoordinates = MouseInfo.getPointerInfo().getLocation();
  
 // convert to *component* co-ordinates
 SwingUtilities.convertPointFromScreen(mouseCoordinates,this);
  
 if (mouseCoordinates.x>=PWIDTH/2)
  return RIGHT;
 else
  return LEFT;
}
Please note, in Java, like most other programming environments, the y-axis is inverted. I.e. the top row of screen pixels is row 0 and the bottom row will be row 767 or 1023 (or whatever the size of your screen is -1).

You will forget this several times during the development of every program you ever write that uses screen co-ordinates. You can't help forgetting it, just remember to look for it when your program comes out upside down. Thankfully, in this program we're only concerned with the x-axis.

And that's it. The rest of the program is unchanged.
// ShowGere.java

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;

public class ShowGere extends JPanel implements ActionListener
{
 private static final int PERIOD = 1000; // Swing timer interval (ms)
 private static final int PWIDTH =  243;
 private static final int PHEIGHT=  244;
 private static final int LEFT =  0; // image 0 points left
 private static final int RIGHT =  1; // image 1 points right
 
 private BufferedImage [] images = new BufferedImage [2];
 
 private int imageIndex;
 
 public ShowGere()
 {
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));

  images [LEFT]  = loadImage("Images/richard_gere_0.jpg");
  images [RIGHT] = loadImage("Images/richard_gere_1.jpg");
  
  imageIndex = LEFT;
  
  new Timer(PERIOD, this).start(); // start Swing timer
  
 } // ShowGere

 public BufferedImage loadImage(String fileName) 
 {
  try {
   BufferedImage im =  ImageIO.read(getClass().getResource(fileName));
   return im; 
  } catch(IOException e) {
   System.out.println("Load Image error for "+fileName+":\n"+e);
   return null;
  }
 }
 
 // triggered by the timer: face the mouse and repaint
 public void actionPerformed(ActionEvent e)
 {
  imageIndex = getMouseDirection(); // is mouse to left or right?
  repaint();
 }
 
 // Is the mouse to the LEFT or RIGHT of the middle of the window?
 public int getMouseDirection(){
 
  // mouse location in *screen* co-ordinates
  Point mouseCoordinates = MouseInfo.getPointerInfo().getLocation();
  
  // convert to *component* co-ordinates
  SwingUtilities.convertPointFromScreen(mouseCoordinates,this);
  
  if (mouseCoordinates.x>=PWIDTH/2) return RIGHT; else return LEFT;
 } // getMouseDirection
 
 public void paintComponent(Graphics g)
 {
  g.drawImage(images [imageIndex],0,0,this);
 }
  
 public static void main(String args[])
 {
  final ShowGere showPanel = new ShowGere();

  JFrame showFrame = new JFrame("Show Images");
  showFrame.getContentPane().add(showPanel,BorderLayout.CENTER);
  showFrame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);
  showFrame.pack();
  showFrame.setResizable(false);  
  showFrame.setVisible(true); 
 } // main
} // ShowGere class
To run the program, copy and save the program listing to a file called "ShowGere.java" in your working directory. (Remember, the filename must match the class name.)

Compile with

javac ShowGere.java

and run with

java ShowGere

Move the mouse around and there you have it: Richard Gere swinging both ways.

Mr Frisky makes a mad dash for freedom.

28 comments:

  1. Some people really don't get old well. Gere is one of them.
    Keep the java tutorials coming, I'll be interested right after my biology exam is over in march.

    ReplyDelete
  2. oh lawd, hilarious post, yet informative.

    ReplyDelete
  3. you are the best bro keep up the good work
    following and supporting

    ReplyDelete
  4. @ Autumnforest - Rain Man was Dustin Hoffman.

    ReplyDelete
  5. omg lol!!!! this is a great prog you got here. lets do something good like. idk. auto gain traffic =]
    strictly business

    ReplyDelete
  6. Ooo ouch.. hopefully there is some hope that the snow will be old news... after all the groundhog didn't see its shadow (?)

    ReplyDelete
  7. I highly disagree with the felching being done to death. (Armageddon, Armageddon! - this may or may not make sense to felching enthusiasts.)

    Looks like I have my Java homework laid out for me...I will forget coordinates.

    ReplyDelete
  8. Feltching awareness needs to be implemented into the community.

    ReplyDelete
  9. Oh I forgot to mention, when I was a young lad, we used to take a cut rubber band and wrap one end around our thumb. We would pull the other end across our palm and then close our fingers in to a fist, leaving an amount of band trailing out of our pinky.
    This was to simulate the butthole of Richard Gere (or sometimes Geraldo, as the rumors went,) and the tension on the band would pull the rubber band (or tail) in to the fist.

    Quite a visual effect! I would type that all in to Google to see who else did it, but I fear for my life.

    ReplyDelete
  10. lol richard gere and sloths now... a bit extreme. no?

    ReplyDelete
  11. @ Rorschach Redemption - if you're on Facebook, perhaps you could hook up with Mr Tomaszewski and Mr Farnum?

    @ Bart - don't knock it till you've tried it.

    ReplyDelete
  12. I was expecting gerbils. It's good to see that Mr. Gere has moved on to bigger and better (if slower) things...

    ReplyDelete
  13. roch... lol. i think you are alone on this one

    Poetry <3

    ReplyDelete
  14. Look man, I think taking Hitler out of the game is a big mistake.

    ReplyDelete
  15. I was always terrible at coding Java.

    ReplyDelete
  16. The man was a GOD in First Knight... but then Connery was all like dude I'm the King but I'm like the perfect human and offer this chick total protection for her people...

    ReplyDelete
  17. I wish I had a sloth like Mr. Gere

    ReplyDelete
  18. I'm not much wiser at java now, but I do want a pet sloth now. So thanks for that.

    ReplyDelete
  19. Erg, the 'y' axis. I used to program all the time, and I always forgot that the coordinates start on the top.

    ReplyDelete
  20. where do you learn all this thing?

    ReplyDelete
  21. Not a very flattery picture of Gere as he looks today, but the picture of him younger..... well, lets just say it got hot in here all of a sudden. (or course it could just be a passing hotflash)

    ReplyDelete
  22. Hmm, thanks for the post, I might use something like this on one of my websites.

    ReplyDelete
  23. I'm so glad you got that reference.

    ReplyDelete