Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Saturday, 23 June 2012

Practical Example of GSON (Part 2)

Please note that this page has moved to: http://www.javacreed.com/gson-deserialiser-example/.

The first article I wrote about GSON (part 1) is (at the time of writing) the most popular article in my small blog. Thus, I decided to write a second article and add more practical and advance examples which anyone can use. As also noted in my previous article, the official GSON site is: http://sites.google.com/site/gson/.

In this article we will see how to parse complex JSON objects into existing Java objects that do not necessary have the same structure as the JSON object. We will see how the use of the GSON deserialiser (JsonDeserializer) in order to control how the JSON object maps to the Java object.

The code shown here is all available at: http://code.google.com/p/gson-practical-examples/source/checkout.

The readers are encouraged to first read part 1 before proceeding, unless they are already familiar with GSON.

A Simple Example

Let's say we have the following JSON object, where it contains four Java books titles written by various, well known, authors.

{
    '1': 'Effective Java (2nd Edition)',
    '2': 'JavaTM Puzzlers: Traps, Pitfalls, and Corner Cases',
    '3': 'Java Concurrency in Practice',
    '4': 'Java: The Good Parts'
}

Note that each name/value pair has a number as its name and the book title as its value. Using the methods discussed in part 1 would create a problem. In that article, Gson is expecting to find variable names in Java with the same name as that found in JSON. But names in Java cannot start with a number. They can contain a number, but cannot start with one (as described in chapter 6 of the Java Language Specification).

So how can we parse this JSON object and use it in Java?
We can use the JsonDeserializer to parse the JSON object into our Java object the way we want it. Using the JsonDeserializer, we have full control over how JSON is parsed as we will see in the following example.

Consider the following simple Java object.


package com.albertattard.examples.gson.part2_1;
import java.util.ArrayList;
import java.util.List;

public class Books {

  private List<string> booksTitles = new ArrayList<>();

  public void addBookTitle(String title) {
    booksTitles.add(title);
  }

  @Override
  public String toString() {
    return booksTitles.toString();
  }
}

This Java object will be used to hold the books listed in the JSON object shown earlier. Note that JSON object has four fields, one for each book, while the Java object has a list in which these books are saved. The structure of these two objects (Java and JSON) is different.

In order to be able to parse JSON to Java we need to create our own instance of the JsonDeserializer interface as shown next.


package com.albertattard.examples.gson.part2_1;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

public class BooksDeserializer implements JsonDeserializer<Books> {

  @Override
  public Books deserialize(final JsonElement json, 
        final Type typeOfT, 
        final JsonDeserializationContext context) 
        throws JsonParseException {

    Books books = new Books();
    // Parsing will be done here.
    return books;
  }
}

The above example is not complete and we still need to add the most important thing, which is the parsing. But let's understand this class before we make it more complex by adding more code to it. The interface JsonDeserializer requires a type, which is the type of object that we will be parsing. In this case, we are parsing JSON into the Java object of type Books. The return type of the deserialize() method must be of the same type as the interface parameter, Books.

How does this work?
Gson will parse the JSON object into a Java object of type JsonElement. The JsonElement can be thought of a tree of name/value pairs containing all elements found in the JSON object. Each child within the JsonElement is yet another JsonElement. In other words we have a tree of JsonElements. Through this object we can retrieve each JSON element by its name and set the Java object accordingly. The following example shows how we can retrieve the first book listed in the JSON object and add it to the Java object.


package com.albertattard.examples.gson.part2_1;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

public class BooksDeserializer implements JsonDeserializer<Books> {

  @Override
  public Books deserialize(final JsonElement json, 
        final Type typeOfT, 
        final JsonDeserializationContext context) 
        throws JsonParseException {
    Books books = new Books();

    JsonObject jsonObject = json.getAsJsonObject();
    books.addBookTitle(jsonObject.get("1").getAsString());

    return books;
  }
}

In the above example, we are retrieving the JSON element with name "1" using the following code fragment:

jsonObject.get("1")

This returns the JsonElement with the name: "1". In this case it is a simple String. Note that in order to retrieve the actual value we need to invoke another method on the JsonElement instance, which returns the value we need, String in this case.

jsonObject.get("1").getAsString()

The rest of the books titles can be retrieved in the same manner.

Before we can utilise our new deserializer, we must instruct GSON to use our deserializer when parsing objects of type Books, as shown in the next code example.


package com.albertattard.examples.gson.part2_1;
import java.io.InputStreamReader;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {
  public static void main(String[] args) throws Exception {
    // Configure GSON
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Books.class,
        new BooksDeserializer());
    Gson gson = gsonBuilder.create();

    // The JSON data
    Reader data = new InputStreamReader(
        Main.class.getResourceAsStream("books.json"), "UTF-8");

    // Parse JSON to Java
    Books books = gson.fromJson(data, Books.class);
    System.out.println(books);
  }
}

In the above example, we are creating an instance of Gson through the GsonBuilder. Using the registerTypeAdapter() method, we are registering our deserializer and instructing GSON to use our deserializer when deserializing objects of type Books. When we request GSON to deserialize an object to the Books class, GSON will use our deserializer . The following list describes what happens when we invoke: gson.fromJson(data, Books.class).
  1. Parse the input as JsonElement. At this stage, the string JSON object is changed into a generic Java object of type JsonElement. This step also ensures that the given JSON data is valid.
  2. Find the deserializer for the given object, in this case the BooksDeserializer instance.
  3. Invokes the method deserialize() and provides the necessary parameters. In his example, our deserialize() will be invoked. Here an object of type Books is created from the given JsonElement object. This is from Java to Java conversion.
  4. Returns the object returned by the deserialize() method to the caller of the fromJson() method. This is like a chain, where GSON receives an object from out deserializer and returns it to its caller.
Running the above example would print the following:

[Effective Java (2nd Edition), JavaTM Puzzlers: Traps, Pitfalls, and Corner Cases, Java Concurrency in Practice, Java: The Good Parts]

This concludes our simple example. This example acts as a primer for other complex parsing. For example, parsing JSON objects that include nested objects, arrays and the like. In the next example we will discuss an enhanced version of the objects discussed here.

Nested Objects

In this example we will describe how to parse nested objects, that is, objects within other objects. Here we will introduce a new entity, the author. A book, together with the title and ISBN can have a list of authors. On the other hand every author can have many books. The JSON object that will be using in this example differs from the previous one to cater for the new entity as shown next:

