in my project i have a scrollpane which can contains various panel, depending by user action.
By the way, i'd like to have each panel of a fixed height, and on add, they should be shown one below the previous. Instead they change their height depending to the number of existing panels.
I wrote a main class with the goal of reproducing current behaviour, and an image which should explain what am I aiming for.
image:
code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class MyClass {
static JScrollPane myScrollPaneContent;
static Box panelContainer;
static int i=0;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run(){
int i=0;
//mainWindow
JFrame mainWindow = new JFrame("MyFrame");
mainWindow.setLayout(new BorderLayout());
mainWindow.setMinimumSize(new Dimension(1050,300));
//panel to be placed in mainwindow (borderlayout.Center)
//contains a menu + scrollpane
JPanel centerPanel = new JPanel();
//Box for myScrollPaneContent
panelContainer = Box.createVerticalBox();
//button for centerPanel
JButton button = new JButton("addPanel");
button.setBackground(Color.green);
button.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
//nothing
}
#Override
public void mousePressed(MouseEvent e) {
//nothing
}
#Override
public void mouseExited(MouseEvent e) {
//nothing
}
#Override
public void mouseEntered(MouseEvent e) {
//nothing
}
#Override
public void mouseClicked(MouseEvent e) {
addPanel();
}
});
centerPanel.add(button);
myScrollPaneContent = new JScrollPane(panelContainer);
myScrollPaneContent.setPreferredSize(new Dimension(600,250));
myScrollPaneContent.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
//all panels are added to the Box
//the box do not need to be added to scroll pane since it has been given into it s constructor
//the scrollpane is added to the centralpanel
centerPanel.add(myScrollPaneContent);
mainWindow.add(centerPanel,BorderLayout.CENTER);
mainWindow.add(Box.createVerticalGlue(),BorderLayout.SOUTH);
mainWindow.setVisible(true);
}
});
}
public static void addPanel(){
switch(i++){
case 0:
//panel 1 for Box
JPanel one = new JPanel();
JLabel labOne = new JLabel("hello");
one.add(labOne);
one.setPreferredSize(new Dimension(1000,25));
one.setBackground(Color.white);
panelContainer.add(one);
break;
case 1:
//panel 2 for Box
JPanel two = new JPanel();
JLabel labTwo = new JLabel("i am a label");
two.add(labTwo);
two.setPreferredSize(new Dimension(1000,30));
two.setBackground(Color.yellow);
panelContainer.add(two);
break;
case 2:
//panel 3 for Box
JPanel three = new JPanel();
JLabel labThree = new JLabel("Bye bye");
three.add(labThree);
three.setPreferredSize(new Dimension(1000,30));
three.setBackground(Color.gray);
panelContainer.add(three);
break;
case 3:
//panel 4 for Box
JPanel four = new JPanel();
JLabel labFour = new JLabel("boyz");
four.add(labFour);
four.setPreferredSize(new Dimension(1000,30));
four.setBackground(Color.blue);
panelContainer.add(four);
break;
default:
i=0;
break;
}
myScrollPaneContent.revalidate();
myScrollPaneContent.repaint();
}
}
You want something like:
JPanel scrollPaneContainer = new JPanel( new BorderLayout() );
Box panelContainer = Box.createVerticalBox();
scrollPaneContainer.add(panelContainer, BorderLayout.PAGE_START);
JScrollPane myScrollPaneContent = new JScrollPane(scrollPaneContainer);
Now the preferred height of your panelContainer will be respected. If there is any extra spaces it will go to the CENTER. If there is not enough space, the scrollbars will appear.
Also, you should NOT be using static variables. This is the sign of a poorly designed GUI. You should NOT be creating your GUI components in main() method. Look at the demos from the Swing tutorial. They show you how to create a panel to hold the Swing components and then add the panel to the frame.
Related
I am a new java programmer and I use stackoverflow since my begin. I code a little "game", and it is a text-based game. Well, i begin a graphical interface, to case the text, and i would have this configuration
Basically, it is a double separation, with 3 horizontals elements. Actually, I have this:
and i want a separation
I have tried to put an other split pane on the top of the first one, like this:
package sample;
import javax.swing.*;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.*;
class Fenetresaisie extends JFrame {
public static class Fenetre {
public final static int HT = 1024;
public final static int LG = 758;
public static void main(String[] args) {
JPanel panel = new JPanel();
JFrame F = new JFrame("CORONAZE");
F.setExtendedState(JFrame.MAXIMIZED_BOTH);
F.setSize(HT, LG);
F.setVisible(true);
F.addWindowListener(new gestionFenetre());
ImageIcon icone = new ImageIcon("images.jpg");
JLabel image = new JLabel(icone);
JTextField textField = new JTextField();
textField.setFont(new Font("Terminal", Font.BOLD, 30));
textField.setForeground(Color.RED);
textField.setBackground(Color.black);
textField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent e) {
textField.getText();
e.getKeyChar();
}
});
JLabel label = new JLabel(">texte de l'histoire ici<");
label.setOpaque(true);
label.setForeground(Color.green);
label.setBackground(Color.BLACK);
panel.add(label);
JSplitPane topJSplitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT, label, textField);
// topJSplitPane.setDividerLocation(400);
JSplitPane bottomJSplitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT, topJSplitPane, textField );
//i added it to have a double separation, but it give 2 sticked splitpane
F.add(topJSplitPane, BorderLayout.CENTER);
F.add(bottomJSplitPane, BorderLayout.SOUTH);
F.setVisible(true);
}
}
static class gestionFenetre extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
}
But it gives me two sticked splitpane :-/
Can you help me please? I hope you understand my message, because I learn English. Contact me below if you want a next phase to this issue, thanks! ^^ Here is the actual graphical test java class:
package sample;
import javax.swing.*;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.*;
class Fenetresaisie extends JFrame {
public static class Fenetre {
public final static int HT = 1024;
public final static int LG = 758;
public static void main(String[] args) {
JPanel panel = new JPanel();
JFrame F = new JFrame("CORONAZE");
F.setExtendedState(JFrame.MAXIMIZED_BOTH);
F.setSize(HT, LG);
F.setVisible(true);
F.addWindowListener(new gestionFenetre());
ImageIcon icone = new ImageIcon("images.jpg");
JLabel image = new JLabel(icone);
JTextField textField = new JTextField();
textField.setFont(new Font("Terminal", Font.BOLD, 30));
textField.setForeground(Color.RED);
textField.setBackground(Color.black);
textField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent e) {
textField.getText();
e.getKeyChar();
}
});
JLabel label = new JLabel(">texte de l'histoire ici<");
label.setOpaque(true);
label.setForeground(Color.green);
label.setBackground(Color.BLACK);
panel.add(label);
JSplitPane topJSplitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT, label, textField);
topJSplitPane.setDividerLocation(400);
// JSplitPane bottomJSplitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT, topJSplitPane, textField );
//i added it to have a double separation, but it give 2 sticked splitpane
F.add(topJSplitPane, BorderLayout.CENTER);
// F.add(bottomJSplitPane, BorderLayout.SOUTH);
F.setVisible(true);
}
}
static class gestionFenetre extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
}
You wrote in your question
I am a new java programmer and I use stackoverflow since my begin
I really think that the way to learn Swing programming is to follow a learning curve that starts with the basics and gradually progresses. Everybody has his preferred way to learn, for example by attending a course or watching a video or reading a book. Personally I prefer books. If you do too, then I can recommend a few.
You also wrote in your question
I code a little "game"
I would say that is a very ambitious project for a beginner. While I'm sure that there are people who learn best by starting off with ambitious projects, I would say they are in the minority.
That said, the key to correctly implementing your GUI is having a deep understanding of how Swing works, in particular layout managers and Component sizes as well as at what point in the code can you set those Component sizes.
The below code will initially display your desired GUI, since I understand, from your question, that that is what you are trying to accomplish now.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class WindowCapture extends WindowAdapter implements Runnable {
private JFrame frame;
private JLabel label;
private JSplitPane splitPane;
private JSplitPane topPane;
#Override // java.lang.Runnable
public void run() {
showGui();
}
#Override // java.awt.event.WindowAdapter
public void windowOpened(WindowEvent event) {
int height = event.getWindow().getHeight();
splitPane.setDividerLocation(0.7);
double high = height * 0.7;
height = (int) Math.rint(high);
high = height * 0.8;
height = (int) Math.rint(high);
label.setPreferredSize(new Dimension(event.getWindow().getWidth(), height));
}
private JTextField createBottomPane() {
JTextField textField = new JTextField(20);
textField.setFont(new Font("Terminal", Font.BOLD, 30));
textField.setForeground(Color.RED);
textField.setBackground(Color.black);
return textField;
}
private JSplitPane createSplitPane() {
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createTopPane(), createBottomPane());
splitPane.setDividerLocation(0.4);
return splitPane;
}
private JSplitPane createTopPane() {
label = new JLabel(">texte de l'histoire ici<");
label.setOpaque(true);
label.setForeground(Color.green);
label.setBackground(Color.BLACK);
topPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
label,
new JPanel());
topPane.setDividerLocation(0.9);
return topPane;
}
public void showGui() {
frame = new JFrame("Window Capture");
frame.addWindowListener(this);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.add(createSplitPane());
frame.setVisible(true);
}
/**
* Start here!
*/
public static void main(String[] args) {
EventQueue.invokeLater(new WindowCapture());
}
}
Here is a screen capture of the running app.
I am making a dating game in the style of the Japanese dating game with pictures and responses for fun and practice. I am trying to have a JOptionPane message dialog show up for each button in a grid layout as a response to each option. In this way it's like a logic tree. I am not used to using action listener as I am somewhat of a beginner. Here is my code. I am just not used to the syntax of doing this.
Can anyone help me?
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.*;
//Implementations of packages
public class NestedPanels extends JPanel {
private static final String[] BTN_TEXTS = { "Say Hello", "Say You Look Good", "Say Sorry I'm Late" }; //three buttons
private static final int TITLE_POINTS = 3; //number of objects in text box
public NestedPanels() { //implemeted class
JPanel southBtnPanel = new JPanel(new GridLayout(3, 2, 1, 1)); //grid layout of buttons and declaration of panel SoutbtnPanel
for (String btnText : BTN_TEXTS) { //BTN TEXT button titles linked to string btnText label
southBtnPanel.add(new JButton(btnText)); //add btnText label
}
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); //layout of buttons "Button text"
setLayout(new BorderLayout());
add(Box.createRigidArea(new Dimension(600, 600))); //space size of text box webapp over all
add(southBtnPanel, BorderLayout.SOUTH);
}
private static void createAndShowGui() {//class to show gui
NestedPanels mainPanel = new NestedPanels(); //mainPanel new class of buttons instantiation
JFrame frame = new JFrame("Date Sim 1.0");//title of webapp on top
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
ImageIcon icon = new ImageIcon("C:/Users/wchri/Pictures/10346538_10203007241845278_2763831867139494749_n.jpg");
JLabel label = new JLabel(icon);
mainPanel.add(label);
frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
System.out.println("Welcome to Date Sim 1.0 with we1. Are you ready to play? Yes/No?");
Scanner in = new Scanner(System.in);
String confirm = in.nextLine();
if (confirm.equalsIgnoreCase("Yes")) {
System.out.println("Ok hot stuff... Let's start.");
NestedPanels mainPanel = new NestedPanels();
} else {
System.out.println("Maybe some other time!");
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Review the following to get an idea of how to add action listener to buttons.
Please note the comments:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class NestedPanels extends JPanel {
private static final String[] BTN_TEXTS = { "Say Hello", "Say You Look Good", "Say Sorry I'm Late" }; //three buttons
//never used : private static final int TITLE_POINTS = 3;
public NestedPanels() {
JPanel southBtnPanel = new JPanel(new GridLayout(3, 2, 1, 1));
for (String btnText : BTN_TEXTS) {
JButton b = new JButton(btnText);
//add action listener
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buttonClicked(e);//when button clicked, invoke method
}
});
//alternative much shorter way to add action listener:
//b.addActionListener(e -> buttonClicked());
southBtnPanel.add(b);
}
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setLayout(new BorderLayout());
//this adds Box to the default BorderLayout.CENTER position
add(Box.createRigidArea(new Dimension(600, 600)));
add(southBtnPanel, BorderLayout.SOUTH);
}
//respond to button clicked
private void buttonClicked(ActionEvent e) {
String msg = ((JButton)e.getSource()).getActionCommand()+" pressed" ;
JOptionPane.showMessageDialog(this, msg ); //display button Action
}
private static void createAndShowGui() {
NestedPanels mainPanel = new NestedPanels();
JFrame frame = new JFrame("Date Sim 1.0");
//no need to invoke twice frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//no need to invoke twice frame.pack();
//no need to invoke twice frame.setVisible(true);
frame.getContentPane().add(mainPanel);
/*
* when posting images, use web resources that anyone can access
*
ImageIcon icon = new ImageIcon("C:/Users/wchri/Pictures/10346538_10203007241845278_2763831867139494749_n.jpg");
JLabel label = new JLabel(icon);
*this adds label to the default BorderLayout.CENTER position, which is already taken by
*the Box. Only one (last) component will be added
mainPanel.add(label);
*
*/
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//remove all code which is not essential to the question
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGui();
}
});
}
}
but I have already instantiated a parent class of extending the jpanel
Did you look at the example code provided in the tutorial???
The example there "
... extends JFrame implements ActionListener
So all you need is:
... extends JPanel implements ActionListener
Or in case you need multiple ActionListeners the more flexible approach to create a custom class.
You can use an "annonymous inner class" for the ActionListener. Something like:
ActionListener al = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
String text = button.getText();
Window window = SwingUtilities.windowForComponent(button);
JOptionPane.showMessageDialog(window, text);
}
};
Then when you create the button you would do:
for (String btnText : BTN_TEXTS)
{
JButton button = new JButton( btnText );
button.addActionListener( al );
southBtnPanel.add( button );
}
I failed to change the height of JPanel or JScrollPane to make more lines to appear, I used GridLayout. It seems that, every component in it should have the same size even when I use setSize(). Should I use another layout?
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class Main {
private JFrame mainFrame;
private JLabel headerLabel;
private JLabel statusLabel;
private JPanel controlPanel;
private imagePanel image;
JTextField textField = new JTextField(20);
public Main() throws IOException{
prepareGUI();
}
class imagePanel extends JPanel {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
try {
BufferedImage image = ImageIO.read(new File("file.jpg"));
g.drawImage(image, 170, 0, null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException{
Main swingControlDemo = new Main();
swingControlDemo.showEventDemo();
}
private void prepareGUI(){
mainFrame = new JFrame("Java SWING Examples");
mainFrame.setSize(400,500);
GridLayout gridlayout = new GridLayout(4, 1);
gridlayout.setVgap(1);
mainFrame.setLayout(gridlayout);
headerLabel = new JLabel("",JLabel.CENTER );
statusLabel = new JLabel("",JLabel.CENTER);
JScrollPane scroller = new JScrollPane(statusLabel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
image = new imagePanel();
image.setLayout(new FlowLayout());
// mainFrame.add(headerLabel);
mainFrame.add(image);
mainFrame.add(controlPanel);
mainFrame.add(scroller);
mainFrame.setVisible(true);
}
private void showEventDemo(){
headerLabel.setText("Control in action: Button");
JButton okButton = new JButton("reload");
JButton submitButton = new JButton("Submit");
JButton cancelButton = new JButton("Cancel");
okButton.setActionCommand("reload");
submitButton.setActionCommand("Submit");
cancelButton.setActionCommand("Cancel");
okButton.addActionListener(new ButtonClickListener());
submitButton.addActionListener(new ButtonClickListener());
cancelButton.addActionListener(new ButtonClickListener());
controlPanel.add(okButton);
controlPanel.add(submitButton);
//controlPanel.add(cancelButton);
controlPanel.add(textField);
System.out.println("---------------------");
mainFrame.setVisible(true);
}
private class ButtonClickListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if( command.equals( "reload" )) {
statusLabel.setText(convertToMultiline("Line1\nLine2\nLine3\nLine4\nLine5\nLine6\nLine7\nLine8\nLine9\nLine2\nLine3\nLine\nLine2\nLine3\nLine\nLine2\nLine3\nLine\nLine2\nLine3\nLine\nLine2\nLine3\nLine\nLine2\nLine3\nLine\nLine2\nLine3\nLine"));
}
else {
statusLabel.setText("Submit Button clicked.");
}
}
}
public static String convertToMultiline(String orig)
{
return "<html>" + orig.replaceAll("\n", "<br>");
}
}
The GUI need to look like this
I want to remove the large vertical gaps between the componets, and the jLabel should use that space
Well in your comment you say you want the label to use the space. But in your picture you show the text area with all the space. How can we answer a question when you give us conflicting requirements? Be specific and accurate when describing a problem.
In any case, the default layout of a JFrame is a BorderLayout so you would probably start with that.
Then the component that you want to grow/shrink as the frame is resized should be added to the CENTER of the frame.
Then you create a second panel to contain your other components. This panel would then be added to either the PAGE_START or PAGE_NORTH of the frame depending on your exact requirement.
The layout manager of this panel can then be whatever your want. Maybe a GridLayout, or a GridBagLayout or a vertical BoxLayout.
Read the section from the Swing tutorial on Layout Managers for more information and working examples. The key point is you create nest panels each with a different layout manager to achieve your layout.
I'm having a problem trying to change JPanels by using buttons. I have a JFrame with 2 panels, 1 of them is for the buttons, which i want them to always be showed. The other one is the one that i will be switching everytime i press one ot the buttons of the other panel. The problem is that everytime i press them nothing really ever displays, i keep my buttons but the other panel that i call does not appear.
Code for one of the buttons is as follows
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ReparacaoPanel r = new ReparacaoPanel(this, this.jPanel1);
this.getContentPane().remove(this.jPanel1);
this.getContentPane().add(r);
//this.setContentPane(r);
this.visiblePanel.setVisible(false);
this.visiblePanel = r;
this.pack();
this.setVisible(true);
r.setLocation(200, 200);
this.getContentPane().revalidate();
this.repaint();
}
If i try to use "this.setContentPane(r);" (it sets the frame to only show the panel) the panel shows. But when i try to call it as i'm trying to do in the code above nothing is showed apart from the panel that has the buttons.
I have no idea what i'm doing wrong, it does not seem to be a problem with the JPanel that i'm trying to call as it shows if used alone.
Anyone can help me out?
Consider this working example for switching manually between panels. Which produces this output.
.........
Some tiny NumberPanel
Every new instance shows another number in the center.
import javax.swing.JPanel;
public class NumberPanel extends JPanel {
private static int counter = 0;
public NumberPanel() {
setLayout(new BorderLayout(0, 0));
JLabel lblNewLabel = new JLabel("" + counter++);
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(lblNewLabel);
}
}
Setting up a frame
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.SOUTH);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.getContentPane().remove(numberPanel);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
}
});
panel.add(btnNewButton);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
}
Testprogram
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestPanelSwitch {
private JFrame frame;
private NumberPanel numberPanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestPanelSwitch window = new TestPanelSwitch();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TestPanelSwitch() {
initialize();
}
private void initialize() {
// see above
}
}
Back to the Question
I think you only need to pack your frame, like in the anonymous ActionListener.
frame.getContentPane().remove(numberPanel);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
EDIT
As leonidas mentioned it is also possible to revalidate the frame. This requires only to replace the upper call to pack by theese.
frame.invalidate();
frame.validate();
I'm trying to create a small GUI, it has 2 JButtons, and 2 JPanels with some drawing animation on each of them. By default it must show first JPanel, and by clicking on second JButton I want to see my second JPanel. So : I create JFrame, Panel1 and Panel2, where I have drawn my animations, create Button1 and Button2 and adding to them ActionListeners. I have also MainPanel which has in a fields variable i. By changing this "i" my constructor adds to MainPanel either Panel1 (default) or Panel2 (by clicking on JButton2 I change i). Than I add this MainPanel to my frame. So my question : in the class MainPanel I have refreshMe method, what should I write there to make my GUI working properly? Thanks. Here is my code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GuiTest {
public static void main(String[] args) {
JFrame f = new JFrame();
MainPanel myPanel = new MainPanel();
f.add(myPanel);
Button1 button1 = new Button1();
Button2 button2 = new Button2();
myPanel.add(button1);
myPanel.add(button2);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
class MainPanel extends JPanel {
Panel1 p1 = new Panel1();
Panel2 p2 = new Panel2();
public int i = 1; //this is being changed later by clicking JButton
// I use this setter later in actionPerformed in order to change i
public void setI(int i) {
this.i = i;
}
MainPanel() {
if (i == 1) {
this.add(p1);
}
if (i == 2) {
this.add(p2);
}
}
public void refreshMe() {
// Need some help here:
// I don't know what should I write, how to make a repaint of myPanel?
System.out.println("just test, if the method refreshMe working by clicking some button");
}
}
class Panel1 extends JPanel {
public Panel1() {
this.setBackground(Color.BLUE);
// a lot of drawing stuff going on here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
class Panel2 extends JPanel {
public Panel2() {
this.setBackground(Color.GREEN);
// a lot of drawing stuff going on here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
class Button1 extends JButton {
MainPanel someObj1 = new MainPanel();
Button1() {
setText("Show Annimation A");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
someObj1.setI(1);
System.out.println("The variable i is now: " + someObj1.i);
someObj1.refreshMe();
}
});
}
}
class Button2 extends JButton {
MainPanel someObj2 = new MainPanel();
Button2() {
setText("Show Annimation B");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
someObj2.setI(2);
System.out.println("The variable i is now: " + someObj2.i);
someObj2.refreshMe();
}
});
}
}
In order to reflect changes after adding/removing or resizing a component that is on a visible container call revalidate() and repaint() on the containers instance after adding/removing or resizing the component.
Though this will not work in your code the main reason being inside JButton classes you recreate a new instance of MainPanel when in fact the 2 JButtons should share the single instance which is being used (you could pass MainPanel instance to the JButtons constructors, but you shouldn't really be extending a JButton unless adding custom functionality):
class Button2 extends JButton {
MainPanel someObj2 = new MainPanel();//you create an instance of MainPanel which isnt even showing and than do changes on that, this way you will never see any of the changes
Button2() {
}
}
A few other suggestions on your code:
Dont extend JButton class unnecessarily, simply create an instance of JButton like you did with JFrame and call methods on JButton instance.
Dont forget to create/manipulate Swing components on Event Dispatch Thread, via SwingUtilities.invokeLater(..) block, read here for more.
Here is your code fixed (above suggestions ect implemented):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
final MainPanel myPanel = new MainPanel();
f.add(myPanel);
JButton button1 = new JButton("Show Animation A");
JButton button2 = new JButton("Show Animation B");
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myPanel.setI(1);
System.out.println("The variable i is now: " + myPanel.i);
myPanel.refreshMe();
}
});
button2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myPanel.setI(2);
System.out.println("The variable i is now: " + myPanel.i);
myPanel.refreshMe();
}
});
myPanel.add(button1);
myPanel.add(button2);
myPanel.checkPanel();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
});
}
}
class MainPanel extends JPanel {
Panel1 p1 = new Panel1();
Panel2 p2 = new Panel2();
public int i = 1; //this is being changed later by clicking JButton
// I use this setter later in actionPerformed in order to change i
public void setI(int i) {
this.i = i;
}
public void refreshMe() {
checkPanel();
revalidate();
repaint();
// Need some help here:
// I don't know what should I write, how to make a repaint of myPanel?
System.out.println("just test, if the method refreshMe working by clicking some button");
}
public void checkPanel() {
if (i == 1) {
this.add(p1);
this.remove(p2);//or it will remain there as this is default flowlayout
} else if (i == 2) {
this.add(p2);
this.remove(p1);
}
}
}
class Panel1 extends JPanel {
public Panel1() {
this.setBackground(Color.BLUE);
// a lot of drawing stuff going on here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
class Panel2 extends JPanel {
public Panel2() {
this.setBackground(Color.GREEN);
// a lot of drawing stuff going on here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
However Id suggest something simpler, fortunately you have 2 choices:
1) Use CardLayout which will allow you to flip between multiple components on a single JFrame/container.
Here is an example I made:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
private final static String PANEL1 = "panel 1";
private final static String PANEL2 = "panel 2";
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel1 = new JPanel();
panel1.add(new JLabel("Panel 1"));
JPanel panel2 = new JPanel();
panel2.add(new JLabel("Panel 2"));
//Create the panel that contains the "cards".
final JPanel cards = new JPanel(new CardLayout());
cards.add(panel1, PANEL1);
cards.add(panel2, PANEL2);
//create button to allow chnage to next card
JButton buttonNext = new JButton(">");
buttonNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
CardLayout cl = (CardLayout) (cards.getLayout());//get cards
cl.next(cards);
}
});
//create button to allow chnage to previous card
JButton buttonPrev = new JButton("<");
buttonPrev.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
CardLayout cl = (CardLayout) (cards.getLayout());//get cards
cl.previous(cards);
}
});
//create panel to hold buttons which will allow switching between cards
JPanel buttonPanel = new JPanel();
buttonPanel.add(buttonPrev);
buttonPanel.add(buttonNext);
frame.add(cards);
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
2) Use removeAll() technique i.e call frame.getContentPane().removeAll() which will remove all components currently on JFrame and than add the new content and call revalidate() and repaint() (also might want to add pack() in there) on JFrame instance to reflect changes. Though Id recommend CardLayout.
I think you can just use CardLayout to implement your function. Please refer to here