Layering JPanels with background image - java

I wanted to have a background image and two panels atop them. Learnt that JLayeredpane's are quite suitable. So I extended a JLayeredPane in my class and tried to draw the image from paint(). I got it working. But when I added other layers over it they weren't visible.
Again I thought of removing the bgimage from LayeredPane, added to the first layer above it(in JPanel). Now the image is not visible. Why does it happen? I wanted to do some thing like the screenshot I've provided. Pls help.
My code:
From my JFrame:
Container cp = this.getContentPane();
JLayeredPane backDropPanel = new JLayeredPane();
cp.add(backDropPanel,BorderLayout.CENTER);
backDropPanel.add(new bgPanel(), new Integer(1),0);
backDropPanel.add(new itemScrollerPanel(), new Integer(1),0);
Panel's:
class bgPanel extends JPanel{
String imageLocation = "/home/phantom/Desktop/BackDrop3.jpg";
private Image bgImage;
bgPanel(){
bgImage = new ImageIcon(imageLocation).getImage();
setPreferredSize(new Dimension(800,500));
setLayout(null);
setOpaque(true);
}
public void paint(Graphics g){
super.paint(g);
g.drawImage(bgImage,0,0,this);
}}
class itemScrollerPanel extends JPanel{
itemScrollerPanel(){
setBounds(0,100,200,200);
setBackground(Color.RED);
setOpaque(true);
}}
In this code I get to see the itemsScrollerPanels's RED BG drawn. But not the image of bgPanel class.
My requirement is something like this:

Without setting your bgPanel size explicitly, I get
System.err.println(bgPanel.getSize());
//java.awt.Dimension[width=0,height=0]
If you change your code from
setPreferredSize(new Dimension(800, 500));
to
setPreferredSize(new Dimension(800, 500));
setSize(800,500);
You should see the panel painted.

Try to change the setOpaque() to false so that all the pixels of JPanel are not painted .Thus making it transparent.If you still cant do it,check whether the Jpanel is actually opaque or not using isOpaque()

Related

How to successfully draw background JPanel once and update foreground JPanel constantly?

I have a custom JLayeredPane, and I am repainting it in my game loop. There are two custom JPanels added into the JLayeredPane. These are foreground and background JPanels. How do I successfully only draw my background JPanel once, (And repaint when window is re-sized or any other reason) to reduce impact on system resources, while continuing to update my foreground JPanel constantly.
To re-iterate, I dont want to constantly repaint the background JPanel in a loop. I want to repaint it only when it is nessessary, as the background does not change. and is large.
In my attempt to do this, I have only drawn the background once. However. the background JPanel is simply not visible. while the foreground JPanel updates as normal. It is almost as if the foreground JPanel paints ontop of the background JPanel, even though I have both of the JPanels set to setOpaque(false)
I have made a mvce which shows my attempt at only drawing the background JPanel once, while updating the foreground JPanel constantly.
The problem with my code is that the background JPanel does not show.
Now. I know that if I were to draw it constantly it would show. But that defeats the purpose of what i'm trying to do. I am trying to only draw it once, and have be seen at the same time
My code successfully only draws the background JPanel once. The problem is that the background JPanel does not show. How do I fix THIS problem
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JLayeredPane {
static JFrame frame;
static Main main;
static Dimension screenSize;
public Main() {
JPanel backPanel = new BackPanel();
JPanel frontPanel = new FrontPanel();
add(backPanel, new Integer(7));
add(frontPanel, new Integer(8));
new Thread(() -> {
while (true){
repaint();
}
}).start();
}
public static void main(String[] args) {
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame = new JFrame("Game"); // Just use the constructor
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main = new Main();
frame.add(main, BorderLayout.CENTER);
frame.pack();
frame.setSize(screenSize);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class BackPanel extends JPanel{
public boolean drawn = false;
public BackPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test1 = new JLabel("Test1");
JLabel test2 = new JLabel("Test2");
add(test1);
add(test2);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawOnce(g);
}
public void drawOnce(Graphics g){
if (!drawn){
g.setColor(Color.red);
g.fillRect(0, 0, screenSize.width, 200);
drawn=true;
}
}
}
public class FrontPanel extends JPanel{
public FrontPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test = new JLabel("Test");
add(test);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(0+screenSize.width/2, 0, screenSize.width/4, 300);
}
}
}
Try RepaintManager.currentManager(component).markCompletelyClean(component). It will prevent the component from repainting. You might need to do this after each time you add new components.
http://docs.oracle.com/javase/6/docs/api/javax/swing/RepaintManager.html#markCompletelyClean%28javax.swing.JComponent%29
I don't know if this two lines of code
super.paintComponent(g);
drawOnce(g);
are the root of problem, I sincerly don't remember how paintComponent works (a test could help) but try to swap them :
drawOnce(g);
super.paintComponent(g);
maybe, on your original version, you tells JVM to paint the whole component and, only after the AWTEvent has been added to the queue, to draw what you need.
I guess that the awt's documentation will explain it.

