Saturday, February 26, 2011

King of Pop


What do you get if you cross Keith Richards with Michael Jackson?


@ Iulian Anghel - If you do manage to hack into my server, while you're there, would you mind fixing the login scripts? (-:

Friday, February 25, 2011

Java : Comment Applet Vous? (Part 2)

Today's post will be the dullest and nerdiest ever. Unless you need to post a "jarred" ("jarchived"?) applet right now, just skip to the pictures at the end. We're only posting this for our own benefit, as creating a jarred applet is the kind of tedious, fiddly, counter-intuitive task that's painful to learn but very easy to forget.

Still with us? Okay, let's reprise what we covered last time:
  • We converted our "PeekaBoo" stand-alone application ("App"), into "PeekaBooApplet".
  • So, "PeekaBoo", an extension of JFrame, became "PeekaBooApplet" an extension of Japplet.
  • Our constructor method was renamed "init()" and was given type void.
  • Our "paintComponent" method was renamed "paint".
  • We were able to delete the "main" method entirely.
  • We then added HTML code to our post to invoke the applet.
  • The HTML included a codebase clause to tell our browsers where to look for the applet and data.
Today, we're going to bundle our applet program (".class") together with its data (two ".jpg"s) into a Java archive (".jar") file. the steps required are:
  • Minimal code changes.
  • Create a "mainClass.txt" file to identify the main entry point of the applet.
  • Create a DOS batch file "makeJar.bat" to automate the archiving process.
  • Modify our HTML to tell our browsers where the archive is stored.
First code change, we like to stick a "Jar" at the end of our class name to avoid confusing ouselves. (We must remember to save the file as "PeekaBooAppletJar.java".)
public class PeekaBooAppletJar extends JApplet implements MouseListener
In our "init()" method, we have to change the pathnames given for the image files from a relative pathname in a file-system to an absolute pathname within the ".jar".
(In practice, this usually just means sticking a "/" at the front.)
images [PEEKA] = loadImage("/Images/peeka.jpg");
images [BOO]   = loadImage("/Images/boo.jpg");
That's it for code changes - told you they were minimal.

We now create a text file "mainClass.txt" which passes information about the main entry point of our applet into the archive making program ("jar"). This is known as a manifest file.
Main-Class: PeekaBooAppletJar

One point to note there has to be a newline at the end of the "Min-Class:" line. We've no idea why - just stick a blank line at the end of the file.

We next need a batch file - "makeJar.bat" - to automate the process of making the ".jar".
@echo off

echo Making PeekaBooAppletJar jar...
jar cvmf mainClass.txt PeekaBooAppletJar.jar PeekaBooAppletJar.class Images
echo.

echo Indexing jar...
jar i PeekaBooAppletJar.jar
echo done

