Subscribe to Martyr2's Programming Underground        RSS Feed
-----

Interfaces and Drawing in Java, Hurray!

Icon 3 Comments
So I am cruising around the boards when I stumble across an interesting post about creating a shapes tool for a graphics Java program. If you are unfamiliar with the shapes tool, the idea is that you click a button, select a shape and then draw the shape onto some window of the program. Select a square, an ellipse or some fancy star and KAPOWY! you have a masterpiece in the making. I figured "Wow, this is a perfect opportunity to show how we can implement an interface for the various shapes and.... the idea of a picture tube as well!" I will explain the concept on this entry of the Programming Underground!

<Katy Perry singing the DIC theme song, whatever that horrible wreck would sound like>

So how would we go about designing a system where the user could essentially load a ton of shapes in it, allow the user to build their own crazy shapes and plug them right into the code for drawing with little effort?

Coming up with the answer, I knew there would have to be a way to have the program understand all sorts of classes that the programmer may create, yet know that they have the basic functionality to at least draw themselves given a location. We don't care what kind of monstrosity the programmer has come up with as long as it draws. Sounds like the job of an interface!

Interfaces are great in that they allow you to define all sorts of classes and, as long as they agree to support certain functions, can play nice with the rest of the objects. For our little program we are going to create a couple shape classes. One being an Ellipse and the other being a Square. We are going to make sure that these two classes know how to draw themselves despite their drawing difference underneath the hood. The Ellipse class is going to use drawOval and the Square class is going to use drawRect respectively.

To kick off the program we will create a standard program which inherits from a JPanel. This will be our canvas for drawing on. But we could essentially pass along any type of Graphics object to our setup and have the "figures" (as we will now call them) draw anywhere. The one thing we have to make sure all figures can do is implement a method called "draw()" which will take in a Graphics object to let the figure know where to draw.

So we create an interface called iDraw to help us do that. Interfaces are like contracts which state that any class which implements the interface MUST support certain functions defined in that interface. If our interface says that a class implementing the iDraw interface MUST have a method called "draw()" defined and that the draw method has to take in a Graphics object, x/y coordinate and width/height, there is no ifs ands or buts about it.

It looks something like this...

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class Drawtest extends JPanel {
	// Arraylist of who knows what, but at least they know how to draw
	private ArrayList<iDraw> figures = new ArrayList<iDraw>();
	
	public Drawtest() {
		super();
	}
	
	// Add some object that implements the iDraw interface to our list of figures
	public void add(iDraw figure) {
		figures.add(figure);
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setTitle("Shapes example");
		frame.setSize(300,300);
		
		// Create a panel to draw on
		Drawtest panel = new Drawtest();
		
		// Add some shapes to our panel
		panel.add(new Ellipse());
		panel.add(new Square());
		
		frame.add(panel);
		frame.setVisible(true);
	}
	
	// Controls painting
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		// Now, we choose where to paint those shapes to using our stored shapes
		
		// Draw the first figure at 50,50 with the width and height being 20
		figures.get(0).draw(g, 50, 50, 20, 20);
		
		// Again, we don't know what this figure is, but we know it can draw so draw it at 100, 100 in a bounding box of 50 x 70
		figures.get(1).draw(g, 100, 100, 50, 70);
		
	}
}

// Class for ellipse that impliments the iDraw interface
class Ellipse implements iDraw {
	public void draw(Graphics g, int x, int y, int w, int h) {
		g.drawOval(x, y, w, h);
	}
}

// Class for square that also implements the iDraw interface
class Square implements iDraw {
	public void draw(Graphics g, int x, int y, int w, int h) {
		g.drawRect(x, y, w, w);
	}
}

// Interface that forces all objects that implement it to create a custom implementation of draw
interface iDraw {
	void draw(Graphics g, int x, int y, int w, int h);
}



So in the code above we have defined an interface called iDraw that states "any class implementing iDraw will have a draw() method". We then continue by creating our two classes Ellipse and Square and say they implement iDraw. Meaning they will have to create their own draw() methods that meet their contractual obligation to the interface.