Get the real size of a JFrame content (NEW)

I am writing a Game in Java, and I don't want to use a layout manager for my JFrame. My class extends JFrame, and looks something like this:
//class field
static JPanel contentPane;
//in the class constructor
this.contentPane = new JPanel();
this.contentPane.setLayout(null);
this.setContentPane(contentPane);
I want my JPanel be exactly 600x600 px, but when I set the size of my JFrame by calling the this.setSize(600,600) method, the JPanel size is less than the 600x600 px because the border of the JFrame window is included too.
How can I set the size of the JPanel to be exactly 600x600 px?
P.S. I have seen all of the previous post and none of them work for me.
For example:
Get the real size of a JFrame content does not work for me.
What else can I do?
How can I set the size of the JPanel to be exactly 600x600 px?
Override the getPreferredSize() method of your custom game panel to return the size you want the panel to be.
#Override Dimension getPreferredSize()
{
return new Dimension(600, 600);
}
Then the basic code to create your frame will be:
GamePanel panel = new GamePanel();
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
Now all your game logic will be contained in the GamePanel class.
If you don't need the Frame-Decorations (icon, title, min/max/close-buttons and the border), you can make a Frame undecorated, then it has exactly the size you gave it
java.awt.Frame.setUndecorated(boolean)

JButton added to JPanel doesn't show

I can't seem to add a JButton to a JPanel.
I have a PropWindow (JFrame) that has a PropView (JPanel) in it. the PropView-JPanel seems to be added correctly because I can draw shapes on it with paint().
But when I use this to try adding a button it just won't show up att all :/
JButton testButton;
public PropView(int width, int height) {
super(true);
setLayout(null);
setSize(width, height);
//TestButton
testButton = new JButton("Test");
testButton.setLocation(10,10);
testButton.setSize(100, 50);
testButton.setVisible(true);
add(testButton);
setFocusable(true);
setVisible(true);
}
The JFrame and the JPanel are both 250x600 px.
I can't tell from the code snippet you posted but just in case: make sure you call pack () on the frame after you have added the panel or any other components.
Also, it's usually discouraged to extend a JPanel or JFrame, unless you have a good reason to do it, just a heads up.
Here you have a short tutorial about displaying frames:
And some sample code in it that might help:
//1. Create the frame.
JFrame frame = new JFrame("FrameDemo");
//2. Optional: What happens when the frame closes?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//3. Create components and put them in the frame.
//...create emptyLabel...
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//4. Size the frame.
frame.pack();
//5. Show it.
frame.setVisible(true);
Make sure you added PropPanel to PropWindow using myPropWindow.getContentPane().add(myPropPanel), not just myPropWindow.add(myPropPanel).

Images and Panels

I'm having a problem adding a JPanel on top of an Image. This is what I'm trying to do:
Image bgImage = loadImage(filename);
JPanel jp = new JPanel();
jp.setBounds(100,100,100,100);
jp.setOpaque(true);
jp.setBackgroudColor(Color.red);
bgImage.add(jp);
After doing this, I only see the bgImage. I tried everything but I still can't show the panel. Can somebody help me?
You cannot place a component inside an Image. What you want to do is paint the Image onto the background of a swing component (like JPanel). All swing components have a paint() method that calls these three methods (perhaps not quite this order): paintComponent(), paintChildren(), paintBorder(). So, you want to override the paintComponent() method to paint your background image over the panel. When this runs, your custom method will be called, and then the paintChildren() method will be called, which will paint all "child" components over the top of your background image:
class BackgroundImagePanel extends JPanel {
public void setBackgroundImage(Image backgroundImage) {
this.backgroundImage = backgroundImage;
}
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.drawImage(backgroundImage, 0, 0, this);
}
private Image backgroundImage;
}
BackgroundImagePanel panel = new BackgroundImagePanel();
panel.setBackgroundImage(image);
panel.add(new JTextField("Enter text here..."));
panel.add(new JButton("Press Me"));
The "BackgroundImagePanel" solution paints the image at its actual size. If this is a requirement, then you can just use a JLabel instead of creating a custom component.
The BackgroundPanel entry shows how you can do this. It also provides a background panel with more custom image painting solutions, that will allow you to scale and tile the image, if this is part of your requirement.

