How to change CardLayout panels from a separate panel? - java

My software layout is kinda wizard-base. So the base panel is divided into two JPanels. One left panel which never changes. And one right panel that works with CardLayout. It has many sub-panels and show each one of them by a method.
I can easily go from one inner panel to another one. But I want to have a button in left panel and change panels of the right side.
Here is a sample code which you can run it:
BASE:
public class Base {
JFrame frame = new JFrame("Panel");
BorderLayout bl = new BorderLayout();
public Base(){
frame.setLayout(bl);
frame.setSize(800, 600);
frame.add(new LeftBar(), BorderLayout.WEST);
frame.add(new MainPanel(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
// TODO code application logic here
new Base();
}
}
Left side
public class LeftBar extends JPanel{
JButton button;
MainPanel mainPanel = new MainPanel();
public LeftBar(){
setPreferredSize(new Dimension(200, 40));
setLayout(new BorderLayout());
setBackground(Color.black);
button = new JButton("Show Second Page");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
mainPanel.showPanel("secondPage");
}
});
add(button, BorderLayout.NORTH);
}
}
Right Side
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel(){
FirstPage firstPage = new FirstPage(this);
SecondPage secondPage = new SecondPage(this);
setLayout(new GridLayout(0,1));
panelHolder.add(firstPage, "firstPage");
panelHolder.add(secondPage, "secondPage");
cl.show(panelHolder, "firstPage");
add(panelHolder);
}
public void showPanel(String panelIdentifier){
cl.show(panelHolder, panelIdentifier);
}
}
Inner panels for right side:
public class FirstPage extends JPanel {
MainPanel mainPanel;
JButton button;
public FirstPage(MainPanel mainPanel) {
this.mainPanel = mainPanel;
setBackground(Color.GRAY);
button = new JButton("Show page");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
mainPanel.showPanel("secondPage");
}
});
add(button);
}
}
public class SecondPage extends JPanel{
MainPanel mainPanel;
JButton button;
public SecondPage(MainPanel mainPanel){
this.mainPanel = mainPanel;
setBackground(Color.white);
add(new JLabel("This is second page"));
}
}
And this is a picture to give you the idea:
As I explained, I can travel "from first" page to "second page" by using this method: mainPanel.showPanel("secondPage"); or mainPanel.showPanel("firstPage");.
But I also have a JButton in the left bar, which I call the same method to show the second panel of the CardLayout. But it does not work. It doesnt give any error though.
Any idea how to change these CardLayout panels from outside of panels?

The problem is that LeftBar has mainPanel member that is initialized to a new instance of MainPanel. So you have two instances of MainPanel, one allocated in Base and added to the frame, the other one allocated in LeftBar.
So LeftBar executes mainPanel.showPanel("secondPage"); on a second instance of MainPanel which is not even a part of a visual hierarchy. To fix this just pass an existing instance of MainPanel to the constructor of LeftBar. You already do this in FirstPage and SecondPage.

Related

Java GUI switching between panels on button click