{
  '1': {
    'title': 'Effective Java (2nd Edition)',
    'isbn': '978-0321356680',
    'authors': ['Joshua Bloch']
  },
  '2': {
    'title': 'JavaTM Puzzlers: Traps, Pitfalls, and Corner Cases',
    'isbn': '978-0321336781',
    'authors': ['Joshua Bloch', 'Neal Gafter']
  },
  '3': {
    'title': 'Java Concurrency in Practice',
    'isbn': '978-0321349606',
    'authors': ['Brian Goetz', 'Tim Peierls', 'Joshua Bloch', 
                'Joseph Bowbeer', 'David Holmes', 'Doug Lea']
  },
  '4': {
    'title': 'Java: The Good Parts',
    'isbn': '978-0596803735',
    'authors': ['Jim Waldo']
  }
}

We still have our four books, only this time we have a more complex and detailed JSON object. Instead of a simple book title, we also have an ISBN and an array of authors.

The new example provides new challenges. One of the authors, Joshua Bloch, has three books. This immediately leads to the following question.

How many instance of this author should we have?
There are two possible answers for this question: just one or three (one for every book). There is no one correct answer, and both cases can be valid. In our examples we are going to have one instance of the author even when he or she has more than one book. We are taking this approach as this approach resembles the reality and helps highlighting the goal of this article (GSON examples). Therefore we will have one author object representing the author Joshua Bloch.

For this example we will be using three domain objects:

  • Author
  • Book
  • Books
All three objects have references to the other objects. For example, the Author class has a list of Books and the Book has a list of Authors. The Books class contains all parsed objects. The Books class also provides the functionality required to maintain one instance for each author as we will see later on in this example.

Author


package com.albertattard.examples.gson.part2_2;
import java.util.HashSet;
import java.util.Set;

public class Author {

  private Set<Book> books = new HashSet<>();
  private String name;

  public Author(final String name) {
    this.name = name;
  }

  public void addBook(Book book) {
    books.add(book);
  }

  public Set<Book> getBooks() {
    return books;
  }

  public String getName() {
    return name;
  }

  @Override
  public String toString() {
    return String.format("%s has %d book(s)", name, books.size());
  }
}

Book


package com.albertattard.examples.gson.part2_2;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Book {

  private Set<Author> authors;
  private String isbn;
  private String title;

  public Book(String title, String isbn, Author... authors) {
    this.title = title;
    this.isbn = isbn;
    this.authors = new HashSet<>(Arrays.asList(authors));
  }

  public Set<Author> getAuthors() {
    return authors;
  }

  @Override
  public String toString() {
    StringBuilder fomrattedString = new StringBuilder();
    fomrattedString.append(title).append(" (").append(isbn)
        .append(")");

    fomrattedString.append(" by: ");
    for (Author author : authors) {
      fomrattedString.append(author.getName()).append(", ");
    }

    // To remove the last comma followed by a space
    return fomrattedString.
             substring(0, fomrattedString.length() - 2);
  }
}

Books


package com.albertattard.examples.gson.part2_2;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Books {

  // A map of authors index by their name.
  private Map<String, Author> authors = new HashMap<>();
  private Set<Book> books = new HashSet<>();

  public void addAuthor(Author author) {
    authors.put(author.getName(), author);
  }

  public void addBook(Book book) {
    books.add(book);
  }

  public Author getAuthorWithName(String name) {
    return authors.get(name);
  }

  @Override
  public String toString() {
    StringBuilder formattedString = new StringBuilder();
    for (Author author : authors.values()) {
      formattedString.append(author).append("\n");
      for (Book book : author.getBooks()) {
        formattedString.append("  ").append(book).append("\n");
      }
      formattedString.append("\n");
    }

    return formattedString.toString();
  }
}





Coming soon.
This article is not complete and more information will follow shortly.

Friday, 17 June 2011

Why should we use dependency injection?

Please note that this page has moved to: http://www.javacreed.com/why-should-we-use-dependency-injection/.

In this article we will explore some of the benefits of dependency injection and how this can be used in all types of programming, including small and simple programs. Some of the example shown below make use of Guice, a dependency injection framework by Google. The same concept applies for any other dependency injection framework.

This article does not provide detailed description of Guice but it only focus on the benefits of dependency injection and design methods that improve modularity, extendibility and testing.

What is dependency injection?

Let say we want to make some tea. How would we do it and what do we need? We need to boil some water, a clean mug, tea bags, sugar and milk (at least that's what I put into mine). In order to make tea we need to provide all these ingredients and we need to manage all these ourselves. We have to fill the kettle with water and heat it up, get the milk from the refrigerator and get the rest.

Now assume that we can make tea, by simply asking someone else to do it for us. Someone that knows how to do the tea just the way we want it. Would that be better than making the tea ourselves? If yes, then welcome to dependency injection.

Dependency injection is a framework that takes care of creating objects for us without we having to worry about providing the right ingredients so to say.

A Simple Example

Let say we have a class, Person, and this class needs to send a message. The Person class requires the aid of some other class, Email, in order to send a message. Following is a simple way of doing this.

public class Email {
  public void sendEmail(String subject, String message){
  }
}

public class Person {
  private Email email = new Email();

  public void greetFriend(){
    email.sendEmail(parameters...);
  }
}

Some code is omitted from the above classes for brevity

We all agree that this is a very simple and straight forward example that involves two simple Java classes. Nevertheless, the above has some limitations as listed below.

  • The Persons class is dependent (has a strong/tight dependency) on the Email class. There is a hard connection between these two classes. Let say we have a new better version of email class, FastEmail, in order for us to use it, we need to go in each and every class that depends on the Email class, such as the Person class, replace it with the new version.
  • Let say we parametrise the Email's constructor. Again we have to go in each and every class that is initialising the Email class, such as the Person class, and change it.
  • A design decision is taken to make the Email class singleton. Similar to above we need to modify all instances where it is used.
  • In order to improve the notifications/messages system, we decide to add different message delivery systems such as SMS or tweets. The Person class and other like it, need to all be modified in order for it to use the new classes.
  • Another developer needs to use the Person class, but would like to use a different notification/message system. This cannot be achieved with the current version of the Person class as it is hardwired to the Email class. What generally happens is that the other developer duplicates the Person class and modifies it as he/she needs. The projects ends up with two versions of the Person class.
  • In the above points we mentioned many scenarios where code has to be changed. All changes made, need to and should be tested. How can we test the Person class without including the message delivery class such as the Email? Testing, in many cases, is left as an afterthought. The way we have the Person class constructed makes it hard to test it without involving the Email class. Furthermore, how would we automate such test? How can we use JUnit or the like to automate out tests?
  • Moving forward in the project, the Person class starts to depend on another class that allow this object to write a letter using the Pen class for example. The Person class can use other ways to write a letter, such as Pencil class or Typewriter class, but this approach does not allow that.

These limitations can be improved by changing the way we think and restructure our code in a modular way. This is independent from dependency injection as we will see in the following section.

Change the way we think

The Email class provides a service, that is, sending of messages over the Internet using the mail protocol. Instead of having the Person class initialising an instance of the Email class, we first create an interface, MessageService, and make the Person class using this interface instead. This removed the dependency that the Person class has on the Email and replaces it with an abstract message delivery interface.

The following three steps: define, implement and use, show how we can develop modular and extendable code. This approach also improves testing as we will see at the end of this article.

  1. Define Interfaces

    Many developers do not use interfaces as they see them as additional non-required code. This may be true (I said maybe as the System class makes use of interfaces) for the famous hello world program, definitely not true for the rest. Like with everything else, we have to see things in context and there will be cases when we can do without interfaces. Nevertheless, developing code using interfaces produce far more modular and extendable code as illustrated in the following examples. The example discussed in the previous section was quite simple, but nevertheless it included several pitfalls which can be easily avoided. Changing code at a later stage involves more work than having it right in the first place.

    We start by defining the MessageService interface that includes one method, sendMessage(String subject, String message). For simplicity we assume that no exceptions are thrown.

    public interface MessageService {
      void sendMessage(String subject, String message);
    }
    
  2. Implement Interfaces

    In the list of limitations we mentioned four possible methods of sending a message: email, fast email, SMS and tweet. Let's create four classes that handle each message delivery method and have all these classes implement the interface created above.

    public class EmailService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Email: %s, %s%n ", subject, message);
      }
    }
    
    public class FastEmailService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Fast Email: %s, %s%n ", subject, message);
      }
    }
    
    public class SMSService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("SMS: %s, %s%n ", subject, message);
      }
    }
    
    public class TweetService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Tweet: %s, %s%n", subject, message);
      }
    }
    
  3. Use Interfaces

    Finally, instead of using classes, we use interfaces. In the Person class, we replace the Email field with the MessageService service interface as shown in red below.

    public class Person {
      private MessageService messageService;
    
      public Person(MessageService messageService){
        this.messageService = messageService;
      }
    
      public void greetFriend(){
        messageService.sendMessage(parameters...);
      }
    }
    

    Note that the Person class is not initialising the message service but it is expecting it as a parameter of its constructor. This is a key element in the design. It improves modularity, extendibility and testing. The Person class is not dependent on any implementation, but on a service defined by an interface. This means that we can use the Person class without having to worry about the underlying implementation. Furthermore, different Person instance can be instantiated using different message services.