Now this is important to understand. Despite what class they might be if they implement iDraw we KNOW FOR SURE that they at least have the draw() method! A powerful assumption.

So we can go ahead and make an ArrayList of iDraw interfaced objects. Java will know nothing about the objects themselves, it only knows that each object has an iDraw interface so it can be used to call the draw() method.

In our main method we create a JFrame, then an instance of our Drawtest class and using a method called "add" to add a figure to our Arraylist of iDraw supporting objects. We can create an Ellipse and pass it to the Drawtest class. We can create a Square and give it to a Drawtest class and Java will accept them all because they support iDraw.

Here is where the cool idea of picture tubes comes in. If we create a class called "ChuckNorris" and say that it implements an iDraw interface, that means ChuckNorris will have a draw() method like the rest. In that method we could use something like drawImage() from the Graphics object (remember we pass that into the method draw) and draw a little picture of Chucky boy kicking butt! Then we can give him to the Drawtest class like any other object and he will be added with the Ellipse and the Square.

In our paintComponent method, we can then read each object and tell it where to paint and its dimensions by calling draw() and giving it the Graphics object of the JPanel along with its coordinates. That means we could draw our Ellipse at coordinates 50,50 and our Square at 100,100 or even Chucky larger than life at 23, 45 with a size of 150 x 150. Knocking out all the other figures.

Our ArrayList will allow us to store all the figures we want as long that they implement the interface. We can add other classes to it for drawing and in the paintComponent we could even loop through the figures to create a crowd for a video game. Or we can drag the image around by redrawing the same shape over and over again. We could create a rubber stamp effect by having a mouseListener following the user's mouse and when they click it draw the appropriate image at the mouse x/y location.

Now there is a slightly different way we could have done this using a base class that we inherit our shapes from etc. The problem with that method is then we bind all classes to having to inherit from "Shape" rather than allowing the programmer to create "ANY" class. So Chucky would have had to inherit from a shape and really, I don't think he would have liked that. He is more complex than the rest of them squares. It also limits the future possibilities for adding other classes to the mix. What about our picture tubes? What if we wanted to instead inherit from the BufferedImage class and put it into the mix? At least this way we could inherit from BufferedImage, give it an iDraw interface and draw() method and throw it into our ArrayList.

The possibilities are endless! I hope you find this code useful and feel free to part it out like you were a chop shop. All code here on the Underground is open to the public to pimp out. Thank you again for reading! :)

If you want more blog entries like this, check out the official blog over on The Coders Lexicon. There you will find more code, more guides and more resources for programmers of all skill levels!

3 Comments On This Entry

Page 1 of 1

Locke Icon

26 May 2009 - 08:28 PM
Speaking on the topic of interfaces...

Are they the same in C# as they are in Java? I've been dealing in Java for a tiny bit over 2 years now, and I've only dabbled here and there in C#. I came across the need (or want) for one in C# and noticed the structure to be remarkably similar. I haven't played around with it much yet, but I was just wondering if they're the same, if nothing else, conceptually?

:)
0

Martyr2 Icon

26 May 2009 - 10:24 PM

Locke, on 26 May, 2009 - 07:28 PM, said:

Speaking on the topic of interfaces...

Are they the same in C# as they are in Java? I've been dealing in Java for a tiny bit over 2 years now, and I've only dabbled here and there in C#. I came across the need (or want) for one in C# and noticed the structure to be remarkably similar. I haven't played around with it much yet, but I was just wondering if they're the same, if nothing else, conceptually?

:)


Yes, the concept of interfaces is virtually identical between C# and Java. They are used to enforce a set of functions and their signatures on classes that wish to implement them. Keep that concept in your mind and you will understand interfaces across the spectrum despite subtle syntax differences.

:)
0

Locke Icon

27 May 2009 - 11:09 AM
:) Thanks a lot. I knew that there are subtle differences between Java and C#, but wasn't sure if interfaces were included with it (besides syntax).
0
Page 1 of 1

October 2014

S M T W T F S
    1 234
567891011
12131415161718
19202122232425
262728293031