Context:
I'm trying to make an app with java swing, however when trying to add a background to the Login Page, the image does not show up. It is there and moves other JComponents when adding a layout to the root JPanel of the Page, it just, doesn't display the image. I've also tried JavaFX but it seems like I'm having the same problem over there.
I've also tried to find if anyone else has the same problem, however couldn't find anything useful. After spending a whole day trying to figure out a solution, I resorted to asking over here
Pc Info:
This is my PC info if it sums up to be a DE promblem
-` mmt007@mmt007desktop
.o+` --------------------
`ooo/ OS: Arch Linux x86_64
`+oooo: Host: B75M-D3P
`+oooooo: Kernel: Linux 6.17.6-arch1-1
-+oooooo+: Uptime: 21 mins
`/:-:++oooo+: Packages: 1022 (pacman), 26 (flatpak)
`/++++/+++++++: Shell: bash 5.3.3
`/++++++++++++++: Display (WX942): 1440x900 in 19", 60 Hz [External]
`/+++ooooooooooooo/` WM: Hyprland 0.51.1 (Wayland)
./ooosssso++osssssso+` Theme: Adwaita-dark [GTK2/3/4]
.oossssso-````/ossssss+` Icons: Adwaita [GTK2/3/4]
-osssssso. :ssssssso. Font: Noto Sans (12pt) [Qt], Adwaita Sans (11pt) [GTK2/3/4]
:osssssss/ osssso+++. Cursor: default (24px)
/ossssssss/ +ssssooo/- Terminal: kitty 0.43.1
`/ossssso+/:- -:/+osssso+- Terminal Font: NimbusMonoPS-Regular (11pt)
`+sso+:-` `.-/+oso: CPU: Intel(R) Core(TM) i5-3570 (4) @ 3.80 GHz
`++:. `-/+/ GPU: Intel Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller @ 1.15 GHz [Integrated]
.` `/ Memory: 3.73 GiB / 7.62 GiB (49%)
Swap: 0 B / 4.00 GiB (0%)
Disk (/): 82.46 GiB / 214.08 GiB (39%) - ext4
Locale: en_US.UTF-8
The Code:
And here is the code that is giving me problems:
Login Page class:
public class LoginPage extends Page {
protected void init() {
root.setLayout(new FlowLayout());
JImageLabel background = new JImageLabel(new ImageIcon("assets/backgrounds/login_background.png"));
background.setSize(400,400);
background.setPreferredSize(new Dimension(800,100));
root.add(background);
root.setBackground(Color.BLACK);
}
}
Page class:
public abstract class Page {
protected final JPanel root = new JPanel();
public Page() { init(); }
protected abstract void init();
}
JImageLabel class:
public class JImageLabel extends JLabel {
private ImageIcon image;
public JImageLabel(ImageIcon image)
{super(image);}
}
Window class:
public class Window extends JFrame {
private static final Window INSTANCE = new Window("Disbot");
private static final Dimension DEFAULT_WINDOW_SIZE = new Dimension(1280,720);
private static Page page = null;
private Window(String title) throws HeadlessException
{super(title);}
public static void init(){
INSTANCE.setDefaultCloseOperation(EXIT_ON_CLOSE);
INSTANCE.setSize(DEFAULT_WINDOW_SIZE);
INSTANCE.setVisible(true);
}
public static void setPage(Page new_page){
page = new_page;
INSTANCE.setContentPane(page.root);
INSTANCE.repaint();
}
}
Main Class:
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Window.init();
Window.setPage(new LoginPage());
});
}
}
Screenshots:
image1 - black blank screen image2 - two jbuttons on either side of the invisible image
Updates
12/29/25
Well, it has been quite some time and so far nothing has worked, I've tried
- Changing the image type
- Changing the image location (and path)
- Setting
.setOpaqueto true - Made sure that the JLabel is actually added to root
- Made sure that root is set as the root node of the JFrame
I'm starting to think it has to do with some bug when using Java Swing/JavaFX in Hyprland/Arch, however I can't confirm it
2 Answers 2
I feel so dumb writing this, but after hours of trying to fix this, I've realized that I used the wrong ffmpeg argument and instead of converting my webp image to PNG, it only changed the name.
Anyways let this be a lesson for future me, and thanks to all that tried to help me in this endeavor.
Happy new years!
Comments
After checking your code carefully, I found the main issue. It comes from the LoginPage class.
Layout:
You chose a FlowLayout but I prefer BorderLayout in this case because the image will be displayed in the center of the frame. FlowLayout is useful when you want to add components in a flowing form like Buttons, but in this case BorderLayout is fine.
Setting label to Opaque:
This one was missing: background.setOpaque(true);. Its very important because it makes image to fit in the Label.
Image Path:
Make sure that you paste your Image path correctly into the ImageIcon; its better if you use getClass() and getResource() which will shorten your image file path to something similar to: /path/image.png.
Full fixed code in the LoginPage class (After checking with my 400x400 image, it is working):
package main;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.ImageIcon;
public class LoginPage extends Page {
protected void init() {
root.setLayout(new BorderLayout()); // Instead of FLowLayout. now Image can be partially displayed in the center of the frame.
JImageLabel background = new JImageLabel(new ImageIcon(getClass().getResource("/package/filename.extension"))); // enter a path in following way.
background.setOpaque(true); // so Image can fit inside of Label
background.setSize(400, 400);
root.add(background);
root.setBackground(Color.BLACK);
}
}
2 Comments
background.setBackground(Color.BLACK) it does change to black. I think it may be a quirk with swing on Hyprland/Arch, but I'm not sure. Thanks for the suggestion though!Explore related questions
See similar questions with these tags.
JFrameis actually a subclass ofjava.awt.WindowJImageLabelandWindoware obsolete. They do nothing that couldn’t be done on instances of the existing Swing class, without subclasses it. And you are overusingstatic.JImageLabel background = new JImageLabel(new ImageIcon(LoginPage.class.getResource("/assets/backgrounds/login_background.png")));