I'm trying to do the following layout, where all JPanels are visible with the exception of panel2 when the program starts. When the user clicks btn1 then JCalendar and panel3 are set to invisible and panel2 becomes visible. The problem I'm having is that panel2 is not showing up with btn1 is clicked. However if i change the borderlayout of panel2 to one that is not being used (in this case WEST) it will show when the button is clicked, but its aligned on the left side and i want it to be centered across the form.
Code:
public class GUI extends JFrame implements ActionListener, PropertyChangeListener
{
private JPanel panel1, panel2, panel3;
private com.toedter.calendar.JCalendar calendar;
private Button btn1, btn2;
private JLabel label1, label2;
public GUI()
{
init();
}
private void init()
{
//panel1 components
panel1 = new JPanel();
btn1 = new JButton("Click me");
panel1.add(btn1);
//panel2 components
panel2 = new JPanel();
label1 = new JLabel("Time:");
label2 = new JLabel("Date:");
panel2.add(label1); panel2.add(label2);
//JCalendar
calendar = new com.toedter.calendar.JCalendar();
//panel3
panel3 = new JPanel();
//Add panels to JFrame
add(panel1, BorderLayout.NORTH);
add(calendar, BorderLayout.CENTER);
add(panel2, BorderLayout.CENTER); //if i set this to WEST it show!!
add(panel3, BorderLayout.EAST);
//event handling
btn1.addActionListener(this);
//hide panel2
panel2.setVisible(false);
pack();
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getSource().equals(btn1)
{
calendar.setVisible(false);
panel3.setVisible(false);
panel2.setVisible(true); //make panel2 visible
panel2.updateUI();
revalidate();
repaint();
}
}
public static void main(String args[])
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GUI().setVisible(true);
}
});
}
When i click btn1, JCalendar and panel3 is invisible but panel2 does not show
There are a number of issues that I can find...
BorderLayout will only ever allow a single component to occupy any given position. That is, two components can not share the CENTER position at the same time, regardless if one is invisible or not.
You should never call updateUI, this is used to tell UI components that the look and feel has changed that they should update in response to it.
Use revalidate to tell the container that some change has occurred to the layout that it should perform a new layout process...
Before click...
After Click...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class GUI extends JFrame implements ActionListener, PropertyChangeListener {
private JPanel panel1, panel2, panel3;
// private com.toedter.calendar.JCalendar calendar;
private JPanel calendar;
private JButton btn1, btn2;
private JLabel label1, label2;
public GUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
init();
}
private void init() {
//panel1 components
panel1 = new JPanel();
btn1 = new JButton("Click me");
panel1.add(btn1);
//panel2 components
panel2 = new JPanel();
label1 = new JLabel("Time:");
label2 = new JLabel("Date:");
panel2.add(label1);
panel2.add(label2);
//JCalendar
calendar = new JPanel();//new com.toedter.calendar.JCalendar();
calendar.setBorder(new LineBorder(Color.RED));
calendar.add(new JLabel("Calendar"));
//panel3
panel3 = new JPanel();
panel3.setBorder(new LineBorder(Color.BLUE));
panel3.add(new JLabel("Panel3"));
panel2.setBorder(new LineBorder(Color.GREEN));
//Add panels to JFrame
add(panel1, BorderLayout.NORTH);
add(calendar, BorderLayout.WEST);
add(panel2, BorderLayout.CENTER);
add(panel3, BorderLayout.EAST);
//event handling
btn1.addActionListener(this);
//hide panel2
panel2.setVisible(false);
pack();
}
public void actionPerformed(ActionEvent ae) {
if (ae.getSource().equals(btn1)) {
calendar.setVisible(false);
panel3.setVisible(false);
panel2.setVisible(true); //make panel2 visible
// panel2.updateUI();
revalidate();
repaint();
}
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
}
});
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
}
}
Now, I'm pretty sure this won't meet you over all requirements (as I see them)...You have at least two options...
Remove the Calendar component and add panel2 to the CENTER position when the button is clicked
Preferably, use a CardLayout
BorderLayout doesn't do overlapping, IIRC none of the layout managers are about "overlapping layout".
You'll need to do it a different way -- try using JLayeredPane with your existing JPanel & BorderLayout as the bottom layer, and then your (optional) panel as the top layer.
See: http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
Related
I have a JPanel and JButton on the JFrame.
on runtime add JLabel to JPanel When click JButton.
I use of the following code:
panel.setLayout(null);
jLabel _lbl=new jLabel();
_lbl.setText("Label");
panel.add(_lbl);
panel.validate();
but no display any JLabel in JPanel.
I see you create a JLabel called _lbl:
JLabel _lbl=new JLabel();
but you never add it to your panel. Instead you add a new JLabel with no text to your panel:
panel.add(new JLabel());
This would ofcourse construct an empty label which wont be visible.
Also try calling revalidate() and repaint() on your JPanel instance after adding the JLabel like so:
JLabel _lbl=new JLabel("Label");//make label and assign text in 1 line
panel.add(_lbl);//add label we made
panel.revalidate();
panel.repaint();
With this you may also need to call pack() on your frames instance so as to resize the JFrame to fit the new components.
Also please never use a null/Absolute layout this is very bad practice (unless doing animation) and may prove to be problematic and very hard to use.
Rather use a LayoutManager:
A Visual Guide to Layout Managers
or if you only have a single component on the JPanel simply call add(label); as it will stretch to the JPanel size.
UPDATE:
Here is a small sample. Simply adds JLabels to the JPanel each time JButton is pressed:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class JavaApplication116 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JavaApplication116().createAndShowUI();
}
});
}
private void createAndShowUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void initComponents(final JFrame frame) {
final JPanel panel = new JPanel(new FlowLayout());
JButton button = new JButton("Add label");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JLabel _lbl = new JLabel("Label");//make label and assign text in 1 line
panel.add(_lbl);//add label we made
panel.revalidate();
panel.repaint();
frame.pack();//so our frame resizes to compensate for new components
}
});
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.getContentPane().add(button, BorderLayout.SOUTH);
}
}
I am trying to add buttons over the images in the panels. I am also trying to switch between the panels. The program is running but when I am clicking the "instructions" button it gives a huge list of errors in the cmd. What is the issue?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.JButton;
import javax.swing.JPanel;
public class htw10 extends JFrame
{
final JFrame f=new JFrame("Hunt The Wumpus");
private static final String FIRST_PANEL="first panel";
private static final String SECOND_PANEL="second panel";
private CardLayout cardLayout=new CardLayout();
private JPanel content;
public void start()
{
// Create a new panel, make 'content' refer to it
content = new JPanel();
// Set the content pane of the window to the panel we just created
f.setContentPane(content);
// Create a button group and some buttons
// Set the layout of the content panel and add buttons
content.setLayout(new FlowLayout());
// Create and add the intro panel and instruction panel to the content panel
content.add(introPanel(),FIRST_PANEL);
content.add(instructionPanel(),SECOND_PANEL);
f.setSize(750,500);
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
f.setVisible(true);
}
private JPanel instructionPanel()
{
JPanel secondPanel=new JPanel();
ImageIcon icon=new ImageIcon("img2.jpg");
JLabel pic2 = new JLabel(icon);
secondPanel.add(pic2);
JButton b1=new JButton("Back");
content.add(b1);
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(content,FIRST_PANEL);
}
});
secondPanel.repaint();
return secondPanel;
}
public JPanel introPanel()
{
JPanel iPanel=new JPanel();
ImageIcon icon=new ImageIcon("img1.jpg");
JLabel picLabel = new JLabel(icon);
iPanel.add(picLabel);
ButtonGroup group=new ButtonGroup();
JButton b1=new JButton("Instructions");
JButton b2=new JButton("Play");
JButton b3=new JButton("Exit");
picLabel.add(b1);
//f.getContentPane().add(picLabel,BorderLayout.SOUTH);
content.add(b1);
content.add(b2);
content.add(b3);
// Add a listener to the 'Instructions' button
// so that the cardLayout is shown when the button is clicked
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(content,SECOND_PANEL);
}
});
iPanel.repaint();
return iPanel;
}
public static void main(String args[])throws Exception
{
htw10 obj=new htw10();
obj.start();
}
}
In line 14, you are declaring a member variable content, but you are not initializing it. Member variables will be automatically initialized to null if you do not initialize them yourself:
private JPanel content; // is automatically set to null
In line 25 you are calling the method setLayout on content:
content.setLayout(new FlowLayout());
This will cause a NullPointerException because content is null.
To learn more about what a NullPointerException is and why it happens, see: What is a NullPointerException, and how do I fix it?
You need to set content to something. It appears that this is supposed to refer to the content pane. Furthermore, you are calling the introPanel() method multiple times, causing multiple instances of this panel to be created. That is not what you want. That panel should be created only once, and then you should use that one. Don't call introPanel() multiple times. Your start() method should look something like this:
public void start()
{
// Create a new panel, make 'content' refer to it
content = new JPanel();
// Set the content pane of the window to the panel we just created
f.setContentPane(content);
// Create a button group and some buttons
ButtonGroup group=new ButtonGroup();
JButton b1=new JButton("Instructions");
JButton b2=new JButton("Play");
JButton b3=new JButton("Exit");
// Set the layout of the content panel and add buttons
content.setLayout(new FlowLayout());
content.add(b1);
content.add(b2);
content.add(b3);
// Create and add the intro panel and instruction panel to the content panel
content.add(introPanel(),FIRST_PANEL);
content.add(instructionPanel(),SECOND_PANEL);
f.setSize(750,360);
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
f.setVisible(true);
// Add a listener to the 'Instructions' button
// so that the cardLayout is shown when the button is clicked
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.show(content,SECOND_PANEL);
}
});
}
I don't think Jpanel has drawImage method which you are trying to call in below code.
public JPanel introPanel()
{
JPanel iPanel=new JPanel();
ImageIcon icon=new ImageIcon("img1.jpg");
iPanel.drawImage(icon, 0, 0,getWidth(),getHeight(),this);
return iPanel;
}
You need a graphics(java.awt.Graphics) object to call drawImage method.
More-over you can try other methods like
public JPanel introPanel()
{
JPanel iPanel=new JPanel();
ImageIcon icon=new ImageIcon("img1.jpg");
JLabel picLabel = new JLabel(icon);
iPanel.add(picLabel);
iPanel.repaint();
return iPanel;
}
How to set Jbuttons to a specific place when you have a background in JLabel : code below
i can't get the jlabel to stay at the top and the buttons to stay south(bottom) ??
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonsClass extends JFrame
implements ActionListener {
JButton b1 = new JButton("button1");
JButton b2 = new JButton("button2");
JButton b3 = new JButton("button3");
JButton b4 = new JButton("button4");
JLabel label = new JLabel("buttons:");
public static void main(String[] args) {
new ButtonsClass();
}
public Jukebox() {
setLayout(new BorderLayout());
setContentPane(new JLabel(new ImageIcon("image.png")));
setLayout(new FlowLayout());
setSize(500,150);
setTitle("Backgroundwithbuttons");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
JPanel top = new JPanel();
top.add(label);
add("North", top);
JPanel bottom = new JPanel();
bottom.add(b1);
bottom.add(b2);
bottom.add(b3);
bottom.add(b4);
add("South", bottom);
setVisible(true);
}
}
" i can't get the jlabel to stay at the top and the buttons to stay south(bottom)"
That's because you set the layout the BorderLayout, then immediately set it to FlowLayout. With FlowLayout, your BorderLayout positioning will do nothing.
setLayout(new BorderLayout());
setContentPane(new JLabel(new ImageIcon("image.png")));
setLayout(new FlowLayout());
Just get rid of the setLayout(new FlowLayout());
Also your constructor is wrong
public Jukebox() {
-Should be-
public ButtonClass() {
Also you need to set the layout of the JLabel that you set as the content pane. Yout constructor should look like this
public ButtonClass() {
JLabel background = new JLabel(new ImageIcon("image.png"));
background.setLayout(new BorderLayout());
setContentPane(background);
setTitle("Background with buttons");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
JPanel top = new JPanel();
top.add(label);
add(top, BorderLayout.NORTH);
JPanel bottom = new JPanel();
bottom.add(b1);
bottom.add(b2);
bottom.add(b3);
bottom.add(b4);
add(bottom, BorderLayout.SOUTH);
//pack();
setVisible(true);
}
Also, add("North", top); is a deprecated method. Instead use add(top, BorderLayout.NORTH) and same for add(bottom, BorderLayout.SOUTH)
Also, Swing apps should be run on the Event Dispatch Thread. You can do so by wrapping the code in your main with a SwingUtilities.invokeLater...
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ButtonClass();
}
});
}
Also, you should set the panel's opaque property to false, if you want the image to show behind them.
top.setOpaque(false);
bottom.setOpaque(false);
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonClass extends JFrame
implements ActionListener {
JButton b1 = new JButton("button1");
JButton b2 = new JButton("button2");
JButton b3 = new JButton("button3");
JButton b4 = new JButton("button4");
JLabel label = new JLabel("buttons:");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ButtonClass();
}
});
}
public ButtonClass() {
label.setForeground(Color.WHITE);
JLabel background = new JLabel(new ImageIcon(getClass().getResource("/resources/space.png")));
background.setLayout(new BorderLayout());
setContentPane(background);
setTitle("Background with buttons");
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
JPanel top = new JPanel();
top.setOpaque(false);
top.add(label);
add(top, BorderLayout.NORTH);
JPanel bottom = new JPanel();
bottom.setOpaque(false);
bottom.add(b1);
bottom.add(b2);
bottom.add(b3);
bottom.add(b4);
add(bottom, BorderLayout.SOUTH);
setSize(400, 300);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {}
}
Try using:
add(bottom, BorderLayout.SOUTH);
instead of:
add("South", bottom);
BorderLayout tutorial
I have a JPanel and JButton on the JFrame.
on runtime add JLabel to JPanel When click JButton.
I use of the following code:
panel.setLayout(null);
jLabel _lbl=new jLabel();
_lbl.setText("Label");
panel.add(_lbl);
panel.validate();
but no display any JLabel in JPanel.
I see you create a JLabel called _lbl:
JLabel _lbl=new JLabel();
but you never add it to your panel. Instead you add a new JLabel with no text to your panel:
panel.add(new JLabel());
This would ofcourse construct an empty label which wont be visible.
Also try calling revalidate() and repaint() on your JPanel instance after adding the JLabel like so:
JLabel _lbl=new JLabel("Label");//make label and assign text in 1 line
panel.add(_lbl);//add label we made
panel.revalidate();
panel.repaint();
With this you may also need to call pack() on your frames instance so as to resize the JFrame to fit the new components.
Also please never use a null/Absolute layout this is very bad practice (unless doing animation) and may prove to be problematic and very hard to use.
Rather use a LayoutManager:
A Visual Guide to Layout Managers
or if you only have a single component on the JPanel simply call add(label); as it will stretch to the JPanel size.
UPDATE:
Here is a small sample. Simply adds JLabels to the JPanel each time JButton is pressed:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class JavaApplication116 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JavaApplication116().createAndShowUI();
}
});
}
private void createAndShowUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void initComponents(final JFrame frame) {
final JPanel panel = new JPanel(new FlowLayout());
JButton button = new JButton("Add label");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JLabel _lbl = new JLabel("Label");//make label and assign text in 1 line
panel.add(_lbl);//add label we made
panel.revalidate();
panel.repaint();
frame.pack();//so our frame resizes to compensate for new components
}
});
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.getContentPane().add(button, BorderLayout.SOUTH);
}
}
I need to add components dynamically. Moreover, I need to alter the layout dynamically.
For reference, here's an sscce that shows the essential method, validate(). This more elaborate example shows both requirements: it changes the layout and adds components dynamically.
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/5750068 */
public class DynamicLayout extends JPanel {
private static final LayoutManager H = new GridLayout(1, 0);
private static final LayoutManager V = new GridLayout(0, 1);
public DynamicLayout() {
this.setLayout(H);
this.setPreferredSize(new Dimension(320, 240));
for (int i = 0; i < 3; i++) {
this.add(new JLabel("Label " + String.valueOf(i), JLabel.CENTER));
}
}
private void display() {
JFrame f = new JFrame("DynamicLayout");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
JPanel p = new JPanel();
p.add(new JButton(new AbstractAction("Horizontal") {
#Override
public void actionPerformed(ActionEvent e) {
DynamicLayout.this.setLayout(H);
DynamicLayout.this.validate();
}
}));
p.add(new JButton(new AbstractAction("Vertical") {
#Override
public void actionPerformed(ActionEvent e) {
DynamicLayout.this.setLayout(V);
DynamicLayout.this.validate();
}
}));
f.add(p, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new DynamicLayout().display();
}
});
}
}
Example of changing the layout Dynamically :
package swinglayout;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LayoutChanger implements ActionListener{
JButton b1;
JButton b2;
JButton b3;
JButton b4;
JButton b5;
JButton b6;
/** This button set the flowlayout on panel2 with left orientation */
JButton flowLayout;
/** This button set the Gridlayout of 2,3 grid on panel2 */
JButton gridLayout;
/** This button set the Borderlayout on panel2*/
JButton borderLayout;
/**
* This panel is control panel where we use button to change
* layout of another panel
*/
JPanel panel;
/** This panel contain multiple button from b1 to b6 */
JPanel panel2;
JFrame frame;
public LayoutChanger() {
//set Default Look and Feel on frame
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container con = frame.getContentPane();
con.setLayout(new BorderLayout());
panel = new JPanel();
panel2 = new JPanel();
//This button are used to only showing the layout effect
b1 = new JButton("HelloButton1");
b2 = new JButton("HelloButton2");
b3 = new JButton("HelloButton3");
b4 = new JButton("HelloButton4");
b5 = new JButton("HelloButton5");
b6 = new JButton("HelloButton6");
// By default panel have layout
panel2.add(b1);
panel2.add(b2);
panel2.add(b3);
panel2.add(b4);
panel2.add(b5);
panel2.add(b6);
// Layout changer button
flowLayout = new JButton("FlowLayout");
gridLayout = new JButton("GridLayout");
borderLayout = new JButton("BorderLayout");
//call Action listener on every layout changer button
flowLayout.addActionListener(this);
gridLayout.addActionListener(this);
borderLayout.addActionListener(this);
panel.add(flowLayout);
panel.add(gridLayout);
panel.add(borderLayout);
// add layout changer button panel at a top
//button panel at the center of container
con.add(panel, BorderLayout.PAGE_START);
con.add(panel2, BorderLayout.CENTER);
frame.setVisible(true);
frame.pack();
}
public void actionPerformed(ActionEvent e) {
//set the flowlayout on panel2
if(e.getSource() == flowLayout) {
FlowLayout flow = new FlowLayout(FlowLayout.LEFT);
panel2.setLayout(flow);
panel2.validate();
}
//set the gridlayout on panel2
if(e.getSource() == gridLayout) {
GridLayout grid = new GridLayout(2,3);
panel2.setLayout(grid);
panel2.validate();
}
//set the gridlayout but the problem if we don't set the constraint
//all button are set on center. So you remove the all button from panel
//Then set grid layout on panel and add them with constraints.
if(e.getSource() == borderLayout) {
panel2.remove(b1);
panel2.remove(b2);
panel2.remove(b3);
panel2.remove(b4);
panel2.remove(b5);
panel2.remove(b6);
BorderLayout border = new BorderLayout();
panel2.setLayout(border);
panel2.add(b1,BorderLayout.NORTH);
panel2.add(b2,BorderLayout.SOUTH);
panel2.add(b3,BorderLayout.EAST);
panel2.add(b4,BorderLayout.WEST);
panel2.add(b5,BorderLayout.CENTER);
panel2.add(b6,BorderLayout.BEFORE_FIRST_LINE);
panel2.validate();
}
}
public static void main(String args[]) {
new LayoutChanger();
}
}
One thing remember is you set new layout on panel don't forgot call the method validate() on panel.If you don't call this method you don't see the effect of change in layout. If you want to see the effect with out call the method you must resize the frame.
Also you can set same layout very easily like FlowLayout,GridLayout and BoxLayout, but when set BorderLayout it required constraints for adding element, so we first remove all component from panel by remove(Component comp) method then add the component in panel by constraint