A ".jar" file is just like a ".zip" file (you can even open a ".jar" with "WinZip").
In our batch file, we're calling the "jar" utility twice. The first call is with flags
  • c - create a new ".jar".
  • v - verbose output.
  • f - write the output to the specified ".jar" filename. (PeekaBooAppletJar.jar".)
  • m - include manifest information from the specified manifest file. ("mainClass.txt".)
The second call is with flag
  • i - create an index in the ".jar" of all the jars in the manifest.
This second step probably isn't necessary for our simple example but we never, ever intend to read the manual for "jar", so we'll never find out.

One last step is to add an archive clause to our HTML.
<applet
 code="PeekaBooApplet.class"
 archive="http://mgt.yourhda.com/Java/PeekaBooAppletJar.jar"
 codebase="http://mgt.yourhda.com/Java/"
 width="237"
 height="315">
</applet>
Putting it all together:

  • Copy yesterdays "PeekaBooApplet.java".
  • Make the above simple changes and save as "PeekaBooAppletjar.java".
  • Compile using javac.
  • Run makeJar.bat.
  • Copy the resulting "PeekaBooAppletJar.jar" to your server.
  • Modify the above HTML to point to your server and save to a blog post or ".html" file.




Click on Catwoman and move the mouse away to test.


That's quite enough on applets.

We'll give it a rest for a while. When we come back: playing MP3s in Java.

Wednesday, February 23, 2011

Java : Comment Applet Vous? (Part 1)

As promised, we're going to show how to convert our "PeekBoo" application into an applet and embed it in a Blogger page. We'll split the process into two posts: part 1 is about writing an applet where you have some control of the directory structure of the hosting server. Part 2 will be about bundling the applet and its data files into a ".JAR" (Java Archive) file.

Our first code change is to define our class as an extension of JApplet rather than JPanel.
public class PeekaBooApplet extends JApplet implements MouseListener
Next, we replace our declaration of the constructor method "PeekaBoo()" with an "init()" method. (The code of the method is unchanged.)
public void init()
Our paint method changes name from "paintComponent(g)" to "paint(g)" (the code is again unchanged).
public void paint(Graphics g)
Now all that's left is to delete the entire "main()" method, and our code is complete:
public class PeekaBooApplet extends JApplet implements MouseListener
{
 private static final int PWIDTH =  237;
 private static final int PHEIGHT=  315;
 private static final int PEEKA =  0; // images[0] is Peeka
 private static final int BOO =  1; // image [1] is Boo
 
 private BufferedImage [] images = new BufferedImage [2];
 
 private int imageIndex;
 
 public void init()
 {
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));

  images [PEEKA] = loadImage("Images/peeka.jpg");
  images [BOO]   = loadImage("Images/boo.jpg");
  
  imageIndex = PEEKA;
  
  addMouseListener(this);  
 }

 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;
  }
  }
  
 public void paint(Graphics g){g.drawImage(images [imageIndex],0,0,this);}

 // stubs for you to play around
 public void mousePressed(MouseEvent e) {}
 public void mouseReleased(MouseEvent e) {}
 public void mouseEntered(MouseEvent e) {}
 
 // On mouse-click, display Boo image
 public void mouseClicked(MouseEvent e) {imageIndex=BOO; repaint();}
 
 // When mouse leaves window, display Peeka image
 public void mouseExited(MouseEvent e) {imageIndex=PEEKA; repaint();}
}
Great, so how do we call it? Save the above code to file "PeekaBooApplet.java" and compile using "javac". Then, save the following piece of HTML code to file "PeekaBooApplet.html" in the same directory. (Check that the directory has a sub-directory called "Images" containing "peeka.jpg" and "boo.jpg" from yesterday.)
<applet
 code="PeekaBooApplet.class"
 width="237"
 height="315">
</applet>
Click on the file "PeekaBooApplet.html" to open it in your browser and you should see CatWoman.
Click on her and move the mouse to see the action of the program.

What's happening here is that the browser is looking for the file "PeekaBooApplet.class" in the same directory as your ".html" file. If found, the program is run using the Java Runtime Environment - pretty much like typing "java" from the command line.

The running program then attempts to load the image files from an "Images" sub-directory of the current directory.

Okay, so now how do we embed our applet in our blogger page? Just putting the above HTML code into your post won't work, because the browser will look for the file "PeekaBooApplet.class" in whatever directory Blogger holds your blog page in.

So, we need to copy our ".class" file to a directory on a server that our readers can see. We're using "http://mgt.yourhda.com/Java" so we amend our HTML to read:
<applet
 code="PeekaBooApplet.class"
 codebase="http://mgt.yourhda.com/Java/"
 width="237"
 height="315">
</applet>
to point the browser to the right working directory.
Now all we need to do is to make sure that our images "peeka.jpg" and "boo.jpg" are copied to the right server sub-directory: "http://mgt.yourhda.com/Java/Images".

Let's try it: click on CatWoman then move your mouse away.








That was easy. But we were messing with our own server, and for this small example it was easy to copy all the required image files to the right place relative to our ".class" file. Next time we'll look at how to bundle everything up into a single ".jar" file.

If you add an applet to your blog, please link in the comments or send us an email:

java@vote-sanchez.com

Tuesday, February 22, 2011

Java : Peeka, Boo!

Our last program responded to mouse movements by polling: every time the Timer event "went off", we checked the current mouse position using MouseInfo.getPointerInfo().getLocation(). Today we're going to modify our program to respond directly to mouse events.

It's best if you make a new working directory, let's say "PeekaBoo", with its own "Images" sub-directory.
Now we need two new images: save them as "peeka.jpg" and "boo.jpg" in the new "Images" directory.



