Showing posts with label APPLICATION. Show all posts
Showing posts with label APPLICATION. Show all posts

Friday, 21 September 2012

Mobile Java

One of the nice things about Java is that is supported on more than desktop platforms, and has been for a long time. This means there is not only a large library of existing software, but also well-tuned development systems to use with mobile platforms.

By "mobile platform", I'm referring to smartphones and tablets. There are other mobile platforms, but these are the most common ones. Netbooks may also run a "mobile" operating system, or they may run a normal desktop OS. Those that run a normal desktop OS will run normal Java SE applications. Java SE is "Java, Standard Edition", the version that typically runs on a desktop or laptop computer.

Java ME is Java, Mobile Edition. It runs on most smartphones, and many tablets. It is very similar to the Java SE version covered in most of my articles. In fact, it is possible to write many applications using a subset of Java that will run without change under both Java SE and Java ME.

But normally a Java ME application will use user interface objects and interfaces that are specific to Java ME. In many ways these are more sophisticated than the ones for Java SE. Creating many types of graphical interfaces, such as tiled graphics, is easier in the mobile edition than in standard Java.

I have been writing small, simple applications for my cellphones for about ten years now. It's nice to be able to write your own little application for your own unique needs. I started writing Java applications for my Nokia 3650, called a "feature phone" at the time I got it. It was a Symbian Series 60 phone that ran an early version of Java ME with a very basic library of GUI features.

My next phone was a step up the Java ladder. It was a Sciphone G2, a fake Android phone. I didn't mind that it was "fake", it ran a real version of Java ME with updated GUI capabilities, which made it far easier to write applications for.

My current phone is a Blackberry Curve 8900. It runs Java ME with all the latest bells and whistles, plus a lot of Blackberry add-ons that make it easy to access the phone's features.

With my Nokia, I had a special Java development environment provided by Nokia that included a simulation of my phone, so that I could see how my programs would run before I put them on the phone. With the G2 I was on my own. I ran a standard Java ME development environment from within Eclipse, a great Java integrated development environment. The version linked above is a version specific to Java ME.

Now I'm back to having a development environment provided by my phone's maker. I have a program that simulates my phone on my computer, which again allows me to try out my programs before I put them on the phone (with my G2 I tested them as well as I could, then loaded them on the phone and hoped for the best.) It is build on Eclipse, so it is still very familiar. There is also a slew of information on the Blackberry site (linked above) about Java development.

Unfortunately, the tutorials on the site don't exactly match the actual current version of the software, but it's close enough it's not too hard to figure out. One thing that confused me, however, is the installation instructions. I thought I had to install the version of Eclipse they called for before installing the "Blackberry Java Eclipse Add-On". It's an add-on, right?

Well, it turns out that the "add-on" from Blackberry is actually the entire thing, Eclipse and all. So you just need to do that one download to get the development environment. Then download the simulator for your phone and any others you want to test your software on. Finally, apply for a signature key to make it so that you can "sign" your software to allow it to be installed on the phone through the software manager or Over The Air (OTA) when using the Blackberry-specific libraries.

If you'd rather not do this, you can develop software using a plain-jane version of Java ME, then transfer the software to your phone however you please. I put the software I developed for my Sciphone G2 on the memory card for my Blackberry, and it runs just fine.

Translating applications between Java SE and Java ME can be simple for ones with minimal amounts of graphics, like programs that mainly use text, buttons, and text entry boxes for communication. Things like games, with a more involved use of graphics, take more effort to translate between the two versions of Java. For these, I usually re-use the game logic code without changes, then rewrite the graphical display parts of the program from scratch. Because I use good object-oriented coding practices (most of the time), this isn't too much effort.

Java ME applets are easy to translate, though I write almost all of my Java software as applications now.

A Java CSV File Reader

One of the most common types of data file is a CSV (Comma Separated Value) file. They can be exported by many popular applications, notable spreadsheet programs like Excel and Numbers. They are easy to read into your Java programs once you know how.

Reading the file is as simple as reading a text file. The file has to be opened, a BufferedReader object is created to read the data in a line at a time.

Once a line of data has been read, we make sure that it's not null, or empty. If it is, we've hit the end of the file and there's no more data to read. If it isn't, we then use the split() method that's a member of Java's String object. This will split a string into an array of Strings using a delimiter that we give it.

The delimiter for a CSV file is a comma, of course. Once we've split() the string, we have all the element in an Array from which our Java programs can use the data. For this example, I just use a for loop to print out the data, but I could just as well sort on the values of one of the cells, or whatever I need to do with it in my program.

The Steps

  1. Open the file with a BufferedReader object to read it a line at a time.

  2. Check to see if we've got actual data to make sure we haven't finished the file.

  3. Split the line we read into an Array of String using String.split()

  4. Use our data.


The Program
// CSVRead.java
//Reads a Comma Separated Value file and prints its contents.

import java.io.*;
import java.util.Arrays;

public class CSVRead{

