Search code examples
javaswingactionlistenercardlayout

Java ActionListener not working but no errors


So, I have been trying to learn how to work with WindowBuilder for the last month. I have watched a few YouTube videos especially about CardLayout, but my buttons don't seem to change the panels.

I'm actually aiming for a runnable game, but since I don't know where exactly to start, I have decided to code the part of the changing panel first.(sb told me my code wasn't exactly good for a game)

I want the panel to change when the player clicks on "New Game". It gave me errors at first, but after a few changes, it doesn't even give errors. So here is my code:

package halma.views;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import java.awt.Color;
import javax.swing.LayoutStyle.ComponentPlacement;
import java.awt.CardLayout;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 

public class MainFrame extends JFrame {

    private JPanel contentPane;
    private JPanel returnBar_panel;
    private JPanel gameBar_panel;
    private JPanel startupReturnBar_Panel;
    private JPanel returnGame_Panel;
    private JPanel gameGUI_Panel;
    private JPanel startupGameBar_Panel;
    private JButton playButton;
    private JButton highScoresButton;
    private JButton exitButton;
    private JPanel resumeReturn_Panel;
    
    static ActionListeners action = new ActionListeners();

    
    CardLayout cardLayout1;  //Used for the buttons' actionlistener.
    CardLayout cardLayout2;
    
    
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        
        
    }

    //The constructor method.
    public MainFrame() {
        createFrame();
        
        cardLayout1 = (CardLayout)(returnBar_panel.getLayout());
        cardLayout2 = (CardLayout)(gameBar_panel.getLayout());
    }
    
    
    
    //The getters and setters that are required for other classes to use the private variables in the "MainFrame" class.
    
    public JButton getPlayButton() {
        return playButton;
    }

    public JPanel getReturnBar_panel() {
        return returnBar_panel;
    }

    public void setReturnBar_panel(JPanel returnBar_panel) {
        this.returnBar_panel = returnBar_panel;
    }

    public JPanel getReturnGame_Panel() {
        return returnGame_Panel;
    }

    public void setReturnGame_Panel(JPanel returnGame_Panel) {
        this.returnGame_Panel = returnGame_Panel;
    }

    public JPanel getGameGUI_Panel() {
        return gameGUI_Panel;
    }

    public void setGameGUI_Panel(JPanel gameGUI_Panel) {
        this.gameGUI_Panel = gameGUI_Panel;
    }

    public void setPlayButton(JButton playButton) {
        this.playButton = playButton;
    }

    public JPanel getResumeReturn_Panel() {
        return resumeReturn_Panel;
    }

    public void setResumeReturn_Panel(JPanel resumeReturn_Panel) {
        this.resumeReturn_Panel = resumeReturn_Panel;
    }

    
    
    //Runs the game.
    public static void runGame() {
        
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MainFrame frame = new MainFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    
    
    //Creating the frame.
    
    public void createFrame() {
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 527, 374);
        setSize(800, 600);
        contentPane = new JPanel();
        contentPane.setBackground(new Color(255, 192, 203));
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        
        returnBar_panel = new JPanel();
        returnBar_panel.setBackground(new Color(255, 192, 203));
        
        gameBar_panel = new JPanel();
        gameBar_panel.setBackground(new Color(255, 192, 203));
        GroupLayout gl_contentPane = new GroupLayout(contentPane);
        gl_contentPane.setHorizontalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_contentPane.createSequentialGroup()
                    .addComponent(returnBar_panel, GroupLayout.PREFERRED_SIZE, 155, GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(ComponentPlacement.RELATED)
                    .addComponent(gameBar_panel, GroupLayout.DEFAULT_SIZE, 603, Short.MAX_VALUE)
                    .addContainerGap())
        );
        gl_contentPane.setVerticalGroup(
            gl_contentPane.createParallelGroup(Alignment.LEADING)
                .addComponent(returnBar_panel, GroupLayout.DEFAULT_SIZE, 551, Short.MAX_VALUE)
                .addComponent(gameBar_panel, GroupLayout.DEFAULT_SIZE, 551, Short.MAX_VALUE)
        );
        gameBar_panel.setLayout(new CardLayout(0, 0));
        
        startupGameBar_Panel = new JPanel();
        
        startupGameBar_Panel.setBackground(new Color(255, 192, 203));
        gameBar_panel.add(startupGameBar_Panel, "name_328512842567600");
        
        playButton = new JButton("New Game");
        playButton.setFocusable(false);
        playButton.setBackground(new Color(255, 160, 122));
        playButton.setForeground(new Color(0, 0, 0));
        playButton.setFont(new Font("Comic Sans MS", Font.ITALIC, 12));
        playButton.addActionListener(action);
        
        
        highScoresButton = new JButton("Records");
        highScoresButton.setForeground(new Color(0, 0, 0));
        highScoresButton.setFocusable(false);
        highScoresButton.setFont(new Font("Comic Sans MS", Font.ITALIC, 12));
        highScoresButton.setBackground(new Color(255, 160, 122));
        
        exitButton = new JButton("Exit");
        exitButton.setForeground(new Color(0, 0, 0));
        exitButton.setFocusable(false);
        exitButton.setFont(new Font("Comic Sans MS", Font.ITALIC, 12));
        exitButton.setBackground(new Color(255, 160, 122));
        GroupLayout gl_startupGameBar_Panel = new GroupLayout(startupGameBar_Panel);
        gl_startupGameBar_Panel.setHorizontalGroup(
            gl_startupGameBar_Panel.createParallelGroup(Alignment.LEADING)
                .addGroup(Alignment.TRAILING, gl_startupGameBar_Panel.createSequentialGroup()
                    .addContainerGap(490, Short.MAX_VALUE)
                    .addGroup(gl_startupGameBar_Panel.createParallelGroup(Alignment.TRAILING, false)
                        .addComponent(exitButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(highScoresButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(playButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGap(24))
        );
        gl_startupGameBar_Panel.setVerticalGroup(
            gl_startupGameBar_Panel.createParallelGroup(Alignment.LEADING)
                .addGroup(Alignment.TRAILING, gl_startupGameBar_Panel.createSequentialGroup()
                    .addContainerGap(341, Short.MAX_VALUE)
                    .addComponent(playButton)
                    .addGap(18)
                    .addComponent(highScoresButton)
                    .addGap(18)
                    .addComponent(exitButton)
                    .addGap(105))
        );
        startupGameBar_Panel.setLayout(gl_startupGameBar_Panel);
        
        gameGUI_Panel = new JPanel();
        gameGUI_Panel.setBackground(Color.RED);
        gameBar_panel.add(gameGUI_Panel, "name_328347141657400");
        gameGUI_Panel.setLayout(new CardLayout(0, 0));
        returnBar_panel.setLayout(new CardLayout(0, 0));
        
        setStartupReturnBar_Panel(new JPanel());
        getStartupReturnBar_Panel().setBackground(new Color(255, 192, 203));
        returnBar_panel.add(getStartupReturnBar_Panel(), "name_328000881526100");
        
        returnGame_Panel = new JPanel();
        returnGame_Panel.setBackground(new Color(255, 192, 203));
        returnBar_panel.add(returnGame_Panel, "name_328006822278900");
        
        resumeReturn_Panel = new JPanel();
        resumeReturn_Panel.setBackground(Color.PINK);
        returnBar_panel.add(resumeReturn_Panel, "name_331156929215800");
        resumeReturn_Panel.setLayout(new CardLayout(0, 0));
        JPanel panel2 = new JPanel();
        contentPane.setLayout(gl_contentPane);
    }

    public JPanel getStartupReturnBar_Panel() {
        return startupReturnBar_Panel;
    }

    public void setStartupReturnBar_Panel(JPanel startupReturnBar_Panel) {
        this.startupReturnBar_Panel = startupReturnBar_Panel;
    }




package halma.views;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ActionListeners extends MainFrame implements ActionListener {
    /**
     * 
     */
    private static final long serialVersionUID = 814839576128286295L;
    MainFrame frame = new MainFrame();
    
    public ActionListeners() {
        
        frame.runGame();
        
        
        
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("meow!");
        frame.cardLayout1.show(frame.getReturnBar_panel(), "resumeReturn_Panel");

        if(e.getSource() == frame.getPlayButton()) {
            System.out.println("T");
            frame.cardLayout1.show(frame.getReturnBar_panel(), "resumeReturn_Panel");
            frame.cardLayout2.show(frame.getGameGUI_Panel(), "Playing");
        }
    }
}

In the Second class, the word "Meow" gets printed, but the panel doesn't change even if I put it out of the if-statement. And the letter T doesn't get printed.


Solution

  • Why would you want an ActionListener to have a Frame? Wouldn't it it make more sense for a Frame to have an ActionListener? Even for a frame to have an action listener makes little sense. You want the component receiving the user action (the source object) to contain the listener. For example, if a user clicks on a button, you want that button to react to the action initiated by the user. For instance, if you have a button that should display "hello" in the console when clicked by the user, you would do something like this:

    helloBtn.addActionListener(listener);
    

    Then, your listener should look something like this:

    public class HelloMsgListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Hello!");
        }
    }
    

    When your listener is this simple, it might make more sense to add it as an anonymous entity.

    The code you wrote is very messy. You created a listener that has a frame, but that frame is not the instance that has the component that contains the listener with the frame.

    The way to fix this is to create a class that creates the frame and runs your application

    public class MyApp {
        
        public static void main (String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                
                @Override
                public void run () {
                    createAndShowGUI();
                }
    
                private void createAndShowGUI () {
                    JFrame frame = new JFrame();
                    ...
                    frame.setVisible(true);
                    // Create the rest of the components and add to frame
                    playButton.addActionListener(new ActionListener() {
                    
                        @Override
                        public void actionPerformed (ActionEvent e) {
                            System.out.println("meow!");
                            frame.cardLayout1.show(frame.getReturnBar_panel(),
                                "resumeReturn_Panel");
                        
                            if (e.getSource() == frame.getPlayButton()) {
                                System.out.println("T");
                                frame.cardLayout1.show(frame.getReturnBar_panel(),
                                    "resumeReturn_Panel");
                                frame.cardLayout2.show(frame.getGameGUI_Panel(), "Playing");
                            }
                        }
                    });
                }
            });
        }
    }
    

    Then, you create your button