There are simple so many ways you might be able to achieve this it's not funny.
For example, you could use a JLabel
to show the image and add another JLabel
ontop of it...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() throws IOException {
setLayout(new BorderLayout());
JLabel background = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("Background.jpg"))));
JLabel text = new JLabel("Say hello to my little friend");
text.setFont(text.getFont().deriveFont(Font.BOLD, 24f));
text.setForeground(Color.WHITE);
background.setLayout(new GridBagLayout());
background.add(text);
add(background);
}
}
}
Now, there are issues with this approach that I don't like, for example, if the text is too large, the background label won't increase in size
So, instead, you could just manipulate the properties of the JLable
and use it to display the background image and text

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() throws IOException {
setLayout(new BorderLayout());
JLabel background = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("Background.jpg"))));
background.setText("Say hello to my little friend");
background.setFont(background.getFont().deriveFont(Font.BOLD, 24f));
background.setForeground(Color.WHITE);
background.setHorizontalAlignment(JLabel.CENTER);
background.setVerticalAlignment(JLabel.CENTER);
background.setHorizontalTextPosition(JLabel.CENTER);
background.setVerticalTextPosition(JLabel.CENTER);
add(background);
}
}
}
Now, if you want to add some additional functionality in the future (anchor position, scale, etc), you could use a custom component for painting the background image...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() throws IOException {
setLayout(new BorderLayout());
BufferedImage background = ImageIO.read(getClass().getResource("Background.jpg"));
BackgroundPane backgroundPane = new BackgroundPane(background);
add(backgroundPane);
backgroundPane.setLayout(new GridBagLayout());
JLabel text = new JLabel("Say hello to my little friend");
text.setFont(text.getFont().deriveFont(Font.BOLD, 24f));
text.setForeground(Color.WHITE);
backgroundPane.add(text);
add(backgroundPane);
}
}
public class BackgroundPane extends JPanel {
private BufferedImage background;
public BackgroundPane(BufferedImage background) {
this.background = background;
}
@Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.drawImage(background, x, y,this);
g2d.dispose();
}
}
}
}
So, lots of options
I'd encourage you to have a look at How to Use Labels and Laying Out Components Within a Container for starters