One can argue that the new version of Person class became more complex to instantiate as it requires parameters. This is a fair statement and here is when dependency injection comes into play.

Using Dependency Injection

As mentioned in the introduction, dependency injection can help us initialising objects and provide these objects all the necessary resources (ingredients). For example, the Person class requires an instance of MessageService. The dependency injection framework will provide that for us. So to create an instance of Person, all we need to do is call something like: dependecyFramework.getInstance(Person.class). Magically, (not really), the dependency injection framework will create an instance of the Person class and provide an instance of the a MessageService to the Person object.

The next natural question will be, how does the dependency injection framework knows how to initialise the MessageService? We need to tell the dependency injection framework how to create an instance of MessageService. With Google Guice we do that by creating a module (extends AbstractModule ) as illustrated below:

public class ProjectModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(MessageService.class).to(EmailService.class);
  }
}

Here we are telling the dependency injection how to create an instance of the MessageService class. We also need to add an annotation to the Person class in order to allow the dependency injection framework to inject the necessary parameters.

public class Person {
  private MessageService messageService;

  @Inject
  public Person(MessageService messageService){
    this.messageService = messageService;
  }

  public void greetFriend(){
    messageService.sendMessage(parameters...);
  }
}

With everything set, we create an instance of the Person class using the dependency injection framework

Injector injector = Guice.createInjector(new ProjectModule());
  Person person = injector.getInstance(Person.class);
  person.greetFriend();

We replaced a couple of lines of code with many others. What's the buzz about this? In the next section we will see some of the benefits of dependency injection and how this can be used to simplify our coding life

Benefits of Dependency Injection

In this section we will see some key benefits of dependency injection

  • Changing the message service

    Let's change the delivery method from email to SMS. How would we do that?

    We only need to change the ProjectModule class to map the MessageService class to the SmsService class as shown in red below.

    public class ProjectModule extends AbstractModule {
    
      @Override
      protected void configure() {
        bind(MessageService.class).to(SmsService.class);
      }
    }
    

    This one change will affect all classes initialised with the dependency injection framework without having to change any of these classes. This leads us to another advantage, testing.

  • Changing the message service

    We can create a MockService class which can be using in JUnit test as shown next.

    public class MockService implements MessageService {
    
      public String subject;
      public String message;
    
      @Override
      public void sendMessage(String subject, String message) {
        this.subject = subject;
        this.message = message;
      }
    
    }
    

    The above mock message service simply stores the parameters into two public fields. These fields can be used to retrieve the values of the parameters and used for testing ass illustrated next.

    public class TestPerson {
    
      private Injector injector;
    
      @Before
      public void init() {
        injector = Guice.createInjector(new AbstractModule() {
          @Override
          protected void configure() {
            bind(MockMessageService.class).in(Singleton.class);
            bind(MessageService.class).to(MockService.class);
          }
        });
      }
    
      @Test
      public void testGreetFriend() {
        Person person = injector.getInstance(Person.class);
        person.greetFriend();
    
        MockService mockService = injector
            .getInstance(MockService.class);
        assertEquals("Greet", mockService.subject);
        assertEquals("Hello my friend", mockService.message);
      }
    }
    

    This may require some explanation. So here we go. We created an injection (Guice dependency injection) just for this testing and provided a custom module (as an abstract inner anonymous class). The custom module wires the MessageService with the MockService instead. Also, we set the MockService as singleton, that is, whenever we request an instance of this class from the injection we always get the same object (singleton). After greetFriend() is invoked, we test using JUnit to make sure that the correct parameters are being passed to the message service instance.

    This design setup allows us to test the Person class independent from the other classes that it depends on in an automated manner.

  • Changing the signature of the Person constructor

    As we mentioned in the limitations, the Person class may evolve and include more functionality. Changing the signature of the Person constructor will not affect us as long as the injector knows how to provide the required parameters.

    public class Person {
      @Inject
      public Person(MessageService messageService, 
                    WritingService writingService){
      }
    }
    

    The Person class will still be initialised in the same way as it is now. Thus changing the Person constructor signature will not affect the other classes that make us of it.

    Person person = injector.getInstance(Person.class);
    

    The same applies for anything that is initialised and handled through the injector.

  • Passing the Injector as parameter

    In a project we can have one instance shared throughout the project. This can be achieved by passing the Injector as a parameter to other objects that needs it. We setup the injector at the beginning (in a main method for example), and then have it set as a constructor parameter in all the classes that require an instance of the injector. Like that one injector will server all classes in the project.