I am learning Java and I have to develop an application using a GUI. I have the application working in command line already, but the GUI is driving me insane and costing me in lost hours of head banging and research which is leading nowhere. Can you please help me get the basics working so that i can develop further from there. I want to have a single frame application that can switch between frames on a button click. I created a frame and added three panels P1-P3. These are set as Card Layout (from what i read from forums). Then I added additional panels to these to which i have set colour and buttons.
'''
public class MyMainForm extends JFrame{
private JPanel P1;
private JPanel P2;
private JPanel P3;
private JButton btnFrame1;
private JButton btnFrame2;
private JButton button1;
private JTextField thisIsPanel3TextField;
private JButton btn2Frame1;
private final JFrame frame = new JFrame("MyMain Frame");
public MyMainForm() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(P1);
pack();
setSize(1000,800);
//setLocation(null);
btnFrame1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
P1.setVisible(false);
setContentPane(new MyMainForm().P2);
}
});
btnFrame2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
P2.setVisible(false);
setContentPane(new MyMainForm().P3);
}
});
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
P3.setVisible(false);
setContentPane(new MyMainForm().P2);
}
});
btn2Frame1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
P1.setVisible(false);
setContentPane(new MyMainForm().P3);
}
});
}
public static void main(String[] args) {
MyMainForm MyMainForm = new MyMainForm();
MyMainForm.setVisible(true);
}
}
'''
I can display P2 or P3 with this new code example above. When i try to go from P2 or P3 back to P1 the content pane doesn't show? Do i need to revalidate the content pane for this to work? I really need to be able to go from P1 to P2
The easiest way to do this is to use a CardLayout. Just follow this example:
JFrame frame = new JFrame();
JPanel p1 = new JPanel();
p1.setBackground(Color.RED);
JPanel p2 = new JPanel();
p2.setBackground(Color.WHITE);
JPanel p3 = new JPanel();
p3.setBackground(Color.BLUE);
//Create the panel that contains the "cards".
JPanel cards = new JPanel(new CardLayout());
cards.add(p1, "Panel 1");
cards.add(p2, "Panel 2");
cards.add(p3, "Panel 3");
// Add your card container to the frame
Container pane = frame.getContentPane();
pane.add(cards, BorderLayout.CENTER);
JButton btn = new JButton("Click me!");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed (ActionEvent e) {
CardLayout cl = (CardLayout)(cards.getLayout());
cl.next(cards);
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(btn);
pane.add(btnPanel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
Alternatively, you can switch to a specific panel by calling cl.show(cards, "Panel X") where X is the number of the panel. This is because the swing argument is the name I assigned to each "card" and the show method recalls panels added to CardLayout by name. For your example, each button should have a listener that uses this method to "show" its assigned panel.

Why does calling a JPanel from other class give NullPointerException error?

I am a newbie at Java GUI,and I'm trying to make my first visual game.A window including two buttons pops up when we run the program,and if you click on one of them,the game starts.At first,I had created a class extending JPanel so my first panel would be created and I would create an object of the class and add it to the JFrame.But I needed to change the panel when the buttons would be clicked,so I created a new JPanel object JPanel in my main game class.
Because the second JPanel was created in a different way,I made my first JPanel into a similar JPanel and put getter and setter to my frame class.But the code gives me NullPointerException error.
Here are my classes:
public class Frame {
//The constructor method for frame.
private static JPanel panel;
public Frame () {
JFrame frame = new JFrame();
frame.add(panel); //Adding the panel of the game to the frame.
frame.setTitle("Halma Game"); //The title of the window popped up when the program runs.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static JPanel getPanel() {
return panel;
}
public static void setPanel(JPanel panel) {
Frame.panel = panel;
}
}
public class MenuPanel extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private JButton playButton;
private JButton recordButton;
private JLabel label;
private JPanel panel = new JPanel();
public MenuPanel() {
panel.setBorder(BorderFactory.createEmptyBorder(300,400,300,400));
panel.setLayout(new GridLayout(0,1));
panel.setBackground(Color.decode("255128255"));
playButton = new JButton("New Game");
playButton.setFocusable(false);
playButton.setBackground(Color.PINK);
playButton.setFont(new Font("Ariel",Font.ITALIC,25));
playButton.addActionListener(this); //??? //Mohreha ro ye abstact beheshon bezani khoobe
panel.add(playButton);
recordButton = new JButton("HighScores");
recordButton.setFocusable(false);
recordButton.setBackground(Color.pink);
playButton.setFont(new Font("Ariel",Font.ITALIC,25));
panel.add(recordButton);
label = new JLabel();
}
#Override
public void actionPerformed(ActionEvent e) {
GamePanel game = new GamePanel();
game.start();
}
}
I haven't yet tried the second JPanel on this code,but this one doesn't seem to work.
hi Elena your panel has not been instantiated yet
private static JPanel panel;
when u call
frame.add(panel); //Adding the panel of the game to the frame.

JPanel won't update

I've hit a problem in getting a JPanel to update.
My simple program uses a custom JPanel which displays a label and a textfield. A Jbutton on the main panel is used to replace the JPanel with a new JPanel. The initial panel shows up fine but when the button is pressed the panel is not updated with a new MyPanel. I can tell that a new object is being created as count is being incremented.
public class SwingTest extends JFrame{
private JPanel mp;
private JPanel vp;
private JButton button;
public static void main(String[] args) {
SwingTest st = new SwingTest();
}
public SwingTest() {
vp = new MyPanel();
mp = new JPanel(new BorderLayout());
mp.add(vp, BorderLayout.CENTER);
button = new JButton("Change");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
vp = new MyPanel();
vp.revalidate();
}
});
mp.add(button, BorderLayout.SOUTH);
this.add(mp);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setSize(250, 150);
pack();
setVisible(true);
}
}
and my custom panel....
public class MyPanel extends JPanel{
private JLabel label;
private JTextField tf;
static int count = 0;
public MyPanel(){
count++;
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
setPreferredSize(new Dimension(400, 200));
c.gridx = 0;
c.gridy = 0;
label = new JLabel(String.valueOf(count));
tf = new JTextField(10);
add(label,c);
c.gridx = 1;
add(tf, c);
}
}
You state:
A Jbutton on the main panel is used to replace the JPanel with a new JPanel.
And yet this code:
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
vp = new MyPanel();
vp.revalidate();
}
});
and yet this code does not do this at all. All it does is change the JPanel referenced by the vp variable, but has absolutely no effect on the JPanel that is being displayed by the GUI, which suggests that you're confusing reference variable with reference or object. To change the JPanel that is displayed, you must do exactly this: add the new JPanel into the container JPanel into the BorderLayout.CENTER (default) position, then call revalidate() and repaint() on the container.
e.g.,
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
// vp = new MyPanel();
// vp.revalidate();
mp.remove(vp); // remove the original MyPanel from the GUI
vp = new MyPanel(); // create a new one
mp.add(vp, BorderLayout.CENTER); // add it to the container
// ask the container to layout and display the new component
mp.revalidate();
mp.repaint();
}
});
Or better still -- use a CardLayout to swap views.
Or better still -- simply clear the value held by the JTextField.
For more on the distinction between reference variable and object, please check out Jon Skeet's answer to this question: What is the difference between a variable, object, and reference?

