Game programming: JFrame, JPanel, paint method
To paint something we first need a surface where to paint on. This surface or canvas where we are going to paint our first example is a JPanel object. In the same way a canvas needs a frame to hold it, our JPanel will be framed in a window made by the JFrame class.
JFrame: The window
The following code creates a window "Mini Tennis" of 300 pixels by 300 pixels. The window won´t be visible until we call setVisible(true). If we don´t include the last line "frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)", when we close the window the program won´t finish and will continue running.
package com.edu4java.minitennis1; import javax.swing.JFrame; public class Game { public static void main(String[] args) { JFrame frame = new JFrame("Mini Tennis"); frame.setSize(300, 300); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
If we run it we will obtain:
With these few instructions we will obtain a window which can be maximize, minimize, change it´s size with the mouse, etc. When we create a JFrame object we start an engine which manages the user interface. This engine communicates with the operative system both to paint in the screen as to receive information from the keyboard and from the mouse. We will call this engine "AWT Engine" or "Swing Engine" because it is made by these two libraries. In the first java versions only AWT existed and then Swing was added. This engine uses several threads.
What is a thread in java?
A program is executed by just one processor, line by line. Threads allow a program to start several executions at the same time. This is as if, there were several processors running at the same time their own sequence of instructions.
Even though threads and concurrence are very powerful tools, there can be problems when two threads enter the same variables. It is interesting to think that two threads can be running the same code at the same time.
We can think that a thread is like a cook preparing a dish reading a recipe. Two concurrent threads would be like two cooks working in the same kitchen, preparing one dish with the same recipe o with differents recipes. The problems come when both try to use the same frying pan at the same time.
AWT Engine and Thread AWT-EventQueue
The AWT Engine starts several threads which can be seen if we start the aplication with debug and we go to the debug perspective. Each thread is as if it was an independent program running at the same time as the other threads. Further on we will see more about threads, meanwhile I am only interested that you remember the third thread we see in the debug view called "Thread [AWT-EventQueue-0]" this thread is the one in charge of painting the screen and receiving the mouse and keyboard events.
JPanel: The canvas
To be able to paint we want to know WHERE and where is an JPanel object which will be included in the window. We extend the JPanel class to be able to overwrite the paint method which is the method called by the AWT Engine to paint what appears in the screen.
package com.edu4java.minitennis1; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Ellipse2D; import javax.swing.JFrame; import javax.swing.JPanel; @SuppressWarnings("serial") public class Game2 extends JPanel { @Override public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.RED); g2d.fillOval(0, 0, 30, 30); g2d.drawOval(0, 50, 30, 30); g2d.fillRect(50, 0, 30, 30); g2d.drawRect(50, 50, 30, 30); g2d.draw(new Ellipse2D.Double(0, 100, 30, 30)); } public static void main(String[] args) { JFrame frame = new JFrame("Mini Tennis"); frame.add(new Game2()); frame.setSize(300, 300); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
The paint method receives by parameter a Graphics2D object which extends from Graphics. Graphics is an old class used by AWT which has been replaced with Graphics2D which has more and better functionality. The parameter is still a Graphics type due to compatibility but we will use Graphics2D, so we need to create a variable g2d "Graphics2D g2d = (Graphics2D) g;". Once we have g2d we can use all the Graphics2D methods to draw.
The first thing we do is choose the colour we use to draw: "g2d.setColor(Color.RED);". After, we draw circles and squares.
Positioning in the canvas. Coordinate "x" and "y"
To draw something inside the canvas we should indicate in which position we are going to start painting. For this, each of the points in the canvas has an associated position (x,y) being (0,0) the point of the top-left corner.
The first red circle is painted with "g2d.fillOval(0, 0, 30, 30)": the first two parameters are the position (x,y) and after comes the width and the height. As a result we have a circle with 30 pixels of diameter in the position(0,0).
The empty circle is drawn with "g2d.drawOval(0, 50, 30, 30)": which draws a circle in the position x=0 (left margin) and y=50 (50 pixels below the top margin) with a height of 30 pixels and a width of 30 pixels.
Rectangles are drawn with "g2d.fillRect(50, 0, 30, 30)" and "g2d.drawRect(50, 50, 30, 30)" in a similar way to the circles.
Lastly "g2d.draw(new Ellipse2D.Double(0, 100, 30, 30))" draws the last circle using an Ellipse2D.Double object.
There are a lot of methods in Graphics2D. Some of them will be seen in the following tutorials.
When does the AWT engine call the paint method?
The AWT engine calls the paint method every time the operative system reports that the canvas has to be painted. When the window is created for the first time paint is called. The paint method is also called if we minimize and after we maximize the window and if we change the size of the window with the mouse.
We can watch this behaviour if we put a breakpoint in the first line of the paint method and we run the program in the debug mode.
It is interesting to see that the paint method is ran by the Thread AWT-EventQueue, which is the one in charge of painting the screen.
<< Index | Next >> |