 public static void main(String[] arg) throws Exception {

  BufferedReader CSVFile = 
        new BufferedReader(new FileReader("Example.csv"));

  String dataRow = CSVFile.readLine(); // Read first line.
  // The while checks to see if the data is null. If 
  // it is, we've hit the end of the file. If not, 
  // process the data.

  while (dataRow != null){
   String[] dataArray = dataRow.split(",");
   for (String item:dataArray) { 
      System.out.print(item + "\t"); 
   }
   System.out.println(); // Print the data line.
   dataRow = CSVFile.readLine(); // Read next line of data.
  }
  // Close the file once all data has been read.
  CSVFile.close();

  // End the printout with a blank line.
  System.out.println();

 } //main()
} // CSVRead


Downloads

This program, and an example CSV file to use it with (a section of a spreadsheed I use to keep track of my integrated circuits) are available at my code archive.

Writing to CSV Files with Java

Writing to a CSV file is as simple as writing a text file. In this case, we write a comma between each field, and a newline at the end of each record.

Give it a try, starting with TextSave.java, modify it appropriately, then see what your favorite spreadsheet program thinks of the results.

Saturday, 15 September 2012

Java's File Names and Class Names

Java is picky about the file names you use.

Each source file can contain one public class. The source file's name has to be the name of that class. By convention, the source file uses a .java filename extension (a tail end of a file name that marks the file as being of a particular type of file.)

So, for a class declared as such:
public class HelloWorld{
...

The file it is stored in should be named HelloWorld.java.

The capitalization should be the same in both cases. Some operating systems don't notice whether file names are capitalized or not. It doesn't matter, you should be in the habit of using the correct capitalization in case you work on a system that does care about capitalization.

When you compile your file with javac, you pass the full file name to javac:

javac HelloWorld.java

Let's say we save the file under a different name. We write the following program:

public class HelloThere{
    public static void main(String arg[]){
        System.out.println("Hello There.");
    }
}

Then we save it as HelloWorld.java, and try to compile it:
>javac HelloWorld.java
FileName.java:1: class HelloThere is public, should be declared 
in a file named HelloThere.java
public class HelloThere{
       ^
1 error


Java lets us know that it won't compile until we rename the file appropriately (according to its rules.)

So let's rename the file. Let's call it HelloThere.javasource. Seems a bit more explicit than just .java, right? Let's run the compiler:

>javac HelloThere.javasource 
error: Class names, 'HelloThere.javasource', are only accepted 
if annotation processing is explicitly requested
1 error

Java's still not happy with us. Annotation processing? That's when we include extra information in the program about the program itself. We're not bothering with that just now. So we should just name the file HelloThere.java, and not get fancy with our file names.

But, under the right circumstances, javac does allow file name extensions other than .java. That's why we always type in the full file name, including .java, when we use javac. We say 'javac HelloThere.java', not just 'javac HelloThere'. Javac can't assume that we mean a .java file, though that's what it will usually be.

The Class File

Once we make javac happy with a proper file name, and a program with no errors, javac produces a new file. This file will have the original file name, but with .java replaced with .class. This is your bytecode file, the file that the Java Virtual Machine can run.

When we run the program with Java, we're running the .class file. In the case of HelloThere, we're running the HelloThere.class file. But we don't type in the full file name. Why?

Unlike javac, java requires a .class file. That's all it will work with. There's no opportunity to have a different extension to the file name. So it assumes the .class part of the file name. But that's not the whole story.

If you add .class yourself, here's what you'll get:
>java HelloThere.class
Exception in thread "main" java.lang.NoClassDefFoundError: 
 HelloThere/class
Caused by: java.lang.ClassNotFoundException: HelloThere.class
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

Pretty ugly. What we're actually doing when we type "java HelloThere" is telling Java to run the class HelloThere. Java assumes that it will find this in a file called "HelloThere.class", so that's what it's looking for first.

We're not telling Java to run the file HelloThere.class, we're telling it to run the class HelloThere, which it expects to find in the file HelloThere.class.

But what if we ask for another class that doesn't have its own .class file?

Just for fun, let's change HelloThere.java like this, and see what happens:

public class HelloThere{
 public static void main(String[] arg){
  System.out.println("Hello.");
 }
}

class HelloZoik{
 public static void main(String[] arg){
  System.out.println("Zoiks!");
 }
}

After we edit it, we compile with 'javac HelloThere.java' and hold our breath.

Hurray! No errors!

Now we have a second class, HelloZoik, in the HelloThere.class file. Can Java find it?

Let's try:

