2

I've made a JPanel with a image as background. But while loading the JPanel first time the rest of the added components but the image are not visible. After rolling the mouse over the image, the buttons become visible. How to make the JButtons visible along with the image as background while loading the panel.

enter image description here

Here is the piece of my code:

    contentPane = new JPanel();
    contentPane.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    homePanel.setBounds(10, 11, 959, 620);
    homePanel.setLayout(null);

    JPanel wizardPanel = new JPanel();
    wizardPanel.setBounds(10, 295, 545, 336);
    wizardPanel.setLayout(null);
    homePanel.add(wizardPanel);

    JLabel backgroundLabel;
    try {
        backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(new File("images/nature.jpg"))));
        backgroundLabel.setBounds(0, 0, 545, 336);
        wizardPanel.add(backgroundLabel);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    JButton btnNewButton = new JButton("New button");
    btnNewButton.setBounds(309, 95, 89, 23);
    wizardPanel.add(btnNewButton);

    JButton btnNewButton_1 = new JButton("New button");
    btnNewButton_1.setBounds(309, 150, 89, 23);
    wizardPanel.add(btnNewButton_1);

    JButton btnNewButton_2 = new JButton("New button");
    btnNewButton_2.setBounds(309, 212, 89, 23);
    wizardPanel.add(btnNewButton_2);
RubioRic
  • 2,442
  • 4
  • 28
  • 35
Lingaraj
  • 99
  • 2
  • 13
  • 2
    Try to call `revalidate()` and `repaint()` on your content pane, once all your components have been added . – Arnaud Apr 06 '16 at 08:24
  • if possible then post whole code. – Vishal Gajera Apr 06 '16 at 08:25
  • 1
    It would be good to have a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). This would make your question much easier to answer. – Tiz Apr 06 '16 at 08:26
  • revalidate() & repaint() didn't work out @vishal.. let me display my complete code – Lingaraj Apr 06 '16 at 08:51
  • @Berger `revalidate ` will work if they are using an actual layout manager – MadProgrammer Apr 06 '16 at 09:13
  • My "guess" is you've called `setVisible` on the frame before you've added your components to it – MadProgrammer Apr 06 '16 at 09:14
  • @MadProgrammer : Oh yes I missed that part, thanks . – Arnaud Apr 06 '16 at 09:17
  • 2
    [This](http://stackoverflow.com/questions/23665784/java-gui-background-image/23667373#23667373) is why I wouldn't use a `JLabel` for displaying a background image, I'd use a `JPanel` or other component you can control better, for [example](http://stackoverflow.com/questions/31526190/jframe-with-background-image-and-a-jpanel/31527567#31527567) and [example](http://stackoverflow.com/questions/22162398/how-to-set-a-background-picture-in-jpanel/22162430#22162430) – MadProgrammer Apr 06 '16 at 09:18
  • 1) One way to get image(s) for an example (as sggested by @Tiz) is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). 2) Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). – Andrew Thompson Apr 06 '16 at 10:33

3 Answers3

2

It's a bad idea to place button over label. Better way is to paint image as panel background or to use JLayer. Here is an example for the first solution:

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.LayoutManager;
import java.util.Objects;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class JImagePanel extends JPanel {

    private final Image image;

    private boolean scale;

    public JImagePanel(Image anImage) {
        image = Objects.requireNonNull(anImage);
    }

    public JImagePanel(Image anImage, LayoutManager aLayout) {
        super(aLayout);
        image = Objects.requireNonNull(anImage);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        final Image toDraw = scale? image.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH) : image;
        g.drawImage(toDraw, 0, 0, this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        } else {
            return new Dimension(image.getWidth(this), image.getHeight(this));
        }
    }

    public boolean isScale() {
        return scale;
    }

    public void setScale(boolean scale) {
        this.scale = scale;
    }


    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    final JImagePanel p = 
                            new JImagePanel(ImageIO.read(JImagePanel.class.getResource("myImage.png")), new FlowLayout());
                    p.setScale(true);
                    p.add(new JButton("Button"));
                    final JFrame frm = new JFrame("Image test");
                    frm.add(p);
                    frm.pack();
                    frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                    frm.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

}
Sergiy Medvynskyy
  • 11,160
  • 1
  • 32
  • 48
  • *"It's a bad idea to place button over label"* - Why? It's wouldn't be my preferred method for at least one specific reason, but if you're going to make the claim, it would be useful for the OP to know why – MadProgrammer Apr 06 '16 at 09:21
  • 2
    `image.getWidth(null)` should be `image.getWidth(this)` and the same thing for `getHeight` and `g.drawImage(toDraw, 0, 0, null)` should be `g.drawImage(toDraw, 0, 0, this)` and [The Perils of Image.getScaledInstance()](https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html) for reasons why I wouldn't use `getScaledInstance` :P – MadProgrammer Apr 06 '16 at 09:22
  • 2
    You should also be loading your UI from within the context of the EDT to solve a bunch of the other potential issues, have a look at [Initial Threads](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) for more details – MadProgrammer Apr 06 '16 at 09:23
  • 1
    @MadProgrammer I've did it to quick ;). But you're right. I've corrected this example. – Sergiy Medvynskyy Apr 06 '16 at 09:29