Conclusion

This ended up to be quite a long article. Dependency injection is quite simple to use and it has quite a "shallow" learning curve. This article does not explain how to use the actual dependency injection framework (such as Guice). Articles about that are easily found. This article described key benefits of using a dependency injection framework even in small projects.

Thursday, 17 December 2009

Simple Java WAV Player

In this article we'll discuss a simple way how to play wav files in Java. We'll start with the complete example and explain each bit in the process. This example only involves one class, the one listed below.

package com.albertattard.pmm;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class TheMusicPlayer {

  public static void play(final InputStream inputStream) {
    new Thread() {
      @Override
      public void run() {
        AudioInputStream audioInputStream = null;
        try {
          audioInputStream = AudioSystem
              .getAudioInputStream(inputStream);
        } catch (UnsupportedAudioFileException e) {
          e.printStackTrace();
          return;
        } catch (IOException e) {
          e.printStackTrace();
          return;
        }

        SourceDataLine sourceDataLine = null;
        try {
          AudioFormat audioFormat 
              = audioInputStream.getFormat();
          DataLine.Info info = new DataLine.Info(
              SourceDataLine.class, audioFormat);
          sourceDataLine = 
              (SourceDataLine) AudioSystem.getLine(info);
          sourceDataLine.open(audioFormat);
        } catch (LineUnavailableException e) {
          e.printStackTrace();
          return;
        }

        sourceDataLine.start();
        byte[] data = new byte[524288];// 128Kb
        try {
          int bytesRead = 0;
          while (bytesRead != -1) {
            bytesRead = 
                audioInputStream.read(data, 0, data.length);
            if (bytesRead >= 0)
              sourceDataLine.write(data, 0, bytesRead);
          }
        } catch (IOException e) {
          e.printStackTrace();
          return;
        } finally {
          sourceDataLine.drain();
          sourceDataLine.close();
        }
      }
    }.start();
  }

  public static void play(final String wavFile)
      throws FileNotFoundException {
    play(new FileInputStream(wavFile));
  }
}

Those of you who are in a hurry, just copy and paste the above code and get on with your life. The others who can spare sometime, just read the following part.

Explained

The class has two static overloaded methods which play the wav file provides as a parameter. The second method simple invokes the first method passing an instance of input stream (and instance of FileInputStream, which inherits from InputStream)

All the logic is found in the first play() method, and that's what we'll be explaining next.

Let say we have a program and would like to play a sound (saved as a wav file) when an event/scenario occurs. The code to do so is very straight forward as illustrated below (a copy and paste from the example above).

        AudioInputStream audioInputStream = null;
        try {
          audioInputStream = AudioSystem
              .getAudioInputStream(The Input Stream);
        } catch (UnsupportedAudioFileException e) {
          e.printStackTrace();
          return;
        } catch (IOException e) {
          e.printStackTrace();
          return;
        }

        SourceDataLine sourceDataLine = null;
        try {
          AudioFormat audioFormat 
              = audioInputStream.getFormat();
          DataLine.Info info = new DataLine.Info(
              SourceDataLine.class, audioFormat);
          sourceDataLine = 
              (SourceDataLine) AudioSystem.getLine(info);
          sourceDataLine.open(audioFormat);
        } catch (LineUnavailableException e) {
          e.printStackTrace();
          return;
        }

        sourceDataLine.start();
        byte[] data = new byte[524288];// 128Kb
        try {
          int bytesRead = 0;
          while (bytesRead != -1) {
            bytesRead = 
                audioInputStream.read(data, 0, data.length);
            if (bytesRead >= 0)
              sourceDataLine.write(data, 0, bytesRead);
          }
        } catch (IOException e) {
          e.printStackTrace();
          return;
        } finally {
          sourceDataLine.drain();
          sourceDataLine.close();
        }

The above code fragment is made from three parts:

  • Initialisation of the audio input stream
  • Initialisation of the audio output
  • Playing the audio data

We're reading bytes from the input stream (the famous wav) and instead of writing/printing these in the console (as we traditionally do with text files), we're writing to the speaker/sound card of the computer.

We start by initialising the It's good to point out that the AudioInputStream, which inherits from the InputStream. This instance behaves the same like any other stream and can be treated/handled in the same manner as other streams.

AudioInputStream audioInputStream = null;
try {
  audioInputStream = AudioSystem
    .getAudioInputStream(The Input Stream);
} catch (UnsupportedAudioFileException e) {
  e.printStackTrace();
  return;
} catch (IOException e) {
  e.printStackTrace();
  return;
}

Then we initialise the audio output (this is NOT an OutputStream), that is, where the sound will be played. This has to match the audio input initialise in the previous step. Remember that there are many different sound files and not all these can be played with the following code.

SourceDataLine sourceDataLine = null;
try {
  AudioFormat audioFormat 
    = audioInputStream.getFormat();
  DataLine.Info info = new DataLine.Info(
    SourceDataLine.class, audioFormat);
  sourceDataLine = 
    (SourceDataLine) AudioSystem.getLine(info);
  sourceDataLine.open(audioFormat);
} catch (LineUnavailableException e) {
  e.printStackTrace();
  return;
}

The first two were quite straight forward. In the third step we're actually playing the sound by reading the bytes and play them in a similar fashion we do with other streams. We're reading a predefined amount of data (128k) into the array called data and saving the amount of bytes read in the other variable bytesRead.

bytesRead = audioInputStream.read(data, 0, data.length);

When the whole file is played, and there is no more data to be played, the read() method returns -1 (like it does with any other InputStream). This will have the while condition to false ending the playing process.

It is good to note that the third step will consume the focus of program until the wav file is played. That is, if you have a two minute wav file, than the above code will take two minutes to execute. All the other parts of the program (that are executed by this thread) will have to wait for the sound/music to finish. Since this is not what we want, the static method play() wraps this code into a thread which is started at the end of the method.

public static void play(final InputStream inputStream) {
  new Thread() {
    @Override
    public void run() {
      Code removed for brevity
    }
  }.start();
}

Since the code is started within a thread the control is immediately returned to the calling method which can proceed without having to wait for the file to play.

To play a wav file, all we need to do is invoke the pay method with the wav file as a parameter as illustrated below.

package com.albertattard.pmm;

public class TheMain {

  public static void main(String[] args) {
    // File downloaded from: 
    //   http://freewavesamples.com/bowed-bass-c2
    TheMusicPlayer.play(TheMain.class
        .getResourceAsStream("Bowed-Bass-C2.wav"));
  }
}

It's good to point out that the wav file Bowed-Bass-C2.wav (available at: http://freewavesamples.com/bowed-bass-c2) is in the same directory/package as the above class.

