Back

HelloPsychophysicist - Pure Java version

This section explains line by line the pure java version of the HelloPsychophysicist project (source: HelloPsychophysicist.java). This example demonstrates how to develop java projects using psychWithJava package in general.

There are seven common steps to writing a java program using the psychWithJava package

  1. Import the necessary classes/packages

  2. First place import lines in the beginning of your Java code, including the necessary classes from psychWithJava package.
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    
    import psychWithJava.FullScreen;
    Alternatively you can import all classes from a package, for example
    import psychWithJava.*;
    After importing classes you will no more have to explicitly type the full path of these classes in your code.

    Declare a public class that inherits from FullScreen and Runnable, and create a main method

    The name of the public class must be the same as the first part (the part before .java) of the file name
    public class HelloPsychophysicist extends FullScreen implements Runnable {
    
      public static void main(String[] args) {
    To execute a Java file, you must have a main method in the public class. The syntax of the main method is important, it has to be exactly as shown above.
    extends and implements keywords are used for inheritance. This syntax means that HelloPsychophysicist is a class that inherits from another class called FullScreen. FullScreen, the most important class of the psychWithJava package, provides many of the methods needed for the Psychophysics experiments. By inheriting from that class HelloPsychophysicist becomes a FullScreen class and more. That is, it has all the methods of FullScreen available. HelloPsychophysicist also inherits from an interface (a sort of class with no method definitions) called Runnable. We do this because a new Thread can be created by using a Runnable object. Threads are useful because multiple of them can run concurrently by the CPU, and we will take advantage of this fact in many of our examples.

  3. Create an instance of the HelloPsychophysicist class

  4. In the main method, create a HelloPsychophysicist object fs as follows
    HelloPsychophysicist fs = new HelloPsychophysicist();
    Recall that HelloPsychophysicist is FullScreen, therefore constructing a HelloPsychophysicist is nearly equivalent to constructing a FullScreen object. See also FullScreen().

  5. Initialize certain aspects of your object

  6. There are a few adjustments you can make for your FullScreen object. For example, here let's set the number of video buffers to 2, which by default is 1
    fs.setNBuffers(2);
    If double buffering doesn't work on your system, try using single buffer (setNBuffers(1)). See also setNBuffers(int).

  7. Create a new Thread with your object and start it

  8. Thread experiment = new Thread(fs);
    experiment.start();
    You can construct a Thread with a Runnable object. Remember that HelloPsychophysicist is a Runnable object, as well as a FullScreen object.

  9. Provide the run() method

  10. A class that implements Runnable interface must have a public method called run(). This method is automatically invoked when you start your Thread.
    public void run()
    the method should be declared exactly as above.

  11. Place the experiment/animation inside run(), use try-catch-finally

  12. public void run(){
      
      try{
        \\your methods for animation 
      } catch(){
        \\catch the exceptions, that is, if something goes wrong
      } finally {
        \\in the end clean up and return the resources used
        closeScreen();
      }
    The program will try to perform the statements inside the try{} part, if anything goes wrong, the execution jumps to the catch{} part. If nothing goes wrong the try{} part is completed and catch{} is skipped. In either case the finally{} part is always executed. You must always invoke closeScreen() method inside finally{}.

    Above 7 steps are going to be nearly identical in all examples, except the names of files and corresponding public classes. If you use an IDE, such as Eclipse, it will assist you with most of the steps. For instance you won't need to remember which classes to import. IDEs usually determine your import needs and place them in the beginning of your file. They will also warn you that you should have a public method called run() since your class inherits from Runnable interface. They will assist for catching the Exceptions, as well.

The experiment/animation, inside the run() method

    This is the part that will vary depending on your experiment. I explain the run() method of the HelloPsychophysicist class below.

  • Display text, wait for a while
  • Display some text, draw it actually on the screen and wait for 2 seconds without doing anything
    try{
      displayText("Hello Psychophysicist (pure Java)");
      updateScreen();
      Thread.sleep(2000);
    displayText(String) method displays the text stored in a String object at the center of the video buffer. It is overloaded, you can define the position where you want to place the upper left corner of the text on your screen by invoking displayText(int,int,String). Next you have to invoke updateScreen() method. Because although you invoked displayText() method, you only painted the text on a back video buffer. To actually display on the computer screen this back buffer should be brought to front by updateScreen(). sleep(long) is a static method of Thread class. It causes the thread stop execution for the given amount of time (in milliseconds). This method throws an InterruptedException, which means that something may go wrong. You have to take care of this, that is, you have to catch that exception and preferably do something
    catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
    this will clear the interrupted status of the thread. In principle, you could just catch the exception and don't do anything, but it is not a proper way of handling exceptions and should not be done. Instead invoke the interrupt() method to clear the interrupted status.

  • Blank the screen, hide the cursor
  • blankScreen();
    hideCursor();
    If you don't blank the screen (back buffer), you will paint over the existing screen. This is useful for animations when you want to update only a portion of the screen. But in this example we need to clean it first. (try and see what happens if you don't do that.) See blankScreen() and hideCursor()

  • Read in and display an image
  • BufferedImage bi1 = ImageIO.read(
        HelloPsychophysicist.class.getResource("psychophysik.png"));
    displayImage(bi1);
    updateScreen();
    There are many ways of reading an image from a file. The way shown above is useful because it works when you package your applications in a single jar file. If you don't have to prepare jar files then you can use the following simpler version
    BufferedImage bi1 = ImageIO.read(new File("psychophysik.png"));
    Currently Java Core API can read png, jpeg and gif image types. But you can find/implement non-standard classes that extend this capability. ImageIO.read() method throws an IOException, you have to catch it and decide what to do
    catch (IOException e) {
      System.err.println("Image File not found");
      e.printStackTrace();
    }
    this will only warn the client but not prevent the termination of the program. displayImage(BufferedImage) method displays an image at the center of the screen. As before, you should invoke updateScreen() method to actually bring the back buffer front. displayImage() is overloaded
    displayImage(0,0,bi2);
    displays the image at the upper left corner.

    See the entire code of HelloPsychophysicist.java



  Back