 java HelloZoik
Zoiks!

It worked! Java found our class inside HelloThere.class.

This shows it's not the file name that we're calling with the 'java' command, it's the class name.

If Java doesn't find the class inside a file with the same name as the class followed by .class, it'll look in the other .class files available.

Should I Still Learn Java?

With all the controversy surrounding Java thanks to the purchase of Sun by Oracle, the lawsuits flying back and forth over the Java Community Process, the Apache Foundation, Android, and all the rest,
  
does it still make sense to learn Java?

After all, the demise and abandonment of Java is being predicted practically every day.

I say Yes, now is the time to learn Java. No matter what your programming skill or background, Java is a valuable language to learn, it will be used and useful for a long time to come.

Never a Dull Moment

The Java language has been a-swirl in controversy since its public announcement. It has not become "the" language in many of the areas it originally claimed to be "the" language to use, but yet it has become popular in many other areas. In fact, Java is neck and neck with the language C for being the most popular computer language:

TIOBE Software Community Index (of most popular programming languages.)

langpop.com Programming Language Popularity Rankings.

Devtopics.com Most Popular Programming Languages.

Why Popularity Matters

Why does popularity matter? Because it entrenches a programming language, not just for now, but for many years to come. In fact, every language that has ever become deeply entrenched is still with us, so there's no way of knowing just how long popularity will keep a programming language alive.

When I was first learning to program, the big languages were assembly (the "real" programmer's language of the time), BASIC, FORTRAN, and COBOL. Every single one of those is still a viable language today. Though if you'd asked me then, I would never have thought COBOL would still be with us today. I would never have believed how popular it is, either.

But COBOL was re-invented in the late 80's. And there were a lot of big-money installations running on it. ADA failed to displace it. It's still here, and it's still a valuable part of a programmer's resume for many jobs.

FORTRAN is a language I expected to re-invent itself. It had already done so by the time I learned it (I first programmed in the original FORTRAN, but FORTRAN IV was already in common use.) But with the promulgation of Pascal, Modula-2, and C in the 80's I figured FORTRAN would be pushed into the recesses of obscurity. I was wrong.

Modula-2 was mishandled by the company that owned the rights to it, so it never took off as well as it might have. Pascal took off even though it was never intended to be anything but a classroom language. C took off since it didn't have Modula-2's licensing disadvantages and it had enough of its advantages to become the "next generation language" of its day.

Modula-2 is still with us, but it's insignificant among languages today. Because it never got popular. The others I mentioned got popular, and they're still popular today. Yeah, even Pascal. You could learn Pascal today and do a lot with it (though I don't recommend it unless you want the academic challenge of broadening yourself as a programmer.) I still write software in Pascal, though mostly for my own use, and only for older computer systems.

The key to a programming language's longevity is popularity. Once a language becomes sufficiently popular, for all practical purposes it will never die.

Java is that popular.

The Many Javas

Java has become deeply ingrained into the modern computer infrastructure. Not only does the Java Virtual Machine support a lot more languages than Java itself, but Java has spawned other languages so close to itself that if you know Java you can pick up the other languages without significant effort. C# is the most popular of these spin off languages.

Plus, there are different versions of Java. The Mobile Edition, used on cell phones, smart phones, and PDAs, is a major programming language for these platforms. Each of these platforms has its individual programming suite, and associated language. Their second language, the Esperanto of the portable world, is Java. Programmers that want their software to move easily between platforms often choose to write their code in Java.

The use of Java on servers is rife as well. Java Enterprise Edition became the most popular use of the Java language when Java was still struggling to be used as an applications programming language over a decade ago. Some say that Java on the server saved the Java language. Certainly this is what makes Java a good language to learn for professional reasons.


The Most Important Reason

The most important reason to ignore all the hullabaloo about Java's impending demise and not worry about learning it is that:

  • it is a good language that's fairly easy to learn,

  • expressive enough to do a lot of different things effectively,

  • easy to develop sophisticated modern programs in

  • without too much work for an individual or small group of developers,

  • gives access to all the important parts of the machine (graphics, sound, filesystem, peripherals)

  • and what you learn travels well to other languages when you go on to learn them.


It's not going to go away any time soon. There's too much momentum. There's no need to worry. Ever since the launch of Java I've heard that it's going to be gone or unusable tomorrow. History shows that just doesn't happen to popular programming languages.

If you learn Java now, you may still be using it 20 years from now. Or 30.

When I sat down to a card punch to write my first program 38 years ago as I write this, the computer lab know-it-all came to look over my shoulder.

"FORTRAN!" he said. "Why are you wasting your time with that language? It's a dead, old language. Did you know it's the oldest computer language? If you really want to be a programmer, you should start right out in BAL*! That's what real programmers use, and you're going to be behind if you waste your time on anything else."

FORTRAN doesn't make the "top 10" in programming languages much any more, but it gave me a good start. It's still among the most popular languages, around #20, or just out of the top 10 if you only count general purpose programming languages (that is, not counting scripting languages, query languages, application-specific languages, and so on.)

And learning FORTRAN never kept me from learning structured languages, AI languages, Object Oriented languages, and so on. Even though my first program included the "dreaded" GO TO statement.

There's never been a better time to learn to program. And there's never been a better time to learn Java (the language is in the best shape it's ever been!)

*Basic Assembly Language, a version of assembly language for IBM computers.

Interactive Keyboard Input In Java: KeyListeners

n a console application, you can get keyboard input using the Scanner class, as described in Keyboard Input for Console Apps. In an graphical app, though, you can use one of the classes built to accept text input (e.g. TextArea or JTextField) or add code to your application to respond directly to the keyboard.

Keyboard input in the Java GUI made simple.
Playing with Today's Program

There are two basic ways of doing this. One is to set up Key Bindings, which maps keystrokes to actions in your application similar to accelerator keys or menu keyboard equivalents. The other is to use a Key Listener, similar to the Mouse Listener, which I detailed in Simple Mouse Interaction.

In this example we're going to use Key Listeners. There is less overhead to setting up a KeyListener when you just need to use a few keys. Key Bindings require more overhead to set up, but when you want to bind actions to a lot of different keystrokes, and manage the actions bound to particular keystrokes at a higher level, Key Bindings are better to use than a simple KeyListener.

As its name implies, a KeyListener is an Event Listener. If you're not sure what that is, read my article on Listeners or follow the prior link to Oracle/Sun's description.

Here's a program that demonstrates simple keyboard interaction. It's based on the MousePanel program I presented in Simple Mouse Interaction. It acts as a sort of "Etch-a-Sketch". You can download the KeyPanel program source from my Java code site.

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

public class KeyPanel extends JPanel implements KeyListener{

public KeyPanel(){
super();
pointX=0;
pointY=0;
oldX=0;
oldY=0;
addKeyListener(this);
}

int pointX, pointY, oldX, oldY;
boolean erase;

public void paintComponent(Graphics g){
// Erase the board if it's been requested.
if (erase) {
g.clearRect(0, 0 , getBounds().width, getBounds().height);
erase = false; // We're done, turn off this flag now.
}

// Draw gray where the pointer was..
g.setColor(Color.GRAY);
g.fillRect(oldX-2, oldY-2, 4, 4);
// Draw "Cursor" at current location in black.
g.setColor(Color.BLACK);
g.fillRect(pointX-2,pointY-2, 4, 4);
}

public void keyPressed(KeyEvent key){

// Copy the last clicked location into the 'old' variables.
oldX=pointX;
oldY=pointY;
// Move the current point depending on which key was pressed.
if (key.getKeyCode() == key.VK_DOWN){
pointY=pointY+5;
if (pointY > getBounds().height){
pointY=getBounds().height;
}
}
if (key.getKeyCode() == key.VK_UP){
pointY=pointY-5;
if (pointY < 0){pointY=0;}
}
if (key.getKeyCode() == key.VK_LEFT){
pointX=pointX-5;
if (pointX < 0){pointX=0;}
}
if (key.getKeyCode() == key.VK_RIGHT){
pointX=pointX+5;
if (pointX > getBounds().width){
pointX=getBounds().width;
}
}

// Set a flag to erase the screen if Space is pressed.
if (key.getKeyCode() == key.VK_SPACE){
erase = true;
}


// Tell the panel that we need to redraw things.
repaint();
}

/* The following methods have to be here to comply
with the MouseListener interface, but we don't
use them, so their code blocks are empty. */
public void keyTyped(KeyEvent key){ }
public void keyReleased(KeyEvent key){ }

public static void main(String arg[]){
JFrame frame = new JFrame("Use Arrows to Draw, Space to Erase.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640,480);

KeyPanel panel = new KeyPanel();
frame.setContentPane(panel);
frame.setVisible(true);

// We *must* do this to see KeyEvents.
panel.setFocusable(true);


// Initialize the drawing pointer.
panel.oldX=panel.getBounds().width/2;
panel.oldY=panel.getBounds().height/2;
panel.pointX=panel.oldX;
panel.pointY=panel.oldY;

}
}

Using this technique with the Simple Video Game Kernel would be similar. The VGKernel would extend KeyListener, register itself, and implement the KeyListener methods. But in those methods, rather than performing the operations that result from the keypress, as in this program, you would want to simply set a flag to show that the key has been pressed. Then, in your core game logic you would test to see whether the key has been pressed, and perform the appropriate actions.

That way the actions are performed at the appropriate time in your game, and not just whenever the key happens to get pressed. Reacting to a key when it is pressed is appropriate for a turn-based game, but not for a real-time game. In a real-time game the action happens according to the timing of the TimerTask that drives the game, which is why we just note that a key has been pressed, and wait until the TimerTask occurs to actually conduct the action related to that key. This would be similar to what we do with the space key here, which sets a flag to tell paintComponent() to erase the screen.

Give this program a try, see if you can extend it to allow the user to select colors to draw with or change the size of the drawing pen.

Calling System Commands in Java

Let's suppose you want to run another program on your system from within Java. Personally, I first decided I wanted to do this for the sake of a prank. You may have more businesslike purposes in mind, yourself.

It's not too hard to do this since Java 1.5, which added the Process and ProcessBuilder classes.

Here's an example program that starts up Firefox at a particular website:

public class OpenSite{
  public static void main(String arg[]){
    try { Process p = new ProcessBuilder("firefox", 
            "http://beginwithjava.blogspot.com/").start(); }
   catch(java.io.IOException io){ }
  }
}

I've compressed the various parts of the action down to one line here:

Process p = new ProcessBuilder("firefox", "http://beginwithjava.blogspot.com/").start();

I'm creating an "anonymous" ProcessBuilder object, calling its start() method, which returns a Process, which I name simply "p".

The whole thing is wrapped up in a try...catch structure because javac wants to see us deal with any I/O errors that result. In this program, I just ignore them.

So you'll want to make sure that you either catch those errors and deal with them, or that they will be unimportant enough that they don't matter.

Also note that the Java program's process will last as long as the external program you call. So if you don't shut down this instance of the firefox process, you'll have Java still running.

If you want to see something fun you can do with this on Mac, check out this article about adding speech to the Simple Video Game Kernel.

Friday, 14 September 2012

A Simple Java Video Game Kernel

Most video games run continuously, rather than waiting for user input before they do something. The heart of a video game of this sort is called the kernel. The kernel is running in the background, collecting user input and updating the display. It uses logic to determine if the game has been won or lost or otherwise control the state of the game.




This simple kernel sends a ball bouncing around on the screen. Turn it into your own Pong, Breakout, or Tank clone.

To run this way, Threads are usually used to allow more than one thing to be going on at a time in a Java program. We've looked at a simple way of using threads before, the Timer class.

Here's a really, really simple video game kernel. It has all the basic elements of a video game.
 
/* A simple video game style kernel
   by Mark Graybill, August 2010
   Uses the Timer Class to move a ball on a playfield.
*/

// Import Timer and other useful stuff:
import java.util.*;
// Import the basic graphics classes.
import java.awt.*;
import javax.swing.*;

public class VGKernel extends JPanel{

// Set up the objects and variables we'll want.
public Rectangle screen, ball; // The screen area and ball location/size.
public Rectangle bounds;  // The boundaries of the drawing area.
public JFrame frame; // A JFrame to put the graphics into.
public VGTimerTask vgTask; // The TimerTask that runs the game.
public boolean down, right; // Direction of ball's travel.

// Create a constructor method that initializes things:
  public VGKernel(){
    super();
    screen = new Rectangle(0, 0, 600, 400);
    ball   = new Rectangle(0, 0, 20, 20);
    bounds = new Rectangle(0, 0, 600, 400); // Give some starter values.
    frame = new JFrame("VGKernel");
    vgTask = new VGTimerTask();
}
  // Create an inner TimerTask class that has access to the
  // members of the VGKernel.
  class VGTimerTask extends TimerTask{
    public void run(){
      moveBall();
      frame.repaint();
    }
  }

// Now the instance methods:
  public void paintComponent(Graphics g){
    // Get the drawing area bounds for game logic.
    bounds = g.getClipBounds();
    // Clear the drawing area, then draw the ball.
    g.clearRect(screen.x, screen.y, screen.width, screen.height);
    g.fillRect(ball.x, ball.y, ball.width, ball.height);
  }

  public void moveBall(){
  // Ball should really be its own class with this as a method.
    if (right) ball.x+=ball.width; // If right is true, move ball right,
    else ball.x-=ball.width;       // otherwise move left.
    if (down)  ball.y+=ball.height; // Same for up/down.
    else ball.y-=ball.width;
    if (ball.x > (bounds.width - ball.width)) // Detect edges and bounce.
      { right = false; ball.x = bounds.width -  ball.width; }
    if (ball.y > (bounds.height - ball.height))
      { down  = false; ball.y = bounds.height - ball.height;}
    if (ball.x <= 0) { right = true; ball.x = 0; }
    if (ball.y <= 0) { down  = true; ball.y = 0; }
  }

  public static void main(String arg[]){
    java.util.Timer vgTimer = new java.util.Timer();  // Create a Timer.
    VGKernel panel = new VGKernel(); // Create and instance of our kernel.
    
    // Set the intial ball movement direction.
    panel.down = true;
    panel.right = true;

    // Set up our JFRame
    panel.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.frame.setSize(panel.screen.width, panel.screen.height);
    panel.frame.setContentPane(panel); 
    panel.frame.setVisible(true);

    // Set up a timer to do the vgTask regularly.
    vgTimer.schedule(panel.vgTask, 0, 100);
  }
}

This example can be expanded with methods to get control inputs, additional players on the playfield (like paddles), and logic to determine when someone scores.

The code here is far from perfect, but I've made some compromises to make things as simple as I could while still showing a full working example. Not that any code that runs and does what is supposed to is really bad, but there are other, better ways of doing this. But this works and is fairly easy to understand.

What the program does is create a JPanel that has an inner class (a class defined within itself) of VGTimerTask. The VGTimerTask is a kind of TimerTask, which can be scheduled to occur on a regular basis by a Timer. Since VGTimerTask is an inner class of VGPanel, it has access to all the members of VGPanel. This is critical. Without that, it wouldn't be able to access the ball and redraw the screen easily (it can still be done, but in a more complex way.)

Timer is a decent way of running a simple game, but more complex games should use some other timing mechanism. java.util.Timer is affected by a number of outside events, so to get smoother, more reliable timing you a timer like the one in the Java3D package would work better.

A Simple Improvement

There are many ways of improving on this basic example. One way that is very simple is to smooth the animation. The movement of the ball is pretty jerky. This is caused by both the distance that the ball moves each "turn", and by the time between screen updates. We can smooth out the animation by addressing both of these.

First, let's change moveBall() to shift the ball a smaller distance each time:


public void moveBall(){
  // Ball should really be its own class with this as a method.
    if (right) ball.x+=ball.width/4; // If right is true, move ball right,
    else ball.x-=ball.width/4;       // otherwise move left.
    if (down)  ball.y+=ball.height/4; // Same for up/down.
    else ball.y-=ball.width/4;
    if (ball.x > (bounds.width - ball.width)) // Detect edges and bounce.
      { right = false; ball.x = bounds.width -  ball.width; }
    if (ball.y > (bounds.height - ball.height))
      { down  = false; ball.y = bounds.height - ball.height;}
    if (ball.x <= 0) { right = true; ball.x = 0; }
    if (ball.y <= 0) { down  = true; ball.y = 0; }
  }
Now the ball is being moved only one quarter of its size each turn.

Next, change the Timer schedule to draw the screen every 20 milliseconds instead of every 100 milliseconds:


// Set up a timer to do the vgTask regularly.
    vgTimer.schedule(panel.vgTask, 0, 20);

Now you have a ball that moves a lot smoother.

I'll be expanding on this basic kernel and improving it in future articles, starting with Java Video game Programming: Game Logic

Controlling Java's Graphics: paintComponent() and repaint()

Why do we put all our graphical drawing code into a paintComponent() method? It seems odd, since it would seem we should be able to simply stick some simple graphics commands into our main() method in a Java application and just get the drawing done. Where does paintComponent come from? If we never call it in our code, how does it get executed?

It seems like magic, doesn't it? You just sort of set it up and somehow it happens. Hopefully when and how we want it to. It seems like a vaguely disquieting form of magic, perhaps.

When Java does graphics, suddenly you're not in the strict control of the program that you are with command line applications. With graphics, your program is now interacting with the other parts of your computer's operating system. It's not just running in its own little corner of the machine. Now it's got a window out on that shared resource, the display, and the window has to interact properly with everything else that's on the display.

Think of it this way, if you are just driving around on private property all by yourself you don't have to worry about traffic. Off on your own stretch of road, with an unused parking lot or two to tool around in, you don't have to worry about sharing. You can cross the center line, pull on and off the road without signalling, you don't even need a license so long as you don't go on a public road.

But once you head for the public roads and freeway, you've got to share. The rules matter. It gets more complicated than buzzing around in a go-cart or whatever on private property. And things happen that you don't have any direct control over, like red lights and merging traffic.

When you move your program on to the display in Java, you don't have to do everything on your own as you would have to in a car. Java's graphics system takes care of a lot for you. Unfortunately this means your code starts looking like magic. Methods get called without you doing the calling. But it's OK. All you need to know is what to expect.

The paintComponent() method redraws your graphics area. In our examples so far this has been a JPanel. There are two ways paintComponent() can get called. One is automatic, the other is up to you.

The automatic way is what we've used so far. The computer's window manager automatically calls for your program to redraw its graphics whenever a window it owns appears to need redrawing. The window manager can decide this for any of a number of reasons. Such as when the window initially appears on screen. Or if the window has been covered up in part or in whole by another window on screen, and the covered part has just been uncovered. Maybe the window had been minimized, and has just been restored.

When these sort of things happen, the Java Runtime Environment calls the paint() method for your container. In our examples so far, our container has been a JFrame. It will be a "heavyweight" component (see the JFrames article for a brief discussion on this.) Once the container redraws itself, it'll pass the command down to its children, that is, the lightweight components that live inside it. A lightweight component from the Swing package uses the paintComponent() method to redraw itself. So that's what gets called. Shazam! It's like magic!

This means you want to set up paintComponent() to draw things the way you want them when it gets called. If you're doing drawings that don't change, like the examples we've done to date, then you don't need to look up any information. If you're doing anything animated or that otherwise changes over time, you need to have paintComponent() be able to look things up at the time of drawing to properly reflect conditions in the drawing.

Now, let's say you've changed something in your program and you want to redraw to show the change. You probably don't want to wait until the window manager thinks your window needs redrawing. If nobody is changing things on the screen otherwise, it may not redraw until way too late!

Does that mean you put a call to paintComponent() in your program? No! You would be taking a chance of breaking something if you did. You want to start from the top, like the Java Runtime Environment did. In your case, you want to call repaint(). This will take things from the top. It also handles some possibilities that jumping in and calling paintComponent() on your own will not.

Like, let's say both you and the window manager decide to redraw at the same time. If you bypass repaint() you'll be slowing down your program by making it repaint twice when it really only needs to redraw once. When you call repaint(), Java catches this for you and saves you some computer time by only redrawing once. It'll also catch redraw requests made while the redrawing is going on and deal with them appropriately. Your paintComponent() method will get called in its own turn when you use repaint().

So, if you have new information you want depicted on screen, use repaint().

Put all your drawing inside paintComponent() and let the system take care of knowing when to call it otherwise. Give paintComponent() the ability to get the information it needs to draw things the way you want them now. If you're getting ahead of what I've written here, and aren't sure how to get through the Object Oriented barriers, look up "inner classes" for a start. It gives you a way to get the information where you need it when you need it.

Very Basic Java Graphics: 3 Examples

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

/* BasicFrame.java

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

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

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

public class BasicFrame extends JFrame{

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

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

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

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

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

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

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

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

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

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

public class CloseFrame extends JFrame{

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

  // The following methods are instance methods.

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

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

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

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

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

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

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

public class BasicJPanel extends JPanel{

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

  // The following methods are instance methods.

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

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

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

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

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

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

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

Drawing Lines

In A Most Basic Graphics App we had the framework of a simple graphics application. We trimmed it down a little, too much really, in Start With a JFrame. The JFrame alone doesn't accomodate graphics as well as we would like. The "window decorations"--the title bar, the frame around the window, close button and so on--all cover part of our drawing area. Likewise, there are other problems that crop up on different JVMs.

So we'll use the BasicPanel.java program from A Most Basic Graphics App to build on now.

We're going to concern ourselves with the part of the program that does the actual drawing:

g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)

In particular, we're going to focus on those four numbers inside the parentheses. What are they? Where do they come from? How can we pick numbers that will let us draw what we want, and what are the limits on what we can put in there?

First, let's look at what our limits are. At the low end, we have the number zero. Computers start counting at zero, and that's the low end number for what we can enter here and expect results. You can put a negative number in here, but unless you do some other things we're not going into here, negative numbers aren't going to do you any good.

For the high number, you can go up to the limits of the type, if you like. In this case we're calling drawLine(int, int, int, int), so we can go up to the limits of an int, or 2147483647, and not cause a problem so far as Java is concerned. We humans like to see our results, though. There's another line of BasicPanel we need to consider. That's this one:

frame.setSize(200,200);
 
This is setting the size of our JFrame (creatively named "frame") to 200 pixels wide and 200 pixels high. Since the JPanel we're drawing to is inside this JFrame, we know that the highest point we're going to see is less than this. How much less varies. It's based on how wide big the window decorations are on the JFrame, and this varies by operating system, and by the user's settings. But we definitely know that anything over 200 on the high end is going to be invisible. Higher numbers won't affect Java or your computer. You won't have a line that shoots out of its window and across your desktop if you make the numbers too high. You just won't see anything outside the JPanel area on which we're drawing.

We can find out exactly how large our drawing area is by using the getClipBounds() method of the Graphics class. Feel free to experiment with it, but for now let's get back to talking about the four numbers we use with drawLine and what they do. Just saying we have a high limit of 200 on those numbers is good enough for now.

OK, so we can use numbers from 0 to somewhere short of 200 in any of those four locations and expect results.

A Pair of Pairs

The four numbers in drawLine aren't just four numbers, they're two pairs of number. The first two numbers are the first pair, the third and fourth numbers are the second pair. Each pair of numbers is a Cartesian coordinate. If you don't remember or haven't studied this in Geometry class, don't sweat it. We'll suss things out well enough here.

g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
 
Notice how in the comment I say we're drawing a line from (10, 10) to (150, 150). Notice the first two numbers in g.drawLine() are 10 and 10, and the second two numbers are 150 and 150. This Means Something. ;)

The first pair marks the starting point for our line, the second pair marks the ending point.

The first number in each pair says how far left or right we want that point. The second number in each pair says how far up or down we want that point.

On left and right, 0 is all the way to the left. The higher the number, the farther over to the right we'll be. In our case, we can go up to 200 (almost.) A number of about 190 will probably take us all the way to the right of our drawing area.

On up and down, 0 is all the way to the top. The higher the number, the lower we'll go. A number of about 185 or so will take us all the way to the bottom of our drawing area.

If we want to draw a line all the way across our drawing area, instead of just partway across, we can replace
 
g.drawLine(10,10,150,150); // Draw a line from (10,10) to (150,150)
with
g.drawLine(0,0,200,200);

This will actually "go over" the edge of our drawing area, but it won't matter. Open up BasicPanel in your editor, make this change, compile it and run it.

Fine, we've mastered drawing a line from the top left to the bottom right. We're not exactly drawing starships yet, are we?

What if we change the pairs of numbers around? Open up your editor and make this change to the drawLine() statement:

g.drawLine(200,200,0,0);
 
Once you compile and run, what do you see? It looks the same, right? That's because we drew a line between the same two points, we just drew from bottom right to top left this time. OK, I hear you saying "Borrrringgg!" Let's move on.

Horizontal Lines

If we want a line to be horizontal, both the up-and-down numbers need to be the same. This means the second number in each pair, the second and fourth numbers. Add the following line to BasicPanel right after your other drawLine() statement:

g.drawLine(10,50,200,50);
 
Compile and run, and now you have a horizontal line. Notice the second and fourth numbers are the same. If you want to move the horizontal line up or down, change the number in the second and fourth position:
 
g.drawLine(10,20,200,20); // A higher horizontal line
g.drawLine(0,0,200,200); // A lower horizontal line

The higher the number you put in the second and fourth positions the lower the horizontal line will be. Go ahead and add these lines to your program, one at a time, and compile and run.

Vertical Lines

Now let's try vertical lines. For these, the first and third numbers (the left-right numbers) need to be the same:
g.drawLine(50,0,50,200); // A vertical line.
Change the 50s to some other number to move the vertical line left or right.

Starting and Ending

Now we can draw multiple lines to build up objects. By starting and ending the lines at the same points, we can make them meet up, and use the individual lines to build up objects. using our vertical and horizontal lines, we can make up squares and rectangles, or draw pictures that look like they're off an Etch-a-Sketch. ;)

Open up BasicPanel and replace all the existing drawLine() statements with the following:

g.drawLine(50,20,150,20); // Draw a horizontal line from (50,20) to (150,20)
g.drawLine(150,20,150,150); // Draw a vertical line from (150,20) to (150,150)
g.drawLine(150,150,20,150); // Draw a horizontal line from (150,150) to (20,150)
g.drawLine(20,150,50,20); // Draw a vertical line from (20,150) to (50,20)

Notice how the points we use match up (look at the pairs in the comments.) The last point is the same as the first to close the box.

Now, if we just wanted to draw boxes Java actually has a way to do this more efficiently. But what we're focusing on here is coordinates and how to use them.

Play around with different points and see what effect you get. Try drawing a triangle. Try drawing different sloping lines, both ones that slope down from left to right and ones that slope up. Remember, when you slope up the point on the right is going to have a second (up-down) number lower than the point on the left.

Once you play around for a while, you'll get the hang of it. If you want a larger screen area to play with, enlarge the numbers in the setSize() statement. Try this for a start:
 
frame.setSize(480,480);
 
This will give you more room to play it. Now you can take numbers up to about 480 before they go out of view. Try using getClipBounds() to find out just how large a number you can get. If you can't get it, don't sweat it, I'll cover it in a future post, or you can do an internet search to find an example in someone else's program, or jump into a Java newbie forum and ask.

The Basic Program Skeleton

The basic skeleton of a Java application goes as follows:
public class YourProgramName{
  public static void main(String arg[]){

    Your Program Goes Here

  }
}

YourProgramName gets replaced by your actual program's name. The program must be stored in a file named YourProgramName.java

The actual code for your program goes in place of Your Program Goes Here.

More complicated programs have more to them than this. For example, you should have your own classes in their own files that contain most of your program logic if you are writing a long program. But this is the most direct and basic structure for a Java program.

The word arg can be whatever you choose to make it, by the way. If your program needs to get information from the system environment, just make sure that the name is the same as what you use in your program. 

main ()

There are two basic types of Java programs: applets and applications.* Applets run through a browser or a special program called AppletViewer. Applications are stand-alone programs that run on the same system they're stored on, like most traditional programs. Since there's lots of information elsewhere on applets, we'll concern ourselves mostly with applications.

Every application has a special method called main(). The main() method marks the starting point in the program for the Java Virtual Machine. Here's a short example program:

public class Hello{
public static void main(String arg[]){
System.out.println("Hello");
}
}

When this program is compiled using javac then run with the command
>java Hello
the JVM loads Hello.class and looks in it for the main() method, then starts executing the code inside main()'s code block.

Now, you'll notice there's a bunch of other stuff with main():
public static void main(String arg[]){

Because of how Java works, that stuff has to be there in a Java application. You can't just put "main(){" on the line by itself. The other stuff has a purpose, though it all looks very confusing, and certainly it looks like a lot of extra junk in a short program.

public allows the method to be accessed from outside the class (and its package--we'll get into that later.) If you leave out public, the JVM can't access main() since it's not available outside of Hello.

static says that this is the one and only main() method for this entire class (or program). You can't have multiple main()s for a class. If you leave static out, you'll get an error.

void says that main() doesn't pass back any data. Since the JVM wouldn't know what to do with any data, since it's not set up to accept data from main(), main() has to be of type void, which is to say that it's a method that doesn't pass any data back to the caller. If you leave this out main() won't have a data type, and all methods have to have a data type, even if it's void.

Inside main()'s parentheses is String arg[]. This is a way for the program to accept data from the host system when it's started. It's required that main() be able to accept data from the system when starting. And the data must be in the form of an array of Strings (or a variable-length list of Strings as of Java 5, but that's something we'll save for later.) The name "arg" can be whatever you want to make it. It's just a name I've given the array. It could just as well be:
public static void main(String fred[]){

I'd just have to be sure to use fred whenever I wanted to access the information that the system has passed to my application when it started, instead of arg.

Finally, after the parentheses, comes the open curly brace { that marks the start of main()'s code block.