Wednesday, 16 December 2009

Playing with the Mouse

In this article I'll be discussing how we can you can enhance an graphical component by handling mouse events such as mouse clicks and movements.

This article will not discuss the graphical aspect and assumes that you know how to create a simple UI component extending the JComponent and adding this component into a JFrame. For more information about how to do this, please read the article: Practical Example of Simple Java UI Component.

A note of caution to the reader: This is not an exhaustive article about events and some topics are simple mentioned while others not discussed at all. While you're encouraged to learn as much as you can, it's best to first read this topic as provided here in the order provided and then expand your knowledge once you have read it.

Create an Environment

Let's start by create a simple components (that does nothing) which will add into a frame.

package com.albertattard.pwtm;

import java.awt.Graphics;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyComponent extends JComponent {
  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
  }
}

Always start with a super simple class and then slowly evolve it testing each change on the way. Don't wait for bulk changes to test as then it may be too late to understand what's wrong.

Now it's time to create the frame and add the above component to it.

package com.albertattard.pwtm;

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class MyFrame extends JFrame {

  private MyComponent myComp;

  public MyFrame() {
    initComponents();
  }

  private void initComponents() {
    setLayout(null);

    myComp = new MyComponent();
    myComp.setBorder(
      BorderFactory.createLineBorder(Color.RED));
    myComp.setBounds(10, 10, 400, 200);
    add(myComp);
  }
}

Now let's kick off this example by creating another with the main method and have this show rolling

package com.albertattard.pwtm;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class MyMain {
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createShowFrame();
      }
    });
  }

  private static void createShowFrame() {
    JFrame frame = new MyFrame();
    frame.setTitle("Playing with the Mouse");
    frame.setSize(600, 400);
    frame.setDefaultCloseOperation(
      JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

Now that we have all the require components in place let's run. The above three classes should produce the following (or something very similar).


Let's start playing

Java provides three methods/mechanisms that allow us, the developers, to use to handle mouse events. Let say that we want to change the background colour of my component whenever the mouse hovers over it and rest the colour when the mouse moves away from the component.

We want that our component (the class called MyComponent defined above) to do something when the mouse is moved over it. Then, we have to register a mouse listener within this component and act accordingly. The JComponent class (which MyComponent inherits from) has all the logic we need, that is, methods that allow us to register mouse listeners. Whenever mouse events are occur, these methods will advise/notify our listeners with the changes and we can act accordingly. We first start by registering a mouse listener and then implement the methods we're interested in as illustrated below.

package com.albertattard.pwtm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyComponent extends JComponent {

  public MyComponent() {
    initListeners();
  }

  private void initListeners() {
    addMouseListener(new MouseAdapter() {
      public void mouseExited(MouseEvent e) {
        setBackground(Color.WHITE);
        repaint();
      }

      public void mouseEntered(MouseEvent e) {
        setBackground(Color.RED);
        repaint();
      }
    });
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    g.setColor(getBackground());
    g.fillRect(0, 0, getWidth(), getHeight());
  }
}

Hold your horses, I'm lost.

There's lot of new code in this class, so let's start understanding this bit by bit. Let's start with the initListeners() method. This method is registering a mouse listener by calling the addMouseListener () method inherited from the JComponent class and pass our listener. For simplicity, some code was removed.

  private void initListeners() {
    addMouseListener(/* The Mouse Listener*/);
  }

After removing all the other code, this method becomes very simple and understandable. If you refer to the previous example, we also included a constructor which is calling this method, which I don't believe it requires explanation. The paintComponent () method was also enhanced which now fills a rectangle with the set colour. This rectangle has the same size of our component which makes it appear as the background colour.

Let's now turn our attention to the MouseListener. What is it? Whenever a mouse event is fired, (in laymen terms) the JVM advise our listener about the change. It does so by execute one of the five methods defined by the MouseListener listed below:

  • mouseClicked()
  • mouseEntered()
  • mouseExited()
  • mousePressed()
  • mouseReleased()

The method names are self explanatory but the process may not be. We first create an instance of the MouseListener, which is an interface, and override these methods. Then we register our listener with the component. When the mouse is clicked on our component, the method mouseClicked() will be executed. When the mouse hovers on our component, the method mouseEntered() is executed and when the mouse moves away from our component, the mouseExited().

One last thing before we return to our example. How many from the mouse listener's methods do we need to use to fulfil our requirement? Only two, as the requirement is to change the background when the mouse hovers in and out of our component. Java provides what are referred to adaptors. WTF? Java provides a skeleton class that implement this interfaces and provide default methods (methods that do nothing) for all the interface methods. We can then extend this class and override the method we want. Since the adaptor overrides all the interface methods, we only have to override those we're interested in, which simplifies our work.

Back to our initListeners() method. We're creating an instance of MouseAdapter, and registering it with our component.

  private void initListeners() {
    addMouseListener(new MouseAdapter() {
      public void mouseExited(MouseEvent e) {
        setBackground(Color.WHITE);
        repaint();
      }

      public void mouseEntered(MouseEvent e) {
        setBackground(Color.RED);
        repaint();
      }
    });
  }

As you can see from the above code fragment, we're only overriding two methods, the mouseEntered() and mouseExited() methods. In these methods we're changing the background colour and calling the repaint method.

Straight forward he

Getting it to the next level

That was fun, but let's improve it. Let's draw (fill) a circle following the mouse motion.

Before we can do so, we have to discuss another thing, the MouseEvent.

Before the event is fired and our listeners' methods invoked, information about the event is gathered (by something else which you don't need to care about, at least for now) and forwarded to you (the developer) as an event object, the MouseEvent in this case. This object contains information pertaining to our event, such as the mouse position, the time of the event and other things which may be useful when processing such event. We can (need to) use such information to achieve our goal as shown below.

package com.albertattard.pwtm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyComponent extends JComponent {

  private Point mousePoint; 

  public MyComponent() {
    setForeground(Color.BLUE); 
    initListeners();
  }

  private void initListeners() {
    addMouseListener(new MouseAdapter() {
      public void mouseExited(MouseEvent e) {
        setBackground(Color.WHITE);
        repaint();
      }

      public void mouseEntered(MouseEvent e) {
        setBackground(Color.RED);
        repaint();
      }
    });

    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }
    });
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    g.setColor(getBackground());
    g.fillRect(0, 0, getWidth(), getHeight());

    if (mousePoint != null) {
      int ballSize = 15;
      g.setColor(getForeground());
      g.fillOval(mousePoint.x - ballSize / 2, 
                 mousePoint.y - ballSize / 2,
                 ballSize, ballSize);
    }
  }
}

The changes from the previous class are highlighted and discussed below.