1

A quick solution might be directly setting JFrame content pane to the image and adding your components to the content pane of this JFrame. Assuming your code is from the body of a JFrame class. My suggestion would more or less look like this:

        JRootPane rootpane = new JRootPane();
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
        rootpane.setContentPane(contentPane);
        contentPane.setLayout(null);

        JPanel homePanel = new JPanel();
        homePanel.setBounds(10, 11, 959, 620);
        homePanel.setLayout(null);

        JRootPane wizardPanel = new JRootPane();
        wizardPanel.setBounds(10, 295, 545, 336);
        wizardPanel.setLayout(null);

        JLabel backgroundLabel;
        try {
            File f = new File("D:\\work\\eclipse\\workspace_eclipse_4.4.1\\trialExamples\\src\\main\\images\\nature.jpg");
            backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(f)));
            backgroundLabel.setBounds(0, 0, 545, 336);
            wizardPanel.setContentPane(backgroundLabel);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        JButton btnNewButton = new JButton("New button");
        btnNewButton.setBounds(309, 95, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton);

        JButton btnNewButton_1 = new JButton("New button");
        btnNewButton_1.setBounds(309, 150, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton_1);

        JButton btnNewButton_2 = new JButton("New button");
        btnNewButton_2.setBounds(309, 212, 89, 23);
        wizardPanel.getContentPane().add(btnNewButton_2);

        homePanel.add(wizardPanel.getContentPane());

        add(homePanel);
can lekili
  • 255
  • 1
  • 8
  • But in addition to that i'm using two more panels on left side ! I just want the image to be displayed in the first panel. – Lingaraj Apr 06 '16 at 08:50
  • 1
    @Lingaraj I edited it to use a JRootPane from within a JPanel. Although this is correct and it works, it's not a nice way to do this. You should be using an extended JPanel where the paintComponent method is overriden. Also it is good practice to use [Layout managers](https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html) – can lekili Apr 06 '16 at 09:10
  • 2
    A better solution would be not to rely on `null` layouts :P – MadProgrammer Apr 06 '16 at 09:16
0

this is crazy !! I got it working by placing the JButtons initialization code block above the Image loading portion it works .....

     package demo;

     import java.awt.EventQueue;
     import java.io.File;
     import java.io.IOException;

     import javax.imageio.ImageIO;
     import javax.swing.ImageIcon;
     import javax.swing.JButton;
     import javax.swing.JFrame;
     import javax.swing.JLabel;
     import javax.swing.JPanel;
     import javax.swing.SwingUtilities;
     import javax.swing.UIManager;
     import javax.swing.border.EmptyBorder;

public class demoframe extends JFrame {

/**
 * 
 */
private static final long serialVersionUID = 1436190962490331120L;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                demoframe frame = new demoframe();

                UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                SwingUtilities.updateComponentTreeUI(frame);

                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public demoframe() {

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 988, 678);
    JPanel contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JPanel panel = new JPanel();
    panel.setBounds(10, 11, 501, 361);
    contentPane.add(panel);
    panel.setLayout(null);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.setBounds(322, 112, 89, 23);
    panel.add(btnNewButton);

    JButton button = new JButton("New button");
    button.setBounds(322, 172, 89, 23);
    panel.add(button);

    JButton button_1 = new JButton("New button");
    button_1.setBounds(322, 244, 89, 23);
    panel.add(button_1);

    JLabel backgroundLabel;
    try {
        backgroundLabel = new JLabel(new ImageIcon(ImageIO.read(new File("images/nature.jpg"))));
        backgroundLabel.setBounds(0, 0, 501, 361);
        panel.add(backgroundLabel);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }



    JPanel panel_1 = new JPanel();
    panel_1.setBounds(521, 11, 441, 361);
    contentPane.add(panel_1);

    JPanel panel_2 = new JPanel();
    panel_2.setBounds(10, 383, 952, 246);
    contentPane.add(panel_2);

}   
 }

Output looks like this now

Lingaraj
  • 99
  • 2
  • 13
  • It's a bad idea to place your components one over another. Better way is to paint your image as background. – Sergiy Medvynskyy Apr 06 '16 at 09:15
  • @SergiyMedvynskyy ... that doesn't really make sense, we always place component over the top each other, it's kind of how the whole thing works ... if you were to paint the image, you'd need a component to paint it with (preferably a `JPanel`) ... but's still the same sort of thing – MadProgrammer Apr 06 '16 at 09:20
  • @MadProgrammer you're right. I've meant that it's bad idea to place button over label. – Sergiy Medvynskyy Apr 06 '16 at 09:23