Instead of implementing "ActionListener" (listening for timer events), our class now implements "MouseListener" (listening for mouse events).
public class PeekaBoo extends JPanel implements MouseListener
We can drop the definition of the PERIOD constant, as we're not using a timer, and change LEFT & RIGHT to PEEKA & BOO.
private static final int PWIDTH =  237;
private static final int PHEIGHT=  315;
private static final int PEEKA =  0; // images[0] is Peeka
private static final int BOO =  1; // image [1] is Boo
Our constructor (initialization) method becomes:
public PeekaBoo()
{
 setPreferredSize(new Dimension(PWIDTH,PHEIGHT));
 images [PEEKA] = loadImage("Images/peeka.jpg");
 images [BOO] = loadImage("Images/boo.jpg");
  
 imageIndex = PEEKA;
  
 addMouseListener(this);  
}
Instead of starting a Timer, we add a mouse listener.
Now all that's required is to tell Java how to respond to mouse events.
// On mouse-click, display Boo image
public void mouseClicked(MouseEvent e) {imageIndex=BOO; repaint();}

// When mouse leaves window, display Peeka image
public void mouseExited(MouseEvent e) {imageIndex=PEEKA; repaint();} 
So, when a mouse-click is detected somewhere in the program window, display the "Boo" image. When the mouse leaves the program window, revert to the "Peeka" image.

And that's it. Here's the full program:
// PeekaBoo.java

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

public class PeekaBoo extends JPanel implements MouseListener
{
 private static final int PWIDTH =  237;
 private static final int PHEIGHT=  315;
 private static final int PEEKA =  0; // images[0] is Peeka
 private static final int BOO =  1; // image [1] is Boo
 
 private BufferedImage [] images = new BufferedImage [2];
 
 private int imageIndex;
 
 public PeekaBoo()
 {
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));

  images [PEEKA] = loadImage("Images/peeka.jpg");
  images [BOO] = loadImage("Images/boo.jpg");
  
  imageIndex = PEEKA;
  
   addMouseListener(this);  
 }

 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;
  }
 }
  
 public void paintComponent(Graphics g){g.drawImage(images [imageIndex],0,0,this);}

 // stubs for you to play around
 public void mousePressed(MouseEvent e) {}
 public void mouseReleased(MouseEvent e) {}
 public void mouseEntered(MouseEvent e) {}
 
 // On mouse-click, display Boo image
 public void mouseClicked(MouseEvent e) {imageIndex=BOO; repaint();}
 
 // When mouse leaves window, display Peeka image
 public void mouseExited(MouseEvent e) {imageIndex=PEEKA; repaint();}
 
 public static void main(String args[])
 {
  final PeekaBoo showPanel = new PeekaBoo();

  JFrame showFrame = new JFrame("Peeka-Boo");
  showFrame.getContentPane().add(showPanel,BorderLayout.CENTER);
  showFrame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);
  showFrame.pack();
  showFrame.setResizable(false);  
  showFrame.setVisible(true); 
 }
}
And that's all there is too it. Save as "PeekaBoo.java" and compile and run in the usual way. Let's try it out. Click on the image below, then move the mouse away.






Something's different...

Apart from the obvious change of image, the program running above is an applet embedded in a web page, rather than a stand-alone app like our program listing.

Next time we'll go through the steps required to convert our app into an applet and post it on blogger.

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.

Saturday, February 19, 2011

Java : When You've Got Timing

In yesterday's post we took our first, tentative steps into the world of Java GUIs with AWT and Swing.

WTF! Too many TLAs (Three Letter Acronyms). Let's back up a little and address each acronym in turn.

GUI : a Graphical User Interface - think of the difference between Windows and DOS (if you're old enough to remember DOS). A GUI usually consists of windows, mouse, buttons, icons and so on.

AWT : the Abstract Window Toolkit. In other languages, we'd call AWT a library of routines. In Java, it's better to think of it as a toolkit providing class definitions for windowing, graphics and user-interface "widget" objects. AWT interacts with the host operating System (OS) - Windows, Mac or Linux - at a low level. Because of this, a window opened using an AWT class will look like a Windows window when the program is run on a Windows PC, and like an OS X window when the program is run on a Mac.

Swing : a GUI widget toolkit kind of built on top of (and beside) AWT, that gives you more control over the look and feel of your applications.

So, yesterday's program defined "ShowImageApp" as an extension of the Swing "JPanel" class. Our program's "main" method constructed a new "showPanel" (the contents of our program's window) and stuffed it into a newly constructed Swing "JFrame" object called "showFrame" (the frame of the window).

Today, we're going to modify our program to load a second image, and to use an AWT timer to switch between the two images at one second intervals.

Let's start with our second image - everything's cuter with hearts:
When you've finished BAAAAWWWW-ing, save this image as "hitler_bambi_1.jpg"
in the same place you stored "hitler_bambi_0.jpg" yesterday.

First, we need to import definitions of timer-related objects:
import java.awt.event.*;
We need a new constant to define the period (in milliseconds) between picture changes.
private static final int PERIOD = 1000;
Now, we change our declaration of variable "image" to an array "images".
private BufferedImage [] images = new BufferedImage [2];
We also need a variable to keep track of which image from our array we should be displaying.
private int imageIndex;
In the "ShowImageApp()" constructor method, we change the initialization code to:
public ShowImageApp()
 {
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));

  images [0] = loadImage("Images/hitler_bambi_0.jpg");
  images [1] = loadImage("Images/hitler_bambi_1.jpg");
  
  imageIndex = 0;
  
  new Timer(PERIOD, this).start(); // start the Swing timer
  
 } // ShowImageApp