An instance field was added to our component. Why? We need to transfer the mouse position, magically provided to us by the mouse events (discussed later on), to the paint method. Since we cannot call the paint method directly from the event (the reapint() call is something else), we need to save this information in the instance field, mousePoint, and the use it from the paint method. This instance field is accessible by both methods. First this field is updated by the method

      public void mouseMoved(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }

within our new adaptor, . The method mouseMoved() is invoked every time the mouse is moved within our component. This is important to understand. Only the mouse events that are related with our component are captured by our listeners. So when the mouse moves out of our component, this method will stop being invoked.

Next we'll discuss the mouse clicks

Handling the clicks

Let say that we also want to handle the mouse click that happen on our component. For simplicity we'll display a simple text in the top left corner listing the number of click that occure as shown below.

A long story short, add a new instance field (called clickCount) of type int and paint its value in the paint method as highlighted below. Also, override the appropriate method in the mouse adaptor.

package com.albertattard.pwtm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyComponent extends JComponent {

  private Point mousePoint;
  private int clickCount; 

  public MyComponent() {
    setForeground(Color.BLUE);
    initListeners();
  }

  private void initListeners() {
    addMouseListener(new MouseAdapter() {
      public void mouseExited(MouseEvent e) {
        setBackground(Color.WHITE);
        repaint();
      }

      public void mouseEntered(MouseEvent e) {
        setBackground(Color.RED);
        repaint();
      }

      @Override
      public void mouseClicked(MouseEvent e) {
        clickCount++;
        repaint();
      }
    });

    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }
    });
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    g.setColor(getBackground());
    g.fillRect(0, 0, getWidth(), getHeight());

    if (mousePoint != null) {
      int ballSize = 15;
      g.setColor(getForeground());
      g.fillOval(mousePoint.x - ballSize / 2,
          mousePoint.y - ballSize / 2, ballSize, ballSize);
    }

    if (clickCount > 0) {
      g.setColor(getForeground());
      g.drawString("Click Count: " + clickCount, 10, 20);
    } else {
      g.setColor(getForeground());
      g.drawString("No Clicks!!!", 10, 20);
    }
  }
}

The above code is not rocket science but it has a little flaw. If you drag the mouse inside the component, the blue circle will not follow the mouse pointer as illustrated below.

Why not? The MouseMotionListener, which the MouseMotionAdapter implements has two methods but we're only overriding one as illustrated below.

    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }
    });

The other method, mouseDragged(), is used to handle mouse dragging events as illustrated code fragment below.

     addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseDragged(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }
      
      @Override
      public void mouseMoved(MouseEvent e) {
        mousePoint = e.getPoint();
        repaint();
      }
    }); 

Dragging is more complex than one may think and is discussed further in the following section

Dragging the mouse

For this example, we'll create a new component and will make use of it rather than keep changing the other one. Like before, we'll start with a simple example and keep building on it. We'll start with the following simple component.

package com.albertattard.pwtm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyDragComponent extends JComponent {

  private Rectangle draggableShape;

  public MyDragComponent() {
    draggableShape = new Rectangle(20, 20, 50, 50);
    setForeground(Color.BLUE);
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.setColor(getBackground());
    g2d.fillRect(0, 0, getWidth(), getHeight());

    g2d.setColor(getForeground());
    g2d.fill(draggableShape);
  }
}

This component simply draws a solid blue 50 by 50 rectangle at the x and y coordinates 20 as illustrated below

Remember to add this component to the frame before you test it out

Let's start be arm our rectangle with a red border when the mouse enters the box as shown below. Note that the component has a red border and the mouse events are triggered for any mouse activity within the component. We need to filter out movements outside the rectangle and only arm the rectangle when the mouse is on it.

How can we do that? Quiet simple. Like before, we create a field (called mouseInside) and will set it to true when the mouse is within the rectangle and false otherwise. The updates are highlighted below.

package com.albertattard.pwtm;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyDragComponent extends JComponent {

  private Rectangle draggableShape;
  private boolean mouseInside; 

  public MyDragComponent() {
    draggableShape = new Rectangle(20, 20, 50, 50);
    setForeground(Color.BLUE);
    initListeners();
  }

  private void initListeners() {
    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        repaint();
      }
    });
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.setColor(getBackground());
    g2d.fillRect(0, 0, getWidth(), getHeight());

    g2d.setColor(getForeground());
    g2d.fill(draggableShape);

    if (mouseInside) {
      g2d.setColor(Color.RED);
      g2d.setStroke(new BasicStroke(3));
      g2d.draw(draggableShape);
      g2d.setStroke(new BasicStroke(1));
    }
  }
}
Why are we resetting the stroke at the end of the paint component method? Ideally you rest all changes made to the graphics component once done as other paint methods for this object such paint border method will inherit your changes. In this case, if you do not reset the stroke the border will be painted with this stroke.

The following code fragment does the trick. The method mouseMoved () is continually called by the underlying system (so to say) every time the mouse is moved over our component. When the mouse point (retrieved from the mouse event provided as the method parameter) is within the rectangle area, the mouseInside field is set to true.

      public void mouseMoved(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        repaint();
      }

Let's not stop here. Let's make the rectangle draggable. By draggable I mean that the user can drag the rectangle around our component as shown below.

This is not an easy task and some may find it hard to understand but let's not panic. The following code does the job.

package com.albertattard.pwtm;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MyDragComponent extends JComponent {

  private Rectangle draggableShape;
  private boolean mouseInside;
  private Point lastMousePoint; 

  public MyDragComponent() {
    draggableShape = new Rectangle(20, 20, 50, 50);
    setForeground(Color.BLUE);
    initListeners();
  }

  private void initListeners() {
    addMouseMotionListener(new MouseMotionAdapter() {
      @Override
      public void mouseMoved(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        lastMousePoint = e.getPoint();
        repaint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        if (mouseInside) {
          if (lastMousePoint != null) {
            draggableShape.x += 
                e.getPoint().x - lastMousePoint.x;
            draggableShape.y += 
                e.getPoint().y - lastMousePoint.y;
          }
        }
        lastMousePoint = e.getPoint();
        repaint();
      }
    });
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.setColor(getBackground());
    g2d.fillRect(0, 0, getWidth(), getHeight());

    g2d.setColor(getForeground());
    g2d.fill(draggableShape);

    if (mouseInside) {
      g2d.setColor(Color.RED);
      g2d.setStroke(new BasicStroke(3));
      g2d.draw(draggableShape);
      g2d.setStroke(new BasicStroke(1));
    }
  }
}

Let's starts discussing the code.

When the mouse is dragged within the rectangle, we're also moving it. The rectangle can be dragged from anywhere within. So we have to take under consideration where the mouse was clicked within the rectangle and shift the rectangle by the offset, that is, by the amount the mouse was moved. We cannot simply set the rectangle's x and y coordinates to match those of the event. The following sketch highlights this (hopefully).

