Michael Gates
Michael Gates

Reputation: 107

Drawing image behind border in Swing JPanel

I've created a JFrame which contains a JPanel in a MigLayout.

Within that layout, I have 5 columns and 4 rows, each has a 'Big Cell' in them.

The 'Big Cell' extends JPanel and has a border color, and within the 'Big cell' is a 'small cell' which also extends JPanel and has a border color. 16x16 grid within the big cell of the small cells.

I am trying to draw an image, but it only draws the image after everything else is drawn (borders, backgrounds, etc.)

But I want to draw the image first, and draw the borders after.

I can't use setIcon for the individual cells because it doesn't draw the image (not sure why) and it makes my grid 10x bigger and the program overflows so big that it wouldn't even fit on a 4k resolution.

Here's a picture of what it looks like

Cell Example

I want each black 'box' or 'Big Cell' to have it's own background image which is painted or rendered behind the little cells with the orange border.

And here's what it looks like with the image painted

Cell Example 2

You might not be able to tell, but that's the image rendered in each 'big cell' as it should except it's in front of everything. It looks like it just 1 image but don't be fooled because it's a seamless image.

Here's the 'BigCell' class which I'm assuming is the root of the issue.

package com.michaelgates.dev.OldLeaf.gui.components;

import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;


public class BigCell extends JPanel
{
    int column;
    int row;
    Cell[][] children;

    JPanel parent;
    Image image;


    public BigCell(int column, int row, JPanel parent)
    {
        this.column = column;
        this.row = row;
        this.parent = parent;

        setLayout(new GridLayout(16, 16, 0, 0));
        setBorder(new LineBorder(Color.DARK_GRAY, 2));

        children = new Cell[16][16];
        for (int i = 0; i < 16; i++)
        {
            for (int j = 0; j < 16; j++)
            {
                Cell cell = new Cell(i, j, this);
                add(cell);
                children[i][j] = cell;
            }
        }


        image = Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("img/acre/acre_0.png"));
    }


    @Override
    public void paint(Graphics g)
    {
        if (image != null)
        {
            g.drawImage(image, 0, 0, (int) getSize().getWidth() - 0, (int) getSize().getHeight() - 0, this);
        }
        super.paint(g);
    }
}

And the 'Cell' class which is the tiny box with an orange border

package com.michaelgates.dev.OldLeaf.gui.components;

import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;


public class Cell extends JPanel
{
    int column;
    int row;
    BigCell parent;


    public Cell(int column, int row, BigCell parent)
    {
        this.column = column;
        this.row = row;
        this.parent = parent;

        setBorder(new LineBorder(Color.orange, 1));
        //setBackground(Color.LIGHT_GRAY);

    }


}

Upvotes: 1

Views: 956

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347204

Change...

@Override
public void paint(Graphics g)
{
    if (image != null)
    {
        g.drawImage(image, 0, 0, (int) getSize().getWidth() - 0, (int) getSize().getHeight() - 0, this);
    }
    super.paint(g);
}

to

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    if (image != null) {
        g.drawImage(image, 0, 0, (int) getSize().getWidth() - 0, (int) getSize().getHeight() - 0, this);
    }
}

paintComponent is called before paintBorder and paintChildren, so it's the perfect place to paint a background image

Then add setOpaque(false); to your Cell's constructor

Background

Take a look at Performing Custom Painting and Painting in AWT and Swing for more details about how painting works in Swing

Upvotes: 1

Related Questions