13 Replies - 26288 Views - Last Post: 28 May 2010 - 12:25 PM Rate Topic: -----

#1 Guest_Jaheen*


Reputation:

Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 04:12 PM

Hello, the last ~6 hours I'm trying to add some components (such as JButtons, Labels etc) on a JFrame which has a background image on it - unsuccessfully.
I've tried numerous ways and methods but nothing works. I can't get both to be displayed, that is.

I've managed to successfully create a JFrame and add a background image to it but I cannot add more components without
'overwriting' or 'hiding' that image no matter what I do.

What I want to do is create 3 java classes. One will be the main class and create the JFrame, the second will paint an image
background to the frame and the third will add some components on it, such as some JButtons, more image labels etc.
(It can also be more than 3 classes of course, I just don't want to put everything in one single class because it looks messy )

This is what I have done so far:

The main class:
import javax.swing.*;
import java.awt.*;


public class ApplicationFrame
{
    public static void main(String[] args)
    {


        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        }
        catch (UnsupportedLookAndFeelException e) {
            // handle exception
        }
        catch (ClassNotFoundException e) {
            // handle exception
        }
        catch (InstantiationException e) {
            // handle exception
        }
        catch (IllegalAccessException e) {
            // handle exception
        }
        

       JFrame frame = new JFrame("Application");

       BackgroundImg panel = new BackgroundImg(Toolkit.getDefaultToolkit().getImage(ApplicationFrame.class.getResource("background.png")));
       frame.getContentPane().add(panel);
      

       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setVisible(true);
       frame.setResizable(false);

       Toolkit kit = frame.getToolkit();
       GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
       GraphicsDevice[] gs = ge.getScreenDevices();
       Insets in = kit.getScreenInsets(gs[0].getDefaultConfiguration());

       Dimension d = kit.getScreenSize();
       int max_width = (d.width - in.left - in.right);
       int max_height = (d.height - in.top - in.bottom);
       frame.setSize(Math.min(max_width, 800), Math.min(max_height, 600));
       frame.setLocation((int) (max_width - frame.getWidth()) / 2, (int) (max_height - frame.getHeight() ) / 2);


    }

}



The "Background Image" class:
import javax.swing.*;
import java.awt.*;


public class BackgroundImg extends JPanel
{
    private Image img;


  public BackgroundImg (String img)
  {
      this(new ImageIcon(img).getImage());
  }


  public BackgroundImg (Image img)
  {
    this.img = img;
    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
    setPreferredSize(size);
    setMinimumSize(size);
    setMaximumSize(size);
    setSize(size);
    setLayout(null);
  }


    @Override
  public void paintComponent(Graphics g) {
    g.drawImage(img, 0, 0, null);
  }
}



And my components class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class ApplicationContents
{
    public static void addContentsToPane(Container pane)
    {
        pane.setLayout(null);

        JButton b1 = new JButton("Test");

        pane.add(b1);

        Insets insets = pane.getInsets();
        Dimension size = new Dimension(120,32);

         b1.setBounds(0 + insets.left, 0 + insets.top,
                     size.width, size.height);


         b1.addActionListener(
                 new ActionListener()
         {
             public void actionPerformed(ActionEvent event)
            {

                 JOptionPane.showMessageDialog(null, "Test" , "Test", JOptionPane.ERROR_MESSAGE);
            }
         }
         );
    }
}




I'd like to add something like this in the main class:
ApplicationContents.addContentsToPane(frame.getContentPane());


Any tips are welcome, I'm in a dead-end here...

Note: I know that I can also add the background image in a panel or label and then put it in the
background using absolute positioning but I'd like to refrain from doing that.
Also I'd like to add the components on a container and call that instead of adding them in a class
and calling the constructor.

Is This A Good Question/Topic? 0

Replies To: Adding a background Image to JFrame and then adding some components on

#2 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8329
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 04:24 PM

Sorry to disappoint you but this will never work.. despite the number of hours you will spent on it

If you want to have a background image, you will have to do all the drawing by yourself
You cannot ask the Java GUI to "draw this image and then draw this over it" the GUI was not desingned that way

So if you want to do all of it by hand you cannot

JButton b1 = new JButton("Test");

by doing this you say to Swing: draw b1 where I told you do do so... and Swing does not give a shit about your background. If you want to keep your background image you have 2 choices:
- rewrite and overload the methods that draw a JButton
- use a JLayeredPane that allows you to stack JComponent one ove the other
Was This Post Helpful? 3
  • +
  • -

#3 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 04:40 PM

View Postpbl, on 27 May 2010 - 03:24 PM, said:

Sorry to disappoint you but this will never work.. despite the number of hours you will spent on it