This loads both images, sets the image index to point at the first (0th!) image, and starts a Timer with period 1000ms.

The "paintComponent()" is modified slightly to display the current image.
public void paintComponent(Graphics g)
 {
  g.drawImage(images [imageIndex],0,0,this);
 }
The only other change we need to make is to tell the program what to do every time the Timer "goes off". For that we define an "actionPerformed" method as follows.
public void actionPerformed(ActionEvent e)
 {
  repaint();
  imageIndex = (imageIndex + 1) % 2;
 }
So, each time the Timer period expires, the "actionperformed" method is called. The method calls "repaint()" to trigger our "paintComponent()" method. The "imageIndex" is then toggled between 0 and 1.

One last change is to the line introducing the "ShowImageApp" class - we need to tell the compiler that "ShowImageApp" objects will listen for Timer actions:
public class ShowImageApp extends JPanel implements ActionListener
In Java jargon, the class implements the abstract interface "ActionListener".

Adding all of the above changes to yesterday's program we get:
// ShowImageApp.java

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

public class ShowImageApp extends JPanel implements ActionListener
{
 private static final int PERIOD = 1000; // Swing timer interval 1.0 secs
 private static final int PWIDTH =  417;
 private static final int PHEIGHT=  400;
 
 private BufferedImage [] images = new BufferedImage [2];
 
 private int imageIndex;
 
 public ShowImageApp()
 {
  setBackground(Color.black);
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));

  images [0] = loadImage("Images/hitler_bambi_0.jpg");
  images [1] = loadImage("Images/hitler_bambi_1.jpg");
  
  imageIndex = 0;
  
  new Timer(PERIOD, this).start(); // start the Swing timer
  
 } // end of constructor

  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: repaint and toggle the image index
 public void actionPerformed(ActionEvent e)
 {
  repaint();
  imageIndex = (imageIndex + 1) % 2; // toggle between 0 and 1
 }
 
 public void paintComponent(Graphics g)
 {
  g.drawImage(images [imageIndex],0,0,this);
 }
  
 public static void main(String args[])
 {
  final ShowImageApp showPanel = new ShowImageApp();

  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
} // ShowImageApp Class
Save the program as "ShowImageApp.java" and compile and run in the same way as yesterday and you should get the cutest flashing image ever.

"Big deal" I hear you say, "we could have done that with a .GIF". So true, but tomorrow we'll make our program interactive with a bit of mouse handling.

Friday, February 18, 2011

Java : Framing Treasured Moments

Yesterday's "Hello world!" program just wrote text to a DOS box. Today's program is going to open up a window and display an image in it. Not quite "Call of Duty: Modern Warfare 3", but remember - baby steps.

We'll start with this heart-warming image of two lovable cartoon characters.

