I'm new here
I need help in placing components on a background image in Jframe using BorderLayout.
I tried adding the components to the label then the label to the frame but it hasn't worked so far
Here's my code:
package com.hosp;
import javax.swing.*;
import java.awt.*;
public class BackgroundImage extends JFrame {
BackgroundImage() {
//get image from package
ImageIcon img=new ImageIcon(getClass().getResource("backgroundimage.jpg"));
//add image to Label
JLabel imageLabel =new JLabel(img,JLabel.CENTER);
//button on screen
JButton btn =new JButton("Save");
//
add(imageLabel);
imageLabel.add(btn,BorderLayout.SOUTH);
}
public static void main(String []args) {
BackgroundImage frame = new BackgroundImage ();
frame.setVisible(true);
frame.setSize(300,300);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
public class backgroundImage extends JFrame{
Class names should start with an upper case character
add(imageLabel);
imageLabel.add(btn,BorderLayout.SOUTH);
validate();
Unlike a JPanel, a JLabel isn't designed to be a "container" to hold other components so it doesn't have a default layout manager so you can't just add the component to it using a BorderLayout constraint.
There is not need for the validate() method. You would only use revalidate() and repaint() when you add a component to a panel AFTER the frame is visible.
So your code should look something like:
add(imageLabel);
imageLabel.setLayout( new BorderLayout() );
imageLabel.add(btn,BorderLayout.SOUTH);
//validate();
Note this will only work if the components you add to the label are smaller than the size of the image, otherwise the component will be truncated to fit in the area of the label.
Check out Background Panel for a more flexible solution.
Related
So, i created an object of class "CustomPanel" that creates a JPanel with a GridLayout and a label inside of it then I added it to my JFrame. It works fine showing the label "HELLO", but when I change the layout manager of the jpanel to (null) it doesn't show anything. I know, I know using null layout is a very bad practice but I just want to know why it isn't showing the components.
Main class:
import javax.swing.JFrame;
public class MainMenu extends javax.swing.JFrame{
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Size the window.
frame.setSize(500, 500);
CustomPanel panel = new CustomPanel();
frame.getContentPane().add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
CustomPanel class with GridLayout (This works fine):
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CustomPanel extends JPanel{
public CustomPanel() {
initUI();
}
public final void initUI() {
// create the panel and set the layout
JPanel main = new JPanel();
main.setLayout(new GridLayout());
// create the labels
JLabel myLabel = new JLabel("HELLO");
// add componets to panel
main.add(myLabel);
this.add(main);
}
}
CustomPanel class with Null layout (This doesn't work):
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CustomPanel extends JPanel{
public CustomPanel() {
initUI();
}
public final void initUI() {
// create the panel and set the layout
JPanel main = new JPanel();
main.setLayout(null);
// create the labels
JLabel myLabel = new JLabel("HELLO");
myLabel.setBounds(10, 10, myLabel.getPreferredSize().width, myLabel.getPreferredSize().height);
// add componets to panel
main.add(myLabel);
this.add(main);
}
}
The jlabel is correctly set inside the jpanel so it should be showing in the upper-left side of the jframe, but it doesn't.
What is causing this? what am I missing?.
The problem is that when you don't use a proper layout manager the main JPanel has a preferred size of 0,0, and won't display within the container that it is placed within. The CustomPanel that holds the main JPanel uses FlowLayout and will use its contained component's preferred sizes to help size and position these components, but since main has no layout, adding the JLabel to main does not increase the preferred size as it should -- yet another reason to use layouts, and CustomPanel will display main as just a sizeless dot. You could of course get around this by giving main a preferred size via main.setPreferredSize(...), but then you'd be solving a kludge with a kludge -- not good. Another possible solution is to change CustomPanel's layout to something else that might expand the main JPanel that it holds, perhaps giving CustomPanel a BorderLayout. In this situation, adding main to CustomPanel in a default fashion will place the main JPanel into the BorderLayout.CENTER position, expanding it to fill CustomPanel, and the JLabel will likely be seen.
The proper solution, of course, is to avoid use of null layouts whenever possible.
The question is that I cannot add JPanel and JLabel in the Frame at the same time.
When i using following code, only MyPanel will be visible. myFrame.add(myLabel);myFrame.add(myPanel);myFrame.setVisible(true);
when I execute: myFrame.add(myLabel);myFrame.setVisible(true);myFrame.add(myPanel);
only myLabel will be visible.
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
MyFrame myFrame = new MyFrame();
MyLabel myLabel = new MyLabel();
MyPanel myPanel = new MyPanel();
myFrame.add(myLabel);
myFrame.add(myPanel);
myFrame.setVisible(true);
}
}
public class MyFrame extends JFrame {
MyFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //exit out of application.
//https://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html#setDefaultCloseOperation%28int%29
this.setSize(750, 750); //set the size.
this.setResizable(true);//resize the frame.
this.setTitle("Welocme to new world."); //set the Title.
ImageIcon imageIcon = new ImageIcon("logo.png");
this.setIconImage(imageIcon.getImage());
this.getContentPane().setBackground(new Color(217, 217, 217));
this.setBackground(Color.YELLOW);//this.setVisible(true);//Make the frame visible.
}}
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel {
MyPanel() {
this.setBackground(Color.white);
this.setBounds(2,2,25,25);
}}
import javax.swing.*;
import java.awt.*;
public class MyLabel extends JLabel {
MyLabel(){
this.setText("<html>Heaven <br/>Heaven's body\"<br/> Whirl around me <br/>Make me wonder</html>");
//,SwingConstants.CENTER);
//https://stackoverflow.com/questions/1090098/newline-in-jlabel
//How to print multi line in java
ImageIcon image = new ImageIcon("Cosmogony_Björk_Cover.jpg");
this.setIcon(image);
//jLabel.setForeground(new Color(217,217,217));
this.setForeground(Color.BLACK);
this.setFont(new Font("helvetica",Font.PLAIN,18));
this.setBackground(Color.gray);
this.setOpaque(true);
//jLabel.setVerticalTextPosition(JLabel.TOP); Set the relative text position of the label.
//jLabel.setBorder();
this.setVerticalAlignment(JLabel.CENTER);
this.setHorizontalAlignment(JLabel.CENTER);
}}
The default Layout Manager of JFrame is the BorderLayout.
Since you did not change the layout manager of your JFrame this is also the current layout manager used in your snippet.
Usually, when using the BorderLayout, you specify which area of the BorderLayout should be populated when adding a component. This is usually done via
frame.add(component, BorderLayout.CENTER);
Notice the area specification in the add() method, which tells the BorderLayout where to place the component.
Here is the issue however. If you use the add() method in combination with the BorderLayout without specifying the placement of the component, it will always place the component in BorderLayout.CENTER. (Causing the component which is currently there to be replaced)
To work around this, do one of the following things:
Specify the placement explicitly, so both components will show up:
frame.add(component1, BorderLayout.PAGE_START);
frame.add(component2, BorderLayout.CENTER);
Or use a different Layout Manager, which will take care of the placement for you. E.g. FlowLayout
JPanel contentPanel = new JPanel(); // JPanel uses flowlayout by default!
contentPanel.add(component1);
contentPanel.add(component2);
myFrame.setContentPane(contentPanel);
You could also explicitly set the layout:
Container contentPane = myFrame.getContentPane();
// creates new FlowLayout and sets on content pane
contentPane.setLayout(new FlowLayout());
contentPane.add(component1);
contentPane.add(component2);
Sidenotes:
Look through the Laying out components within a container Oracle tutorial, which will give you more information on which layout managers there are and how to work with them.
When building your GUI, setVisible() on the JFrame should be the last thing you are doing after adding all components. Because if you add components after setting the frame visible, the changes will not immediately take effect without you telling swing that something changed.
When correctly working with the Swing Layout Managers, there should be no need to use things like setBounds(...) or setSize(). After adding all components, calling pack() on the JFrame is the preferred way to go. This will size the JFrame according to the preferred size of the components inside.
private void setupGUI(){
// Setup Frame
f = new JFrame("Shape Image Generator");
f.setBounds(500, 150, 450, 350);
f.setLayout(new GridLayout(8,1));
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
}
I create the frame above, then 8 panels. I create various components and add them to the panels and everything works fine. Until I created an ImageIcon and added it to a label and added that label to the 8th panel. The image used is 140x129 pixels. The problem is, only the top.... maybe 1/4 of the image is showing. If I change the frames dimensions in the code, more empty space is created between each panel, but only a slight bit more of the image is shown, so the image is still off of the screen. I'd say the window is easily adding 10 pixels of spacing for every 1 more pixel of the image it shows. If I drag the corners of the window to expand it, the same thing happens. If the window is maximized I still can only see a little over half of my now very stretched image.
Things I tried:
None of my components have preferred dimensions set, but I tried setting a preferred dimension for the label then panel that contains the ImageIcon and it only added the difference between the image and preferred size in gray space above the image, pushing it further offscreen. So, I undid that.
Adding the label containing the ImageIcon to a different panel which was not the 8th and last panel, in this case, the image is still cut off, but at the point that it gets cut off, the components on the panel underneath it appear (over top of the background coloring which cuts off the image).
Exhaustively Googling this situation with about 30 different ways of phrasing it and not finding a solution.
(row1 - row8 are JPanels, I didn't include the coding for them)
ImageIcon iconStart = createImageIcon("/images/ShapeClipart.png", "Shapes");
JLabel imgLabel = new JLabel();
row8.add(imgLabel);
// Add image to image label
imgLabel.setIcon(iconStart);
// Add panels to frame
f.add(row1);
f.add(row2);
f.add(row3);
f.add(row4);
f.add(row5);
f.add(row6);
f.add(row7);
f.add(row8);
f.setVisible(true);
Window at execution
Window when stretched
edit:
adding f.pack() makes a very tall skinny window (the windows height taller than my screen) but it still looks like when I manually expand the window (empty space between panels, image partially offscreen), even if I take out f.setBounds and only use f.setLocation.
You are using a GridLayout. This gives all of the enclosed panels the same amount of space. In this case it is a vertical grid.
You should probably use something a bit different. I might try a BorderLayout in the JFrame and put the a panel containing the top seven panels (in a GridLayout) into the CENTER, and then put the JLabel into the SOUTH portion of the JFrame.
There are other ways to lay it out, but this is the first I could think of.
GridLayout makes each cell in the grid the same size and the size of each cell is determined by the largest Component contained in the grid.
In your code, the icon is the largest component and you also have only one column in your grid so every row has the same height as your icon.
Since you also limit the size of your JFrame by calling method setBounds(), the Swing infrastructure cuts off the icon so that all the components fit into the bounds you specified.
One alternative, but not the only one, is to use BoxLayout since it uses the preferred size of each of its contained components.
Here is a sample GUI that matches the screen capture that you posted and uses BoxLayout.
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.net.URL;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class Shapes23 implements Runnable {
private JFrame frame;
#Override // java.lang.Runnable
public void run() {
showGui();
}
private JPanel createEighthRow() {
JPanel eighthRow = new JPanel();
URL url = getClass().getResource("paint-bursht.jpg");
Icon ico = new ImageIcon(url);
JLabel label = new JLabel(ico);
eighthRow.add(label);
return eighthRow;
}
private JPanel createFifthRow() {
JPanel fifthRow = new JPanel();
JTextField textField = new JTextField(20);
fifthRow.add(textField);
return fifthRow;
}
private JPanel createFirstRow() {
JPanel firstRow = new JPanel();
JLabel label = new JLabel("2D Shapes");
firstRow.add(label);
return firstRow;
}
private JPanel createFourthRow() {
JPanel fourthRow = new JPanel();
fourthRow.add(createRadioButton("Sphere"));
fourthRow.add(createRadioButton("Cube"));
fourthRow.add(createRadioButton("Cone"));
fourthRow.add(createRadioButton("Cylinder"));
fourthRow.add(createRadioButton("Torus"));
return fourthRow;
}
private JPanel createMainPanel() {
JPanel mainPanel = new JPanel();
BoxLayout layout = new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS);
mainPanel.setLayout(layout);
mainPanel.add(createFirstRow());
mainPanel.add(createSecondRow());
mainPanel.add(createThirdRow());
mainPanel.add(createFourthRow());
mainPanel.add(createFifthRow());
mainPanel.add(createSixthRow());
mainPanel.add(createSeventhRow());
mainPanel.add(createEighthRow());
return mainPanel;
}
private JRadioButton createRadioButton(String text) {
JRadioButton radioButton = new JRadioButton(text);
return radioButton;
}
private JPanel createSecondRow() {
JPanel secondRow = new JPanel();
secondRow.add(createRadioButton("Circle"));
secondRow.add(createRadioButton("Rectangle"));
secondRow.add(createRadioButton("Square"));
secondRow.add(createRadioButton("Triangle"));
return secondRow;
}
private JPanel createSeventhRow() {
JPanel seventhRow = new JPanel();
JButton button = new JButton("Enter");
seventhRow.add(button);
return seventhRow;
}
private JPanel createSixthRow() {
JPanel sixthRow = new JPanel();
JTextField textField = new JTextField(20);
sixthRow.add(textField);
return sixthRow;
}
private JPanel createThirdRow() {
JPanel thirdRow = new JPanel();
JLabel label = new JLabel("3D Shapes");
thirdRow.add(label);
return thirdRow;
}
private void showGui() {
frame = new JFrame("Shape Image Generator");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Shapes23());
}
}
Here is a screen capture of how it looks. Note that I couldn't find the same icon as in your screen capture so I just used a different one.
So I am trying to start a graphics program, where I have a JFrame that holds multiple JPanels. The JPanels need to combine to create 1 image, however when I run my program I see borders around the images. I cannot quite distinguish if the border is caused by the JLabel that holds the image or if it is because of the JPanel or because of the Layout Manager.
How can I remove the border? Would i need to change the layout manager? If so how?
import java.util.*;
import java.awt.*;
import javax.swing.*;
public class StarryNight {
JFrame backGround;
JPanel rootPanel;
JLabel rootImage;
public StarryNight(){
backGround = new JFrame("Starry Starry Night");
backGround.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
backGround.setResizable(false);
backGround.setSize(1000,667);
backGround.getContentPane().setBackground(Color.BLACK);
backGround.setLayout(new BoxLayout(backGround.getContentPane(),BoxLayout.Y_AXIS));
rootPanel = new JPanel();
rootPanel.setSize(1000, 667);
rootPanel.setBackground(Color.BLUE);;
rootImage = new JLabel();
rootImage.setIcon(new ImageIcon(getClass().getResource("Starry Night.jpg")));
rootPanel.add(rootImage);
JPanel jap = new JPanel();
jap.setSize(1000,100);
jap.setBackground(Color.GREEN);
backGround.add(rootPanel);
backGround.add(jap);
backGround.pack();
backGround.setVisible(true);
}
private static void runGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
StarryNight ssn= new StarryNight();
}
public static void main(String args[]){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
runGUI();
}
});
}
}
rootPanel = new JPanel();
By default a JPanel uses a FlowLayout which defaults to allows 5 pixels before/after components. So when you add our image to the panel you will see 5 pixels of space on all sides.
If you don't want that space then look at the FlowLayout API and create a FlowLayout without spaces between the components and then add that layout to the rootPanel. Something like:
rootPanel = new JPanel( new FlowLayout(...) );
I want to create a Window with an image and a text so far i've got this:
public void ShowPng1() {
ImageIcon theImage = new ImageIcon("Icon_Entry_21.gif");
panel.setSize(270, 270);
JLabel label = new JLabel("Hello, World!");
JLabel imageLabel = new JLabel(theImage);
imageLabel.setOpaque(true);
panel.add(imageLabel);
panel.add(label);
panel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setVisible(true);
}
My panel:
private JFrame panel = new JFrame();
For some reason it won't load nor image nor text, it just pops up as a white window. What can be the problem? I've also tried changing the format to .png, didn't work.
UPDATE
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Img {
private JFrame panel = new JFrame();
public Img(){
ShowPng1();
}
public void ShowPng1() {
ImageIcon theImage = new ImageIcon("Icon_Entry_21.gif");
panel.setSize(300, 300);
panel.setResizable(false);
JLabel label = new JLabel("Hello, World!");
JLabel imageLabel = new JLabel(theImage);
imageLabel.setOpaque(true);
panel.add(imageLabel);
panel.add(label, BorderLayout.PAGE_END);
panel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setVisible(true);
}
public static void main(String[] args) {
new Img();
}
}
I've managed to get this working, which is ridiculous because I can't figure out how to make it work with my program. Reimeus gave me an idea on creating this script separately, the fix and that worked. I will have to look through my entire program to see if I'm missing anything. Creating it in a separate class should work as well.
it just pops up as a white window
Sounds like you're blocking the EDT on startup. You may need to use one of Swing's concurrency mechanisms to solve it. Post a Minimal, Complete, Tested and Readable example so we can determine this for sure.
In the meantime...
You're displacing the component containing the theImage component in the BorderLayout.CENTER location
panel.add(label);
You could organize your labels so that they can appear simultaneously (placing the components at 2 different BorderLayout locations will do)
panel.add(imageLabel);
panel.add(label, BorderLayout.PAGE_END);
You should make a JPanel and add it to the frame, and then add the labels to the panel
Something like
private JPanel panel = new JPanel;
and then add it to the frame in your method calling
frame.add(panel);