If you want to have a background image, you will have to do all the drawing by yourself
You cannot ask the Java GUI to "draw this image and then draw this over it" the GUI was not desingned that way

So if you want to do all of it by hand you cannot

JButton b1 = new JButton("Test");

by doing this you say to Swing: draw b1 where I told you do do so... and Swing does not give a shit about your background. If you want to keep your background image you have 2 choices:
- rewrite and overload the methods that draw a JButton
- use a JLayeredPane that allows you to stack JComponent one ove the other



Oh god, I wish I knew that 6 hours ago... I really do.

Well, is using JLayeredPane going to allow me to retain my BackgroundImg and contents container as they are?
I mean all I want to do is set a background image using:
BackgroundImg panel = new BackgroundImg(Toolkit.getDefaultToolkit().getImage(ApplicationFrame.class.getResource("background.png")));
frame.getContentPane().add(panel);



And then put a container on top of that which will contain some buttons, labels etc while the background image is still there.
i.e
ApplicationContents.addContentsToPane(frame.getContentPane());


Could you give me an example on how to do that with JLayeredPane?
Was This Post Helpful? 0
  • +
  • -

#4 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8329
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 04:49 PM

Here is the link to JLayeredPane

http://java.sun.com/...ayeredPane.html

just be careful, the LayerNumber should be an Integer object not just a simple int (since JRE 1.5 that might not make a difference thow)

The principle is simple, you put your JComponent giving them a layer number
they will be drawed one after the other from the lowest level to the highest
Was This Post Helpful? 0
  • +
  • -

#5 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 05:53 PM

Sigh, I can't get JLayeredPane to work no matter what.
How am I supposed to add 2 different components on it and then add it in the frame?
I've being trying to add my BackgroundImg first but it doesn't show even that.

This is what I have done so far to test it...
import javax.swing.*;
import java.awt.*;

public class ApplicationFrame extends JFrame
{
    public ApplicationFrame()
    {

        super("LayeredPane Demonstration");
        setSize(800, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    

        BackgroundImg panel = new BackgroundImg(Toolkit.getDefaultToolkit().getImage(ApplicationFrame.class.getResource("background.png")));
        //getContentPane().add(panel);

        JLayeredPane lp = getLayeredPane();
        lp.add(panel, new Integer(1));
        
        //lp.add((getContentPane().add(panel)), new Integer(1));
        //lp.add(add(panel), new Integer(1));
        
    }


    public static void main(String[] args)
    {
        ApplicationFrame sl = new ApplicationFrame();
        sl.setVisible(true);
    }
}


Was This Post Helpful? 0
  • +
  • -

#6 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8329
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 07:02 PM

You have to add the LayeredPane to your JFrame

add(lp, BorderLayout.CENTER);
Was This Post Helpful? 0
  • +
  • -

#7 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 27 May 2010 - 08:18 PM

View Postpbl, on 27 May 2010 - 06:02 PM, said:

You have to add the LayeredPane to your JFrame

add(lp, BorderLayout.CENTER);


Just did that, still it doesn't work.

This is what I got...
import javax.swing.*;
import java.awt.*;

public class ApplicationFrame
{
    
    public static void main(String[] args)
    {

        BackgroundImg panel = new BackgroundImg(Toolkit.getDefaultToolkit().getImage(ApplicationFrame.class.getResource("background.png")));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(800, 600);
        frame.setLayout(new BorderLayout());

        JLayeredPane lp = new JLayeredPane();
        //JLayeredPane lp = frame.getLayeredPane();

        lp.add(panel, new Integer(1));
        //frame.getContentPane().add(panel);

        frame.add(lp, BorderLayout.CENTER);
        
    }
}


I kind of suspect that the problem might be in
lp.add(panel, new Integer(1));


Is that correct? The rest of the code looks fine...
Was This Post Helpful? 0
  • +
  • -

#8 g00se  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2689
  • View blog
  • Posts: 11,351
  • Joined: 20-September 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 12:51 AM

Your main problem is calling setVisible on the frame before it's properly laid out, otherwise the basics are OK for it to work (see it in action with a particularly hideous background image below). For it to work properly, you need to make some changes: if you want components to appear properly over background images, you must be sure to call super.paintComponent. Also, don't be tempted to set null layouts - it will cause more problems than it solves.

See the adjustments i made in the code in the image of my editor below.

Attached image(s)

  • Attached Image
  • Attached Image

This post has been edited by g00se: 28 May 2010 - 12:54 AM

Was This Post Helpful? 1
  • +
  • -

#9 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 04:30 AM

Thanks for testing my code, g00se. I called super.paintComponent and removed null layouts, still can't get it to work.
The frame shows but it's empty. I got a couple of questions though. Did you use JLayeredPane? Judging from your images,
probably not, I tried both ways but it doesn't work. Also I'd like to be able to position my frame's components myself
anywhere in the frame I want, is there any way to do that without a null layout? The outcome never appears the way I want
it to when I use layout managers...

This is my current code...
import javax.swing.*;
import java.awt.*;

public class ApplicationFrame
{