Make a new sub-directory of your Java working directory and call it "Images". Save the image in there as "hitler_bambi_0.jpg". (If you're offended by cartoon deer, you can use any image you like, but be sure to change the image and directory names in your program later.)

Now for our program:
// ShowImageApp.java

// import definitions for the pre-defined classes & methods we'll be using
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;

public class ShowImageApp extends JPanel
{
 // define constants to determine the width & height of our window
 private static final int PWIDTH =  417;
 private static final int PHEIGHT=  400;
 
 // declare a variable to hold our image;
 private BufferedImage image;
 
 // ShowImageApp() is a constructor method for initializing new ShowImageApp objects
 public ShowImageApp()
 {
  setPreferredSize(new Dimension(PWIDTH,PHEIGHT));
  image = loadImage("Images/hitler_bambi_0.jpg");
 }

 // Load the image from <filename>, returning it as a BufferedImage
  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;
  }
 }
 
 // tells the window manager how to paint the window
 public void paintComponent(Graphics g)
 {
  g.drawImage(image,0,0,this);  
 }
  
 public static void main(String args[])
 {
  // construct a new object, showPanel, of class ShowImageApp
  ShowImageApp showPanel = new ShowImageApp();

  // construct a new window-frame object, showFrame
  JFrame showFrame = new JFrame("Frame title goes here");

  // link the panel to the frame
  showFrame.getContentPane().add(showPanel,BorderLayout.CENTER);

  // tell Java to shut down when we close the window
  showFrame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);

  // don't allow the window to be resized
  showFrame.setResizable(false);

  // display the window
  showFrame.pack();
  showFrame.setVisible(true); 
 } // main
} // ShowImageApp class
Whoah! That's a big jump in complexity from the "Hello World" program. Let's strip out some of the noise and show some simplified pseudo-code.
import definitions;

public class ShowImageApp extends JPanel
{
 define constants & declare variables;
 
 ShowImageApp() is a constructor method for the ShowImageApp class

 loadImage(filename) loads an image into a BufferedImage
  
 paintComponent(Graphics g) tells the JVM how to paint the window
  
 public static void main(String args[])
 {
  construct a new ShowImageApp object called showPanel;

  construct a new window frame called showFrame;
  tell JVM that showPanel is the content of showFrame;
  tell JVM to shut down when we close the window;
  make the window size fixed;  
  display the window;
 }
}

So, yesterday's program defined the "HelloWorldApp" class: today's defines "ShowImageApp".
Yesterday's "main" method just printed a line of text: today's constructs a new object "showPanel"; makes a window for it "showFrame"; links the two; does some housekeeping; and displays the window.

The most confusing part of this program for me as a beginner is the overloading (re-definition) of the word "ShowImageApp". In a better designed language, the constructor method for the "ShowImageApp" class might have been called "makeShowImageApp". This would make it a little clearer that the constructor is just an initialization method for a new class object. The declaration of "showPanel" would then read:
ShowImageApp showPanel = new makeShowImageApp();
Sadly, we're stuck with Java's execrable syntax.

The most complicated part of our program is perhaps the method "loadImage". You'll see code like
try{some action}catch{some exception}
quite a lot in Java - usually when performing input/output (I/O) of some kind. It just tells the JVM to try to do something, and if something goes wrong, to handle the exception gracefully.

To run the program, copy and save the first program listing (not the pseudo-code) to a file called "ShowImageApp.java" in your working directory. (Remember, the filename must match the class name.)

Compile with

javac ShowImageApp.java

and run with

java ShowImageApp

Your most likely source of problems is that the program looks for the image in the wrong place and with the wrong name. Java is case sensitive! But, Windows often "fixes" file commands for you so cases "kind of" match. Make sure your images sub-directory is called "Images" not "images" or "ImAgEs".

Once you get the program working, you can swap the image for something from your fap folder. remember to change the definitions of PWIDTH and PHEIGHT to match the size (in pixels) of your new image.

Have fun.

Thursday, February 17, 2011

Java : Hello World

We're dragging our feet a bit here as "Hello World" programs are mind-numbingly dull. But, we've got to start somewhere. So, with a rolled howl, we'll lead our low lol herd to a lewd ho roll (in ASCII). ("Hello World" doesn't even have any good anagrams.)

First off, create a desktop shortcut to make it easy to start a DOS box in your Java working directory. On our Windows XP laptop, we copied the "Command Prompt" shortcut from <start><All Programs><Accessories> to the desktop. Right click on the DOS prompt icon and you should see "Target: %SystemRoot%\system32\cmd.exe". Change the "Start in:" field to your working Java directory. In our case "C:\Documents and Settings\Sucio\Desktop\Java".

