Get up to 80 % extra points for free! More info:

Lesson 9 - Drawing on Graphics in Java Swing

In the previous lesson, Birthday Reminder in Java Swing - Finishing the Application, we finished programming a birthday reminder. In that application, we tried out basic form elements as well as models and working with error states. We can already create quite sophisticated applications. Today's lesson will be devoted to drawing.

Drawing on Graphics

We'll create an application to help with selling cinema tickets. As we know, there are many seats in the auditorium and employees of the cinema should see in the app which seats are already taken. Maybe you'd think of using a label for each seat. However, if the cinema had 15 rows with 30 seats in each row, we'd have 450 labels. As you might have guessed, there's a better way than adding JLabel1, JLabel2, ... Moreover, how'd we handle these in this case? If we need to render something more complicated than just one or two images, we'll use Graphics. It involves placing a component (most commonly JPanel or Canvas) on the form and rendering what we need on its canvas.

Let's simplify the application as much as possible. There's no need to have it complicated. It'll only be able to display one auditorium that will be initially empty. The user clicks the taken seats with the mouse and then presses the Save button, which saves a simple txt file to the selected location with the information about the auditorium seat occupancy. We'll try the saving to learn how to work with dialogs.

Designing the Form

Create a new Java Application without the main class, add a new CinemaJFrame to it, and set the title to "Auditorium occupancy record". Drag a JPanel (it's in the palette's Swing Containers section) across most of the form. Name it canvasJPanel. Place a JButton with the text "Save" below the JPanel and name it as saveJButton.

Java Swing Cinema Form - Form Applications in Java Swing

The Logic Layer

You may not be surprised that we'll add an Auditorium class to the app. It'll have one private field which will be a two-dimensional array of seats. If you haven't worked with a 2D array yet, you can imagine it as a table. A one-dimensional (classic) array is actually just one row. We then work with the 2D array in exactly the same way as with the one-dimensional. We just have to specify two coordinates (X and Y). In some languages, there's a 2D array data type but not in Java. If we want a 2D array, we simply declare it as an array of arrays. So we have an array (the rows) and there is another array (a column) in each item of this array. So we end up with a table.

class Auditorium
{
    private boolean[][] seats = new boolean[30][15];

}

The seats are of the boolean type since we're only interested whether the seat is taken or not. The width of the array is 30 and its height is 15.

We add 2 private constants to the class; one constant specifying the size of the rendered seat in pixels, and the other the space between the seats in pixels. Get used to using constants. When you'll want to increase the seat size, you just change the constant and won't have to mess with the rendering code.

private static final int SIZE = 16;
private static final int SPACE = 2;

We can move to methods.

Rendering

The auditorium should be able to render itself. We've already mentioned that we'll draw on a canvas. The canvas is of the Graphics type and we'll accept it as a parameter of a draw() method. We'll then draw on the canvas using the methods it provides. For now, it's only the fillRect() method we're interested in. It draws a rectangle filled with a certain color. There's a lot of methods for different geometric shapes, both filled or outlined. You can take a look at those, we'll try some of them in the next lessons.

Using two nested loops, we'll go through all the seats in the array and either draw a green or red square on the canvas. We'll use the outer loop to iterate over the rows and the inner loop for the columns in the current row. We'll determine the color by whether the seat at the given coordinate is true or false. The method's code will be as follows:

public void draw(Graphics g)
{
    for (int j = 0; j < seats[0].length; j++)
    {
        for (int i = 0; i < seats.length; i++)
        {
            if (seats[i][j])
                g.setColor(Color.RED);
            else
                g.setColor(Color.GREEN);
            g.fillRect(i * (SIZE + SPACE), j * (SIZE + SPACE), SIZE, SIZE);
        }
    }

}

Note that we don't use the values 30 and 15 in the loops, but seats.length and seats[0].length. The first expression is the width of the array (the number of columns), the second is its height (the number of rows). (Of course, it's up to us which dimension we choose to be the height and which the width). Of course, we don't use a fixed size because we may increase/decrease the array size in the future and we'd have to search for the usage of values 30 and 15 ​​everywhere in the code instead. It's always better to avoid these problems and work with the array's length directly.

The rendering itself is also worth mentioning. We use the setColor() method to set the color. It takes one of the Color class constants as a parameter. We also use the fillRect() method, its parameters are the coordinates of the upper left corner of the rectangle and its height and width. Since each seat is 16 pixels wide + 2 pixels space, its coordinates must be multiplied by this value. For example, if i has the value of 2 (so we're drawing the third column), we draw on the x-coordinate of 36, not 2 :) The same applies to the y-coordinate.

Later, you can try to replace fillRect() with the fillOval() method. It works exactly the same way but draws an ellipse. Definitely try to draw other shapes after you finish this application.

Canvas

We used JPanel as a canvas for our application. Of course, it's rendered as a panel, not as cinema seats :) To change this behavior, we must inherit JPanel and override its paintComponent() method to draw the auditorium instead.

So we'll add a Canvas class to the project. Its contents will be as follows:

public class Canvas extends JPanel {

    private Auditorium auditorium;

    public Canvas(Auditorium auditorium)
    {
        super();
        this.auditorium = auditorium;
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        auditorium.draw(g);
    }

}

We pass the auditorium instance to the class constructor. Then we overwrite the paintComponent() method to render the auditorium.

Note: Besides the paintComponent() method, the component also has the paint() method, which we can also override and achieve the same result. That's a little confusing at least. According to the manual, we should override paintComponent() as it's the Swing method, paint() is from AWT.

Wiring the Form With the Logic Layer

The core logic is done, let's wire it to the form. We'll go to the form code and create a private Auditorium instance in the class:

private Auditorium auditorium = new Auditorium();

Now it's necessary to tell NetBeans that the JPanel, which we've dragged on the form, shouldn't be of the JPanel type, but our modified Canvas. Select the JPanel and move to the Code tab in the Properties window. We'll put the following value in the Custom Creation Code property:

new Canvas(auditorium);
Java Swing Custom Creation Code in Netbeans - Form Applications in Java Swing

This will modify the creation code for this panel that NetBeans generates and would look like this otherwise:

new JPanel();

The paintComponent() event is called by the system when the window has to be repainted. This is, of course, the case when the application is started, but also when it's restored from minimization or when we move over another window over it and so on.

When we run the app, the customized panel really looks like cinema seats:

Drawing shapes on JPanel in Java Swing - Form Applications in Java Swing

The panel is still of the JPanel type. If we wanted to call some specific methods on it, we'd have to cast it. We won't need it in our case.

In the next lesson, Handling Click on Coordinates in Java Swing, we'll show how to click on a particular seat to change its state and also how to save it. As always, you can download the attached project in case something doesn't work in your app.


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 28x (27.37 kB)
Application includes source codes in language Java

 

Previous article
Birthday Reminder in Java Swing - Finishing the Application
All articles in this section
Form Applications in Java Swing
Skip article
(not recommended)
Handling Click on Coordinates in Java Swing
Article has been written for you by David Capka Hartinger
Avatar
User rating:
No one has rated this quite yet, be the first one!
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn university David learned IT at the Unicorn University - a prestigious college providing education on IT and economics.
Activities