The button on my screen won't switch me toward

2019-08-05 19:51发布

问题:

The button on my screen won't track me towards my GamePane class. I think it's because of the ActionListener. I have also heard of using a MouseListener but I don't know what that is.

GameFrame:

The GameFrame holds the component for the game screen. This screen won't show up when the start button is pressed.

import java.awt.CardLayout;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class GamePane extends JPanel {// *change GamePane to GamePane
    // This is were the game screen is made and the player is created.

    private static final long serialVersionUID = 1L;
    JLabel player = new JLabel();
    int playerSpeed = 1;
    int FPS = 30;

    // Set the timer
    // Timer tm = new Timer(1000 / FPS, this);
    // tm.start();

    // The keys set holds the keys being pressed
    private final Set<Integer> keys = new HashSet<>();

    public static void main(String[] args) {
        // Open the GUI window
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                // Create a new object and
                // run its go() method
                new GamePane().go();
            }
        });
    }

    GamePane() {
        // Run the parent class constructor
        super();
        // Allow the panel to get focus
        setFocusable(true);
        // Don't let keys change the focus
        setFocusTraversalKeysEnabled(false);
    }

    /**
     * The frame that shows my game
     */
    protected void go() {
        // Setup the window
        JFrame GameFrame = new JFrame();
        // Add this panel to the window
        GameFrame.setLayout(new CardLayout());
        GameFrame.setContentPane(this);

        // Set the window properties
        GameFrame.setTitle("game");
        GameFrame.setSize(800, 400);
        GameFrame.setLocationRelativeTo(null);
        GameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GameFrame.setVisible(true);
        GameFrame.add(new ButtonPane(GameFrame), "game");
    }
}

ButtonPane:

This is were the pane containing the button is created. The button is also created in the button pane.

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class ButtonPane extends JPanel {
    private static final long serialVersionUID = 1L;
    private JButton startBTN;//Calls the JButton
    JFrame game;

    public ButtonPane(JFrame MainFrame) {
        game = MainFrame;
        setLayout(new GridBagLayout());
        MainFrame.setBackground(Color.BLUE);//Sets the menu stages color blue
        startBTN = new JButton("Start");//Creates a new button
        add(startBTN);//Adds the button on the startStage

        startBTN.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button pressed");
//                ((CardLayout) game.getContentPane().getLayout()).show(game.getContentPane(), "game");
                if (game.getContentPane().getLayout() instanceof CardLayout) {
                    System.out.println("is card layout");
                    CardLayout layout = (CardLayout) getParent().getLayout();
                    layout.show(game.getContentPane(), "game");
                }
            }
        });
    }
}

回答1:

There is to much going on in your code and too much "guess work". You've also coupled you code together making it near impossible to maintain or manage.

Step back and reassess you design. You need:

  • A container which acts as the "main view", this is the container which is used to switch between various views, it acts as the main "controller" for the navigation
  • A menu component
  • A game component
  • A frame to hold the "main view"

Let's start with the frame. The frame should be as dumb as possible. It's sole job is to get the "main view" on the screen, very little else

Maybe something like...

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        JFrame frame = new JFrame();
        frame.add(new MainPane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
});

The MainPane (or main view) doesn't care about the frame, so we don't need to pass anything else to it. Because the "main view" is acting as our navigation controller, you want to avoid exposing it to other views. Those views shouldn't care how the navigation works, only that they can move between views.

So, instead of passing MainPane to the subviews, we create a concept of "navigation controller" which is used to allow the subviews to make requests about what they would like to do, it's then up to the implementation to make that work.

public interface NavigationController {
    public void showGame();
    public void showMenu();
}

MainPane then acts as the "main container" for all the other top level subviews and the NavigationController

public class MainPane extends JPanel implements NavigationController {

    public MainPane() {
        setLayout(new CardLayout());
        add(new MenuPane(this), "menu");
        add(new GamePane(this), "game");
    }

    protected CardLayout getCardLayout() {
        return (CardLayout) getLayout();
    }

    @Override
    public void showGame() {
        getCardLayout().show(this, "game");
    }

    @Override
    public void showMenu() {
        getCardLayout().show(this, "menu");
    }

}

It's whole responsibility is to facilitate the switching between the top level subviews

Then our subviews....

public class MenuPane extends JPanel {

    private NavigationController controller;

    public MenuPane(NavigationController controller) {
        this.controller = controller;
        setLayout(new GridBagLayout());
        JButton btn = new JButton("Do you want to play a game?");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.showGame();
            }
        });
        add(btn);
    }

}

public class GamePane extends JPanel {

    private NavigationController controller;

    public GamePane(NavigationController controller) {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        add(new JLabel("Ready player one"), gbc);

        gbc.weighty = 0;
        JButton btn = new JButton("Had enough");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.showMenu();
            }
        });
        add(btn, gbc);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

}

These views do a single job (what ever that job is) and delegate the navigation responsibility back to the NavigationController

If you're wondering, MenuPane would be your equivalent of ButtonPane

Runnable Example...

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public interface NavigationController {

        public void showGame();

        public void showMenu();
    }

    public class MainPane extends JPanel implements NavigationController {

        public MainPane() {
            setLayout(new CardLayout());
            add(new MenuPane(this), "menu");
            add(new GamePane(this), "game");
        }

        protected CardLayout getCardLayout() {
            return (CardLayout) getLayout();
        }

        @Override
        public void showGame() {
            getCardLayout().show(this, "game");
        }

        @Override
        public void showMenu() {
            getCardLayout().show(this, "menu");
        }

    }

    public class MenuPane extends JPanel {

        private NavigationController controller;

        public MenuPane(NavigationController controller) {
            this.controller = controller;
            setLayout(new GridBagLayout());
            JButton btn = new JButton("Do you want to play a game?");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    controller.showGame();
                }
            });
            add(btn);
        }

    }

    public class GamePane extends JPanel {

        private NavigationController controller;

        public GamePane(NavigationController controller) {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            add(new JLabel("Ready player one"), gbc);

            gbc.weighty = 0;
            JButton btn = new JButton("Had enough");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    controller.showMenu();
                }
            });
            add(btn, gbc);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}


标签: java graphics