How to set an image as a background for Frame in Swing GUI of java?

I have created one GUI using Swing of Java. I have to now set one sample.jpeg image as a background to the frame on which I have put my components.How to do that ?
There is no concept of a "background image" in a JPanel, so one would have to write their own way to implement such a feature.
One way to achieve this would be to override the paintComponent method to draw a background image on each time the JPanel is refreshed.
For example, one would subclass a JPanel, and add a field to hold the background image, and override the paintComponent method:
public class JPanelWithBackground extends JPanel {
private Image backgroundImage;
// Some code to initialize the background image.
// Here, we use the constructor to load the image. This
// can vary depending on the use case of the panel.
public JPanelWithBackground(String fileName) throws IOException {
backgroundImage = ImageIO.read(new File(fileName));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the background image.
g.drawImage(backgroundImage, 0, 0, this);
}
}
(Above code has not been tested.)
The following code could be used to add the JPanelWithBackground into a JFrame:
JFrame f = new JFrame();
f.getContentPane().add(new JPanelWithBackground("sample.jpeg"));
In this example, the ImageIO.read(File) method was used to read in the external JPEG file.
This is easily done by replacing the frame's content pane with a JPanel which draws your image:
try {
final Image backgroundImage = javax.imageio.ImageIO.read(new File(...));
setContentPane(new JPanel(new BorderLayout()) {
#Override public void paintComponent(Graphics g) {
g.drawImage(backgroundImage, 0, 0, null);
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
This example also sets the panel's layout to BorderLayout to match the default content pane layout.
(If you have any trouble seeing the image, you might need to call setOpaque(false) on some other components so that you can see through to the background.)
The Background Panel entry shows a couple of different ways depending on your requirements.
You can either make a subclass of the component
http://www.jguru.com/faq/view.jsp?EID=9691
Or fiddle with wrappers
http://www.java-tips.org/java-se-tips/javax.swing/wrap-a-swing-jcomponent-in-a-background-image.html
Perhaps the easiest way would be to add an image, scale it, and set it to the JFrame/JPanel (in my case JPanel) but remember to "add" it to the container only after you've added the other children components.
ImageIcon background=new ImageIcon("D:\\FeedbackSystem\\src\\images\\background.jpg");
Image img=background.getImage();
Image temp=img.getScaledInstance(500,600,Image.SCALE_SMOOTH);
background=new ImageIcon(temp);
JLabel back=new JLabel(background);
back.setLayout(null);
back.setBounds(0,0,500,600);
Here is another quick approach without using additional panel.
JFrame f = new JFrame("stackoverflow") {
private Image backgroundImage = ImageIO.read(new File("background.jpg"));
public void paint( Graphics g ) {
super.paint(g);
g.drawImage(backgroundImage, 0, 0, null);
}
};
if you are using netbeans you can add a jlabel to the frame and through properties change its icon to your image and remove the text. then move the jlabel to the bottom of the Jframe or any content pane through navigator
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class BackgroundImageJFrame extends JFrame
{
JButton b1;
JLabel l1;
public BackgroundImageJFrame()
{
setTitle("Background Color for JFrame");
setSize(400,400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
/*
One way
-----------------*/
setLayout(new BorderLayout());
JLabel background=new JLabel(new ImageIcon("C:\\Users\\Computer\\Downloads\\colorful design.png"));
add(background);
background.setLayout(new FlowLayout());
l1=new JLabel("Here is a button");
b1=new JButton("I am a button");
background.add(l1);
background.add(b1);
// Another way
setLayout(new BorderLayout());
setContentPane(new JLabel(new ImageIcon("C:\\Users\\Computer\\Downloads \\colorful design.png")));
setLayout(new FlowLayout());
l1=new JLabel("Here is a button");
b1=new JButton("I am a button");
add(l1);
add(b1);
// Just for refresh :) Not optional!
setSize(399,399);
setSize(400,400);
}
public static void main(String args[])
{
new BackgroundImageJFrame();
}
}

Categories

Resources