    public static void main(String[] args)
    {


        BackgroundImg panel = new BackgroundImg(Toolkit.getDefaultToolkit().getImage(ApplicationFrame.class.getResource("background.png")));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);

        ApplicationContents.addContentsToPane(panel);
        frame.setVisible(true);
       
    }
}



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


public class BackgroundImg extends JPanel
{
    private Image img;


  public BackgroundImg (String img)
  {
      this(new ImageIcon(img).getImage());
  }


  public BackgroundImg (Image img)
  {
    this.img = img;
    Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
    setPreferredSize(size);
    setMinimumSize(size);
    setMaximumSize(size);
    setSize(size);
    //setLayout(null);
  }


    @Override
  public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
    g.drawImage(img, 0, 0, null);
  }
}



import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class ApplicationContents
{
    public static void addContentsToPane(Container pane)
    {
        //pane.setLayout(null);
        pane.setLayout(new FlowLayout());

        JButton b1 = new JButton("Test");

        pane.add(b1);

        //Insets insets = pane.getInsets();
        //Dimension size = new Dimension(120,32);

        // b1.setBounds(0 + insets.left, 0 + insets.top,
         //            size.width, size.height);


         b1.addActionListener(
                 new ActionListener()
         {
             public void actionPerformed(ActionEvent event)
            {

                 JOptionPane.showMessageDialog(null, "Test" , "Test", JOptionPane.ERROR_MESSAGE);
            }
         }
         );
    }
}


Was This Post Helpful? 0
  • +
  • -

#10 g00se  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2689
  • View blog
  • Posts: 11,351
  • Joined: 20-September 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 04:54 AM

Quote

Did you use JLayeredPane?


No

You didn't add the panel to your frame. Change that to

	frame.getContentPane().add(panel);
        frame.setVisible(true);



You need to learn layout managers - you almost never want or need to use a null layout

This post has been edited by g00se: 28 May 2010 - 04:57 AM

Was This Post Helpful? 1
  • +
  • -

#11 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 05:32 AM

Everything works great now, thanks a lot g00se :bigsmile:

Regarding null layout, I just love the way you can put everything wherever you want.
I've been using layout managers for quite some time and while I could create a gui much quicker
than using a null layout, I was rarely 100% satisfied with the result.
Was This Post Helpful? 0
  • +
  • -

#12 g00se  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 2689
  • View blog
  • Posts: 11,351
  • Joined: 20-September 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 06:27 AM

Regarding the null layout: in your particular case, you have an unresizable frame, so that sorts out the problems of repositioning on resize. However, you don't know the size of the display on which your app runs, which you cater for in your code. Since you don't know, how are you going to use absolute pixel locations anyway?
Was This Post Helpful? 0
  • +
  • -

#13 Jaheen  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 12
  • Joined: 27-May 10

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 08:29 AM

View Postg00se, on 28 May 2010 - 05:27 AM, said:

You don't know the size of the display on which your app runs, which you cater for in your code. Since you don't know, how are you going to use absolute pixel locations anyway?


Your arguments are valid, I know that a frame with a null layout can be messed up upon resizing and if the size
of the display on which the app is going to run is smaller than the app's size it will be almost unviewable.

However, I believe that I got those conevered. I'm going to render the frame unresizable and set its size to ~800x600.
I know that this won't solve the screen size issue but I doubt anyone got a computer with lower resolution than 800x600 nowadays :rolleyes2:

Also I realize that in a professional application every single aspect should be covered instead of forcing your client to view an
unresizable application at a certain resolution. Oh well, I guess for the current app that won't be an issue.


EDIT: Got one last question:
Is it possible to implement an ActionListener to ApplicationContents?
I'm currently handling the button clicks via an inner class, however I'd like to do that
via an actionPerformed method or by using an external class which will handle solely the action events.

b1.addActionListener(this);

doesn't work...
non-static variable this cannot be referenced from a static context
         b1.addActionListener(this);


EDIT2: Solved it :bigsmile:

This post has been edited by Jaheen: 28 May 2010 - 12:26 PM

Was This Post Helpful? 0
  • +
  • -

#14 giuseppe105  Icon User is offline

  • D.I.C Regular

Reputation: 9
  • View blog
  • Posts: 444
  • Joined: 15-May 08

Re: Adding a background Image to JFrame and then adding some components on

Posted 28 May 2010 - 12:25 PM

put your code in the constructor not in the main static method.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1