To do this we added a new field called lastMousePoint, which is used to save the last mouse position (as the name infers). Instead of setting the rectangle coordinates equal to the mouse coordinates we adjust them by how much the mouse was moved using the following (copy and paste from above) logic.

      @Override
      public void mouseDragged(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        if (mouseInside) {
          if (lastMousePoint != null) {
            draggableShape.x += 
                e.getPoint().x - lastMousePoint.x;
            draggableShape.y += 
                e.getPoint().y - lastMousePoint.y; 
          }
        }
        lastMousePoint = e.getPoint();
        repaint();
      }

It is important to also update the lastMousePoint field before we exit the above method.

A tip for the champions. If you observe the previous class, you notice that the field lastMousePoint is only used within the adaptor. Ideally we move this field within the adaptor as highlighted below.

 addMouseMotionListener(new MouseMotionAdapter() {
      
      private Point lastMousePoint; 
      
      @Override
      public void mouseMoved(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        lastMousePoint = e.getPoint();
        repaint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        if (mouseInside) {
          if (lastMousePoint != null) {
            draggableShape.x += 
                e.getPoint().x - lastMousePoint.x;
            draggableShape.y += 
                e.getPoint().y - lastMousePoint.y;
          }
        }
        lastMousePoint = e.getPoint();
        repaint();
      }
    });

Too keep it simple, the above change will not apply to the rest of the examples

One last thing before we go. Note that we're able to drag the rectangle outside the component printable area. This is not always good and we would like to prevent this as illustrated below.

This is not a difficult change. All we need to do is cap the changes to the rectangle as illustrated in the following code fragment.

      @Override
      public void mouseDragged(MouseEvent e) {
        mouseInside = draggableShape.contains(e.getPoint());
        if (mouseInside) {
          if (lastMousePoint != null) {
            draggableShape.x += 
                e.getPoint().x - lastMousePoint.x;
            draggableShape.y += 
                e.getPoint().y - lastMousePoint.y;

            draggableShape.x = Math.max(draggableShape.x, 0);
            draggableShape.x = Math.min(draggableShape.x,
                getWidth() - draggableShape.width);
            draggableShape.y = Math.max(draggableShape.y, 0);
            draggableShape.y = Math.min(draggableShape.y,
                getHeight() - draggableShape.height);
          }
        }
        lastMousePoint = e.getPoint();
        repaint();
      }

The rest of the class is not listed for brevity.

Tuesday, 13 October 2009

Practical Example of Simple Java UI Component

In this article we'll discuss how to create a simple Java graphical component such as a javax.swing.JButton (without going into details of event handling) and include it within an application. Our component will display (paint) a flat rectangle of a set colour as illustrated below.

We'll be making use of two classes one representing the simple custom component and the other will be mounting the frame and including our component in it. All classes discussed here are saved under the package "com.albertattard.cgui". You can change this to your own package. In this article we'll only be exploring the creation of simple custom UI component. Many other related topics will be only mentioned here but not discussed. While you are encouraged to explore all the topics that are only mentioned (but not discussed) here, one must be cautious not to overwhelm him/herself in the process.

Custom UI Component

All Java Swing (don't worry if you don't know with Swing means but if you insist here is a link which may answer some of your questions: http://java.sun.com/docs/books/tutorial/uiswing/) graphical components inherit from the javax.swing.JComponent abstract class. Our component is no exception. So let's start by creating a simple class called: FlatRectComponent. This class will be extending the JComponent class mentioned earlier and will override the paintComponent() method as highlighted in the example below.

package com.albertattard.cgui;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class FlatRectComponent extends JComponent {
  @Override
  protected void paintComponent(Graphics g) {
    // Clear the previous screen
    super.paintComponent(g);
    // Set the painting colour to magenta
    g.setColor(Color.MAGENTA);
    // Draw a solid rectangle at coordinates x and y set to 
    // 10px with width and height set to 100px
    g.fillRect(10, 10, 100, 100);
  }
}
Why did we override the paintComponent() method? All UI programs are responsible from painting themselves on the screen. For example this article you're reading is an image displayed on your screen (unless you printed it on a piece of paper). The browser downloaded this article as HTML and transformed (or better rendered) it as an image. All other applications do the same. For example a button, is a simple set of paint instructions which makes it look real (as you see it on the screen). Also events, such as mouse hovering, may change the way the button or any other graphical component looks making the graphics interacting with the user inputs.

In the case of Java, all graphical components are responsible of painting themselves by overriding the paintComponent() method and paint on the provided java.awt.Graphics. In the above example, we're simply painting a flat rectangle in magenta. Then this method is called by some other class which displays it on the screen as you see it. You don't have to worry about how or what invokes this method. Just remember that you cannot call it yourself.

Alone this class is not of much use. But since it's inheriting from the JComponent class, we can include it with other Java Swing components such as javax.swing.JFrame.

Including it in a JFrame

Let's create a simple frame which will host our new component. For simplicity, we're not going to discuss Layout Managers. We're going to use the absolute layout where we specify the location and size for every component. An example of our frame class is shown below.

package com.albertattard.cgui;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class FrameDemo extends JFrame {

  private static void createFrame() {
    JFrame frame = new FrameDemo();
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    frame.setTitle("Custom UI Demo");
    frame.setSize(600, 400);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        createFrame();
      }
    });
  }

  private FrameDemo() {
    // Set the layout of this frame to absolute layout
    setLayout(null);

    // Create the flat rectangle component and add it to 
    // the frame
    FlatRectComponent comp = new FlatRectComponent();
    comp.setBounds(0, 0, 200, 200);
    add(comp);
  }
}
The above class contains two static methods and a constructor. Let's analyse these further starting from the main() method. The main() method is the first method called by the JVM. This is from where the application starts. This method calls the other static method createFrame() by scheduling a job on the AWT event dispatching thread. This sounds as complex as rocket science but you have nothing to be afraid from. For now all you have to do is copy and paste it. The static method createFrame() creates an instance of our frame class, FrameDemo and set the frame properties, such as title, size and location.

The constructor of this class starts by setting the layout manager to absolute layout. Then it creates an instance of our components and set its size and location accordingly. The setBounds() method takes four parameters, the first two represent the location as x and y coordinate while the latter to represent the size. Finally it adds this component to its container (don't worry about containers for now - this is the fort time I'm asking to accept something as is without having to dig any further). This is a very important step. Many forget to add the components and then wonder why these don't appear in the frame.