On Windows 7, the Target would be "%windir%\system32\cmd.exe" and we'd probably start in "%HOMEDRIVE%%HOMEPATH%\Java" which comes out as "C:\Users\Sucio\Java".
(I changed the name of my shortcut to "JAVA Prompt.)

So, I'm sure you're itching to try something so let's get started. Here's the text of our simple "Hello World" program.

class HelloWorldApp {
    public static void main(String[] args) {
      System.out.println("Viva Sucio!");
    }
}
There's a very good description of what every word of this program is doing at <Jimmy Wales' blog>. For now, we'll just say that the program defines a class of objects called HelloWorldApp and tells Java what the object can do (its methods - in this case, just the method main).

Copy and paste the simple program into a new file "HelloWorldApp.java" in your working directory. (Note, a java program must have a file name ending with ".java"; and the name must match that of the class defined by the program - in our case "HelloWorldApp".)

Once you've saved the program, at the command prompt, type

javac HelloWorldApp.java

and press enter. If you haven't screwed up, there'll be a slight pause and then you'll get a new prompt as though nothing's happened. But, if you list the directory contents, you'll find that there's now a new file called "HelloWorldApp.class". (If the PC complains that it can't find javac, it's because you didn't set the PATH environment variable properly. Follow the link in yesterday's post to find instructions.)

So what happened here? The Java compiler ("javac") compiled (translated) the Java class definition in our program source file into bytecode. Bytecode is a special kind of machine instruction which can be run (interpreted) by something called the Java Virtual Machine (JVM). the bytecode program is stored in a ".class" file.

Rather than waffling let's have a go: type

java HelloWorldApp

and press enter. Your "Hello World" message (in our case "Viva Sucio!") should appear on the screen, followed by a new prompt.

The JVM ("java") loaded the bytecode in "HelloWorldApp.class" and started running the program at the "main" entry point. The "main" method told the JVM to print the line of text "Viva Sucio!" to the system output stream.

Hopefully some the the jargon in our last post is getting clearer now. We downloaded the Java Runtime Environment (JRE) which contained the Java Virtual Machine (JVM - "java"). We also downloaded the Java Development Kit (JDK) which contained the Java compiler ("javac").


Play around a bit changing the message string in the program.

    ,/,         ,.%((.)))             |.
   '///_,      (///)\\)))          ,  |||/
    \  ,'     (([]-[]-\\\)         y-";,-"
     | |       )| -    @)))        | |
     |  \      ((\___,"((         /  |
     |   `---.__))|   |())___.---'   |
      `-._       "-_   _ -"       _,-"
          "-.__,"         ".__.-"
              ( @   / \   @ )
               `---'   `---'
                |         |
                |    .    |
               /           \
              /    "-.-"    \
             /      /^\      \
            /      /   \      \
           /      /     \      \
          (    ."        ".     \
           \    )          \     \
            \   ".          `.    \
             ".   \            \   \
               `.  `)           \  ".
                 \  (            \  \
                .mno/            |   \
                                  Oonm'
"Sarah Palin nude" - That should get the google hits up.


(Based on an image by hjw at the ASCII pôrn archive.)

Tuesday, February 15, 2011

Java : Baby Steps

As we indicated yesterday, we plan to post a series of pieces about Java. We don't intend (or expect) to teach anybody basic programming concepts - like for loops - there are plenty of better places to learn that stuff. What we'll focus on is the practical difficulties for a newbie getting started with Java.

The first big hurdle we encountered was in installing the language - almost a show-stopper. We decided to install the Java Development Kit (JDK) and the Netbeans Integrated Development Environment (IDE) at the same time, and downloaded the  <JDK 6 Update 23 with NetBeans 6.9.1>  package from <oracle.com>.

We started up the installer and then sloped away for a coffee. When we got back, there was a shiny new "Netbeans" icon on our desktop. After a precautionary reboot, we clicked on Netbeans and received a couple of error messages: "The JDK is missing" and "Cannot locate java installation in specified jdkhome : C:\Program Files\Java\jdk1.6.0_23. Do you want to try to use the default version?" We then wasted an hour or two tinkering with environment variables and the Netbeans configuration file ("netbeans.conf") before realizing that the first error message meant exactly what it said - the JDK was missing: it hadn't installed at all.

So, we ran the installer again, and this time the JDK installed.
WTF?! The first of many Half-Assed Excellence awards for Sun/Oracle.


We then followed the instruction in step 4 on the oracle.com page linked <here> to set our PATH environment variable. This is so you can compile a program by typing "javac Sucio.java" in a DOS box, rather than having to type "C:\Program Files\Java\jdk1.6.0_23\bin\javac Sucio.java" - which would get old very fast (unless you're Mavis Beacon).

Having gone to the trouble of downloading and installing Netbeans, we decided not to use it just yet. IDEs are a great tool for experienced programmers to crank out code quickly, but they can get in the way of learning about a language. (And we're too lazy to RTFM.)

So, for now, we're going to edit our code using Programmer's Notepad - a nice little editor that knows about Java syntax (and a lot of others) - which can be downloaded free <here>.

Next time, we'll run through compiling a traditional "Hello World" program:

class HelloWorldApp {
    public static void main(String[] args) {
      System.out.println("Viva Sucio!");
    }
}

(The code sample above was posted using google-code-prettify following the instructions posted <here>.)

Monday, February 14, 2011

Java : Javanna Learn Java?

When we started this blog last September, one of our goals was to become more proficient in "shooping". In particular, we wanted to learn just-enough GIMP to improve the crappy appearance of the software we occasionally write.

Three months later, the GIMP thing had developed a life of its own. It was only after we spent a week creating the "Personal-Space Invaders" .GIF and found ourselves thinking "it would have been easier to write the game" that we remembered our original plan.

So, we've spent the past week or so learning the rudiments of Java and posting occasional test applets to see if it's possible to publish programs on blogger. Why Java? We want to use something that we can share with our readers, it's free, it's (kind of) portable and it's close enough to the vanilla C that we usually tinker in. Why not Flash? We'd all end up infected with McAfee malware.

For the next few weeks (until the Java ad revenue dries up), we'll be posting applets and very simple tutorials on Java programming. (They'll have to be simple - we're just learning too.) If you want to follow along, you'll need to install the Java Development Kit from oracle.com. We'll post about the problems we had installing JDK 6 Update 23 with NetBeans 6.9.1 on a Windows XP (SP2) laptop tomorrow.

This brings us on to a word of warning: Sun's (now Oracle's) Java products are flaky. Installers don't always install fully - they often require manual tinkering, updates are naggy and annoying, and the run-time software may crash your machine or make your browser unstable. So, if you're not planning to go along with the tutorials, and you have no desire to play Java games like Minecraft, you're probably better off not installing any Java components.

If you don't think you want to program but you would like to be able to view our applets, you'll need the Java Runtime Environment (JRE) from here. The JRE page has a link to other pages where you can test whether your Java installation is working and up to date: but the tests and troubleshooting guides are pretty useless for anything other than Windows XP/Vista/7.

 
For those choosing not to install Java, we'll try to remember to post a description of what the applet is doing, alongside the "no Java" button to the left.


A final warning: Java is "portable" in the sense that if you work really, really hard, you can make it run under enough browsers and operating systems to cover (say) 99% of your target audience. we're not going to work that hard. After updating all our system software, our scuttling crablet sort of kinda works on our Ubuntu (amd64) machine - but crashes the browser and scrambles the screen. We haven't managed to view it at all on our OSX 10.5.8 machine. So, the 1% of our regular readers who use Linux, and the rather larger proportion of you that use Macs, are likely to be disappointed.

Thankfully, very few of you use Internet Explorer, and none seem to be using the dreaded IE6. But, if you do try to view the applets with an old machine with an outdated Java Runtime Environment, we've no idea what you'll see. We'll leave the agonizing over backwards-compatibility to pony-tailed toss-pots who get paid to worry about such stuff.

In recognition of our sloppy attitude, we award ourselves, (and Sun/Oracle) this special
Certificate of Half-Assed Excellence.


Tomorrow we'll go over a few of the quirks we found when trying to install the JDK.

Saturday, February 12, 2011

Test : Can You Hear Me Now?



Let's try again without Google docs...

Friday, February 11, 2011

Test : Another Crabby Applet





Just doodling.

Like the previous post, this is a Java applet bundled up into a ".jar" and hosted at docs.google.com. I find I can see the crab in Firefox, Internet Explorer and Chrome on Windows XP (SP2) and Windows 7. I haven't yet been able to get it running in Safari (OS X) or Firefox/Chromium (Ubuntu amd64 - probably a plug-in issue).

In the comments please let me know whether you see a crab and what browser/OS you're using.

(It seems that I can't view the applet from any browser that's logged in to my docs.google.com account. Probably a security measure to protect users from self-modifying applets.)

Wednesday, February 9, 2011

Test : Please Ignore






Nothing to see here: move along.