cannot add dynamic jtextfields and save their values

In previos my questions I asked similar questions to this. But in my previous projects I used GUI builder, so now I would like to add JTextField to the Panel dynamically without Builder. I don't why but for some reason I cannot execute this code:
public class Reference {
JFrame frame = new JFrame();
JPanel MainPanel = new JPanel();
MainPanel main = new MainPanel();
JPanel SubPanel = new JPanel();
JButton addButton = new JButton();
JButton saveButton = new JButton();
private List<JTextField> listTf = new ArrayList<JTextField>();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Reference();
}
public Reference() {
frame.add(main);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(addButton, BorderLayout.EAST);
frame.add(saveButton, BorderLayout.WEST);
frame.pack();
frame.setSize(500, 300);
frame.setVisible(true);
main.setLayout(new BorderLayout());
main.setBackground(Color.green);
main.add(SubPanel);
SubPanel.setBackground(Color.yellow);
addButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
main.add(new SubPanel());
main.revalidate();
}
});
saveButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
for (int i = 0; i < main.getComponentCount();) {
SubPanel panel = (SubPanel)main.getComponent(i);
JTextField firstName = panel.getFirstName();
String text = firstName.getText();
System.out.println( text );
}}
});
}
private class SubPanel extends JPanel {
JTextField firstName = new JTextField(15);
public SubPanel() {
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
this.add(firstName);
listTf.add(firstName);
}
public JTextField getFirstName()
{
return firstName;
}
}
public class MainPanel extends JPanel
{
List<SubPanel> subPanels = new ArrayList<SubPanel>();
public MainPanel()
{
}
public void addSubPanel()
{
SubPanel panel = new SubPanel();
add(panel);
subPanels.add(panel);
}
public SubPanel getSubPanel(int index)
{
return subPanels.get(index);
}
}
}
And by saveButton trying to get value of JTextField, but without success. In output I can see just JFrame with 2 Buttons, but ActionListener of addButton and saveButton is not active. I cannot understand where is wrong.
Any help would be much appreciated.
In Swing, the order you do some things is very important, for example...
frame.add(main);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(addButton, BorderLayout.EAST);
frame.add(saveButton, BorderLayout.WEST);
frame.pack();
frame.setSize(500, 300);
frame.setVisible(true);
You add main to your frame
You set the frames layout (!?)
You add your buttons
You pack the frame
You set it's size (!?)
You make it visible
The problem here is step #2. If, instead, we simply remove step #2 (step #4 and #5 aren't great either), you will find that your window now contains main...
frame.add(main);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(addButton, BorderLayout.EAST);
frame.add(saveButton, BorderLayout.WEST);
frame.pack();
frame.setVisible(true);
This...
for (int i = 0; i < main.getComponentCount();) {
SubPanel panel = (SubPanel) main.getComponent(i);
a bad idea of three reasons;
Your loop will never advance (i will always be 0)
You are blindly casting the contents of main without actually knowing what's on it
MainPanel already has a List of SubPanels...
You need to make sure that you are adding SubPanels via the addSubPanel method (and this should probably return an instance of the SubPanel) and provide a means by which you can access this List, maybe via a getter of some sort. Although, I'd be more interested in their values (ie the text field text) rather then the SubPanel itself ;)

Update label of a JPanel when change the value of one variable from another JPanel

I am new on Java.
I have developed an application with some different JPanels (using a BorderLayout, 3 panels in this case).
In panel 1, I have a JLabel and a variable (a class) that is related with its value (method get);
in panel 2, I updated the value of the variable (method set) because it is done when an action is performed in this second panel.
How Could I get the value of the JLabel in panel 1 updated?
I don't know how to trigger an event or something similar after updating the value from panel 2 and how to make panel 1 to listen to this change.
Let me explain a bit more. I have a JFrame with two JPanels and I update the model from one panel. Once the model is updated, the JLabel from the other JPanel should be updated:
Main: JFrame
public class MainClass extends JFrame
{
public MainClass()
{
// JPanel 1
....
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,300);
setLocationRelativeTo(null);
setTitle("Test");
setResizable(false);
setVisible(true);
// JPanel 1
this.add(west, BorderLayout.WEST);
// JPanel 2
this.add(board, BorderLayout.CENTER);
}
public static void main(String[] args)
{
// put your code here
new MainClass ();
}
}
JPanel 1
public class West extends JPanel
{
contFase = new Contador(titulo, valor);
JLabel lblTitulo;
...
lblTitulo.setText = contFase.getText();
this.add(lblTitulo);
...
}
JPanel 2
public class Board extends JPanel implements ActionListener
{
....
public void actionPerformed(ActionEvent e)
{
...
//Here Label of panel 1 should be updated with the model
contFase.setValor(contFase.getValor() + pacman.comerElemento(fase.getPacdots(), fase.getPowerPellets()));
...
}
}
I have little idea how your code looks like because you didn't show any, but here is an example of how to edit a JLabel when an action is taken (in this case - pressing a button). The layout of the components on panels does not matter, but I put 2 panels like you wanted.
public class ValueUpdate extends JFrame {
int x = 0;
final JLabel label = new JLabel(String.valueOf(x));
ValueUpdate() {
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
panel1.add(label);
JButton btn = new JButton("Increment");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
x++;
label.setText(String.valueOf(x));
}
});
panel2.add(btn);
getContentPane().add(panel1, BorderLayout.CENTER);
getContentPane().add(panel2, BorderLayout.PAGE_END);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args) {
new ValueUpdate();
}
}

Categories

Resources