How many instances of our component can we include in the frame? As many as you want. In practice there's a limit which is dependent on the amount of memory available to your application, but you don't have to worry about that neither as our application is fairly simple and consume very little memory. Let's amend the previous frame class and include another instance of the FlatRectComponent UI component. All we need to do is create another instance and adding this instance to the frame's container. We also need to set the bounds of the new component such that this don't conflict with the previous one as otherwise we may have a graphical issue. The following code fragment highlights the changes made to the frame class. Only the constructor was changed, the other methods are unchanged and thus not shown here. Also, note that a border was added to the components to visualise the component perimeter.

  private FrameDemo() {
    setLayout(null);

    // The first component
    FlatRectComponent comp1 = new FlatRectComponent();
    comp1.setBounds(0, 0, 200, 200);
    comp1.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp1);

    // The second component
    FlatRectComponent comp2 = new FlatRectComponent();
    comp2.setBounds(250, 50, 200, 200);
    comp2.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp2); 
  }
The program should now display two, identical, components as illustrated below.

Customising the Custom UI Component

As is, our component is not much of use as we cannot customise it. The painComponent() method make use of literals and constants and so our component will always look like that. In order to be able customise it we need to add some states to our custom UI component.

What are these? States in objects are instance fields, or as some call them: class variables. The instance fields are used to save the state of the object. The state of the object is all information about the object. For example our custom UI component displays a rectangle. This rectangle needs to have an x and y coordinates and a size. A rectangle cannot exist without these states (properties). Try to draw a rectangle on a piece of paper yourself without making use of the mentioned states. You'll notice that you cannot as, as soon as you draw it, you have provided the x, y and size states. In this case we need to capture these states in some instance fields. The same applies for the rectangle colour.

We can start by adding an instance of the java.awt.Rectangle class and save our rectangle states (size and location) there. Alternatively, we can create four integer variables which represent the x, y, width and height values for our rectangle. Even though it may sound more complex I suggest we go with the first option as this give us other functionality already available in the Rectangle class, which otherwise we have to program, such as the translate() method.

package com.albertattard.cgui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;

@SuppressWarnings("serial")
public class FlatRectComponent extends JComponent {

  private Rectangle rect = new Rectangle(10, 10, 100, 100); 

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    // Make use of the 2D version of the Graphics component
    Graphics2D g2D = (Graphics2D) g; 

    g2D.setColor(Color.MAGENTA);
    g2D.fill(rect); 
  }
}
In the above example we've changed the way the rectangle is painted. Before we used literals, while now we're painting an instance of Rectangle. Also, now we're using a java.awt.Graphics2D component instead of the Graphics component. We're not going to go into much detail about this here as otherwise we'll be ending up writing a book. But in a nutshell, the Graphics2D inherits from the Graphics and adds more functionality (methods) which we can use. The object invoking out paintComponent() method (which we agreed not to discuss here) will be passing an instance of java.awt.Graphics2D to the paintComponent() method. All we're doing is recasting it back to its original form. Don't worry about this for now. All you need to know is that you should cast your Graphics to Graphics2D.

So far we have not yet provided any means (methods) which allow the rectangle instance field, rect, to be changed. That is, there is no way how one can change the x, y and size values for this instance. Let's add four methods, which can be used to set the any of the rectangle states.

package com.albertattard.cgui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import javax.swing.JComponent;

@SuppressWarnings("serial")
public class FlatRectComponent extends JComponent {

  private Rectangle rect = new Rectangle(10, 10, 100, 100);

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2D = (Graphics2D) g;

    g2D.setColor(Color.MAGENTA);
    g2D.fill(rect);
  }

  public void setHeight(int height) {
    rect.height = height;
    repaint();
  }

  public void setWidth(int width) {
    rect.width = width;
    repaint();
  }

  public void setX(int x) {
    rect.x = x;
    repaint();
  }

  public void setY(int y) {
    rect.y = y;
    repaint();
  }
}
Note that at the end of every setXXX() method we're calling the repaint() method. All we're doing here is instructing the frame's container (this is the guy which is invoking our paintComponent() method) to repaint this component. The frame's container will in turn call the paintComponent() method for this component and providing the appropriate information. It is important to do so after every change as otherwise your changes will not immediately appear. But these will appear only when the frame completely repaints all its components. Remember that you cannot call the paintComponent() yourself. All you can do is call the repaint() method.

So far we've only provided a means to customise our component. But we have not yet customized it. Let's do that. We can customise our component by calling the setXXX() from the frame class as highlighted bold below. The following code fragment only shows the constructor of the frame class as the other methods are unchanged.

  private FrameDemo() {
    setLayout(null);

    // The first component
    FlatRectComponent comp1 = new FlatRectComponent();
    comp1.setBounds(0, 0, 200, 200);
    comp1.setX(5);
    comp1.setY(5);
    comp1.setWidth(190);
    comp1.setHeight(190); 
    comp1.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp1);

    // The second component
    FlatRectComponent comp2 = new FlatRectComponent();
    comp2.setBounds(250, 50, 200, 200);
    comp2.setX(50);
    comp2.setY(50);
    comp2.setWidth(100);
    comp2.setHeight(100); 
    comp2.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp2);
  }
The above program should produce the following outcome.

Note that now the coloured rectangle size and location can be varied from the setter methods provided. This makes our component customizable. We can also change the paint colour by including an instance field representing the colour and a method in our custom UI component which changes the colour as illustrated below.

// imports not shown here 
public class FlatRectComponent extends JComponent {
  private Color rectColour = Color.MAGENTA; 

  // other field and methods are not show for brevity

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2D = (Graphics2D) g;

    g2D.setColor(rectColour); 
    g2D.fill(rect);
  }

  public void setRectangleColour(Color rectColour) {
    this.rectColour = rectColour;
    repaint();
  }
}
All we need to do now is call this method and change the colour accordingly as highlighted below.

  private FrameDemo() {
    setLayout(null);

    // The first component
    FlatRectComponent comp1 = new FlatRectComponent();
    comp1.setBounds(0, 0, 200, 200);
    comp1.setX(5);
    comp1.setY(5);
    comp1.setWidth(190);
    comp1.setHeight(190);
    comp1.setRectangleColour(Color.GREEN); 
    comp1.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp1);

    // The second component
    FlatRectComponent comp2 = new FlatRectComponent();
    comp2.setBounds(250, 50, 200, 200);
    comp2.setX(50);
    comp2.setY(50);
    comp2.setWidth(100);
    comp2.setHeight(100);
    comp2.setRectangleColour(Color.CYAN); 
    comp2.setBorder(
      BorderFactory.createLineBorder(Color.BLACK, 1));
    add(comp2);
  }

The following screenshot shows the final version of our program.

Conclusion

In this article we've saw how to create a simple custom Java UI component and display a simple flat rectangle. We've also added methods which can be used to customise this component.